feat(letta-brain): B1 — Letta-backed agent mode (Hermes-front bridge, production)#104
Merged
Merged
Conversation
A Hermes gateway with LETTA_BRAIN_URL + LETTA_BRAIN_AGENT_ID (or
gateway.letta_brain.{base_url,agent_id} in config.yaml) forwards each
turn to a bound Letta agent over REST instead of running the native
AIAgent loop. Surfaces, pairing/group approval, budget, and the reply
path are untouched — the delegation slots into the existing
remote-brain seam in _run_agent_inner, right beside proxy mode.
Throwaway prototype for Swarm Map v1 spec §2B/§3 slice 0 — exists to
answer 'what shape does the Hermes-front proxy want to be?'
Verdict: a config-driven mode at the proxy seam. Do not merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Productionizes the #96 prototype's door-context gap (B1.5, ratified: sender- tagged message text). A shared Letta brain sees only the message text over REST, so it can't tell who is speaking or which group — multiplayer is broken. We prepend a compact one-line tag; Letta's server-side history then accumulates identity turn over turn. Current-turn sender + group label only, NOT transcripts. - letta_brain.py: build_sender_tag()/apply_sender_tag() + send_message() gains sender/group params. Documents the no-trailing-slash /messages requirement. - run.py: _run_agent_via_letta derives sender (user_name) + group (chat_name, else type:id; None for DMs) from the SessionSource and passes them through. Validated live 2026-07-21 (self-hosted Letta on Primo): given '[from Alice in #family] ...' the agent replied 'Alice is messaging me from the group #family.' — the inline tag conveys identity, no memory-sync needed. 12/12 tests (8 new: tag construction, send forwarding, DM vs group vs chat_name dispatch). ruff clean. Draft — real B1 also needs SSE streaming + per-agent serialization (spec B3); this lands the door-context bridge. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… tool-only turns Swarm Map v1 slice 4: the slice-0 prototype (#96) graduates to the real Hermes-front bridge, per the spec verdict ("real B1 = productionize the prototype + reuse proxy mode's streaming consumer"): - B3 per-agent serialization: turns queue on a per-(server|agent) asyncio lock — Letta processes an agent's messages sequentially, so concurrent group messages must never overlap in flight. Staleness is re-checked after the wait so superseded turns are dropped, not sent. - Streaming: letta_brain.stream_message consumes Letta's SSE endpoint (/messages/stream, stream_tokens) and feeds the same GatewayStreamConsumer proxy mode uses — the setup block is extracted verbatim into _setup_platform_stream_consumer, shared by both remote- brain modes. Defensive parser (parse_stream_line) skips unknown shapes. - Double-turn safety: fallback from a failed stream to the live-validated blocking client happens ONLY when the failure is provably pre-delivery (LettaBrainError.retryable: aiohttp missing, connect-refused, 404/405). Ambiguous failures surface as errors — Letta owns server-side history, and a blind retry would process the turn twice. Partial text that already reached the platform is delivered, never retried. - Auth: LETTA_BRAIN_API_KEY / gateway.letta_brain.api_key → Bearer header (Letta Cloud / secured servers). - Tool-only turns: a turn ending without assistant_message is a quiet empty reply + audit log (message_types), not a user-facing error — resolves the prototype's TODO. 21/21 letta tests (9 new), 170 green across letta + proxy + stream- consumer + platform-streaming suites; ruff clean. The 9 aiohttp-less proxy failures pre-exist on main (env without the optional extra). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Swarm Map v1 slice 4 — real B1 (spec
memory/specs/2026-07-19-swarm-map-v1-definition.md§2B/§3). Supersedes prototype #96 and B1.5 #101: both ride in as the first two commits (rebased onto current main), the third graduates them to production.What
A Hermes gateway with
LETTA_BRAIN_URL+LETTA_BRAIN_AGENT_ID(+ optionalLETTA_BRAIN_API_KEY) becomes the messaging door for a Letta brain: surfaces, pairing/group approval, audit, and budget all run as normal, then the turn is forwarded to the bound Letta agent over REST and the reply rides the normal delivery path.Production hardening over the prototype
GatewayStreamConsumerproxy mode uses (_setup_platform_stream_consumerextracted verbatim, shared);LETTA_BRAIN_STREAMING=offforces blockingLettaBrainError.retryable); partials delivered, never retriedTests
21/21 letta (9 new), 170 green across letta/proxy/stream-consumer/streaming-defaults; ruff clean. (9 aiohttp-less proxy failures pre-exist on main in envs without the optional extra.)
Not in this PR (spec-tracked)
B2 (Swarm Map wires door↔brain), B4/C1 verification, interrupt handling, media forwarding.
🤖 Generated with Claude Code