Agent: browser (--web) and editor (--acp) front ends on one shared session - #467
Merged
Merged
Conversation
- The run_command live-output sink captured the console before it was created, so the first output line threw a NullPointerException inside the reader and every command's result became "[output unavailable]". The sink now looks the console up when a line arrives. - /clear left the REPL's tool note and last message in place: the next request still carried the note of a forgotten turn, and /retry repeated a message from before the clear. Both are pinned by new LocalAgentTest cases that were red before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
The whole conversation state and every slash command lived as locals in LocalAgent.run(), so only the console could drive the agent. It now lives in AgentSession, and a front end is a small SessionFrontend port: where a line goes, where a turn's events go, how to wait for a turn, and who answers approvals and questions. - AgentSession: history, approval mode, transcript, tool-call log, token figures, tool note, retry, compaction, /load, /save, /loop; one request at a time; cancel() from any thread. - TurnRecorder records a turn and forwards every event to the front end's renderer; ConsoleRenderer is the console half, ConsoleSession keeps the old name for recorder + console renderer. - ModeGatedApprovalStrategy: auto approves, manual asks the front end of the running request, nobody to ask means no. - TaskLoop runs its steps through a step function; ModelEndpoint owns --model/--base-url; Prompts owns the prompt resources. - LocalAgent keeps only the entry point and the two consoles. - A message typed twice on purpose is now in the record twice (a retry is still noted once). Tests: AgentSessionTest drives the session through a recording front end (commands, approval per mode, live command output, cancel from another thread, retry, clear, /loop with and without anybody to ask); TurnRecorderTest and ModeGatedApprovalStrategyTest cover the two new building blocks. All 255 tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
The same AgentSession, served in a browser: Atmosphere's prebuilt AI Console on an embedded Jetty 12, no Spring. Streaming, tool cards, approvals through the console's Approve/Deny buttons (Atmosphere's own /__approval protocol, resolved against the connection's registry), all slash commands, and /stop. - WebServer: Jetty + AtmosphereServlet with an explicit annotation map (no classpath scan, fat-jar safe). Atmosphere reads that map only when it scans a package, and skips its classpath scan whenever JUnit is on the classpath, so packages=all and scanClassPath=false make tests and production take the same path. - WebAccessGuard in front of everything, the WebSocket upgrade included: a per-start token exchanged for an HttpOnly SameSite=Strict cookie, same-origin check, loopback Host check against DNS rebinding. Binds 127.0.0.1 by default; the banner prints the SSH/PuTTY tunnel. - WebAgentEndpoint: @aiendpoint with timeout -1 (the default would cut a request after two minutes); one shared session per process, a new message replaces a running one. - WebFrontend: the SessionFrontend for one Atmosphere connection. - WebConsole serves the console pages from the starter jar (CSP nonce filled in) plus /api/console/info; the release jar packs only those pages from the starter, none of its Spring classes. - AgentOptions: --web, --web-port (8787), --web-host, --web-token, --acp. Tests: WebServerTest (11) drives the real server over HTTP and a WebSocket speaking atmosphere.js's protocol: no token/wrong token/no cookie refused, WebSocket upgrade refused without the token, token to cookie exchange, foreign Origin refused, console page and info served, streaming, commands, Approve runs the command, Deny keeps it from running, /stop ends a slow request. Also verified by hand in headless Chromium against the console. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
The agent speaks ACP (JSON-RPC over stdin/stdout) so JetBrains IDEs and Zed can drive it natively, and VS Code through an ACP extension. One ACP session is one AgentSession whose workspace is the directory the editor names, so the tools stay confined to the open project. - AcpServer: initialize, session/new (approval modes as ACP session modes, slash commands announced as available_commands_update), session/prompt, session/set_mode, session/cancel. stdout is the protocol; anything else printed lands on stderr. - AcpFrontend: streamed text as agent_message_chunk, each tool call as a tool_call with kind, arguments and the file it touches, then a tool_call_update with the result; running command output is pushed to the card. Approvals go through session/request_permission (allow / allow always -> auto mode / reject); a cancelled or missing answer is a no. - SlashCommands carry a description and argument hint for the editor. - AcpServerTest drives the server with plain JSON-RPC as an editor sends it, over the real session and the real OpenAiCompatServer with a scripted engine: handshake, streaming, tool calls in cwd, allow, reject, cancelled dialog, allow-always, set_mode, cancel, attached resources. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
…e release jar - smoke-agent-jar.sh: two more steps on the release-jar pair. --web on port 0: the console is 401 without the token, the token link answers 302 with the session cookie, the console page is served with it and carries a real CSP nonce. --acp through smoke/agent_acp_smoke.py, a standard-library Python editor: handshake, modes, a streamed answer, the announced commands, a read_file tool card that brings a marker back, only JSON-RPC on stdout, a clean exit when stdin closes. - Agent README: the three front ends on one session, --web (security, SSH/PuTTY tunnel), --acp (JetBrains acp.json, Zed, VS Code), options, what is verified where, updated limitations. - Root README: short pointer to --web and --acp. - CLAUDE.md: AgentSession / SessionFrontend / TurnRecorder architecture, the mode-gated approval wrapper, the web front end (including the Atmosphere classpath-scanning trap under JUnit and the WebSocket test client race), the ACP mapping, the console pages unpacked from the starter jar, and the two step-0 fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
bernardladenthin
had a problem deploying
to
startgate
September 29, 2026 08:00 — with
GitHub Actions
Error
bernardladenthin
had a problem deploying
to
maven-central
September 29, 2026 08:00 — with
GitHub Actions
Failure
bernardladenthin
had a problem deploying
to
maven-central
September 29, 2026 08:00 — with
GitHub Actions
Failure
|
4 of 6 tasks
This branch had an error being deployed
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.



