Skip to content

Commit dc9a9f4

Browse files
authored
Merge pull request #12 from getlark/vd-20260317-1344
docs, examples, and v0.6.0 release
2 parents a82ff90 + 6a6e20f commit dc9a9f4

22 files changed

Lines changed: 1452 additions & 123 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ Thumbs.db
3030
# Scratch files
3131
scratch_*
3232

33+
# Python bytecode
34+
__pycache__/
35+
*.pyc
36+
*.pyo
37+
3338
# Logs and temp
3439
*.log
3540
npm-debug.log*

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,43 @@ Run AI agents inside sandboxes and communicate with them over WebSocket.
1414
### 1. Start the runtime (inside a sandbox)
1515

1616
```bash
17+
export OPENAI_API_KEY=your_openai_api_key
1718
npx -y runtimeuse
1819
```
1920

20-
This starts a WebSocket server on port 8080 using the OpenAI agent handler by default. Use `--agent claude` for Claude. The Claude handler also requires the `claude` CLI to be installed in the sandbox, for example with `npm install -g @anthropic-ai/claude-code`.
21+
This starts a WebSocket server on port 8080 using the default OpenAI handler. For fuller Claude-based sandbox examples, see [`examples/`](./examples).
2122

2223
### 2. Connect from Python
2324

