Skip to content

feat(agents): add a Letta Code agent - #368

Merged
earakely-scale merged 14 commits into
mainfrom
letta-code-agent
Oct 28, 2026
Merged

earakely-scale merged 14 commits into
mainfrom
letta-code-agent

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Supersedes #345, by @sarahwooders, so that CI and review can run on a branch of this repository. The commits from #345 are kept unchanged. Three commits on top address the reviews' findings and a slow turn found end to end.

What and why

Adds agents/letta-code/, a Letta Code agent built the same way as the other CLI agents, alongside OpenCode. Tasks can name it as letta-code (alias in aliases.toml) or as @local/agentenv-framework/agents/letta-code.

  • How it runs: each turn is one headless letta --backend local -p ... --output-format stream-json run in /app, and its stream-json events are the turn's trajectory.
  • Model endpoint: the local backend calls the task's [model] endpoint, $LITELLM_BASE_URL/v1, as an OpenAI-compatible provider, through a per-turn relay that adds [model.headers] and the run's attribution. No Letta account or server is needed.
  • Memory across turns: a context's first task creates a Letta agent and conversation, and later tasks resume the same conversation. The agent's memory therefore persists across a context's turns, and snapshot/v1 save/load carries it to another context.
  • MCP: the task env's MCP servers, including peer_agents, are exposed to the model as direct tools.
  • Image and release: Node and the CLI are pinned by checksum and package-lock.json (Letta Code 0.34.26). git is included because Letta Code keeps agent memory in git. The image is registered in the release's image build and dependabot lists, and install/v1 covers containers and vm hosts.
  • Smoke task: letta-code-smoke is added.

The agent's README.md has the Extension | Implementation table. agent-config, mcp-config, peer-agents, skill-config, trajectory, snapshot, attribution-probe and install are implemented; staging/v1 is the SDK default.

The fix on top (b66a98d)

The review on #345 had three open findings:

  • A load cancelled during its swap kept the old conversation reference. The swap and the binding of the restored conversation now run in one shielded step, shielded(swap()). So a cancel that waits out the swap still leaves the restored files with their conversation.

  • A cancelled restore or changelog write kept writing after the lock was released. Every file thread that runs under the workspace or changelog lock now goes through shielded_thread:

    • the save's workspace archive;
    • the load's extract into its temporary directory;
    • the changelog's captures, baseline and applies.

    A cancel therefore waits for the thread before it releases the lock or removes the directory. A turn's attachment download is left as it was, so a cancelled turn still stops at once.

  • Magic numbers in mcp_tools.ts. The call timeout and output limit are named, MCP_CALL_TIMEOUT_MS and MCP_CALL_MAX_OUTPUT_BYTES.

shielded_thread is now shielded(asyncio.to_thread(...)), and shielded takes any awaitable. 8cb6e00 keeps its wait shielded through a repeated cancel too, and names the context dir's hash length and an attachment's prefix length.

The relay lists only the turn's model (196a183)

Over an OpenAI-compatible endpoint that lists 3006 models, a one-word reply took 50–98 s. That made the validator's concurrent 120 s prompts time out, so it exited 1.

A CPU profile put 45 of letta agents create's 48 s in the CLI's currentModels. It merges each listed model into its own list with a scan of them all, and every command that loads models runs it, including every turn's -p run.

The per-turn relay now answers GET /v1/models with the turn's model alone, without asking the endpoint, so each turn takes about 4 s:

Step Before After
agents create 47.7 s 1.0 s
Turn 1 / turn 2 98.1 s / 48.2 s 4.2 s / 4.2 s

How it was tested

From #345: agent-env a2a-agent validate --id letta-code --sandbox local exits 0, and agent-env run agents --task letta-code-smoke passes. Both ran with openai/gpt-4.1-mini through an OpenAI-compatible endpoint, on Docker 20.10. make lint and make unit-test pass, and check_plugin_api.py reports no break.

On top of that:

Command Result
pytest tst/unit/agents/letta_code 15 passed; each new cancellation test fails without its fix
pytest -n 4 tst/unit/agents tst/unit/bundle/shipped_bundles_test.py tst/unit/test_infra_images_script.py 805 passed, 45 skipped
ruff check All checks passed

End to end, on a 4-vCPU Ubuntu 24.04 VM, with Docker Engine 29.1 from the distribution and openai/gpt-4.1-mini through the endpoint above:

Command Result
agent-env run agents --task letta-code-smoke passed; the prompt step took 8.2 s
agent-env a2a-agent validate --id letta-code --sandbox local exit 0 in 138 s, no timeouts
The same, after agent-env run agents --task claude-code-smoke puts the recall judge in the store exit 0 in 140 s, and again in 136 s on 8cb6e00. Every extension is supported. Snapshot save and load pass, recall_after_load is true, and the peer call, changelog roundtrip and install pass.
agent-env a2a-agent validate --id opencode --sandbox local, the baseline exit 0 in 207 s; its smoke prompt took 6.1 s

