background-agents 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +402 -0
- package/dist/debug.d.ts +7 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +19 -0
- package/dist/debug.js.map +1 -0
- package/dist/factory.d.ts +31 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +47 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/base.d.ts +160 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +656 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/claude.d.ts +14 -0
- package/dist/providers/claude.d.ts.map +1 -0
- package/dist/providers/claude.js +122 -0
- package/dist/providers/claude.js.map +1 -0
- package/dist/providers/codex.d.ts +14 -0
- package/dist/providers/codex.d.ts.map +1 -0
- package/dist/providers/codex.js +160 -0
- package/dist/providers/codex.js.map +1 -0
- package/dist/providers/gemini.d.ts +16 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +91 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +6 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/opencode.d.ts +14 -0
- package/dist/providers/opencode.d.ts.map +1 -0
- package/dist/providers/opencode.js +100 -0
- package/dist/providers/opencode.js.map +1 -0
- package/dist/sandbox/daytona-ssh.d.ts +9 -0
- package/dist/sandbox/daytona-ssh.d.ts.map +1 -0
- package/dist/sandbox/daytona-ssh.js +113 -0
- package/dist/sandbox/daytona-ssh.js.map +1 -0
- package/dist/sandbox/daytona.d.ts +4 -0
- package/dist/sandbox/daytona.d.ts.map +1 -0
- package/dist/sandbox/daytona.js +238 -0
- package/dist/sandbox/daytona.js.map +1 -0
- package/dist/sandbox/index.d.ts +14 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +15 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/session.d.ts +64 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +113 -0
- package/dist/session.js.map +1 -0
- package/dist/types/events.d.ts +114 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +50 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/provider.d.ts +124 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/provider.js +2 -0
- package/dist/types/provider.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/install.d.ts +27 -0
- package/dist/utils/install.d.ts.map +1 -0
- package/dist/utils/install.js +86 -0
- package/dist/utils/install.js.map +1 -0
- package/dist/utils/json.d.ts +8 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +15 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/session.d.ts +17 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js +59 -0
- package/dist/utils/session.js.map +1 -0
- package/next.config.codeagentsdk.cjs +22 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
# Coding Agents SDK
|
|
2
|
+
|
|
3
|
+
A unified TypeScript interface for AI coding agents—Claude, Codex, Gemini, and OpenCode. Commands run in secure [Daytona](https://daytona.io) sandboxes by default, with real-time PTY streaming.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Daytona } from "@daytonaio/sdk"
|
|
7
|
+
import { createSession } from "background-agents"
|
|
8
|
+
|
|
9
|
+
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
10
|
+
const sandbox = await daytona.create({ envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY } })
|
|
11
|
+
const session = await createSession("claude", { sandbox })
|
|
12
|
+
|
|
13
|
+
for await (const event of session.run("Hello!")) {
|
|
14
|
+
if (event.type === "token") process.stdout.write(event.text)
|
|
15
|
+
if (event.type === "end") break
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
await sandbox.delete()
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Same pattern for any provider: create a sandbox, create a session, stream events, then tear down. Swap the provider name and env keys as needed.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Secure by default** — Execution runs in isolated Daytona sandboxes
|
|
28
|
+
- **Real-time streaming** — PTY-based streaming for live token output
|
|
29
|
+
- **Unified API** — One interface for [Claude](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://developers.openai.com/codex/cli), [Gemini](https://geminicli.com/docs/), and [OpenCode](https://opencode.ai/docs/)
|
|
30
|
+
- **Zero-friction setup** — Provider CLI is installed when you create a session (`skipInstall: true` to skip). Env and Codex login run on every `run()`.
|
|
31
|
+
- **Session persistence** — Resume conversations across runs
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Provider support
|
|
36
|
+
|
|
37
|
+
| Provider | Status | Auth |
|
|
38
|
+
|----------|--------|------|
|
|
39
|
+
| [Claude](https://docs.anthropic.com/en/docs/claude-code) | ✅ | `ANTHROPIC_API_KEY` |
|
|
40
|
+
| [Codex](https://developers.openai.com/codex/cli) | ✅ | `OPENAI_API_KEY` |
|
|
41
|
+
| [OpenCode](https://opencode.ai/docs/) | ✅ | Provider-specific (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`) |
|
|
42
|
+
| [Gemini](https://geminicli.com/docs/) | 🚧 | `GOOGLE_API_KEY` |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Prerequisites
|
|
47
|
+
|
|
48
|
+
A [Daytona](https://daytona.io) API key (or [run locally](#local-mode-dangerous) without a sandbox).
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export DAYTONA_API_KEY=dtn_your_api_key
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install background-agents
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For sandboxed execution, also install the Daytona SDK:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install @daytonaio/sdk
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Next.js:** Merge the SDK's Next config so native deps (e.g. `ssh2` / `cpu-features`) are not bundled:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
// next.config.js or next.config.mjs
|
|
72
|
+
import codeagentsdk from 'background-agents/next.config'
|
|
73
|
+
export default { ...codeagentsdk, ...yourConfig }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
**1. Create a sandbox** — Pass provider API keys via the sandbox; the SDK does not read your host env.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { Daytona } from "@daytonaio/sdk"
|
|
84
|
+
import { createSession } from "background-agents"
|
|
85
|
+
|
|
86
|
+
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
87
|
+
const sandbox = await daytona.create({
|
|
88
|
+
envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**2. Create a session** — The provider CLI is installed in the sandbox (unless `skipInstall: true`).
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const session = await createSession("claude", {
|
|
96
|
+
sandbox,
|
|
97
|
+
model: "sonnet",
|
|
98
|
+
timeout: 120,
|
|
99
|
+
systemPrompt: "You are a helpful coding assistant.",
|
|
100
|
+
})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**3. Stream responses**
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
for await (const event of session.run("Hello!")) {
|
|
107
|
+
if (event.type === "token") process.stdout.write(event.text)
|
|
108
|
+
if (event.type === "tool_start") console.log(`\n[Tool: ${event.name}]`)
|
|
109
|
+
if (event.type === "end") break
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**4. Cleanup**
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
await sandbox.delete()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Optional: Git workflow** — Use the [Daytona Git SDK](https://www.daytona.io/docs/en/typescript-sdk/git/) to clone before and push after:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const repoPath = "workspace/repo"
|
|
123
|
+
await sandbox.git.clone("https://github.com/user/repo.git", repoPath)
|
|
124
|
+
// ... run session ...
|
|
125
|
+
await sandbox.git.push(repoPath)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Full example
|
|
131
|
+
|
|
132
|
+
End-to-end example with event handling and cleanup:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { Daytona } from "@daytonaio/sdk"
|
|
136
|
+
import { createSession } from "background-agents"
|
|
137
|
+
|
|
138
|
+
async function main() {
|
|
139
|
+
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
140
|
+
const sandbox = await daytona.create({
|
|
141
|
+
envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const session = await createSession("claude", { sandbox })
|
|
146
|
+
|
|
147
|
+
for await (const event of session.run("List /tmp then write /tmp/out.txt with 'done'")) {
|
|
148
|
+
switch (event.type) {
|
|
149
|
+
case "token":
|
|
150
|
+
process.stdout.write(event.text)
|
|
151
|
+
break
|
|
152
|
+
case "tool_start":
|
|
153
|
+
console.log("\n🛠️", event.name, event.input ?? "")
|
|
154
|
+
break
|
|
155
|
+
case "end":
|
|
156
|
+
console.log("\nDone.")
|
|
157
|
+
break
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} finally {
|
|
161
|
+
await sandbox.delete()
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
main()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### CLI commands (reference)
|
|
169
|
+
|
|
170
|
+
Each provider is invoked via its CLI. Optional flags in brackets.
|
|
171
|
+
|
|
172
|
+
| Provider | Command |
|
|
173
|
+
|----------|---------|
|
|
174
|
+
| **Claude** | `claude -p --output-format stream-json --verbose --dangerously-skip-permissions` `[--model <m>] [--resume <id>]` `<prompt>` |
|
|
175
|
+
| **Codex** | `codex exec --json --skip-git-repo-check --yolo` `[--model <m>] [resume <id>]` `<prompt>` |
|
|
176
|
+
| **OpenCode** | `opencode run --format json --variant medium -m <model>` `[-s <id>]` `<prompt>` (via `bash -lc "…"`) |
|
|
177
|
+
| **Gemini** | `gemini -p --output-format stream-json --yolo` `[--model <m>] [--resume <id>]` `<prompt>` |
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## API reference
|
|
182
|
+
|
|
183
|
+
### `createSession(provider, options)`
|
|
184
|
+
|
|
185
|
+
Creates a session with the given provider and options (e.g. `sandbox`, `model`, `timeout`). Installs the provider CLI in the sandbox before returning unless `skipInstall: true`. Codex login runs automatically on each `run()` when needed.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const session = await createSession("claude", {
|
|
189
|
+
sandbox,
|
|
190
|
+
model: "sonnet",
|
|
191
|
+
timeout: 120,
|
|
192
|
+
})
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `session.run(prompt)`
|
|
196
|
+
|
|
197
|
+
Returns an async iterable of events. Stream and handle them uniformly across providers.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
for await (const event of session.run("Hello")) {
|
|
201
|
+
// event.type: "session" | "token" | "tool_start" | "tool_delta" | "tool_end" | "end" | "agent_crashed"
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Event stream
|
|
206
|
+
|
|
207
|
+
| Event | Description | Fields |
|
|
208
|
+
|-------|-------------|--------|
|
|
209
|
+
| `session` | Session started (for resumption) | `id: string` |
|
|
210
|
+
| `token` | Streamed assistant text | `text: string` |
|
|
211
|
+
| `tool_start` | Tool invoked | `name: string`, `input?: unknown` |
|
|
212
|
+
| `tool_delta` | Streaming tool input | `text: string` |
|
|
213
|
+
| `tool_end` | Tool finished | `output?: string` |
|
|
214
|
+
| `end` | Turn complete | — |
|
|
215
|
+
| `agent_crashed` | Process exited without completing (crash/kill) | `message?: string`, `output?: string` (raw tail of stdout/stderr; often not JSONL) |
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
type Event =
|
|
219
|
+
| { type: "session"; id: string }
|
|
220
|
+
| { type: "token"; text: string }
|
|
221
|
+
| { type: "tool_start"; name: string; input?: unknown }
|
|
222
|
+
| { type: "tool_delta"; text: string }
|
|
223
|
+
| { type: "tool_end"; output?: string }
|
|
224
|
+
| { type: "end" }
|
|
225
|
+
| { type: "agent_crashed"; message?: string; output?: string }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Normalized tool names
|
|
229
|
+
|
|
230
|
+
Tool names are normalized across providers. Each has a defined `tool_start` input and `tool_end` output.
|
|
231
|
+
|
|
232
|
+
| Tool | `tool_start` input | Claude | Codex | OpenCode |
|
|
233
|
+
|------|--------------------|:------:|:-----:|:--------:|
|
|
234
|
+
| **write** | `{ file_path, content?, kind }` | ✅ | ✅ | ✅ |
|
|
235
|
+
| **read** | `{ file_path }` | ✅ | — | ✅ |
|
|
236
|
+
| **edit** | `{ file_path, ... }` | ✅ | — | ✅ |
|
|
237
|
+
| **glob** | `{ pattern }` | ✅ | — | ✅ |
|
|
238
|
+
| **grep** | `{ pattern, path? }` | ✅ | — | ✅ |
|
|
239
|
+
| **shell** | `{ command, description? }` | ✅ | ✅ | ✅ |
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Model selection
|
|
244
|
+
|
|
245
|
+
Set `model` when creating the session.
|
|
246
|
+
|
|
247
|
+
| Provider | Example | Docs |
|
|
248
|
+
|----------|---------|------|
|
|
249
|
+
| **Claude** | `model: "sonnet"` or `"opus"`, `"haiku"` | [Claude Code models](https://code.claude.com/docs/en/model-config) |
|
|
250
|
+
| **Codex** | `model: "gpt-4o"` or `"o1"`, `"o3"` | [Codex CLI models](https://developers.openai.com/codex/models) |
|
|
251
|
+
| **OpenCode** | `model: "openai/gpt-4o"` (provider/model) | [OpenCode models](https://opencode.ai/docs/models/) |
|
|
252
|
+
| **Gemini** | `model: "gemini-2.0-flash"` or `"gemini-1.5-pro"` | [Gemini CLI model](https://geminicli.com/docs/cli/model) |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Sandboxed background sessions
|
|
257
|
+
|
|
258
|
+
For long-running or restart-tolerant flows: start the agent in the sandbox, write the event stream to log files there, and poll with **getEvents**. All state except the session ID lives in the sandbox.
|
|
259
|
+
|
|
260
|
+
- **Session ID** — One UUID per background session; host stores only this.
|
|
261
|
+
- **start()** — Returns immediately with `{ executionId, pid, outputFile }`; the agent runs in the background.
|
|
262
|
+
- **isRunning()** — True while the turn is in progress, false after.
|
|
263
|
+
- **Crash detection** — If the process exits without completing, **getEvents** returns an `agent_crashed` event. You can treat it like `end` to stop polling and show a warning.
|
|
264
|
+
|
|
265
|
+
**Example:** start, persist `sandboxId` and `backgroundSessionId`, then reattach after a restart.
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
import { Daytona } from "@daytonaio/sdk"
|
|
269
|
+
import { createBackgroundSession, getBackgroundSession } from "background-agents"
|
|
270
|
+
|
|
271
|
+
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY! })
|
|
272
|
+
const sandbox = await daytona.create({
|
|
273
|
+
envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
const bgSession = await createBackgroundSession("claude", {
|
|
277
|
+
sandbox,
|
|
278
|
+
model: "sonnet",
|
|
279
|
+
// Optional: per-session system prompt (applied once, persisted across turns).
|
|
280
|
+
systemPrompt: "You are a helpful coding assistant.",
|
|
281
|
+
})
|
|
282
|
+
await bgSession.start("Do a long-running refactor...")
|
|
283
|
+
// Persist sandbox.id and bgSession.id, then exit.
|
|
284
|
+
|
|
285
|
+
// --- After restart ---
|
|
286
|
+
const sandboxAgain = await daytona.get(sandboxId)
|
|
287
|
+
const bgAgain = await getBackgroundSession({
|
|
288
|
+
sandbox: sandboxAgain,
|
|
289
|
+
backgroundSessionId,
|
|
290
|
+
// Re-apply session options so the provider is recreated with the same model
|
|
291
|
+
// and system prompt when reattaching.
|
|
292
|
+
model: "sonnet",
|
|
293
|
+
systemPrompt: "You are a helpful coding assistant.",
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
async function poll() {
|
|
297
|
+
const { events } = await bgAgain.getEvents()
|
|
298
|
+
for (const e of events) {
|
|
299
|
+
if (e.type === "token") process.stdout.write(e.text)
|
|
300
|
+
else if (e.type === "tool_start") console.log("[Tool]", e.name)
|
|
301
|
+
}
|
|
302
|
+
if (!(await bgAgain.isRunning())) return
|
|
303
|
+
setTimeout(poll, 2000)
|
|
304
|
+
}
|
|
305
|
+
poll()
|
|
306
|
+
|
|
307
|
+
await bgAgain.cancel() // kill agent in sandbox (no-op if stopped)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Local mode (dangerous)
|
|
313
|
+
|
|
314
|
+
Runs the provider CLI on your machine instead of a sandbox. Only use when you fully trust the code.
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
const session = await createSession("claude", { dangerouslyAllowLocalExecution: true })
|
|
318
|
+
for await (const event of session.run("Hello")) {
|
|
319
|
+
if (event.type === "token") process.stdout.write(event.text)
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Interactive REPL
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Claude (default)
|
|
329
|
+
DAYTONA_API_KEY=... ANTHROPIC_API_KEY=... npx tsx scripts/repl.ts
|
|
330
|
+
|
|
331
|
+
# Other providers
|
|
332
|
+
npx tsx scripts/repl.ts --provider codex # OPENAI_API_KEY
|
|
333
|
+
npx tsx scripts/repl.ts --provider opencode
|
|
334
|
+
npx tsx scripts/repl.ts --provider gemini # GEMINI_API_KEY (or GOOGLE_API_KEY)
|
|
335
|
+
|
|
336
|
+
# Polling-based (background session)
|
|
337
|
+
DAYTONA_API_KEY=... ANTHROPIC_API_KEY=... npx tsx scripts/repl-polling.ts
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npx tsx scripts/repl.ts -h # help; providers: claude, codex, opencode, gemini
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## How it works
|
|
347
|
+
|
|
348
|
+
1. **Sandbox** — You create a Daytona sandbox and pass it to `createSession`.
|
|
349
|
+
2. **CLI** — Provider CLI is installed in the sandbox at session creation (unless `skipInstall: true`). Each `run()` sets env and, for Codex, runs `codex login --with-api-key`.
|
|
350
|
+
3. **PTY** — Commands run in a PTY for real-time streaming.
|
|
351
|
+
4. **Events** — JSON from the CLI is parsed into typed events.
|
|
352
|
+
5. **Cleanup** — You call `sandbox.delete()` when done.
|
|
353
|
+
|
|
354
|
+
```
|
|
355
|
+
┌─────────────┐ ┌──────────────────────────────────────┐
|
|
356
|
+
│ Your App │────▶│ Daytona Sandbox │
|
|
357
|
+
│ │◀────│ ┌─────────────┐ ┌─────────────┐ │
|
|
358
|
+
│ │ │ │ PTY Stream │◀──▶│ Agent CLI │ │
|
|
359
|
+
│ │ │ └─────────────┘ └─────────────┘ │
|
|
360
|
+
└─────────────┘ └──────────────────────────────────────┘
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Debug mode
|
|
366
|
+
|
|
367
|
+
Set `CODING_AGENTS_DEBUG=1` (or any non-empty value) to log debugging information to stderr:
|
|
368
|
+
|
|
369
|
+
- **Agent lifecycle** — when sessions and background sessions are created, when runs start and end
|
|
370
|
+
- **Background agents** — when a turn starts (session dir, turn number, output file), when the background process is started (pid), and each time events are polled (cursor, event count)
|
|
371
|
+
- **Unparsed output** — any CLI line that didn’t parse as an event (helps spot hangs where the agent prints something the SDK doesn’t recognize)
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
CODING_AGENTS_DEBUG=1 npx tsx scripts/repl-polling.ts
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Development
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
npm install
|
|
383
|
+
npm run build
|
|
384
|
+
npm test # unit tests (integration/sandbox-background skipped without keys)
|
|
385
|
+
DAYTONA_API_KEY=... ANTHROPIC_API_KEY=... npm run test -- tests/integration/sandbox-background.test.ts # real sandbox background test
|
|
386
|
+
DAYTONA_API_KEY=... ANTHROPIC_API_KEY=... npx tsx scripts/test-sdk-full.ts # integration
|
|
387
|
+
DAYTONA_API_KEY=... ANTHROPIC_API_KEY=... npx tsx scripts/repl.ts # REPL
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Resources
|
|
393
|
+
|
|
394
|
+
**Sandbox** — [Daytona Docs](https://www.daytona.io/docs/) · [Daytona GitHub](https://github.com/daytonaio/daytona)
|
|
395
|
+
|
|
396
|
+
**Agents** — [Claude Code](https://docs.anthropic.com/en/docs/claude-code) · [Codex CLI](https://developers.openai.com/codex/cli) · [Gemini CLI](https://geminicli.com/docs/) · [OpenCode](https://opencode.ai/docs/)
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
MIT
|
package/dist/debug.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug logging for the SDK. Enable with env CODING_AGENTS_DEBUG=1 (or non-empty).
|
|
3
|
+
* Logs agent lifecycle (start/stop), background runs, and any lines that fail to parse.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isDebugEnabled(): boolean;
|
|
6
|
+
export declare function debugLog(message: string, sessionId?: string | null, ...args: unknown[]): void;
|
|
7
|
+
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAID,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAK7F"}
|
package/dist/debug.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug logging for the SDK. Enable with env CODING_AGENTS_DEBUG=1 (or non-empty).
|
|
3
|
+
* Logs agent lifecycle (start/stop), background runs, and any lines that fail to parse.
|
|
4
|
+
*/
|
|
5
|
+
const DEBUG_ENABLED = typeof process !== "undefined" &&
|
|
6
|
+
process.env &&
|
|
7
|
+
String(process.env.CODING_AGENTS_DEBUG ?? "").trim() !== "";
|
|
8
|
+
export function isDebugEnabled() {
|
|
9
|
+
return DEBUG_ENABLED;
|
|
10
|
+
}
|
|
11
|
+
const PREFIX = "[background-agents]";
|
|
12
|
+
export function debugLog(message, sessionId, ...args) {
|
|
13
|
+
if (!DEBUG_ENABLED)
|
|
14
|
+
return;
|
|
15
|
+
const sessionTag = sessionId != null && sessionId !== "" ? ` sessionId=${sessionId}` : "";
|
|
16
|
+
const line = args.length ? `${message} ${args.map(a => (typeof a === "object" ? JSON.stringify(a) : String(a))).join(" ")}` : message;
|
|
17
|
+
process.stderr.write(`${PREFIX}${sessionTag} ${line}\n`);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=debug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,aAAa,GACjB,OAAO,OAAO,KAAK,WAAW;IAC9B,OAAO,CAAC,GAAG;IACX,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAA;AAE7D,MAAM,UAAU,cAAc;IAC5B,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,MAAM,MAAM,GAAG,qBAAqB,CAAA;AAEpC,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,SAAyB,EAAE,GAAG,IAAe;IACrF,IAAI,CAAC,aAAa;QAAE,OAAM;IAC1B,MAAM,UAAU,GAAG,SAAS,IAAI,IAAI,IAAI,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACzF,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAA;IACrI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,UAAU,IAAI,IAAI,IAAI,CAAC,CAAA;AAC1D,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ProviderName, ProviderOptions } from "./types/index.js";
|
|
2
|
+
import { Provider } from "./providers/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create a provider instance by name
|
|
5
|
+
*
|
|
6
|
+
* @param name - The provider name ("claude", "codex", "opencode", "gemini")
|
|
7
|
+
* @param options - Provider options (sandbox or dangerouslyAllowLocalExecution)
|
|
8
|
+
* @returns A provider instance
|
|
9
|
+
* @throws Error if the provider name is unknown
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { Daytona } from "@daytonaio/sdk"
|
|
14
|
+
* const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
15
|
+
* const sandbox = await daytona.create({ envVars: { ... } })
|
|
16
|
+
* const provider = createProvider("claude", { sandbox })
|
|
17
|
+
*
|
|
18
|
+
* // Or with dangerous local execution:
|
|
19
|
+
* const provider = createProvider("claude", { dangerouslyAllowLocalExecution: true })
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function createProvider(name: ProviderName | string, options: ProviderOptions): Provider;
|
|
23
|
+
/**
|
|
24
|
+
* Get all available provider names
|
|
25
|
+
*/
|
|
26
|
+
export declare function getProviderNames(): ProviderName[];
|
|
27
|
+
/**
|
|
28
|
+
* Check if a provider name is valid
|
|
29
|
+
*/
|
|
30
|
+
export declare function isValidProvider(name: string): name is ProviderName;
|
|
31
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAmE,MAAM,sBAAsB,CAAA;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,QAAQ,CAa9F;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,YAAY,EAAE,CAEjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,YAAY,CAElE"}
|
package/dist/factory.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ClaudeProvider, CodexProvider, OpenCodeProvider, GeminiProvider } from "./providers/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a provider instance by name
|
|
4
|
+
*
|
|
5
|
+
* @param name - The provider name ("claude", "codex", "opencode", "gemini")
|
|
6
|
+
* @param options - Provider options (sandbox or dangerouslyAllowLocalExecution)
|
|
7
|
+
* @returns A provider instance
|
|
8
|
+
* @throws Error if the provider name is unknown
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { Daytona } from "@daytonaio/sdk"
|
|
13
|
+
* const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
14
|
+
* const sandbox = await daytona.create({ envVars: { ... } })
|
|
15
|
+
* const provider = createProvider("claude", { sandbox })
|
|
16
|
+
*
|
|
17
|
+
* // Or with dangerous local execution:
|
|
18
|
+
* const provider = createProvider("claude", { dangerouslyAllowLocalExecution: true })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createProvider(name, options) {
|
|
22
|
+
switch (name) {
|
|
23
|
+
case "claude":
|
|
24
|
+
return new ClaudeProvider(options);
|
|
25
|
+
case "codex":
|
|
26
|
+
return new CodexProvider(options);
|
|
27
|
+
case "opencode":
|
|
28
|
+
return new OpenCodeProvider(options);
|
|
29
|
+
case "gemini":
|
|
30
|
+
return new GeminiProvider(options);
|
|
31
|
+
default:
|
|
32
|
+
throw new Error(`Unknown provider: ${name}. Valid providers are: claude, codex, opencode, gemini`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get all available provider names
|
|
37
|
+
*/
|
|
38
|
+
export function getProviderNames() {
|
|
39
|
+
return ["claude", "codex", "opencode", "gemini"];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if a provider name is valid
|
|
43
|
+
*/
|
|
44
|
+
export function isValidProvider(name) {
|
|
45
|
+
return getProviderNames().includes(name);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,cAAc,CAAC,IAA2B,EAAE,OAAwB;IAClF,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;QACpC,KAAK,OAAO;YACV,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAA;QACnC,KAAK,UAAU;YACb,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAA;QACtC,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;QACpC;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,wDAAwD,CAAC,CAAA;IACtG,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,gBAAgB,EAAE,CAAC,QAAQ,CAAC,IAAoB,CAAC,CAAA;AAC1D,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding Agents SDK
|
|
3
|
+
*
|
|
4
|
+
* A TypeScript SDK for interacting with various AI coding agents.
|
|
5
|
+
* Create a sandbox with @daytonaio/sdk and pass it to createSession.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Daytona } from "@daytonaio/sdk"
|
|
10
|
+
* import { createSession } from "background-agents"
|
|
11
|
+
*
|
|
12
|
+
* const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
13
|
+
* const sandbox = await daytona.create({ envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY } })
|
|
14
|
+
* const session = await createSession("claude", { sandbox })
|
|
15
|
+
*
|
|
16
|
+
* for await (const event of session.run("Hello")) {
|
|
17
|
+
* if (event.type === "token") process.stdout.write(event.text)
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* await sandbox.delete()
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export type { Event, SessionEvent, TokenEvent, ToolStartEvent, ToolDeltaEvent, ToolEndEvent, EndEvent, EventType, ToolName, WriteToolInput, ReadToolInput, EditToolInput, GlobToolInput, GrepToolInput, ShellToolInput, ToolInputMap, ProviderName, ProviderCommand, RunOptions, RunDefaults, ProviderOptions, EventHandler, IProvider, CodeAgentSandbox, ExecuteBackgroundOptions, AdaptSandboxOptions, } from "./types/index.js";
|
|
24
|
+
export { adaptDaytonaSandbox } from "./sandbox/index.js";
|
|
25
|
+
export { Provider, ClaudeProvider, CodexProvider, OpenCodeProvider, GeminiProvider, } from "./providers/index.js";
|
|
26
|
+
export { createProvider, getProviderNames, isValidProvider, } from "./factory.js";
|
|
27
|
+
export { createSession, type SessionOptions, createBackgroundSession, getBackgroundSession, type BackgroundSessionOptions, type BackgroundSession, } from "./session.js";
|
|
28
|
+
export { safeJsonParse, loadSession, storeSession, clearSession, getDefaultSessionPath, isCliInstalled, installProvider, ensureCliInstalled, getPackageName, getInstallationStatus, } from "./utils/index.js";
|
|
29
|
+
export { isDebugEnabled, debugLog } from "./debug.js";
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,YAAY,EACV,KAAK,EACL,YAAY,EACZ,UAAU,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,cAAc,EACd,aAAa,EACb,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,UAAU,EACV,WAAW,EACX,eAAe,EACf,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAGxD,OAAO,EACL,QAAQ,EACR,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACL,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,qBAAqB,GACtB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coding Agents SDK
|
|
3
|
+
*
|
|
4
|
+
* A TypeScript SDK for interacting with various AI coding agents.
|
|
5
|
+
* Create a sandbox with @daytonaio/sdk and pass it to createSession.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { Daytona } from "@daytonaio/sdk"
|
|
10
|
+
* import { createSession } from "background-agents"
|
|
11
|
+
*
|
|
12
|
+
* const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
|
|
13
|
+
* const sandbox = await daytona.create({ envVars: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY } })
|
|
14
|
+
* const session = await createSession("claude", { sandbox })
|
|
15
|
+
*
|
|
16
|
+
* for await (const event of session.run("Hello")) {
|
|
17
|
+
* if (event.type === "token") process.stdout.write(event.text)
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* await sandbox.delete()
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
// Sandbox adapter (wrap a Daytona sandbox from @daytonaio/sdk; uses SSH for background start when createSshAccess exists)
|
|
24
|
+
export { adaptDaytonaSandbox } from "./sandbox/index.js";
|
|
25
|
+
// Providers
|
|
26
|
+
export { Provider, ClaudeProvider, CodexProvider, OpenCodeProvider, GeminiProvider, } from "./providers/index.js";
|
|
27
|
+
// Factory
|
|
28
|
+
export { createProvider, getProviderNames, isValidProvider, } from "./factory.js";
|
|
29
|
+
// Session (provider with run defaults; recommended entry points)
|
|
30
|
+
export { createSession, createBackgroundSession, getBackgroundSession, } from "./session.js";
|
|
31
|
+
// Utilities
|
|
32
|
+
export { safeJsonParse, loadSession, storeSession, clearSession, getDefaultSessionPath, isCliInstalled, installProvider, ensureCliInstalled, getPackageName, getInstallationStatus, } from "./utils/index.js";
|
|
33
|
+
// Debug (enable with CODING_AGENTS_DEBUG=1)
|
|
34
|
+
export { isDebugEnabled, debugLog } from "./debug.js";
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAgCH,0HAA0H;AAC1H,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAExD,YAAY;AACZ,OAAO,EACL,QAAQ,EACR,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,sBAAsB,CAAA;AAE7B,UAAU;AACV,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,eAAe,GAChB,MAAM,cAAc,CAAA;AAErB,iEAAiE;AACjE,OAAO,EACL,aAAa,EAEb,uBAAuB,EACvB,oBAAoB,GAGrB,MAAM,cAAc,CAAA;AAErB,YAAY;AACZ,OAAO,EACL,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,qBAAqB,GACtB,MAAM,kBAAkB,CAAA;AAEzB,4CAA4C;AAC5C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA"}
|