Skip to content

Commit f5d1a63

Browse files
committed
feat: sync universal schema and sdk updates
1 parent 79bb441 commit f5d1a63

56 files changed

Lines changed: 6711 additions & 3885 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ Universal schema guidance:
3838
- Never use synthetic data or mocked responses in tests.
3939
- Never manually write agent types; always use generated types in `resources/agent-schemas/`. If types are broken, fix the generated types.
4040
- The universal schema must provide consistent behavior across providers; avoid requiring frontend/client logic to special-case agents.
41+
- When parsing agent data, if something is unexpected or does not match the schema, bail out and surface the error rather than trying to continue with partial parsing.
42+
- When defining the universal schema, choose the option most compatible with native agent APIs, and add synthetics to fill gaps for other agents.
43+
- Use `docs/glossary.md` as the source of truth for universal schema terminology and keep it updated alongside schema changes.
44+
- On parse failures, emit an `agent.unparsed` event (source=daemon, synthetic=true) and treat it as a test failure. Preserve raw payloads when `include_raw=true`.
45+
- Track subagent support in `docs/conversion.md`. For now, normalize subagent activity into normal message/tool flow, but revisit explicit subagent modeling later.
4146

4247
### CLI ⇄ HTTP endpoint map (keep in sync)
4348

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ description = "Universal agent API for AI coding assistants"
1212

1313
[workspace.dependencies]
1414
# Internal crates
15-
sandbox-agent-core = { path = "server/packages/sandbox-agent" }
15+
sandbox-agent = { path = "server/packages/sandbox-agent" }
1616
sandbox-agent-error = { path = "server/packages/error" }
1717
sandbox-agent-agent-management = { path = "server/packages/agent-management" }
1818
sandbox-agent-agent-credentials = { path = "server/packages/agent-credentials" }

README.md

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Sandbox Agent SDK
22

3-
Universal API for running Claude Code, Codex, OpenCode, and Amp inside sandboxes.
3+
Universal API for automatic coding agents in sandboxes. Supprots Claude Code, Codex, OpenCode, and Amp.
44

55
- **Any coding agent**: Universal API to interact with all agents with full feature coverage
66
- **Server or SDK mode**: Run as an HTTP server or with the TypeScript SDK
@@ -16,14 +16,14 @@ Roadmap:
1616

1717
## Agent Support
1818