Summary
llama-atmosphere-agentthat is not presentation moved into a front-end-independentAgentSession: history, slash commands,/compact,/loop,/retry, transcript, approval mode, cancellation and running a turn. A front end implementsSessionFrontend.TurnRecorderrecords each turn and forwards it to that front end's renderer, so the history note,/callsand the transcript are the same whichever front end showed the turn.ModeGatedApprovalStrategyreads the session's mode on every call, so switching modes in any front end applies to the next call.--web: the agent runs in a browser through Atmosphere's prebuilt AI console on embedded Jetty 12 (no Spring). It listens on 127.0.0.1 only. Access needs the token from the printed address, which is exchanged for an HttpOnly, SameSite=Strict cookie. Requests with a non-loopback Host or a foreign Origin are refused. Approvals appear as Approve/Deny cards, and/stopcancels a running turn. The banner explains the SSH/PuTTY tunnel.--acp: the Agent Client Protocol on stdin/stdout, for JetBrains IDEs and Zed (VS Code needs an ACP extension). Each editor session gets its own workspace, the editor'scwd. Answers stream; tool calls appear as cards with kind and file location; approvals usesession/request_permission(allow / allow all → auto / reject). Modes appear as ACP session modes, slash commands asavailable_commands_update, andsession/cancelstops a turn.run_commandoutput came back as[output unavailable: NullPointerException], because the live-output sink captured the console before it existed./clearleft the pending tool note and the/retrymessage behind.Commits:
d9d1027c976163AgentSessionextractionefc5550--webbfab8ed--acpdc550f6Dependencies:
atmosphere-spring-boot-starter, excluded transitively. The assembly unpacks only itsMETA-INF/resources/atmosphere/console/**.acp-core,acp-json-jackson2).The agent release jar grows from ~7 MB to ~14 MB. Bytecode stays within 65.
Test plan
mvn verifyinllama-atmosphere-agentpasses, 277 tests with 63 skipped (JLine screen tests without the patched JLine, and model-backed tests). New test classes:AgentSessionTest(13)WebServerTest(11): real Jetty and Atmosphere over a WebSocket speaking the atmosphere.js protocol, covering streaming, approvals,/stopand the token guardAcpServerTest(9): plain JSON-RPC as an editor sends it, covering handshake, streaming, tool cards, allow / reject / cancelled dialog / allow-all, set_mode, cancel and attached resourcesTurnRecorderTest(4)ModeGatedApprovalStrategyTest(3)AgentOptionsTest--webchecked by hand in headless Chromium: token login, approval card, result, and 401 without a token..github/smoke-agent-jar.shrun locally against a real release-jar pair built here (agent jar next to a freshly built core fat jar):--webpasses: 401 without token, 302 plus cookie, console page with a real CSP nonce.--acppasses handshake, modes, streamed answer, command list, JSON-only stdout and clean exit. Itsread_fileround fails locally only because the local model (SmolLM2-135M) makes no tool calls. CI uses the Qwen2.5-1.5B tool model that step 4 already relies on.Related issues / PRs
—
Checklist
CONTRIBUTING.mdandCODE_OF_CONDUCT.md--webexposes a shell-capable agent over HTTP. It is loopback-only with token auth, cookie exchange and Host/Origin checks by default;--web-host 0.0.0.0prints a warning.🤖 Generated with Claude Code
https://claude.ai/code/session_01FtfgoazykGcQSCR3TYBmTQ
Generated by Claude Code