Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lex.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ version = "0.1.0"
lex = "0.9.7"

[dependencies]
"lex-llm" = { path = "../lex-llm" }
"lex-agent" = { path = "../lex-agent" }
"lex-trail" = { path = "../lex-trail" }
"lex-spec" = { path = "../lex-spec" }
"lex-schema" = { path = "../lex-schema" }
lex-llm = { git = "https://github.com/alpibrusl/lex-llm" }
lex-agent = { git = "https://github.com/alpibrusl/lex-agent" }
lex-trail = { git = "https://github.com/alpibrusl/lex-trail" }
lex-spec = { git = "https://github.com/alpibrusl/lex-spec" }
lex-schema = { git = "https://github.com/alpibrusl/lex-schema" }
lex-os-manifest = { git = "https://github.com/alpibrusl/lex-os-manifest" }
lex-web = { git = "https://github.com/alpibrusl/lex-web" }
Comment on lines +7 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: these new Git dependencies are unpinned and there is no lockfile in this repo. Future installs/builds will resolve mutable default branches from these remote repos, so a compromised repo or force-pushed branch can inject code into lex-code builds. Pin each dependency to an immutable commit/tag, and commit a lockfile if Lex supports one.


[bin]
name = "lex-code"
Expand Down
11 changes: 9 additions & 2 deletions src/agents/build.lex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import "lex-llm/provider" as prov

import "lex-llm/providers" as providers

import "lex-llm/providers/vertex" as vtx

import "../tools/index" as tools

import "../permissions/rules" as rules
Expand All @@ -20,7 +22,7 @@ fn agent() -> [env] ag.AgentDef {
}

fn openai_agent() -> [env] ag.AgentDef {
let base := { name: "build", goal: bpo.system(), model: prov.gpt55(), provider: providers.openai(), tools: tools.all_tools(), options: { temperature: None, top_p: None, max_steps: Some(50), max_tokens: None }, permission_spec: None }
let base := { name: "build", goal: bpo.system(), model: prov.gpt4o(), provider: providers.openai(), tools: tools.all_tools(), options: { temperature: None, top_p: None, max_steps: Some(50), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.build_permission())
}

Expand All @@ -30,7 +32,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "build", goal: bpo.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: list.concat(tools.standard_tools(), tools.lex_cli_tools()), options: { temperature: None, top_p: None, max_steps: Some(10), max_tokens: None }, permission_spec: None }
let base := { name: "build", goal: bpo.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.all_tools(), options: { temperature: None, top_p: None, max_steps: Some(20), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.build_permission())
}

Expand All @@ -44,3 +46,8 @@ fn google_agent() -> [env] ag.AgentDef {
ag.with_permission_gate(base, rules.build_permission())
}

fn vertex_agent() -> [env] ag.AgentDef {
let base := { name: "build", goal: bpo.system(), model: vtx.gemini_35_flash(), provider: providers.vertex(), tools: tools.all_tools(), options: { temperature: None, top_p: None, max_steps: Some(50), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.build_permission())
}

2 changes: 1 addition & 1 deletion src/agents/explore.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "explore", goal: ep.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.explore_permission()), options: { temperature: None, top_p: None, max_steps: Some(20), max_tokens: None }, permission_spec: None }
let base := { name: "explore", goal: ep.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.explore_permission())
}

Expand Down
4 changes: 2 additions & 2 deletions src/agents/plan.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "plan", goal: pp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.plan_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
let base := { name: "plan", goal: pp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.plan_permission())
}

Expand All @@ -31,7 +31,7 @@ fn vllm_agent() -> [env] ag.AgentDef {
}

fn openai_agent() -> [env] ag.AgentDef {
let base := { name: "plan", goal: pp.system(), model: prov.gpt55(), provider: providers.openai(), tools: tools.tools_for_spec(rules.plan_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
let base := { name: "plan", goal: pp.system(), model: prov.gpt4o(), provider: providers.openai(), tools: tools.tools_for_spec(rules.plan_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.plan_permission())
}

Expand Down
4 changes: 2 additions & 2 deletions src/agents/refactor.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "refactor", goal: rp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.refactor_permission()), options: { temperature: None, top_p: None, max_steps: Some(40), max_tokens: None }, permission_spec: None }
let base := { name: "refactor", goal: rp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.refactor_permission())
}

Expand All @@ -31,7 +31,7 @@ fn vllm_agent() -> [env] ag.AgentDef {
}