19-
| Feature | [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) | [Codex](https://github.com/openai/codex) | [OpenCode](https://github.com/opencode-ai/opencode) | [Amp](https://ampcode.com) |
19+
| Feature | [Claude Code*](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) | [Codex](https://github.com/openai/codex) | [OpenCode](https://github.com/opencode-ai/opencode) | [Amp](https://ampcode.com) |
2020
|---------|:-----------:|:-----:|:--------:|:---:|
2121
| Stability | Stable | Stable | Experimental | Experimental |
2222
| Text Messages |||||
23-
| Tool Calls | ||||
24-
| Tool Results | ||||
25-
| Questions (HITL) | | || |
26-
| Permissions (HITL) | | || |
23+
| Tool Calls | * ||||
24+
| Tool Results | * ||||
25+
| Questions (HITL) | * | || |
26+
| Permissions (HITL) | * | || |
2727
| Images | ||| |
2828
| File Attachments | ||| |
2929
| Session Lifecycle | ||| |
@@ -34,13 +34,15 @@ Roadmap:
3434
| MCP Tools | || | |
3535
| Streaming Deltas | ||| |
3636

37+
* Claude headless CLI does not natively support tool calls/results or HITL questions/permissions yet; these are WIP.
38+
3739
Want support for another agent? [Open an issue](https://github.com/anthropics/sandbox-agent/issues/new) to request it.
3840

3941
## Architecture
4042

4143
- TODO
42-
- Embedded (runs agents locally)
43-
- Sandboxed
44+
- Local
45+
- Remote/Sandboxed
4446

4547
## Components
4648

@@ -49,6 +51,26 @@ Want support for another agent? [Open an issue](https://github.com/anthropics/sa
4951
- Inspector: inspect.sandboxagent.dev
5052
- CLI: TODO
5153

54+
## Quickstart
55+
56+
### SDK
57+
58+
- Local
59+
- Remote/Sandboxed
60+
61+
Docs
62+
63+
### Server
64+
65+
- Run server
66+
- Auth
67+
68+
Docs
69+
70+
### CLI
71+
72+
Docs
73+
5274
## Project Goals
5375

5476
This project aims to solve 3 problems with agents:
@@ -98,4 +120,3 @@ TODO
98120

99121
- the harnesses do a lot of heavy lifting
100122
- the difference between opencode, claude, and codex is vast & vastly opinionated
101-

ROADMAP.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
## launch
22

3+
- provide mock data for validating your rendering
4+
- provides history with all items, then iterates thorugh all items on a stream
5+
- this is a special type of serve function
6+
- make sure claude.md covers everything
37
- re-review agent schemas and compare it to ours
8+
- write integration guide
9+
- add optional raw payloads to events via query parameters
410
- auto-serve frontend from cli
511
- verify embedded sdk works
612
- fix bugs in ui
713
- double messages
814
- user-sent messages
915
- permissions
16+
- add an API option to stream only the next assistant item after a posted message (single-response stream)
1017
- consider migraing our standard to match the vercel ai standard
1118
- discuss actor arch in readme + give example
1219
- skillfile
@@ -18,9 +25,18 @@
1825
- **Auto-configure MCP & Skills**: Auto-load MCP servers & skills for your agents
1926
- **Process & logs manager**: Manage processes, logs, and ports for your agents to run background processes
2027
- **Codex app-server concurrency**: Run a single shared Codex app-server with multiple threads in parallel (like OpenCode), with file-write safety
28+
- persistence
2129

2230
## later
2331

32+
- missing features
33+
- file changes
34+
- api compat
35+
- vercel ai sdk + hono proxy
36+
- tanstack ai
37+
- opencode ui
38+
- synthetic question tool
39+
- since claude headless does not support this
2440
- guides:
2541
- ralph
2642
- swarms

docker/release/linux-x86_64.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
2020
--mount=type=cache,target=/usr/local/cargo/git \
2121
--mount=type=cache,target=/build/target \
2222
RUSTFLAGS="-C target-feature=+crt-static" \
23-
cargo build -p sandbox-agent-core --release --target x86_64-unknown-linux-musl && \
23+
cargo build -p sandbox-agent --release --target x86_64-unknown-linux-musl && \
2424
mkdir -p /artifacts && \
2525
cp target/x86_64-unknown-linux-musl/release/sandbox-agent /artifacts/sandbox-agent-x86_64-unknown-linux-musl
2626

docker/release/macos-aarch64.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ COPY . .
5555
RUN --mount=type=cache,target=/usr/local/cargo/registry \
5656
--mount=type=cache,target=/usr/local/cargo/git \
5757
--mount=type=cache,target=/build/target \
58-
cargo build -p sandbox-agent-core --release --target aarch64-apple-darwin && \
58+
cargo build -p sandbox-agent --release --target aarch64-apple-darwin && \
5959
mkdir -p /artifacts && \
6060
cp target/aarch64-apple-darwin/release/sandbox-agent /artifacts/sandbox-agent-aarch64-apple-darwin
6161

docker/release/macos-x86_64.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ COPY . .
5555
RUN --mount=type=cache,target=/usr/local/cargo/registry \
5656
--mount=type=cache,target=/usr/local/cargo/git \
5757
--mount=type=cache,target=/build/target \
58-
cargo build -p sandbox-agent-core --release --target x86_64-apple-darwin && \
58+
cargo build -p sandbox-agent --release --target x86_64-apple-darwin && \
5959
mkdir -p /artifacts && \
6060
cp target/x86_64-apple-darwin/release/sandbox-agent /artifacts/sandbox-agent-x86_64-apple-darwin
6161

docker/release/windows.Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ COPY . .
4242
RUN --mount=type=cache,target=/usr/local/cargo/registry \
4343
--mount=type=cache,target=/usr/local/cargo/git \
4444
--mount=type=cache,target=/build/target \
45-
cargo build -p sandbox-agent-core --release --target x86_64-pc-windows-gnu && \
45+
cargo build -p sandbox-agent --release --target x86_64-pc-windows-gnu && \
4646
mkdir -p /artifacts && \
4747
cp target/x86_64-pc-windows-gnu/release/sandbox-agent.exe /artifacts/sandbox-agent-x86_64-pc-windows-gnu.exe
4848

docs/conversion.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ Notes:
1717
- When a provider does not supply IDs (Claude), we synthesize item_id values and keep native_item_id null.
1818
- native_session_id is the only provider session identifier. It is intentionally used for thread/session/run ids.
1919
- native_item_id preserves the agent-native item/message id when present.
20+
- source indicates who emitted the event: agent (native) or daemon (synthetic).
21+
- raw is always present on events. When clients do not opt-in to raw payloads, raw is null.
22+
- opt-in via `include_raw=true` on events endpoints (HTTP + SSE).
23+
- If parsing fails, emit agent.unparsed (source=daemon, synthetic=true). Tests must assert zero unparsed events.
2024

2125
Events / Message Flow
2226

@@ -42,14 +46,14 @@ Synthetics
4246
+------------------------------+------------------------+--------------------------+--------------------------------------------------------------+
4347
| Synthetic element | When it appears | Stored as | Notes |
4448
+------------------------------+------------------------+--------------------------+--------------------------------------------------------------+
45-
| session.started | When agent emits no explicit start | session.started event | Mark origin=daemon |
46-
| session.ended | When agent emits no explicit end | session.ended event | Mark origin=daemon; reason may be inferred |
49+
| session.started | When agent emits no explicit start | session.started event | Mark source=daemon |
50+
| session.ended | When agent emits no explicit end | session.ended event | Mark source=daemon; reason may be inferred |
4751
| item_id (Claude) | Claude provides no item IDs | item_id | Maintain provider_item_id map when possible |
48-
| user message (Claude) | Claude emits only assistant output | item.completed | Mark origin=daemon; preserve raw input in event metadata |
52+
| user message (Claude) | Claude emits only assistant output | item.completed | Mark source=daemon; preserve raw input in event metadata |
4953
| question events (Claude) | Plan mode ExitPlanMode tool usage | question.requested/resolved | Synthetic mapping from tool call/result |
5054
| native_session_id (Codex) | Codex uses threadId | native_session_id | Intentionally merged threadId into native_session_id |
5155
+------------------------------+------------------------+--------------------------+--------------------------------------------------------------+
52-
| message.delta (Claude/Amp) | No native deltas | item.delta | Synthetic delta with full message content; origin=daemon |
56+
| message.delta (Claude/Amp) | No native deltas | item.delta | Synthetic delta with full message content; source=daemon |
5357
+------------------------------+------------------------+--------------------------+--------------------------------------------------------------+
5458
| message.delta (OpenCode) | part delta before message | item.delta | If part arrives first, create item.started stub then delta |
5559
+------------------------------+------------------------+--------------------------+--------------------------------------------------------------+
@@ -68,5 +72,9 @@ Policy:
6872
Message normalization notes
6973

7074
- user vs assistant: normalized via role in the universal item; provider role fields or item types determine role.
75+
- file artifacts: always represented as content parts (type=file_ref) inside message/tool_result items, not a separate item kind.
76+
- reasoning: represented as content parts (type=reasoning) inside message items, with visibility when available.
77+
- subagents: OpenCode subtask parts and Claude Task tool usage are currently normalized into standard message/tool flow (no dedicated subagent fields).
7178
- OpenCode unrolling: message.updated creates/updates the parent message item; tool-related parts emit separate tool item events (item.started/ item.completed) with parent_id pointing to the message item.
72-
- If a message.part.updated arrives before message.updated, we create a stub item.started (origin=daemon) so deltas have a parent.
79+
- If a message.part.updated arrives before message.updated, we create a stub item.started (source=daemon) so deltas have a parent.
80+
- Tool calls/results are always emitted as separate tool items to keep behavior consistent across agents.

docs/glossary.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Glossary (Universal Schema)
2+
3+
This glossary defines the universal schema terms used across the daemon, SDK, and tests.
4+
5+
Session terms
6+
- session_id: daemon-generated identifier for a universal session.
7+
- native_session_id: provider-native thread/session/run identifier (thread_id merged here).
8+
- session.started: event emitted at session start (native or synthetic).
9+
- session.ended: event emitted at session end (native or synthetic); includes reason and terminated_by.
10+
- terminated_by: who ended the session: agent or daemon.
11+
- reason: why the session ended: completed, error, or terminated.
12+
13+
Event terms
14+
- UniversalEvent: envelope that wraps all events; includes source, type, data, raw.
15+
- event_id: unique identifier for the event.
16+
- sequence: monotonic event sequence number within a session.
17+
- time: RFC3339 timestamp for the event.
18+
- source: event origin: agent (native) or daemon (synthetic).
19+
- raw: original provider payload for native events; optional for synthetic events.
20+
21+
Item terms
22+
- item_id: daemon-generated identifier for a universal item.
23+
- native_item_id: provider-native item/message identifier when available; null otherwise.
24+
- parent_id: item_id of the parent item (e.g., tool call/result parented to a message).
25+
- kind: item category: message, tool_call, tool_result, system, status, unknown.
26+
- role: actor role for message items: user, assistant, system, tool (or null).
27+
- status: item lifecycle status: in_progress, completed, failed (or null).
28+
29+
Item event terms
30+
- item.started: item creation event (may be synthetic).
31+
- item.delta: streaming delta event (native where supported; synthetic otherwise).
32+
- item.completed: final item event with complete content.
33+
34+
Content terms
35+
- content: ordered list of parts that make up an item payload.
36+
- content part: a typed element inside content (text, json, tool_call, tool_result, file_ref, image, status, reasoning).
37+
- text: plain text content part.
38+
- json: structured JSON content part.
39+
- tool_call: tool invocation content part (name, arguments, call_id).
40+
- tool_result: tool result content part (call_id, output).
41+
- file_ref: file reference content part (path, action, diff).
42+
- image: image content part (path, mime).
43+
- status: status content part (label, detail).
44+
- reasoning: reasoning content part (text, visibility).
45+
- visibility: reasoning visibility: public or private.
46+
47+
HITL terms
48+
- permission.requested / permission.resolved: human-in-the-loop permission flow events.
49+
- permission_id: identifier for the permission request.
50+
- question.requested / question.resolved: human-in-the-loop question flow events.
51+
- question_id: identifier for the question request.
52+
- options: question answer options.
53+
- response: selected answer for a question.
54+
55+
Synthetic terms
56+
- synthetic event: a daemon-emitted event used to fill gaps in provider-native schemas.
57+
- source=daemon: marks synthetic events.
58+
- synthetic delta: a single full-content delta emitted for providers without native deltas.
59+
60+
Provider terms
61+
- agent: the native provider (claude, codex, opencode, amp).
62+
- native payload: the provider’s original event/message object stored in raw.

0 commit comments

Comments
 (0)