Skip to content

feat(server): serve the CAS harness API from the stage image - #21

Merged
yash-kark merged 1 commit into
feat/p1-sdk-2-remove-events-sinkfrom
feat/p1-sdk-11-app-server
Oct 28, 2026
Merged

yash-kark merged 1 commit into
feat/p1-sdk-2-remove-events-sinkfrom
feat/p1-sdk-11-app-server

Conversation

@yash-kark

Copy link
Copy Markdown
Contributor

Stack: 11 of 12 (base #20). Plan: .claude/plans/p1-sdk-egress-routes.md phase 11 (C3; D22, D23). Q16–Q18 are resolved with the plan's recommendations: the SDK ships the server, the event mapping follows D23, and messages are handled as in D22.

What changes

  • New computeragent.server (extra server: starlette, uvicorn). It runs as python -m computeragent.server on 0.0.0.0:8080 (PORT overrides the port). Routes, bodies, status codes and error codes follow CAS's harness-server:
    • MicroVM lifecycle hooks and /v1/health;
    • sessions (create, get, delete), messages, end-input and cancel;
    • GET …/events as server-sent events, with Last-Event-ID / ?lastEventId replay and a 20 s keepalive;
    • POST …/permission/:callId for approvals;
    • the fs/{file,tree,edit,mkdir,move} routes.
  • Sessions and keys. One ComputerAgent per session, built from the image's COMPUTERAGENT_* settings with no api_key=.
    • envs.LYZR_API_KEY seeds the key and every other envs key is ignored; each message's credential replaces the key before its turn.
    • Turns run one at a time per process.
    • identity is not read; engine is checked against the registered engines.
    • messages become the first turns, and streamingInput: false closes input after them.
    • sessionStore is passed through.
  • Events (server/events.py), in CAS's sse-events.ts shapes:
    • ca_session_started once per session.
    • ca_turn_started and ca_redaction_decision come from the SDK's telemetry. A pipeline middleware observes them inline, so they always precede the turn's output.
    • sdk_message payloads are converted to the TS Claude Agent SDK's JSON shapes; gitagent's outputs are best-effort mapped.
    • Tool-gate decisions arrive as ca_permission_decision (source: "policy"); approvals as ca_permission_request and the client's decision.
    • ca_usage_snapshot is sent before the turn's result, because the CAS client stops reading a turn at its result. A blocked input gets a result marked ca_policy_blocked.
    • ca_session_ended is sent once, when the session ends.
  • Small SDK additions:
    • ComputerAgent.workspace and ComputerAgent.telemetry_pipeline;
    • computeragent.engines.registered_engines().
  • Docs: guide §14, README install line, CHANGELOG Added. The plan marks Q16–Q18 resolved.

Deviations from the plan text (reviewers, please check)

  • Turn end. The plan said a turn ends with ca_session_ended. The reference harness ends a turn with its result and sends ca_session_ended once per session, so the server follows the harness, and the plan's D23 wording is corrected.
  • Status codes. POST …/messages returns 200 {ok: true} and POST /v1/sessions adds eventsUrl, as the harness does. The plan said 202 and {sessionId}.
  • File deletes. These never remove a directory tree: a non-empty directory answers 409 WORKDIR_DIRECTORY_NOT_EMPTY, even with recursive=true (the harness deletes recursively).
  • Approvals. These reach the client only when the tool gate has no opinion: the SDK's guardrails gate decides first. That's the existing coordinator order.

Tests

  • ruff clean; mypy at 18 (baseline); pytest -m "not integration": 648 passed; uv build OK.
  • New files: tests/test_server_app.py, tests/test_server_events.py, tests/test_server_fs.py. The tests run the real ComputerAgent and coordinator with a fake engine; only the agent document and the guardrails check are mocked. They cover:
    • every SSE event checked against sse-events.ts field sets;
    • the blocked turn, the engine error and the approval round trip;
    • replay, path escapes and secrets never logged.
  • End to end (cas-e2e-dummy/run_cas_e2e.sh, MicroVM, run with IMAGE_APP=sdk): real CAS boots python -m computeragent.server through the fake AWS, and the real egress proxy sits in front of the fake gateway.

🤖 Generated with Claude Code

@vrajp-lyzr
vrajp-lyzr added this pull request to stack #24 October 27, 2026 12:33
@yash-kark yash-kark mentioned this pull request Oct 28, 2026
@yash-kark
yash-kark force-pushed the feat/p1-sdk-11-app-server branch 7 times, most recently from fbbd638 to 4165713 Compare October 28, 2026 17:19
Base automatically changed from feat/p1-sdk-10-per-turn-key to feat/p1-sdk-2-remove-events-sink October 28, 2026 17:20
computeragent.server (extra `server`), run as `python -m computeragent.server`
on 0.0.0.0:8080: Lambda MicroVM lifecycle hooks, health, sessions, messages,
events (SSE with Last-Event-ID replay), end-input, cancel, approvals and the
workspace file routes, following computeragent-enterprise's harness-server.

- One ComputerAgent per session from the image's settings; envs.LYZR_API_KEY
  seeds the key and each message's credential replaces it; turns run one at a
  time per process.
- Events in sse-events.ts shapes: ca_turn_started and ca_redaction_decision
  (observed inline on the telemetry pipeline), sdk_message in the TS SDK's
  JSON shape, ca_permission_request/decision, ca_usage_snapshot before the
  turn's result, one ca_session_ended per session.
- File routes confined to the workspace; deletes remove a file or an empty
  directory only.
- Plan: Q16-Q18 resolved with the plan's recommendations; the turn-end wording
  corrected to the reference harness's behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yash-kark
yash-kark force-pushed the feat/p1-sdk-11-app-server branch from 4165713 to f0b45a0 Compare October 28, 2026 17:20
@yash-kark
yash-kark merged commit 8d76e37 into feat/p1-sdk-2-remove-events-sink Oct 28, 2026
0 of 4 checks passed
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