fn openai_agent() -> [env] ag.AgentDef {
let base := { name: "refactor", goal: rp.system(), model: prov.gpt55(), provider: providers.openai(), tools: tools.tools_for_spec(rules.refactor_permission()), options: { temperature: None, top_p: None, max_steps: Some(40), max_tokens: None }, permission_spec: None }
let base := { name: "refactor", goal: rp.system(), model: prov.gpt4o(), provider: providers.openai(), tools: tools.tools_for_spec(rules.refactor_permission()), options: { temperature: None, top_p: None, max_steps: Some(40), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.refactor_permission())
}

Expand Down
4 changes: 2 additions & 2 deletions src/agents/review.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "review", goal: rvp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.review_permission()), options: { temperature: None, top_p: None, max_steps: Some(25), max_tokens: None }, permission_spec: None }
let base := { name: "review", goal: rvp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.review_permission())
}

Expand All @@ -31,7 +31,7 @@ fn vllm_agent() -> [env] ag.AgentDef {
}

fn openai_agent() -> [env] ag.AgentDef {
let base := { name: "review", goal: rvp.system(), model: prov.gpt55(), provider: providers.openai(), tools: tools.tools_for_spec(rules.review_permission()), options: { temperature: None, top_p: None, max_steps: Some(25), max_tokens: None }, permission_spec: None }
let base := { name: "review", goal: rvp.system(), model: prov.gpt4o(), provider: providers.openai(), tools: tools.tools_for_spec(rules.review_permission()), options: { temperature: None, top_p: None, max_steps: Some(25), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.review_permission())
}

Expand Down
4 changes: 2 additions & 2 deletions src/agents/spec_agent.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "spec", goal: sp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.spec_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
let base := { name: "spec", goal: sp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.spec_permission())
}

Expand All @@ -31,7 +31,7 @@ fn vllm_agent() -> [env] ag.AgentDef {
}