Before 196a183 the same validator exited 1 in 336 s: every concurrent prompt timed out, and the peer call timed out at 300 s.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; both previous findings are addressed.

Summary

Adds the letta-code agent with persistent conversations, MCP tools, snapshots, and container or host installation.

  • AgentEnv tasks can run Letta Code with context memory.
  • The Letta Code agent can be built or installed on supported hosts.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Task[A2A task] --> Bridge[Letta Code bridge]
    Bridge --> CLI[Letta Code CLI]
    CLI --> Relay[Per-turn model relay]
    Relay --> Endpoint[Configured model endpoint]
    CLI --> MCP[Task and peer tools]
    CLI --> State[Per-context conversation and memory]
    State --> Snapshot[Snapshot save and load]
    CLI --> Result[Task result and live trajectory]
Loading

Reviews (2) · Last reviewed commit: "fix(agents): hold Letta Code's shield th..." · Reviewed by Greptile

letta-integration Bot and others added 12 commits October 27, 2026 03:31
…llation-safe

Stage the restored conversation before touching the target context, swap it
in only after the workspace swap succeeds, and put /app back if it fails.
Run snapshot file work in a thread that a cancelled caller still waits for,
so cancellation can no longer release the lock or delete staging mid-move.
Record attribution when the relay forwards a model request, not at CLI
start. Name the CLI timeout and relay size limit, and pin Node 22.23.4,
the minimum the locked CLI supports.
…leanup fails

Once the staged conversation is in place, removing the previous tree is
best-effort cleanup, so a non-removable old file can no longer fail the
commit and leave the new conversation paired with the old workspace.
0.34.26 ships @modelcontextprotocol/sdk 1.32.2, which resolves
GHSA-46jr-4wx8-v453 and GHSA-6qxp-vccf-f47h.
… cancel leaves them

A snapshot load cancelled during its swap now still binds the context to
the conversation it restored: the swap and the binding run in one shielded
step. Every file thread that runs under the workspace or changelog lock is
shielded, so a cancel no longer releases the lock, or removes a temporary
directory, while the thread still writes. The MCP tool mod names its call
timeout and output limit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@socket-security

socket-security Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​letta-ai/​letta-code@​0.34.268410010099100

View full report

@socket-security

socket-security Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
High priority
High CVE: npm sharp: Vulnerabilities in libheif: GHSA-g89c-p67h-r497 and GHSA-2jg2-4ch7-h545

CVE: GHSA-rgj7-g3m4-5g8c sharp: Vulnerabilities in libheif: GHSA-g89c-p67h-r497 and GHSA-2jg2-4ch7-h545 (HIGH)

Affected versions: < 0.35.4

Patched version: 0.35.4

From: src/agent_env/agents/agents/letta-code/package-lock.json → npm/@letta-ai/letta-code@0.34.26 → npm/sharp@0.34.5

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/sharp@0.34.5. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
High priority
High CVE: npm sharp inherited vulnerabilities in libvips: CVE-2026-33327, CVE-2026-33328, CVE-2026-35590, CVE-2026-35591

CVE: GHSA-f88m-g3jw-g9cj sharp inherited vulnerabilities in libvips: CVE-2026-33327, CVE-2026-33328, CVE-2026-35590, CVE-2026-35591 (HIGH)

Affected versions: < 0.35.0

Patched version: 0.35.0

From: src/agent_env/agents/agents/letta-code/package-lock.json → npm/@letta-ai/letta-code@0.34.26 → npm/sharp@0.34.5

ℹ Read more on: This package | This alert | What is a CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known high severity CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/sharp@0.34.5. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn

View full report

The CLI merges each model an endpoint lists into its own list with a scan
of them all, and it does so in every command that loads models. Over an
endpoint that lists 3006 models that took about 45 s of CPU in agents
create and again in every turn's run, so a one-word reply took 50-98 s and
the validator's concurrent prompts timed out at 120 s. The per-turn relay
now answers GET /v1/models with the turn's model alone, without asking the
endpoint: a turn takes about 4 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@earakely-scale
earakely-scale marked this pull request as ready for review October 28, 2026 16:22
@earakely-scale
earakely-scale requested a review from a team as a code owner October 28, 2026 16:22
Comment thread src/agent_env/agents/agents/letta-code/letta_code_bridge.py Outdated
Comment thread src/agent_env/agents/agents/letta-code/letta_code_bridge.py Outdated
…name its id lengths

shielded waited on its work unshielded after the first cancel, so a second
cancel reached the work itself: a load could release the workspace lock,
and skip binding its conversation, while its thread still wrote. The wait
is now shielded until the work is done. The context dir's hash length and
an attachment's prefix length are named.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 3051296 into main Oct 28, 2026
26 checks passed
@earakely-scale
earakely-scale deleted the letta-code-agent branch October 28, 2026 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant