Repository navigation
feat(agents): add a Letta Code agent - #368
Conversation
…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>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
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.
|
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>
…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>
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 asletta-code(alias inaliases.toml) or as@local/agentenv-framework/agents/letta-code.letta --backend local -p ... --output-format stream-jsonrun in/app, and its stream-json events are the turn's trajectory.[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.snapshot/v1save/load carries it to another context.peer_agents, are exposed to the model as direct tools.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, andinstall/v1covers containers andvmhosts.letta-code-smokeis added.The agent's
README.mdhas the Extension | Implementation table.agent-config,mcp-config,peer-agents,skill-config,trajectory,snapshot,attribution-probeandinstallare implemented;staging/v1is 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: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_MSandMCP_CALL_MAX_OUTPUT_BYTES.shielded_threadis nowshielded(asyncio.to_thread(...)), andshieldedtakes 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'scurrentModels. 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-prun.The per-turn relay now answers
GET /v1/modelswith the turn's model alone, without asking the endpoint, so each turn takes about 4 s:agents createHow it was tested
From #345:
agent-env a2a-agent validate --id letta-code --sandbox localexits 0, andagent-env run agents --task letta-code-smokepasses. Both ran withopenai/gpt-4.1-minithrough an OpenAI-compatible endpoint, on Docker 20.10.make lintandmake unit-testpass, andcheck_plugin_api.pyreports no break.On top of that:
pytest tst/unit/agents/letta_codepytest -n 4 tst/unit/agents tst/unit/bundle/shipped_bundles_test.py tst/unit/test_infra_images_script.pyruff checkEnd to end, on a 4-vCPU Ubuntu 24.04 VM, with Docker Engine 29.1 from the distribution and
openai/gpt-4.1-minithrough the endpoint above:agent-env run agents --task letta-code-smokeagent-env a2a-agent validate --id letta-code --sandbox localagent-env run agents --task claude-code-smokeputs the recall judge in the storerecall_after_loadis true, and the peer call, changelog roundtrip and install pass.agent-env a2a-agent validate --id opencode --sandbox local, the baselineBefore 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


Confidence Score: 5/5
The PR appears safe to merge; both previous findings are addressed.Summary
Adds the
letta-codeagent with persistent conversations, MCP tools, snapshots, and container or host installation.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]Reviews (2) · Last reviewed commit: "fix(agents): hold Letta Code's shield th..." · Reviewed by Greptile