fn openai_agent() -> [env] ag.AgentDef {
let base := { name: "spec", goal: sp.system(), model: prov.gpt55(), provider: providers.openai(), tools: tools.tools_for_spec(rules.spec_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
let base := { name: "spec", goal: sp.system(), model: prov.gpt4o(), provider: providers.openai(), tools: tools.tools_for_spec(rules.spec_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.spec_permission())
}

Expand Down
2 changes: 1 addition & 1 deletion src/agents/test_agent.lex
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn mistral_agent() -> [env] ag.AgentDef {
}

fn ollama_agent() -> [env] ag.AgentDef {
let base := { name: "test", goal: tp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: tools.tools_for_spec(rules.test_permission()), options: { temperature: None, top_p: None, max_steps: Some(30), max_tokens: None }, permission_spec: None }
let base := { name: "test", goal: tp.system(), model: prov.ollama(providers.ollama_model()), provider: providers.ollama_local(), tools: [], options: { temperature: None, top_p: None, max_steps: Some(3), max_tokens: None }, permission_spec: None }
ag.with_permission_gate(base, rules.test_permission())
}

Expand Down
97 changes: 97 additions & 0 deletions src/permissions/manifests.lex
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Per-mode trust manifests for lex-os integration.
#
# Each AgentMode maps to a Grant that constrains what the mode can do
# on the three trust dimensions: filesystem, network, exec.
#
# Grant levels (from lex-types):
# filesystem: None | ReadOnly | ReadWrite | Full
# network: None | Loopback | Allowlist | Full
# exec: None | Sandboxed | Full
#
# Manifests are written to /tmp at call time and passed to `lex-os check`.

import "std.str" as str

import "std.int" as int

import "std.io" as io

fn manifest_json(goal :: Str, filesystem :: Str, network :: Str, exec_level :: Str, floor :: Str, wall :: Int, cmds :: Int, money :: Int, api_calls :: Int) -> Str {
str.join([
"{\"goal\":{\"description\":\"", goal, "\"},",
"\"grant\":{\"filesystem\":\"", filesystem, "\",\"network\":\"", network, "\",\"exec\":\"", exec_level, "\"},",
"\"budget\":{\"wall_clock_secs\":", int.to_str(wall), ",",
"\"max_commands\":", int.to_str(cmds), ",",
"\"max_money_cents\":", int.to_str(money), ",",
"\"max_api_calls\":", int.to_str(api_calls), "},",
"\"isolation_floor\":\"", floor, "\",\"egress\":[]}"
], "")
}

fn explore_manifest_json() -> Str {
manifest_json("lex-code explore mode", "ReadOnly", "None", "None", "Namespace", 300, 200, 0, 50)
}

fn plan_manifest_json() -> Str {
manifest_json("lex-code plan mode", "ReadOnly", "None", "None", "Namespace", 300, 200, 0, 50)
}

fn review_manifest_json() -> Str {
manifest_json("lex-code review mode", "ReadOnly", "None", "None", "Namespace", 300, 200, 0, 50)
}

fn spec_manifest_json() -> Str {
manifest_json("lex-code spec mode", "ReadWrite", "None", "None", "Namespace", 300, 200, 0, 50)
}

fn test_manifest_json() -> Str {
manifest_json("lex-code test mode", "ReadWrite", "None", "Sandboxed", "Gvisor", 300, 200, 0, 50)
}

fn refactor_manifest_json() -> Str {
manifest_json("lex-code refactor mode", "ReadWrite", "None", "Sandboxed", "Gvisor", 300, 200, 0, 50)
}

fn build_manifest_json() -> Str {
manifest_json("lex-code build mode", "Full", "Allowlist", "Full", "MicroVm", 600, 500, 500, 100)
}

fn json_for_mode(mode :: Str) -> Str {
if mode == "explore" {
explore_manifest_json()
} else {
if mode == "plan" {
plan_manifest_json()
} else {
if mode == "review" {
review_manifest_json()
} else {
if mode == "spec" {
spec_manifest_json()
} else {
if mode == "test" {
test_manifest_json()
} else {
if mode == "refactor" {
refactor_manifest_json()
} else {
build_manifest_json()
}
}
}
}
}
}
}

fn temp_path_for_mode(mode :: Str) -> Str {
str.concat("/tmp/lex-code-manifest-", str.concat(mode, ".json"))
}

fn write_manifest_for_mode(mode :: Str) -> [io] Result[Str, Str] {
let path := temp_path_for_mode(mode)
match io.write(path, json_for_mode(mode)) {
Ok(_) => Ok(path),
Err(e) => Err(e),
}
}
2 changes: 1 addition & 1 deletion src/permissions/rules.lex
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn spec_permission() -> sp.Spec {
}

fn refactor_permission() -> sp.Spec {
allow_tools("refactor_tools", list.concat(["read", "write", "edit", "grep", "glob", "bash", "lex_check", "lex_audit", "sigid_lookup", "effects_of", "lex_store_diff", "lex_store_apply", "lex_store_merge"], list.concat(vcs_read_names(), vcs_write_names())))
allow_tools("refactor_tools", list.concat(["read", "write", "edit", "grep", "glob", "bash", "lex_check", "os_check", "lex_audit", "sigid_lookup", "effects_of", "lex_store_diff", "lex_store_apply", "lex_store_merge"], list.concat(vcs_read_names(), vcs_write_names())))
}

fn test_permission() -> sp.Spec {
Expand Down
9 changes: 9 additions & 0 deletions src/server/session.lex
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ fn pick_agent(mode :: AgentMode, provider_tag :: Str) -> [env] ag.AgentDef {
Test => test_a.vllm_agent(),
Review => review_a.vllm_agent(),
},
"vertex" => match mode {
Build => build_agent.vertex_agent(),
Plan => plan_agent.google_agent(),
Explore => explore_agent.google_agent(),
Refactor => refactor_agent.google_agent(),
Spec => spec_a.google_agent(),
Test => test_a.google_agent(),
Review => review_a.google_agent(),
},
_ => match mode {
Build => build_agent.agent(),
Plan => plan_agent.agent(),
Expand Down
4 changes: 3 additions & 1 deletion src/tools/index.lex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import "./standard/todowrite" as todo_tool

import "./lex_check" as check_tool

import "./os_check" as os_check_tool

import "./lex_audit" as audit_tool

import "./lex_run" as run_tool
Expand Down Expand Up @@ -99,7 +101,7 @@ fn vcs_tools() -> List[t.Tool] {
}

fn all_tools() -> List[t.Tool] {
list.concat([read_tool.tool(), write_tool.tool(), edit_tool.tool(), grep_tool.tool(), glob_tool.tool(), bash_tool.tool(), todo_tool.tool(), check_tool.tool(), audit_tool.tool(), run_tool.tool(), test_tool.tool(), spec_check_tool.tool(), spec_smt_tool.tool(), sigid_tool.tool(), attest_tool.tool(), effects_tool.tool(), store_diff_tool.tool(), store_apply_tool.tool(), store_merge_tool.tool(), guidelines_tool.tool()], vcs_tools())
list.concat([read_tool.tool(), write_tool.tool(), edit_tool.tool(), grep_tool.tool(), glob_tool.tool(), bash_tool.tool(), todo_tool.tool(), check_tool.tool(), os_check_tool.tool(), audit_tool.tool(), run_tool.tool(), test_tool.tool(), spec_check_tool.tool(), spec_smt_tool.tool(), sigid_tool.tool(), attest_tool.tool(), effects_tool.tool(), store_diff_tool.tool(), store_apply_tool.tool(), store_merge_tool.tool(), guidelines_tool.tool()], vcs_tools())
}

fn tools_for_spec(spec :: sp.Spec) -> List[t.Tool] {
Expand Down
Loading
Loading