2425
```python
2526
import asyncio
26-
from runtimeuse_client import RuntimeUseClient, QueryOptions
27+
from runtimeuse_client import (
28+
QueryOptions,
29+
RuntimeEnvironmentDownloadableInterface,
30+
RuntimeUseClient,
31+
TextResult,
32+
)
33+
34+
WORKDIR = "/runtimeuse"
2735

2836
async def main():
2937
client = RuntimeUseClient(ws_url="ws://localhost:8080")
3038

3139
result = await client.query(
32-
prompt="What is 2 + 2?",
40+
prompt="Summarize the contents of the codex repository.",
3341
options=QueryOptions(
3442
system_prompt="You are a helpful assistant.",
35-
model="gpt-4.1",
43+
model="gpt-5.4",
44+
pre_agent_downloadables=[
45+
RuntimeEnvironmentDownloadableInterface(
46+
download_url="https://github.com/openai/codex/archive/refs/heads/main.zip",
47+
working_dir=WORKDIR,
48+
)
49+
],
3650
),
3751
)
3852

53+
assert isinstance(result.data, TextResult)
3954
print(result.data.text)
4055

4156
asyncio.run(main())
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
title: Agent Runtime
3+
description: CLI flags, built-in agent handlers, and custom handler authoring for the runtimeuse server.
4+
---
5+
6+
The [agent runtime](https://www.npmjs.com/package/runtimeuse) is the process that runs inside the sandbox. It exposes a WebSocket server, receives invocations from the Python client, and delegates work to an agent handler.
7+
8+
## CLI
9+
10+
```bash
11+
npx -y runtimeuse # OpenAI handler on port 8080
12+
npx -y runtimeuse --agent claude # Claude handler
13+
npx -y runtimeuse --port 3000 # custom port
14+
npx -y runtimeuse --handler ./my-handler.js # custom handler entrypoint
15+
```
16+
17+
## Built-in Handlers
18+
19+
- `openai`: the default handler, uses the [OpenAI Agents SDK](https://openai.github.io/openai-agents-js/) with shell and web search tools.
20+
- `claude`: uses [Claude Agents SDK](https://platform.claude.com/docs/en/agent-sdk/overview) with Claude Code preset.
21+
22+
### OpenAI Handler
23+
24+
Requires `OPENAI_API_KEY` to be set in the environment. The handler runs the agent with shell access and web search enabled.
25+
26+
```bash
27+
export OPENAI_API_KEY=your_openai_api_key
28+
npx -y runtimeuse
29+
```
30+
31+
### Claude Handler
32+
33+
Requires the `@anthropic-ai/claude-code` CLI and `ANTHROPIC_API_KEY`. Always set `IS_SANDBOX=1` and `CLAUDE_SKIP_ROOT_CHECK=1` in the sandbox environment.
34+
35+
```bash
36+
npm install -g @anthropic-ai/claude-code
37+
export ANTHROPIC_API_KEY=your_anthropic_api_key
38+
export IS_SANDBOX=1
39+
export CLAUDE_SKIP_ROOT_CHECK=1
40+
npx -y runtimeuse --agent claude
41+
```
42+
43+
## Programmatic Startup
44+
45+
If you want to embed RuntimeUse directly in your own Node process, start it programmatically:
46+
47+
```typescript
48+
import { RuntimeUseServer, openaiHandler } from "runtimeuse";
49+
50+
const server = new RuntimeUseServer({
51+
handler: openaiHandler,
52+
port: 8080,
53+
});
54+
55+
await server.startListening();
56+
```
57+
58+
## Custom Handlers
59+
60+
When the built-in handlers are not enough, you can pass your own handler to `RuntimeUseServer`:
61+
62+
```typescript
63+
import { RuntimeUseServer } from "runtimeuse";
64+
import type {
65+
AgentHandler,
66+
AgentInvocation,
67+
AgentResult,
68+
MessageSender,
69+
} from "runtimeuse";
70+
71+
const handler: AgentHandler = {
72+
async run(
73+
invocation: AgentInvocation,
74+
sender: MessageSender,
75+
): Promise<AgentResult> {
76+
sender.sendAssistantMessage(["Running agent..."]);
77+
78+
const output = await myAgent(
79+
invocation.systemPrompt,
80+
invocation.userPrompt,
81+
);
82+
83+
return {
84+
type: "structured_output",
85+
structuredOutput: output,
86+
metadata: { duration_ms: 1500 },
87+
};
88+
},
89+
};
90+
91+
const server = new RuntimeUseServer({ handler, port: 8080 });
92+
await server.startListening();
93+
```
94+
95+
### Handler Contracts
96+
97+
Your handler receives an `AgentInvocation` with:
98+
99+
| Field | Type | Description |
100+
| ----- | ---- | ----------- |
101+
| `systemPrompt` | `string` | System prompt for the agent. |
102+
| `userPrompt` | `string` | User prompt sent from the Python client. |
103+
| `model` | `string` | Model name passed by the client. |
104+
| `outputFormat` | `{ type: "json_schema"; schema: ... } \| undefined` | Present when the client requests structured output. Pass to your agent to enforce the schema. |
105+
| `signal` | `AbortSignal` | Fires when the client sends a cancel message. Pass to any async operations that support cancellation. |
106+
| `logger` | `Logger` | Use `invocation.logger.log(msg)` to emit log lines visible in sandbox logs. |
107+
108+
Use `MessageSender` to stream intermediate output before returning the final result:
109+
110+
- `sendAssistantMessage(textBlocks: string[])`: emit text blocks the Python client receives via `on_assistant_message`.
111+
- `sendErrorMessage(error: string, metadata?: Record<string, unknown>)`: signal a non-fatal error before aborting.
112+
113+
Return an `AgentResult` from your handler:
114+
115+
```typescript
116+
// Text result
117+
return { type: "text", text: "...", metadata: { duration_ms: 100 } };
118+
119+
// Structured output result
120+
return { type: "structured_output", structuredOutput: { file_count: 42 }, metadata: {} };
121+
```
122+
123+
`metadata` is optional and is passed through to `result.metadata` on the Python side.

docs/content/docs/index.mdx

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,34 @@
11
---
22
title: Introduction
3-
description: Run AI agents in sandboxes and communicate with them over WebSocket.
3+
description: Run AI agents (Claude Code, OpenAI Agents, and more) in any sandbox, controlled from Python over WebSocket.
44
---
55

6-
## What is RuntimeUse?
6+
[RuntimeUse](https://github.com/getlark/runtimeuse) is an open-source runtime and client library for running AI agents inside isolated sandboxes and controlling them from Python over WebSocket.
77

8-
RuntimeUse lets you run an AI agent inside any sandbox and communicate with it over WebSocket. It handles the runtime lifecycle for you: file downloads, pre-commands, artifact uploads, cancellation, and structured results.
98

10-
It is made up of two parts:
9+
<img src="/terminal.svg" alt="RuntimeUse terminal" style={{ maxWidth: '560px', width: '100%' }} />
1110

12-
1. **`runtimeuse`**: the TypeScript runtime that runs inside the sandbox and exposes a WebSocket server.
13-
2. **`runtimeuse-client`**: the Python client that connects from outside the sandbox and sends invocations.
1411

15-
Today, the recommended path is to run the runtime in the sandbox and use the Python client from your application code.
12+
<Card
13+
title="Quickstart"
14+
description="See how to integrate with popular sandbox providers."
15+
href="/quickstart"
16+
/>
1617

17-
## Built-in Agent Handlers
1818

19-
The runtime ships with two built-in handlers:
19+
## When to use
2020

21-
- **`openai`** (default) — uses `@openai/agents` SDK
22-
- **`claude`** — uses `@anthropic-ai/claude-agent-sdk` with Claude Code tools and `bypassPermissions` mode
21+
- Your agent needs filesystem, CLI, or network access inside an isolated runtime.
22+
- Your application should stay outside the sandbox while still controlling the run.
23+
- You don't want to build infrastructure for interacting with your agent in sandbox.
2324

24-
Switch between them with `--agent openai` or `--agent claude`.
25+
## What it handles
2526

26-
The Claude handler also requires the `claude` CLI to be installed in the sandbox, for example:
27+
- **Task invocations**: send a prompt to any agent runtime and receive a result over WebSocket as text or typed JSON.
28+
- **pre_agent_downloadables**: fetch code, repos, or data into the sandbox before the run starts.
29+
- **Pre-commands**: run bash commands before the agent starts executing.
30+
- **Artifact uploads**: move generated files out of the sandbox with a presigned URL handshake.
31+
- **Streaming and cancellation**: receive progress updates and stop runs cleanly.
32+
- **Secret-aware execution**: redact sensitive values before they leave the sandbox.
2733

28-
```bash
29-
npm install -g @anthropic-ai/claude-code
30-
```
3134

32-
## Key Features
33-
34-
- **Sandbox-agnostic** — works with any provider that can run `npx` and expose a port
35-
- **Artifact management** — files written to the artifacts directory are automatically detected and uploaded through a presigned URL handshake with the client
36-
- **Secret redaction** — secret values are recursively replaced before they leave the sandbox
37-
- **Pre-commands** — run shell commands before agent invocation with automatic secret redaction and abort support
38-
39-
<Cards>
40-
<Card title="Quickstart" href="/docs/quickstart" />
41-
<Card title="Runtime Package" href="https://github.com/getlark/runtimeuse/tree/main/packages/runtimeuse" />
42-
<Card title="Python Client" href="https://github.com/getlark/runtimeuse/tree/main/packages/runtimeuse-client-python" />
43-
</Cards>

docs/content/docs/meta.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"pages": [
3+
"index",
4+
"quickstart",
5+
"python-client",
6+
"agent-runtime"
7+
]
8+
}

0 commit comments

Comments
 (0)