mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
Compare commits
4 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf484e7c96 | ||
|
|
d55b0dfb88 | ||
|
|
251f731232 | ||
|
|
b45989a082 |
36 changed files with 187 additions and 828 deletions
16
Cargo.toml
16
Cargo.toml
|
|
@ -4,7 +4,7 @@ members = ["server/packages/*", "gigacode"]
|
||||||
exclude = ["factory/packages/desktop/src-tauri", "foundry/packages/desktop/src-tauri"]
|
exclude = ["factory/packages/desktop/src-tauri", "foundry/packages/desktop/src-tauri"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [ "Rivet Gaming, LLC <developer@rivet.gg>" ]
|
authors = [ "Rivet Gaming, LLC <developer@rivet.gg>" ]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|
@ -13,13 +13,13 @@ description = "Universal API for automatic coding agents in sandboxes. Supports
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Internal crates
|
# Internal crates
|
||||||
sandbox-agent = { version = "0.4.1", path = "server/packages/sandbox-agent" }
|
sandbox-agent = { version = "0.4.2", path = "server/packages/sandbox-agent" }
|
||||||
sandbox-agent-error = { version = "0.4.1", path = "server/packages/error" }
|
sandbox-agent-error = { version = "0.4.2", path = "server/packages/error" }
|
||||||
sandbox-agent-agent-management = { version = "0.4.1", path = "server/packages/agent-management" }
|
sandbox-agent-agent-management = { version = "0.4.2", path = "server/packages/agent-management" }
|
||||||
sandbox-agent-agent-credentials = { version = "0.4.1", path = "server/packages/agent-credentials" }
|
sandbox-agent-agent-credentials = { version = "0.4.2", path = "server/packages/agent-credentials" }
|
||||||
sandbox-agent-opencode-adapter = { version = "0.4.1", path = "server/packages/opencode-adapter" }
|
sandbox-agent-opencode-adapter = { version = "0.4.2", path = "server/packages/opencode-adapter" }
|
||||||
sandbox-agent-opencode-server-manager = { version = "0.4.1", path = "server/packages/opencode-server-manager" }
|
sandbox-agent-opencode-server-manager = { version = "0.4.2", path = "server/packages/opencode-server-manager" }
|
||||||
acp-http-adapter = { version = "0.4.1", path = "server/packages/acp-http-adapter" }
|
acp-http-adapter = { version = "0.4.2", path = "server/packages/acp-http-adapter" }
|
||||||
|
|
||||||
# Serialization
|
# Serialization
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,108 @@ await session.prompt([
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Event types
|
||||||
|
|
||||||
|
Each event's `payload` contains a session update. The `sessionUpdate` field identifies the type.
|
||||||
|
|
||||||
|
<AccordionGroup>
|
||||||
|
<Accordion title="agent_message_chunk">
|
||||||
|
Streamed text or content from the agent's response.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "agent_message_chunk",
|
||||||
|
"content": { "type": "text", "text": "Here's how the repository is structured..." }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="agent_thought_chunk">
|
||||||
|
Internal reasoning from the agent (chain-of-thought / extended thinking).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "agent_thought_chunk",
|
||||||
|
"content": { "type": "text", "text": "I should start by looking at the project structure..." }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="user_message_chunk">
|
||||||
|
Echo of the user's prompt being processed.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "user_message_chunk",
|
||||||
|
"content": { "type": "text", "text": "Summarize the repository structure." }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="tool_call">
|
||||||
|
The agent invoked a tool (file edit, terminal command, etc.).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "tool_call",
|
||||||
|
"toolCallId": "tc_abc123",
|
||||||
|
"title": "Read file",
|
||||||
|
"status": "in_progress",
|
||||||
|
"rawInput": { "path": "/src/index.ts" }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="tool_call_update">
|
||||||
|
Progress or result update for an in-progress tool call.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "tool_call_update",
|
||||||
|
"toolCallId": "tc_abc123",
|
||||||
|
"status": "completed",
|
||||||
|
"content": [{ "type": "text", "text": "import express from 'express';\n..." }]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="plan">
|
||||||
|
The agent's execution plan for the current task.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "plan",
|
||||||
|
"entries": [
|
||||||
|
{ "content": "Read the project structure", "status": "completed" },
|
||||||
|
{ "content": "Identify main entrypoints", "status": "in_progress" },
|
||||||
|
{ "content": "Write summary", "status": "pending" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="usage_update">
|
||||||
|
Token usage metrics for the current turn.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "usage_update"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
|
<Accordion title="session_info_update">
|
||||||
|
Session metadata changed (e.g. agent-generated title).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sessionUpdate": "session_info_update",
|
||||||
|
"title": "Repository structure analysis"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Accordion>
|
||||||
|
</AccordionGroup>
|
||||||
|
|
||||||
## Fetch persisted event history
|
## Fetch persisted event history
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ Agents are installed lazily on first use. To avoid the cold-start delay, pre-ins
|
||||||
sandbox-agent install-agent --all
|
sandbox-agent install-agent --all
|
||||||
```
|
```
|
||||||
|
|
||||||
The `rivetdev/sandbox-agent:0.4.1-full` Docker image ships with all agents pre-installed.
|
The `rivetdev/sandbox-agent:0.4.2-full` Docker image ships with all agents pre-installed.
|
||||||
|
|
||||||
## Production-ready agent orchestration
|
## Production-ready agent orchestration
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ try {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `daytona` provider uses the `rivetdev/sandbox-agent:0.4.1-full` image by default and starts the server automatically.
|
The `daytona` provider uses the `rivetdev/sandbox-agent:0.4.2-full` image by default and starts the server automatically.
|
||||||
|
|
||||||
## Using snapshots for faster startup
|
## Using snapshots for faster startup
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ Run the published full image with all supported agents pre-installed:
|
||||||
docker run --rm -p 3000:3000 \
|
docker run --rm -p 3000:3000 \
|
||||||
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
|
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
|
||||||
-e OPENAI_API_KEY="$OPENAI_API_KEY" \
|
-e OPENAI_API_KEY="$OPENAI_API_KEY" \
|
||||||
rivetdev/sandbox-agent:0.4.1-full \
|
rivetdev/sandbox-agent:0.4.2-full \
|
||||||
server --no-token --host 0.0.0.0 --port 3000
|
server --no-token --host 0.0.0.0 --port 3000
|
||||||
```
|
```
|
||||||
|
|
||||||
The `0.4.1-full` tag pins the exact version. The moving `full` tag is also published for contributors who want the latest full image.
|
The `0.4.2-full` tag pins the exact version. The moving `full` tag is also published for contributors who want the latest full image.
|
||||||
|
|
||||||
If you also want the desktop API inside the container, install desktop dependencies before starting the server:
|
If you also want the desktop API inside the container, install desktop dependencies before starting the server:
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ const docker = new Docker();
|
||||||
const PORT = 3000;
|
const PORT = 3000;
|
||||||
|
|
||||||
const container = await docker.createContainer({
|
const container = await docker.createContainer({
|
||||||
Image: "rivetdev/sandbox-agent:0.4.1-full",
|
Image: "rivetdev/sandbox-agent:0.4.2-full",
|
||||||
Cmd: ["server", "--no-token", "--host", "0.0.0.0", "--port", `${PORT}`],
|
Cmd: ["server", "--no-token", "--host", "0.0.0.0", "--port", `${PORT}`],
|
||||||
Env: [
|
Env: [
|
||||||
`ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}`,
|
`ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}`,
|
||||||
|
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
---
|
|
||||||
title: "Foundry Self-Hosting"
|
|
||||||
description: "Environment, credentials, and deployment setup for Sandbox Agent Foundry auth, GitHub, and billing."
|
|
||||||
---
|
|
||||||
|
|
||||||
This guide documents the deployment contract for the Foundry product surface: app auth, GitHub onboarding, repository import, and billing.
|
|
||||||
|
|
||||||
It also covers the local-development bootstrap that uses `.env.development` only when `NODE_ENV=development`.
|
|
||||||
|
|
||||||
## Local Development
|
|
||||||
|
|
||||||
For backend local development, the Foundry backend now supports a development-only dotenv bootstrap:
|
|
||||||
|
|
||||||
- It loads `.env.development.local` and `.env.development`
|
|
||||||
- It does this **only** when `NODE_ENV=development`
|
|
||||||
- It does **not** load dotenv files in production
|
|
||||||
|
|
||||||
The example file lives at [`/.env.development.example`](https://github.com/rivet-dev/sandbox-agent/blob/main/.env.development.example).
|
|
||||||
|
|
||||||
To use it locally:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp .env.development.example .env.development
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the backend with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
just foundry-backend-start
|
|
||||||
```
|
|
||||||
|
|
||||||
That recipe sets `NODE_ENV=development`, which enables the dotenv loader.
|
|
||||||
|
|
||||||
### Local Defaults
|
|
||||||
|
|
||||||
These values can be safely defaulted for local development:
|
|
||||||
|
|
||||||
- `APP_URL=http://localhost:4173`
|
|
||||||
- `BETTER_AUTH_URL=http://localhost:7741`
|
|
||||||
- `BETTER_AUTH_SECRET=sandbox-agent-foundry-development-only-change-me`
|
|
||||||
- `GITHUB_REDIRECT_URI=http://localhost:7741/v1/auth/callback/github`
|
|
||||||
|
|
||||||
These should be treated as development-only values.
|
|
||||||
|
|
||||||
## Production Environment
|
|
||||||
|
|
||||||
For production or self-hosting, set these as real environment variables in your deployment platform. Do not rely on dotenv file loading.
|
|
||||||
|
|
||||||
### App/Auth
|
|
||||||
|
|
||||||
| Variable | Required | Notes |
|
|
||||||
|---|---:|---|
|
|
||||||
| `APP_URL` | Yes | Public frontend origin |
|
|
||||||
| `BETTER_AUTH_URL` | Yes | Public auth base URL |
|
|
||||||
| `BETTER_AUTH_SECRET` | Yes | Strong random secret for auth/session signing |
|
|
||||||
|
|
||||||
### GitHub OAuth
|
|
||||||
|
|
||||||
| Variable | Required | Notes |
|
|
||||||
|---|---:|---|
|
|
||||||
| `GITHUB_CLIENT_ID` | Yes | GitHub OAuth app client id |
|
|
||||||
| `GITHUB_CLIENT_SECRET` | Yes | GitHub OAuth app client secret |
|
|
||||||
| `GITHUB_REDIRECT_URI` | Yes | GitHub OAuth callback URL |
|
|
||||||
|
|
||||||
Use GitHub OAuth for:
|
|
||||||
|
|
||||||
- user sign-in
|
|
||||||
- user identity
|
|
||||||
- org selection
|
|
||||||
- access to the signed-in user’s GitHub context
|
|
||||||
|
|
||||||
## GitHub App
|
|
||||||
|
|
||||||
If your Foundry deployment uses GitHub App-backed organization install and repo import, also configure:
|
|
||||||
|
|
||||||
| Variable | Required | Notes |
|
|
||||||
|---|---:|---|
|
|
||||||
| `GITHUB_APP_ID` | Yes | GitHub App id |
|
|
||||||
| `GITHUB_APP_CLIENT_ID` | Yes | GitHub App client id |
|
|
||||||
| `GITHUB_APP_CLIENT_SECRET` | Yes | GitHub App client secret |
|
|
||||||
| `GITHUB_APP_PRIVATE_KEY` | Yes | PEM private key for installation auth |
|
|
||||||
|
|
||||||
For `.env.development` and `.env.development.local`, store `GITHUB_APP_PRIVATE_KEY` as a quoted single-line value with `\n` escapes instead of raw multi-line PEM text.
|
|
||||||
|
|
||||||
Recommended GitHub App permissions:
|
|
||||||
|
|
||||||
- Repository `Metadata: Read`
|
|
||||||
- Repository `Contents: Read & Write`
|
|
||||||
- Repository `Pull requests: Read & Write`
|
|
||||||
- Repository `Checks: Read`
|
|
||||||
- Repository `Commit statuses: Read`
|
|
||||||
|
|
||||||
Set the webhook URL to `https://<your-backend-host>/v1/webhooks/github` and generate a webhook secret. Store the secret as `GITHUB_WEBHOOK_SECRET`.
|
|
||||||
|
|
||||||
This is required, not optional. Foundry depends on GitHub App webhook delivery for installation lifecycle changes, repo access changes, and ongoing repo / pull request sync. If the GitHub App is not installed for the workspace, or webhook delivery is misconfigured, Foundry will remain in an install / reconnect state and core GitHub-backed functionality will not work correctly.
|
|
||||||
|
|
||||||
Recommended webhook subscriptions:
|
|
||||||
|
|
||||||
- `installation`
|
|
||||||
- `installation_repositories`
|
|
||||||
- `pull_request`
|
|
||||||
- `pull_request_review`
|
|
||||||
- `pull_request_review_comment`
|
|
||||||
- `push`
|
|
||||||
- `create`
|
|
||||||
- `delete`
|
|
||||||
- `check_suite`
|
|
||||||
- `check_run`
|
|
||||||
- `status`
|
|
||||||
|
|
||||||
Use the GitHub App for:
|
|
||||||
|
|
||||||
- installation/reconnect state
|
|
||||||
- org repo import
|
|
||||||
- repository sync
|
|
||||||
- PR creation and updates
|
|
||||||
|
|
||||||
Use GitHub OAuth for:
|
|
||||||
|
|
||||||
- who the user is
|
|
||||||
- which orgs they can choose
|
|
||||||
|
|
||||||
## Stripe
|
|
||||||
|
|
||||||
For live billing, configure:
|
|
||||||
|
|
||||||
| Variable | Required | Notes |
|
|
||||||
|---|---:|---|
|
|
||||||
| `STRIPE_SECRET_KEY` | Yes | Server-side Stripe secret key |
|
|
||||||
| `STRIPE_PUBLISHABLE_KEY` | Yes | Client-side Stripe publishable key |
|
|
||||||
| `STRIPE_WEBHOOK_SECRET` | Yes | Signing secret for billing webhooks |
|
|
||||||
| `STRIPE_PRICE_TEAM` | Yes | Stripe price id for the Team plan checkout session |
|
|
||||||
|
|
||||||
Stripe should own:
|
|
||||||
|
|
||||||
- hosted checkout
|
|
||||||
- billing portal
|
|
||||||
- subscription status
|
|
||||||
- invoice history
|
|
||||||
- webhook-driven state sync
|
|
||||||
|
|
||||||
## Mock Invariant
|
|
||||||
|
|
||||||
Foundry’s mock client path should continue to work end to end even when the real auth/GitHub/Stripe path exists.
|
|
||||||
|
|
||||||
That includes:
|
|
||||||
|
|
||||||
- sign-in
|
|
||||||
- org selection/import
|
|
||||||
- settings
|
|
||||||
- billing UI
|
|
||||||
- workspace/task/session flow
|
|
||||||
- seat accrual
|
|
||||||
|
|
||||||
Use mock mode for deterministic UI review and local product development. Use the real env-backed path for integration and self-hosting.
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://mintlify.com/docs.json",
|
"$schema": "https://mintlify.com/docs.json",
|
||||||
"theme": "willow",
|
"theme": "mint",
|
||||||
"name": "Sandbox Agent SDK",
|
"name": "Sandbox Agent SDK",
|
||||||
"appearance": {
|
"appearance": {
|
||||||
"default": "dark",
|
"default": "dark",
|
||||||
|
|
@ -25,11 +25,6 @@
|
||||||
},
|
},
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"links": [
|
"links": [
|
||||||
{
|
|
||||||
"label": "Gigacode",
|
|
||||||
"icon": "terminal",
|
|
||||||
"href": "https://github.com/rivet-dev/sandbox-agent/tree/main/gigacode"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"label": "Discord",
|
"label": "Discord",
|
||||||
"icon": "discord",
|
"icon": "discord",
|
||||||
|
|
@ -90,13 +85,10 @@
|
||||||
"group": "System",
|
"group": "System",
|
||||||
"pages": ["file-system", "processes", "computer-use", "common-software"]
|
"pages": ["file-system", "processes", "computer-use", "common-software"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"group": "Orchestration",
|
|
||||||
"pages": ["orchestration-architecture", "session-persistence", "observability", "multiplayer", "security"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"group": "Reference",
|
"group": "Reference",
|
||||||
"pages": [
|
"pages": [
|
||||||
|
"troubleshooting",
|
||||||
"architecture",
|
"architecture",
|
||||||
"cli",
|
"cli",
|
||||||
"inspector",
|
"inspector",
|
||||||
|
|
@ -129,5 +121,10 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"styles": ["/theme.css"]
|
"__removed": [
|
||||||
|
{
|
||||||
|
"group": "Orchestration",
|
||||||
|
"pages": ["orchestration-architecture", "session-persistence", "observability", "multiplayer", "security"]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
title: Gigacode
|
|
||||||
url: "https://github.com/rivet-dev/sandbox-agent/tree/main/gigacode"
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"license": {
|
"license": {
|
||||||
"name": "Apache-2.0"
|
"name": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"version": "0.4.1"
|
"version": "0.4.2"
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
# Pi Agent Support Plan (pi-mono)
|
|
||||||
|
|
||||||
## Implementation Status Update
|
|
||||||
|
|
||||||
- Runtime selection now supports two internal modes:
|
|
||||||
- `PerSession` (default for unknown/non-allowlisted Pi capabilities)
|
|
||||||
- `Shared` (allowlist-only compatibility path)
|
|
||||||
- Pi sessions now use per-session process isolation by default, enabling true concurrent Pi sessions in Inspector and API clients.
|
|
||||||
- Shared Pi server code remains available and is used only when capability checks allow multiplexing.
|
|
||||||
- Session termination for per-session Pi mode hard-kills the underlying Pi process and clears queued prompts/pending waiters.
|
|
||||||
- In-session concurrent sends are serialized with an unbounded daemon-side FIFO queue per session.
|
|
||||||
|
|
||||||
## Investigation Summary
|
|
||||||
|
|
||||||
### Pi CLI modes and RPC protocol
|
|
||||||
- Pi supports multiple modes including interactive, print/JSON output, RPC, and SDK usage. JSON mode outputs a stream of JSON events suitable for parsing, and RPC mode is intended for programmatic control over stdin/stdout.
|
|
||||||
- RPC mode is started with `pi --mode rpc` and supports options like `--provider`, `--model`, `--no-session`, and `--session-dir`.
|
|
||||||
- The RPC protocol is newline-delimited JSON over stdin/stdout:
|
|
||||||
- Commands are JSON objects written to stdin.
|
|
||||||
- Responses are JSON objects with `type: "response"` and optional `id`.
|
|
||||||
- Events are JSON objects without `id`.
|
|
||||||
- `prompt` can include images using `ImageContent` (base64 or URL) alongside text.
|
|
||||||
- JSON/print mode (`pi -p` or `pi --print --mode json`) produces JSONL for non-interactive parsing and can resume sessions with a token.
|
|
||||||
|
|
||||||
### RPC commands
|
|
||||||
RPC commands listed in `rpc.md` include:
|
|
||||||
- `new_session`, `get_state`, `list_sessions`, `delete_session`, `rename_session`, `clear_session`
|
|
||||||
- `prompt`, `queue_message`, `abort`, `get_queued_messages`
|
|
||||||
|
|
||||||
### RPC event types
|
|
||||||
RPC events listed in `rpc.md` include:
|
|
||||||
- `agent_start`, `agent_end`
|
|
||||||
- `turn_start`, `turn_end`
|
|
||||||
- `message_start`, `message_update`, `message_end`
|
|
||||||
- `tool_execution_start`, `tool_execution_update`, `tool_execution_end`
|
|
||||||
- `auto_compaction`, `auto_retry`, `hook_error`
|
|
||||||
|
|
||||||
`message_update` uses `assistantMessageEvent` deltas such as:
|
|
||||||
- `start`, `text_start`, `text_delta`, `text_end`
|
|
||||||
- `thinking_start`, `thinking_delta`, `thinking_end`
|
|
||||||
- `toolcall_start`, `toolcall_delta`, `toolcall_end`
|
|
||||||
- `toolcall_args_start`, `toolcall_args_delta`, `toolcall_args_end`
|
|
||||||
- `done`, `error`
|
|
||||||
|
|
||||||
`tool_execution_update` includes `partialResult`, which is described as accumulated output so far.
|
|
||||||
|
|
||||||
### Schema source locations (pi-mono)
|
|
||||||
RPC types are documented as living in:
|
|
||||||
- `packages/ai/src/types.ts` (Model types)
|
|
||||||
- `packages/agent/src/types.ts` (AgentResponse types)
|
|
||||||
- `packages/coding-agent/src/core/messages.ts` (message types)
|
|
||||||
- `packages/coding-agent/src/modes/rpc/rpc-types.ts` (RPC protocol types)
|
|
||||||
|
|
||||||
### Distribution assets
|
|
||||||
Pi releases provide platform-specific binaries such as:
|
|
||||||
- `pi-darwin-arm64`, `pi-darwin-x64`
|
|
||||||
- `pi-linux-arm64`, `pi-linux-x64`
|
|
||||||
- `pi-win-x64.zip`
|
|
||||||
|
|
||||||
## Integration Decisions
|
|
||||||
- Follow the OpenCode pattern: a shared long-running process (stdio RPC) with session multiplexing.
|
|
||||||
- Primary integration path is RPC streaming (`pi --mode rpc`).
|
|
||||||
- JSON/print mode is a fallback only (diagnostics or non-interactive runs).
|
|
||||||
- Create sessions via `new_session`; store the returned `sessionId` as `native_session_id`.
|
|
||||||
- Use `get_state` as a re-sync path after server restarts.
|
|
||||||
- Use `prompt` for send-message, with optional image content.
|
|
||||||
- Convert Pi events into universal events; emit daemon synthetic `session.started` on session creation and `session.ended` only on errors/termination.
|
|
||||||
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
### 1) Agent Identity + Capabilities
|
|
||||||
Files:
|
|
||||||
- `server/packages/agent-management/src/agents.rs`
|
|
||||||
- `server/packages/sandbox-agent/src/router.rs`
|
|
||||||
- `docs/cli.mdx`, `docs/conversion.mdx`, `docs/session-transcript-schema.mdx`
|
|
||||||
- `README.md`, `frontend/packages/website/src/components/FAQ.tsx`
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Add `AgentId::Pi` with string/binary name `"pi"` and parsing rules.
|
|
||||||
- Add Pi to `all_agents()` and agent lists.
|
|
||||||
- Define `AgentCapabilities` for Pi:
|
|
||||||
- `tool_calls=true`, `tool_results=true`
|
|
||||||
- `text_messages=true`, `streaming_deltas=true`, `item_started=true`
|
|
||||||
- `reasoning=true` (from `thinking_*` deltas)
|
|
||||||
- `images=true` (ImageContent in `prompt`)
|
|
||||||
- `permissions=false`, `questions=false`, `mcp_tools=false`
|
|
||||||
- `shared_process=true`, `session_lifecycle=false` (no native session events)
|
|
||||||
- `error_events=true` (hook_error)
|
|
||||||
- `command_execution=false`, `file_changes=false`, `file_attachments=false`
|
|
||||||
|
|
||||||
### 2) Installer and Binary Resolution
|
|
||||||
Files:
|
|
||||||
- `server/packages/agent-management/src/agents.rs`
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Add `install_pi()` that:
|
|
||||||
- Downloads the correct release asset per platform (`pi-<platform>`).
|
|
||||||
- Handles `.zip` on Windows and raw binaries elsewhere.
|
|
||||||
- Marks binary executable.
|
|
||||||
- Add Pi to `AgentManager::install`, `is_installed`, `version`.
|
|
||||||
- Version detection: try `--version`, `version`, `-V`.
|
|
||||||
|
|
||||||
### 3) Schema Extraction for Pi
|
|
||||||
Files:
|
|
||||||
- `resources/agent-schemas/src/pi.ts` (new)
|
|
||||||
- `resources/agent-schemas/src/index.ts`
|
|
||||||
- `resources/agent-schemas/artifacts/json-schema/pi.json`
|
|
||||||
- `server/packages/extracted-agent-schemas/build.rs`
|
|
||||||
- `server/packages/extracted-agent-schemas/src/lib.rs`
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Implement `extractPiSchema()`:
|
|
||||||
- Download pi-mono sources (zip/tarball) into a temp dir.
|
|
||||||
- Use `ts-json-schema-generator` against `packages/coding-agent/src/modes/rpc/rpc-types.ts`.
|
|
||||||
- Include dependent files per `rpc.md` (ai/types, agent/types, core/messages).
|
|
||||||
- Extract `RpcEvent`, `RpcResponse`, `RpcCommand` unions (exact type names from source).
|
|
||||||
- Add fallback schema if remote fetch fails (minimal union with event/response fields).
|
|
||||||
- Wire pi into extractor index and artifact generation.
|
|
||||||
|
|
||||||
### 4) Universal Schema Conversion (Pi -> Universal)
|
|
||||||
Files:
|
|
||||||
- `server/packages/universal-agent-schema/src/agents/pi.rs` (new)
|
|
||||||
- `server/packages/universal-agent-schema/src/agents/mod.rs`
|
|
||||||
- `server/packages/universal-agent-schema/src/lib.rs`
|
|
||||||
- `server/packages/sandbox-agent/src/router.rs`
|
|
||||||
|
|
||||||
Mapping rules:
|
|
||||||
- `message_start` -> `item.started` (kind=message, role=assistant, native_item_id=messageId)
|
|
||||||
- `message_update`:
|
|
||||||
- `text_*` -> `item.delta` (assistant text delta)
|
|
||||||
- `thinking_*` -> `item.delta` with `ContentPart::Reasoning` (visibility=Private)
|
|
||||||
- `toolcall_*` and `toolcall_args_*` -> ignore for now (tool_execution_* is authoritative)
|
|
||||||
- `error` -> `item.completed` with `ItemStatus::Failed` (if no later message_end)
|
|
||||||
- `message_end` -> `item.completed` (finalize assistant message)
|
|
||||||
- `tool_execution_start` -> `item.started` (kind=tool_call, ContentPart::ToolCall)
|
|
||||||
- `tool_execution_update` -> `item.delta` for a synthetic tool_result item:
|
|
||||||
- Maintain a per-toolCallId buffer to compute delta from accumulated `partialResult`.
|
|
||||||
- `tool_execution_end` -> `item.completed` (kind=tool_result, output from `result.content`)
|
|
||||||
- If `isError=true`, set item status to failed.
|
|
||||||
- `agent_start`, `turn_start`, `turn_end`, `agent_end`, `auto_compaction`, `auto_retry`, `hook_error`:
|
|
||||||
- Map to `ItemKind::Status` with a label like `pi.agent_start`, `pi.auto_retry`, etc.
|
|
||||||
- Do not emit `session.ended` for these events.
|
|
||||||
- If event parsing fails, emit `agent.unparsed` (source=daemon, synthetic=true) and fail tests.
|
|
||||||
|
|
||||||
### 5) Shared RPC Server Integration
|
|
||||||
Files:
|
|
||||||
- `server/packages/sandbox-agent/src/router.rs`
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Add a new managed stdio server type for Pi, similar to Codex:
|
|
||||||
- Create `PiServer` struct with:
|
|
||||||
- stdin sender
|
|
||||||
- pending request map keyed by request id
|
|
||||||
- per-session native session id mapping
|
|
||||||
- Extend `ManagedServerKind` to include Pi.
|
|
||||||
- Add `ensure_pi_server()` and `spawn_pi_server()` using `pi --mode rpc`.
|
|
||||||
- Add a `handle_pi_server_output()` loop to parse stdout lines into events/responses.
|
|
||||||
- Session creation:
|
|
||||||
- On `create_session`, ensure Pi server is running, send `new_session`, store sessionId.
|
|
||||||
- Register session with `server_manager.register_session` for native mapping.
|
|
||||||
- Sending messages:
|
|
||||||
- Use `prompt` command; include sessionId and optional images.
|
|
||||||
- Emit synthetic `item.started` only if Pi does not emit `message_start`.
|
|
||||||
|
|
||||||
### 6) Router + Streaming Path Changes
|
|
||||||
Files:
|
|
||||||
- `server/packages/sandbox-agent/src/router.rs`
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Add Pi handling to:
|
|
||||||
- `create_session` (new_session)
|
|
||||||
- `send_message` (prompt)
|
|
||||||
- `parse_agent_line` (Pi event conversion)
|
|
||||||
- `agent_modes` (default to `default` unless Pi exposes a mode list)
|
|
||||||
- `agent_supports_resume` (true if Pi supports session resume)
|
|
||||||
|
|
||||||
### 7) Tests
|
|
||||||
Files:
|
|
||||||
- `server/packages/sandbox-agent/tests/...`
|
|
||||||
- `server/packages/universal-agent-schema/tests/...` (if present)
|
|
||||||
|
|
||||||
Tasks:
|
|
||||||
- Unit tests for conversion:
|
|
||||||
- `message_start/update/end` -> item.started/delta/completed
|
|
||||||
- `tool_execution_*` -> tool call/result mapping with partialResult delta
|
|
||||||
- failure -> agent.unparsed
|
|
||||||
- Integration tests:
|
|
||||||
- Start Pi RPC server, create session, send prompt, stream events.
|
|
||||||
- Validate `native_session_id` mapping and event ordering.
|
|
||||||
- Update HTTP/SSE test coverage to include Pi agent if relevant.
|
|
||||||
|
|
||||||
## Risk Areas / Edge Cases
|
|
||||||
- `tool_execution_update.partialResult` is cumulative; must compute deltas.
|
|
||||||
- `message_update` may emit `done`/`error` without `message_end`; handle both paths.
|
|
||||||
- No native session lifecycle events; rely on daemon synthetic events.
|
|
||||||
- Session recovery after RPC server restart requires `get_state` + re-register sessions.
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
- Pi appears in `/v1/agents`, CLI list, and docs.
|
|
||||||
- `create_session` returns `native_session_id` from Pi `new_session`.
|
|
||||||
- Streaming prompt yields universal events with proper ordering:
|
|
||||||
- message -> item.started/delta/completed
|
|
||||||
- tool execution -> tool call + tool result
|
|
||||||
- Tests pass and no synthetic data is used in test fixtures.
|
|
||||||
|
|
||||||
## Sources
|
|
||||||
- https://upd.dev/badlogic/pi-mono/src/commit/d36e0ea07303d8a76d51b4a7bd5f0d6d3c490860/packages/coding-agent/docs/rpc.md
|
|
||||||
- https://buildwithpi.ai/pi-cli
|
|
||||||
- https://takopi.dev/docs/pi-cli/
|
|
||||||
- https://upd.dev/badlogic/pi-mono/releases
|
|
||||||
|
|
@ -64,7 +64,7 @@ icon: "rocket"
|
||||||
docker run -p 2468:2468 \
|
docker run -p 2468:2468 \
|
||||||
-e ANTHROPIC_API_KEY="sk-ant-..." \
|
-e ANTHROPIC_API_KEY="sk-ant-..." \
|
||||||
-e OPENAI_API_KEY="sk-..." \
|
-e OPENAI_API_KEY="sk-..." \
|
||||||
rivetdev/sandbox-agent:0.4.1-full \
|
rivetdev/sandbox-agent:0.4.2-full \
|
||||||
server --no-token --host 0.0.0.0 --port 2468
|
server --no-token --host 0.0.0.0 --port 2468
|
||||||
```
|
```
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
|
||||||
|
|
@ -1,388 +0,0 @@
|
||||||
---
|
|
||||||
title: "Session Transcript Schema"
|
|
||||||
description: "Universal event schema for session transcripts across all agents."
|
|
||||||
---
|
|
||||||
|
|
||||||
Each coding agent outputs events in its own native format. The sandbox-agent converts these into a universal event schema, giving you a consistent session transcript regardless of which agent you use.
|
|
||||||
|
|
||||||
The schema is defined in [OpenAPI format](https://github.com/rivet-dev/sandbox-agent/blob/main/docs/openapi.json). See the [HTTP API Reference](/api-reference) for endpoint documentation.
|
|
||||||
|
|
||||||
## Coverage Matrix
|
|
||||||
|
|
||||||
This table shows which agent feature coverage appears in the universal event stream. All agents retain their full native feature coverage—this only reflects what's normalized into the schema.
|
|
||||||
|
|
||||||
| Feature | Claude | Codex | OpenCode | Amp | Pi (RPC) |
|
|
||||||
|--------------------|:------:|:-----:|:------------:|:------------:|:------------:|
|
|
||||||
| Stability | Stable | Stable| Experimental | Experimental | Experimental |
|
|
||||||
| Text Messages | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
| Tool Calls | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
| Tool Results | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
| Questions (HITL) | ✓ | | ✓ | | |
|
|
||||||
| Permissions (HITL) | ✓ | ✓ | ✓ | - | |
|
|
||||||
| Images | - | ✓ | ✓ | - | ✓ |
|
|
||||||
| File Attachments | - | ✓ | ✓ | - | |
|
|
||||||
| Session Lifecycle | - | ✓ | ✓ | - | |
|
|
||||||
| Error Events | - | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
| Reasoning/Thinking | - | ✓ | - | - | ✓ |
|
|
||||||
| Command Execution | - | ✓ | - | - | |
|
|
||||||
| File Changes | - | ✓ | - | - | |
|
|
||||||
| MCP Tools | ✓ | ✓ | ✓ | ✓ | |
|
|
||||||
| Streaming Deltas | ✓ | ✓ | ✓ | - | ✓ |
|
|
||||||
| Variants | | ✓ | ✓ | ✓ | ✓ |
|
|
||||||
|
|
||||||
Agents: [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) · [Pi](https://buildwithpi.ai/pi-cli)
|
|
||||||
|
|
||||||
- ✓ = Appears in session events
|
|
||||||
- \- = Agent supports natively, schema conversion coming soon
|
|
||||||
- (blank) = Not supported by agent
|
|
||||||
- Pi runtime model is router-managed per-session RPC (`pi --mode rpc`); it does not use generic subprocess streaming.
|
|
||||||
|
|
||||||
<AccordionGroup>
|
|
||||||
<Accordion title="Text Messages">
|
|
||||||
Basic message exchange between user and assistant.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Tool Calls & Results">
|
|
||||||
Visibility into tool invocations (file reads, command execution, etc.) and their results. When not natively supported, tool activity is embedded in message content.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Questions (HITL)">
|
|
||||||
Interactive questions the agent asks the user. Emits `question.requested` and `question.resolved` events.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Permissions (HITL)">
|
|
||||||
Permission requests for sensitive operations. Emits `permission.requested` and `permission.resolved` events.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Images">
|
|
||||||
Support for image attachments in messages.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="File Attachments">
|
|
||||||
Support for file attachments in messages.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Session Lifecycle">
|
|
||||||
Native `session.started` and `session.ended` events. When not supported, the daemon emits synthetic lifecycle events.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Error Events">
|
|
||||||
Structured error events for runtime failures.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Reasoning/Thinking">
|
|
||||||
Extended thinking or reasoning content with visibility controls.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Command Execution">
|
|
||||||
Detailed command execution events with stdout/stderr.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="File Changes">
|
|
||||||
Structured file modification events with diffs.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="MCP Tools">
|
|
||||||
Model Context Protocol tool support.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Streaming Deltas">
|
|
||||||
Native streaming of content deltas. When not supported, the daemon emits a single synthetic delta before `item.completed`.
|
|
||||||
</Accordion>
|
|
||||||
<Accordion title="Variants">
|
|
||||||
Model variants such as reasoning effort or depth. Agents may expose different variant sets per model.
|
|
||||||
</Accordion>
|
|
||||||
</AccordionGroup>
|
|
||||||
|
|
||||||
Want support for another agent? [Open an issue](https://github.com/rivet-dev/sandbox-agent/issues/new) to request it.
|
|
||||||
|
|
||||||
## UniversalEvent
|
|
||||||
|
|
||||||
Every event from the API is wrapped in a `UniversalEvent` envelope.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `event_id` | string | Unique identifier for this event |
|
|
||||||
| `sequence` | integer | Monotonic sequence number within the session (starts at 1) |
|
|
||||||
| `time` | string | RFC3339 timestamp |
|
|
||||||
| `session_id` | string | Daemon-generated session identifier |
|
|
||||||
| `native_session_id` | string? | Provider-native session/thread identifier (e.g., Codex `threadId`, OpenCode `sessionID`) |
|
|
||||||
| `source` | string | Event origin: `agent` (native) or `daemon` (synthetic) |
|
|
||||||
| `synthetic` | boolean | Whether this event was generated by the daemon to fill gaps |
|
|
||||||
| `type` | string | Event type (see [Event Types](#event-types)) |
|
|
||||||
| `data` | object | Event-specific payload |
|
|
||||||
| `raw` | any? | Original provider payload (only when `include_raw=true`) |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"event_id": "evt_abc123",
|
|
||||||
"sequence": 1,
|
|
||||||
"time": "2025-01-28T12:00:00Z",
|
|
||||||
"session_id": "my-session",
|
|
||||||
"native_session_id": "thread_xyz",
|
|
||||||
"source": "agent",
|
|
||||||
"synthetic": false,
|
|
||||||
"type": "item.completed",
|
|
||||||
"data": { ... }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Event Types
|
|
||||||
|
|
||||||
### Session Lifecycle
|
|
||||||
|
|
||||||
| Type | Description | Data |
|
|
||||||
|------|-------------|------|
|
|
||||||
| `session.started` | Session has started | `{ metadata?: any }` |
|
|
||||||
| `session.ended` | Session has ended | `{ reason, terminated_by, message?, exit_code? }` |
|
|
||||||
|
|
||||||
### Turn Lifecycle
|
|
||||||
|
|
||||||
| Type | Description | Data |
|
|
||||||
|------|-------------|------|
|
|
||||||
| `turn.started` | Turn has started | `{ phase: "started", turn_id?, metadata? }` |
|
|
||||||
| `turn.ended` | Turn has ended | `{ phase: "ended", turn_id?, metadata? }` |
|
|
||||||
|
|
||||||
**SessionEndedData**
|
|
||||||
|
|
||||||
| Field | Type | Values |
|
|
||||||
|-------|------|--------|
|
|
||||||
| `reason` | string | `completed`, `error`, `terminated` |
|
|
||||||
| `terminated_by` | string | `agent`, `daemon` |
|
|
||||||
| `message` | string? | Error message (only present when reason is `error`) |
|
|
||||||
| `exit_code` | int? | Process exit code (only present when reason is `error`) |
|
|
||||||
| `stderr` | StderrOutput? | Structured stderr output (only present when reason is `error`) |
|
|
||||||
|
|
||||||
**StderrOutput**
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `head` | string? | First 20 lines of stderr (if truncated) or full stderr (if not truncated) |
|
|
||||||
| `tail` | string? | Last 50 lines of stderr (only present if truncated) |
|
|
||||||
| `truncated` | boolean | Whether the output was truncated |
|
|
||||||
| `total_lines` | int? | Total number of lines in stderr |
|
|
||||||
|
|
||||||
### Item Lifecycle
|
|
||||||
|
|
||||||
| Type | Description | Data |
|
|
||||||
|------|-------------|------|
|
|
||||||
| `item.started` | Item creation | `{ item }` |
|
|
||||||
| `item.delta` | Streaming content delta | `{ item_id, native_item_id?, delta }` |
|
|
||||||
| `item.completed` | Item finalized | `{ item }` |
|
|
||||||
|
|
||||||
Items follow a consistent lifecycle: `item.started` → `item.delta` (0 or more) → `item.completed`.
|
|
||||||
|
|
||||||
### HITL (Human-in-the-Loop)
|
|
||||||
|
|
||||||
| Type | Description | Data |
|
|
||||||
|------|-------------|------|
|
|
||||||
| `permission.requested` | Permission request pending | `{ permission_id, action, status, metadata? }` |
|
|
||||||
| `permission.resolved` | Permission decision recorded | `{ permission_id, action, status, metadata? }` |
|
|
||||||
| `question.requested` | Question pending user input | `{ question_id, prompt, options, status }` |
|
|
||||||
| `question.resolved` | Question answered or rejected | `{ question_id, prompt, options, status, response? }` |
|
|
||||||
|
|
||||||
**PermissionEventData**
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `permission_id` | string | Identifier for the permission request |
|
|
||||||
| `action` | string | What the agent wants to do |
|
|
||||||
| `status` | string | `requested`, `accept`, `accept_for_session`, `reject` |
|
|
||||||
| `metadata` | any? | Additional context |
|
|
||||||
|
|
||||||
**QuestionEventData**
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `question_id` | string | Identifier for the question |
|
|
||||||
| `prompt` | string | Question text |
|
|
||||||
| `options` | string[] | Available answer options |
|
|
||||||
| `status` | string | `requested`, `answered`, `rejected` |
|
|
||||||
| `response` | string? | Selected answer (when resolved) |
|
|
||||||
|
|
||||||
### Errors
|
|
||||||
|
|
||||||
| Type | Description | Data |
|
|
||||||
|------|-------------|------|
|
|
||||||
| `error` | Runtime error | `{ message, code?, details? }` |
|
|
||||||
| `agent.unparsed` | Parse failure | `{ error, location, raw_hash? }` |
|
|
||||||
|
|
||||||
The `agent.unparsed` event indicates the daemon failed to parse an agent payload. This should be treated as a bug.
|
|
||||||
|
|
||||||
## UniversalItem
|
|
||||||
|
|
||||||
Items represent discrete units of content within a session.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `item_id` | string | Daemon-generated identifier |
|
|
||||||
| `native_item_id` | string? | Provider-native item/message identifier |
|
|
||||||
| `parent_id` | string? | Parent item ID (e.g., tool call/result parented to a message) |
|
|
||||||
| `kind` | string | Item category (see below) |
|
|
||||||
| `role` | string? | Actor role for message items |
|
|
||||||
| `status` | string | Lifecycle status |
|
|
||||||
| `content` | ContentPart[] | Ordered list of content parts |
|
|
||||||
|
|
||||||
### ItemKind
|
|
||||||
|
|
||||||
| Value | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `message` | User or assistant message |
|
|
||||||
| `tool_call` | Tool invocation |
|
|
||||||
| `tool_result` | Tool execution result |
|
|
||||||
| `system` | System message |
|
|
||||||
| `status` | Status update |
|
|
||||||
| `unknown` | Unrecognized item type |
|
|
||||||
|
|
||||||
### ItemRole
|
|
||||||
|
|
||||||
| Value | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `user` | User message |
|
|
||||||
| `assistant` | Assistant response |
|
|
||||||
| `system` | System prompt |
|
|
||||||
| `tool` | Tool-related message |
|
|
||||||
|
|
||||||
### ItemStatus
|
|
||||||
|
|
||||||
| Value | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `in_progress` | Item is streaming or pending |
|
|
||||||
| `completed` | Item is finalized |
|
|
||||||
| `failed` | Item execution failed |
|
|
||||||
|
|
||||||
## Content Parts
|
|
||||||
|
|
||||||
The `content` array contains typed parts that make up an item's payload.
|
|
||||||
|
|
||||||
### text
|
|
||||||
|
|
||||||
Plain text content.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "type": "text", "text": "Hello, world!" }
|
|
||||||
```
|
|
||||||
|
|
||||||
### json
|
|
||||||
|
|
||||||
Structured JSON content.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "type": "json", "json": { "key": "value" } }
|
|
||||||
```
|
|
||||||
|
|
||||||
### tool_call
|
|
||||||
|
|
||||||
Tool invocation.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `name` | string | Tool name |
|
|
||||||
| `arguments` | string | JSON-encoded arguments |
|
|
||||||
| `call_id` | string | Unique call identifier |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "tool_call",
|
|
||||||
"name": "read_file",
|
|
||||||
"arguments": "{\"path\": \"/src/main.ts\"}",
|
|
||||||
"call_id": "call_abc123"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### tool_result
|
|
||||||
|
|
||||||
Tool execution result.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `call_id` | string | Matching call identifier |
|
|
||||||
| `output` | string | Tool output |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "tool_result",
|
|
||||||
"call_id": "call_abc123",
|
|
||||||
"output": "File contents here..."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### file_ref
|
|
||||||
|
|
||||||
File reference with optional diff.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `path` | string | File path |
|
|
||||||
| `action` | string | `read`, `write`, `patch` |
|
|
||||||
| `diff` | string? | Unified diff (for patches) |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "file_ref",
|
|
||||||
"path": "/src/main.ts",
|
|
||||||
"action": "write",
|
|
||||||
"diff": "@@ -1,3 +1,4 @@\n+import { foo } from 'bar';"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### image
|
|
||||||
|
|
||||||
Image reference.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `path` | string | Image file path |
|
|
||||||
| `mime` | string? | MIME type |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "type": "image", "path": "/tmp/screenshot.png", "mime": "image/png" }
|
|
||||||
```
|
|
||||||
|
|
||||||
### reasoning
|
|
||||||
|
|
||||||
Model reasoning/thinking content.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `text` | string | Reasoning text |
|
|
||||||
| `visibility` | string | `public` or `private` |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "type": "reasoning", "text": "Let me think about this...", "visibility": "public" }
|
|
||||||
```
|
|
||||||
|
|
||||||
### status
|
|
||||||
|
|
||||||
Status indicator.
|
|
||||||
|
|
||||||
| Field | Type | Description |
|
|
||||||
|-------|------|-------------|
|
|
||||||
| `label` | string | Status label |
|
|
||||||
| `detail` | string? | Additional detail |
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "type": "status", "label": "Running tests", "detail": "3 of 10 passed" }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Source & Synthetics
|
|
||||||
|
|
||||||
### EventSource
|
|
||||||
|
|
||||||
The `source` field indicates who emitted the event:
|
|
||||||
|
|
||||||
| Value | Description |
|
|
||||||
|-------|-------------|
|
|
||||||
| `agent` | Native event from the agent |
|
|
||||||
| `daemon` | Synthetic event generated by the daemon |
|
|
||||||
|
|
||||||
### Synthetic Events
|
|
||||||
|
|
||||||
The daemon emits synthetic events (`synthetic: true`, `source: "daemon"`) to provide a consistent event stream across all agents. Common synthetics:
|
|
||||||
|
|
||||||
| Synthetic | When |
|
|
||||||
|-----------|------|
|
|
||||||
| `session.started` | Agent doesn't emit explicit session start |
|
|
||||||
| `session.ended` | Agent doesn't emit explicit session end |
|
|
||||||
| `turn.started` | Agent doesn't emit explicit turn start |
|
|
||||||
| `turn.ended` | Agent doesn't emit explicit turn end |
|
|
||||||
| `item.started` | Agent doesn't emit item start events |
|
|
||||||
| `item.delta` | Agent doesn't stream deltas natively |
|
|
||||||
| `question.*` | Claude Code plan mode (from ExitPlanMode tool) |
|
|
||||||
|
|
||||||
### Raw Payloads
|
|
||||||
|
|
||||||
Pass `include_raw=true` to event endpoints to receive the original agent payload in the `raw` field. Useful for debugging or accessing agent-specific data not in the universal schema.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const events = await client.getEvents("my-session", { includeRaw: true });
|
|
||||||
// events[0].raw contains the original agent payload
|
|
||||||
```
|
|
||||||
|
|
@ -29,25 +29,6 @@ Verify the agent is installed:
|
||||||
ls -la ~/.local/share/sandbox-agent/bin/
|
ls -la ~/.local/share/sandbox-agent/bin/
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Binary libc mismatch (musl vs glibc)
|
|
||||||
|
|
||||||
Claude Code binaries are available in both musl and glibc variants. If you see errors like:
|
|
||||||
|
|
||||||
```
|
|
||||||
cannot execute: required file not found
|
|
||||||
Error loading shared library libstdc++.so.6: No such file or directory
|
|
||||||
```
|
|
||||||
|
|
||||||
This means the wrong binary variant was downloaded.
|
|
||||||
|
|
||||||
**For sandbox-agent 0.2.0+**: Platform detection is automatic. The correct binary (musl or glibc) is downloaded based on the runtime environment.
|
|
||||||
|
|
||||||
**For sandbox-agent 0.1.x**: Use Alpine Linux which has native musl support:
|
|
||||||
|
|
||||||
```dockerfile
|
|
||||||
FROM alpine:latest
|
|
||||||
RUN apk add --no-cache curl ca-certificates libstdc++ libgcc bash
|
|
||||||
```
|
|
||||||
|
|
||||||
## Daytona Network Restrictions
|
## Daytona Network Restrictions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
const REPO_ROOT = path.resolve(__dirname, "..", "..", "..");
|
const REPO_ROOT = path.resolve(__dirname, "..", "..", "..");
|
||||||
|
|
||||||
/** Pre-built Docker image with all agents installed. */
|
/** Pre-built Docker image with all agents installed. */
|
||||||
export const FULL_IMAGE = "rivetdev/sandbox-agent:0.4.1-full";
|
export const FULL_IMAGE = "rivetdev/sandbox-agent:0.4.2-full";
|
||||||
|
|
||||||
export interface DockerSandboxOptions {
|
export interface DockerSandboxOptions {
|
||||||
/** Container port used by sandbox-agent inside Docker. */
|
/** Container port used by sandbox-agent inside Docker. */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "acp-http-client",
|
"name": "acp-http-client",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "Protocol-faithful ACP JSON-RPC over streamable HTTP client.",
|
"description": "Protocol-faithful ACP JSON-RPC over streamable HTTP client.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-shared",
|
"name": "@sandbox-agent/cli-shared",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "Shared helpers for sandbox-agent CLI and SDK",
|
"description": "Shared helpers for sandbox-agent CLI and SDK",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli",
|
"name": "@sandbox-agent/cli",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "CLI for sandbox-agent - run AI coding agents in sandboxes",
|
"description": "CLI for sandbox-agent - run AI coding agents in sandboxes",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-darwin-arm64",
|
"name": "@sandbox-agent/cli-darwin-arm64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "sandbox-agent CLI binary for macOS ARM64",
|
"description": "sandbox-agent CLI binary for macOS ARM64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-darwin-x64",
|
"name": "@sandbox-agent/cli-darwin-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "sandbox-agent CLI binary for macOS x64",
|
"description": "sandbox-agent CLI binary for macOS x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-linux-arm64",
|
"name": "@sandbox-agent/cli-linux-arm64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "sandbox-agent CLI binary for Linux arm64",
|
"description": "sandbox-agent CLI binary for Linux arm64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-linux-x64",
|
"name": "@sandbox-agent/cli-linux-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "sandbox-agent CLI binary for Linux x64",
|
"description": "sandbox-agent CLI binary for Linux x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/cli-win32-x64",
|
"name": "@sandbox-agent/cli-win32-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "sandbox-agent CLI binary for Windows x64",
|
"description": "sandbox-agent CLI binary for Windows x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode",
|
"name": "@sandbox-agent/gigacode",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "Gigacode CLI (sandbox-agent with OpenCode attach by default)",
|
"description": "Gigacode CLI (sandbox-agent with OpenCode attach by default)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode-darwin-arm64",
|
"name": "@sandbox-agent/gigacode-darwin-arm64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "gigacode CLI binary for macOS arm64",
|
"description": "gigacode CLI binary for macOS arm64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode-darwin-x64",
|
"name": "@sandbox-agent/gigacode-darwin-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "gigacode CLI binary for macOS x64",
|
"description": "gigacode CLI binary for macOS x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode-linux-arm64",
|
"name": "@sandbox-agent/gigacode-linux-arm64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "gigacode CLI binary for Linux arm64",
|
"description": "gigacode CLI binary for Linux arm64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode-linux-x64",
|
"name": "@sandbox-agent/gigacode-linux-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "gigacode CLI binary for Linux x64",
|
"description": "gigacode CLI binary for Linux x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/gigacode-win32-x64",
|
"name": "@sandbox-agent/gigacode-win32-x64",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "gigacode CLI binary for Windows x64",
|
"description": "gigacode CLI binary for Windows x64",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/persist-indexeddb",
|
"name": "@sandbox-agent/persist-indexeddb",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "IndexedDB persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
"description": "IndexedDB persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/persist-postgres",
|
"name": "@sandbox-agent/persist-postgres",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "PostgreSQL persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
"description": "PostgreSQL persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/persist-rivet",
|
"name": "@sandbox-agent/persist-rivet",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "Rivet Actor persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
"description": "Rivet Actor persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/persist-sqlite",
|
"name": "@sandbox-agent/persist-sqlite",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "SQLite persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
"description": "SQLite persistence driver for the Sandbox Agent TypeScript SDK (DEPRECATED)",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@sandbox-agent/react",
|
"name": "@sandbox-agent/react",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "React components for Sandbox Agent frontend integrations",
|
"description": "React components for Sandbox Agent frontend integrations",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sandbox-agent",
|
"name": "sandbox-agent",
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"description": "Universal API for automatic coding agents in sandboxes. Supports Claude Code, Codex, OpenCode, and Amp.",
|
"description": "Universal API for automatic coding agents in sandboxes. Supports Claude Code, Codex, OpenCode, and Amp.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
||||||
|
|
@ -1093,9 +1093,9 @@ fn write_mock_agent_process_launcher(path: &Path) -> Result<(), AgentError> {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
let script = if cfg!(windows) {
|
let script = if cfg!(windows) {
|
||||||
"@echo off\r\nsandbox-agent mock-agent-process %*\r\n"
|
"@echo off\r\nif not \"%SANDBOX_AGENT_BIN%\"==\"\" (\r\n \"%SANDBOX_AGENT_BIN%\" mock-agent-process %*\r\n exit /b %errorlevel%\r\n)\r\nsandbox-agent mock-agent-process %*\r\n"
|
||||||
} else {
|
} else {
|
||||||
"#!/usr/bin/env sh\nexec sandbox-agent mock-agent-process \"$@\"\n"
|
"#!/usr/bin/env sh\nif [ -n \"${SANDBOX_AGENT_BIN:-}\" ]; then\n exec \"$SANDBOX_AGENT_BIN\" mock-agent-process \"$@\"\nfi\nexec sandbox-agent mock-agent-process \"$@\"\n"
|
||||||
};
|
};
|
||||||
write_text_file(path, script)
|
write_text_file(path, script)
|
||||||
}
|
}
|
||||||
|
|
@ -1969,6 +1969,34 @@ exit 0
|
||||||
assert_eq!(result.artifacts[0].source, InstallSource::Builtin);
|
assert_eq!(result.artifacts[0].source, InstallSource::Builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mock_launcher_prefers_sandbox_agent_bin() {
|
||||||
|
let temp_dir = tempfile::tempdir().expect("create tempdir");
|
||||||
|
let manager = AgentManager::with_platform(temp_dir.path(), Platform::LinuxX64);
|
||||||
|
|
||||||
|
manager
|
||||||
|
.install(
|
||||||
|
AgentId::Mock,
|
||||||
|
InstallOptions {
|
||||||
|
reinstall: true,
|
||||||
|
version: None,
|
||||||
|
agent_process_version: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.expect("mock install");
|
||||||
|
|
||||||
|
let launcher = manager.agent_process_path(AgentId::Mock);
|
||||||
|
let mut file = fs::File::open(&launcher).expect("open mock launcher");
|
||||||
|
let mut contents = String::new();
|
||||||
|
file.read_to_string(&mut contents)
|
||||||
|
.expect("read mock launcher");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
contents.contains("SANDBOX_AGENT_BIN"),
|
||||||
|
"mock launcher should reference SANDBOX_AGENT_BIN"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn install_pi_skips_native_and_installs_fallback_npm_launcher() {
|
fn install_pi_skips_native_and_installs_fallback_npm_launcher() {
|
||||||
let _env_lock = env_lock().lock().expect("env lock");
|
let _env_lock = env_lock().lock().expect("env lock");
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ impl AcpProxyRuntime {
|
||||||
|
|
||||||
let resolve_started = std::time::Instant::now();
|
let resolve_started = std::time::Instant::now();
|
||||||
let manager = self.inner.agent_manager.clone();
|
let manager = self.inner.agent_manager.clone();
|
||||||
let launch = tokio::task::spawn_blocking(move || manager.resolve_agent_process(agent))
|
let mut launch = tokio::task::spawn_blocking(move || manager.resolve_agent_process(agent))
|
||||||
.await
|
.await
|
||||||
.map_err(|err| SandboxError::StreamError {
|
.map_err(|err| SandboxError::StreamError {
|
||||||
message: format!("failed to resolve agent process launch spec: {err}"),
|
message: format!("failed to resolve agent process launch spec: {err}"),
|
||||||
|
|
@ -307,6 +307,16 @@ impl AcpProxyRuntime {
|
||||||
message: err.to_string(),
|
message: err.to_string(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
if agent == AgentId::Mock {
|
||||||
|
if let Ok(exe) = std::env::current_exe() {
|
||||||
|
let path = exe.to_string_lossy().to_string();
|
||||||
|
launch
|
||||||
|
.env
|
||||||
|
.entry("SANDBOX_AGENT_BIN".to_string())
|
||||||
|
.or_insert(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
server_id = server_id,
|
server_id = server_id,
|
||||||
agent = agent.as_str(),
|
agent = agent.as_str(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue