background-agents 0.1.1 → 0.1.2

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.
Files changed (210) hide show
  1. package/README.md +173 -241
  2. package/dist/agents/claude/index.d.ts +11 -0
  3. package/dist/agents/claude/index.d.ts.map +1 -0
  4. package/dist/agents/claude/index.js +78 -0
  5. package/dist/agents/claude/index.js.map +1 -0
  6. package/dist/agents/claude/parser.d.ts +16 -0
  7. package/dist/agents/claude/parser.d.ts.map +1 -0
  8. package/dist/agents/claude/parser.js +87 -0
  9. package/dist/agents/claude/parser.js.map +1 -0
  10. package/dist/agents/claude/tools.d.ts +7 -0
  11. package/dist/agents/claude/tools.d.ts.map +1 -0
  12. package/dist/agents/claude/tools.js +15 -0
  13. package/dist/agents/claude/tools.js.map +1 -0
  14. package/dist/agents/codex/index.d.ts +11 -0
  15. package/dist/agents/codex/index.d.ts.map +1 -0
  16. package/dist/agents/codex/index.js +60 -0
  17. package/dist/agents/codex/index.js.map +1 -0
  18. package/dist/agents/codex/parser.d.ts +12 -0
  19. package/dist/agents/codex/parser.d.ts.map +1 -0
  20. package/dist/agents/codex/parser.js +108 -0
  21. package/dist/agents/codex/parser.js.map +1 -0
  22. package/dist/agents/codex/tools.d.ts +11 -0
  23. package/dist/agents/codex/tools.d.ts.map +1 -0
  24. package/dist/agents/codex/tools.js +40 -0
  25. package/dist/agents/codex/tools.js.map +1 -0
  26. package/dist/agents/eliza/bundle-content.d.ts +6 -0
  27. package/dist/agents/eliza/bundle-content.d.ts.map +1 -0
  28. package/dist/agents/eliza/bundle-content.js +7 -0
  29. package/dist/agents/eliza/bundle-content.js.map +1 -0
  30. package/dist/agents/eliza/cli.bundle.js +579 -0
  31. package/dist/agents/eliza/cli.d.ts +10 -0
  32. package/dist/agents/eliza/cli.d.ts.map +1 -0
  33. package/dist/agents/eliza/cli.js +342 -0
  34. package/dist/agents/eliza/cli.js.map +1 -0
  35. package/dist/agents/eliza/index.d.ts +22 -0
  36. package/dist/agents/eliza/index.d.ts.map +1 -0
  37. package/dist/agents/eliza/index.js +54 -0
  38. package/dist/agents/eliza/index.js.map +1 -0
  39. package/dist/agents/eliza/parser.d.ts +16 -0
  40. package/dist/agents/eliza/parser.d.ts.map +1 -0
  41. package/dist/agents/eliza/parser.js +67 -0
  42. package/dist/agents/eliza/parser.js.map +1 -0
  43. package/dist/agents/eliza/patterns.d.ts +41 -0
  44. package/dist/agents/eliza/patterns.d.ts.map +1 -0
  45. package/dist/agents/eliza/patterns.js +259 -0
  46. package/dist/agents/eliza/patterns.js.map +1 -0
  47. package/dist/agents/eliza/tools.d.ts +7 -0
  48. package/dist/agents/eliza/tools.d.ts.map +1 -0
  49. package/dist/agents/eliza/tools.js +14 -0
  50. package/dist/agents/eliza/tools.js.map +1 -0
  51. package/dist/agents/gemini/index.d.ts +11 -0
  52. package/dist/agents/gemini/index.d.ts.map +1 -0
  53. package/dist/agents/gemini/index.js +46 -0
  54. package/dist/agents/gemini/index.js.map +1 -0
  55. package/dist/agents/gemini/parser.d.ts +31 -0
  56. package/dist/agents/gemini/parser.d.ts.map +1 -0
  57. package/dist/agents/gemini/parser.js +106 -0
  58. package/dist/agents/gemini/parser.js.map +1 -0
  59. package/dist/agents/gemini/tools.d.ts +7 -0
  60. package/dist/agents/gemini/tools.d.ts.map +1 -0
  61. package/dist/agents/gemini/tools.js +23 -0
  62. package/dist/agents/gemini/tools.js.map +1 -0
  63. package/dist/agents/goose/index.d.ts +11 -0
  64. package/dist/agents/goose/index.d.ts.map +1 -0
  65. package/dist/agents/goose/index.js +73 -0
  66. package/dist/agents/goose/index.js.map +1 -0
  67. package/dist/agents/goose/parser.d.ts +24 -0
  68. package/dist/agents/goose/parser.d.ts.map +1 -0
  69. package/dist/agents/goose/parser.js +86 -0
  70. package/dist/agents/goose/parser.js.map +1 -0
  71. package/dist/agents/goose/tools.d.ts +10 -0
  72. package/dist/agents/goose/tools.d.ts.map +1 -0
  73. package/dist/agents/goose/tools.js +30 -0
  74. package/dist/agents/goose/tools.js.map +1 -0
  75. package/dist/agents/index.d.ts +27 -0
  76. package/dist/agents/index.d.ts.map +1 -0
  77. package/dist/agents/index.js +46 -0
  78. package/dist/agents/index.js.map +1 -0
  79. package/dist/agents/opencode/index.d.ts +12 -0
  80. package/dist/agents/opencode/index.d.ts.map +1 -0
  81. package/dist/agents/opencode/index.js +53 -0
  82. package/dist/agents/opencode/index.js.map +1 -0
  83. package/dist/agents/opencode/parser.d.ts +15 -0
  84. package/dist/agents/opencode/parser.d.ts.map +1 -0
  85. package/dist/agents/opencode/parser.js +71 -0
  86. package/dist/agents/opencode/parser.js.map +1 -0
  87. package/dist/agents/opencode/tools.d.ts +7 -0
  88. package/dist/agents/opencode/tools.d.ts.map +1 -0
  89. package/dist/agents/opencode/tools.js +10 -0
  90. package/dist/agents/opencode/tools.js.map +1 -0
  91. package/dist/agents/openhands/index.d.ts +17 -0
  92. package/dist/agents/openhands/index.d.ts.map +1 -0
  93. package/dist/agents/openhands/index.js +67 -0
  94. package/dist/agents/openhands/index.js.map +1 -0
  95. package/dist/agents/openhands/parser.d.ts +16 -0
  96. package/dist/agents/openhands/parser.d.ts.map +1 -0
  97. package/dist/agents/openhands/parser.js +93 -0
  98. package/dist/agents/openhands/parser.js.map +1 -0
  99. package/dist/agents/openhands/tools.d.ts +7 -0
  100. package/dist/agents/openhands/tools.d.ts.map +1 -0
  101. package/dist/agents/openhands/tools.js +24 -0
  102. package/dist/agents/openhands/tools.js.map +1 -0
  103. package/dist/agents/pi/index.d.ts +14 -0
  104. package/dist/agents/pi/index.d.ts.map +1 -0
  105. package/dist/agents/pi/index.js +54 -0
  106. package/dist/agents/pi/index.js.map +1 -0
  107. package/dist/agents/pi/parser.d.ts +21 -0
  108. package/dist/agents/pi/parser.d.ts.map +1 -0
  109. package/dist/agents/pi/parser.js +91 -0
  110. package/dist/agents/pi/parser.js.map +1 -0
  111. package/dist/agents/pi/tools.d.ts +8 -0
  112. package/dist/agents/pi/tools.d.ts.map +1 -0
  113. package/dist/agents/pi/tools.js +16 -0
  114. package/dist/agents/pi/tools.js.map +1 -0
  115. package/dist/agents/picocode/index.d.ts +18 -0
  116. package/dist/agents/picocode/index.d.ts.map +1 -0
  117. package/dist/agents/picocode/index.js +68 -0
  118. package/dist/agents/picocode/index.js.map +1 -0
  119. package/dist/agents/picocode/parser.d.ts +19 -0
  120. package/dist/agents/picocode/parser.d.ts.map +1 -0
  121. package/dist/agents/picocode/parser.js +104 -0
  122. package/dist/agents/picocode/parser.js.map +1 -0
  123. package/dist/agents/picocode/tools.d.ts +9 -0
  124. package/dist/agents/picocode/tools.d.ts.map +1 -0
  125. package/dist/agents/picocode/tools.js +27 -0
  126. package/dist/agents/picocode/tools.js.map +1 -0
  127. package/dist/background/index.d.ts +6 -0
  128. package/dist/background/index.d.ts.map +1 -0
  129. package/dist/background/index.js +5 -0
  130. package/dist/background/index.js.map +1 -0
  131. package/dist/background/session.d.ts +47 -0
  132. package/dist/background/session.d.ts.map +1 -0
  133. package/dist/background/session.js +481 -0
  134. package/dist/background/session.js.map +1 -0
  135. package/dist/background/types.d.ts +55 -0
  136. package/dist/background/types.d.ts.map +1 -0
  137. package/dist/background/types.js +5 -0
  138. package/dist/background/types.js.map +1 -0
  139. package/dist/core/agent.d.ts +95 -0
  140. package/dist/core/agent.d.ts.map +1 -0
  141. package/dist/core/agent.js +8 -0
  142. package/dist/core/agent.js.map +1 -0
  143. package/dist/core/index.d.ts +7 -0
  144. package/dist/core/index.d.ts.map +1 -0
  145. package/dist/core/index.js +6 -0
  146. package/dist/core/index.js.map +1 -0
  147. package/dist/core/registry.d.ts +48 -0
  148. package/dist/core/registry.d.ts.map +1 -0
  149. package/dist/core/registry.js +68 -0
  150. package/dist/core/registry.js.map +1 -0
  151. package/dist/core/tools.d.ts +31 -0
  152. package/dist/core/tools.d.ts.map +1 -0
  153. package/dist/core/tools.js +82 -0
  154. package/dist/core/tools.js.map +1 -0
  155. package/dist/debug.js +1 -1
  156. package/dist/debug.js.map +1 -1
  157. package/dist/factory.d.ts +1 -4
  158. package/dist/factory.d.ts.map +1 -1
  159. package/dist/factory.js +1 -4
  160. package/dist/factory.js.map +1 -1
  161. package/dist/index.d.ts +29 -11
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +41 -14
  164. package/dist/index.js.map +1 -1
  165. package/dist/providers/base.d.ts +45 -18
  166. package/dist/providers/base.d.ts.map +1 -1
  167. package/dist/providers/base.js +228 -265
  168. package/dist/providers/base.js.map +1 -1
  169. package/dist/providers/gemini.d.ts.map +1 -1
  170. package/dist/providers/gemini.js +18 -8
  171. package/dist/providers/gemini.js.map +1 -1
  172. package/dist/sandbox/daytona.d.ts +5 -1
  173. package/dist/sandbox/daytona.d.ts.map +1 -1
  174. package/dist/sandbox/daytona.js +157 -214
  175. package/dist/sandbox/daytona.js.map +1 -1
  176. package/dist/sandbox/index.d.ts +3 -3
  177. package/dist/sandbox/index.d.ts.map +1 -1
  178. package/dist/sandbox/index.js +2 -2
  179. package/dist/sandbox/index.js.map +1 -1
  180. package/dist/session.d.ts +62 -51
  181. package/dist/session.d.ts.map +1 -1
  182. package/dist/session.js +94 -90
  183. package/dist/session.js.map +1 -1
  184. package/dist/types/index.d.ts +2 -2
  185. package/dist/types/index.d.ts.map +1 -1
  186. package/dist/types/index.js +2 -2
  187. package/dist/types/index.js.map +1 -1
  188. package/dist/types/provider.d.ts +37 -94
  189. package/dist/types/provider.d.ts.map +1 -1
  190. package/dist/types/provider.js +3 -0
  191. package/dist/types/provider.js.map +1 -1
  192. package/dist/utils/index.d.ts +2 -3
  193. package/dist/utils/index.d.ts.map +1 -1
  194. package/dist/utils/index.js +2 -3
  195. package/dist/utils/index.js.map +1 -1
  196. package/dist/utils/install.d.ts +12 -2
  197. package/dist/utils/install.d.ts.map +1 -1
  198. package/dist/utils/install.js +40 -4
  199. package/dist/utils/install.js.map +1 -1
  200. package/package.json +24 -13
  201. package/src/index.ts +156 -0
  202. package/dist/sandbox/daytona-ssh.d.ts +0 -9
  203. package/dist/sandbox/daytona-ssh.d.ts.map +0 -1
  204. package/dist/sandbox/daytona-ssh.js +0 -113
  205. package/dist/sandbox/daytona-ssh.js.map +0 -1
  206. package/dist/utils/session.d.ts +0 -17
  207. package/dist/utils/session.d.ts.map +0 -1
  208. package/dist/utils/session.js +0 -59
  209. package/dist/utils/session.js.map +0 -1
  210. package/next.config.codeagentsdk.cjs +0 -22
package/README.md CHANGED
@@ -1,34 +1,42 @@
1
- # Coding Agents SDK
1
+ # Background Agents SDK
2
2
 
3
- A unified TypeScript interface for AI coding agentsClaude, Codex, Gemini, and OpenCode. Commands run in secure [Daytona](https://daytona.io) sandboxes by default, with real-time PTY streaming.
3
+ A TypeScript SDK for running AI coding agents (Claude, Codex, Gemini, Goose, OpenCode, Pi) in secure [Daytona](https://daytona.io) sandboxes. Designed for background execution with polling-based event streaming.
4
4
 
5
5
  ```typescript
6
6
  import { Daytona } from "@daytonaio/sdk"
7
7
  import { createSession } from "background-agents"
8
8
 
9
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 })
10
+ const sandbox = await daytona.create()
12
11
 
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
12
+ const session = await createSession("claude", {
13
+ sandbox,
14
+ env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }
15
+ })
16
+
17
+ await session.start("Refactor the auth module")
18
+
19
+ // Poll for events
20
+ while (await session.isRunning()) {
21
+ const { events } = await session.getEvents()
22
+ for (const event of events) {
23
+ if (event.type === "token") process.stdout.write(event.text)
24
+ }
25
+ await new Promise(r => setTimeout(r, 1000))
16
26
  }
17
27
 
18
28
  await sandbox.delete()
19
29
  ```
20
30
 
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
31
  ---
24
32
 
25
33
  ## Features
26
34
 
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
35
+ - **Secure sandboxed execution** — Agents run in isolated Daytona sandboxes
36
+ - **Background execution** — Start agents, poll for events, survive restarts
37
+ - **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/), [Goose](https://block.github.io/goose/docs/), [OpenCode](https://opencode.ai/docs/), and [Pi](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent)
38
+ - **Zero-friction setup** — Provider CLI auto-installed in sandbox
39
+ - **Session persistence** — Resume conversations across runs and restarts
32
40
 
33
41
  ---
34
42
 
@@ -36,16 +44,29 @@ Same pattern for any provider: create a sandbox, create a session, stream events
36
44
 
37
45
  | Provider | Status | Auth |
38
46
  |----------|--------|------|
39
- | [Claude](https://docs.anthropic.com/en/docs/claude-code) | ✅ | `ANTHROPIC_API_KEY` |
47
+ | [Claude](https://docs.anthropic.com/en/docs/claude-code) | ✅ | `ANTHROPIC_API_KEY` or `CLAUDE_CODE_CREDENTIALS` |
40
48
  | [Codex](https://developers.openai.com/codex/cli) | ✅ | `OPENAI_API_KEY` |
49
+ | [Goose](https://block.github.io/goose/docs/) | ✅ | Provider-specific (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) |
41
50
  | [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` |
51
+ | [Gemini](https://geminicli.com/docs/) | | `GEMINI_API_KEY` |
52
+ | [Pi](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent) | ✅ | Provider-specific (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`) |
53
+
54
+ ### CLI reference commands
55
+
56
+ | Provider | CLI Command |
57
+ |----------|-------------|
58
+ | Claude | `claude -p --output-format stream-json --verbose --dangerously-skip-permissions "prompt"` |
59
+ | Codex | `codex exec --json --skip-git-repo-check --yolo "prompt"` |
60
+ | Goose | `goose run --output-format stream-json --text "prompt"` |
61
+ | OpenCode | `opencode run --format json --variant medium "prompt"` |
62
+ | Gemini | `gemini --output-format stream-json --yolo -p "prompt"` |
63
+ | Pi | `pi --mode json -p "prompt"` |
43
64
 
44
65
  ---
45
66
 
46
67
  ## Prerequisites
47
68
 
48
- A [Daytona](https://daytona.io) API key (or [run locally](#local-mode-dangerous) without a sandbox).
69
+ A [Daytona](https://daytona.io) API key for secure sandboxed execution.
49
70
 
50
71
  ```bash
51
72
  export DAYTONA_API_KEY=dtn_your_api_key
@@ -56,125 +77,87 @@ export DAYTONA_API_KEY=dtn_your_api_key
56
77
  ## Installation
57
78
 
58
79
  ```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 }
80
+ npm install background-agents @daytonaio/sdk
74
81
  ```
75
82
 
76
83
  ---
77
84
 
78
85
  ## Quick start
79
86
 
80
- **1. Create a sandbox** — Pass provider API keys via the sandbox; the SDK does not read your host env.
81
-
82
87
  ```typescript
83
88
  import { Daytona } from "@daytonaio/sdk"
84
89
  import { createSession } from "background-agents"
85
90
 
91
+ // 1. Create sandbox
86
92
  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
- ```
93
+ const sandbox = await daytona.create()
91
94
 
92
- **2. Create a session** — The provider CLI is installed in the sandbox (unless `skipInstall: true`).
93
-
94
- ```typescript
95
+ // 2. Create session
95
96
  const session = await createSession("claude", {
96
97
  sandbox,
98
+ env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
97
99
  model: "sonnet",
98
- timeout: 120,
99
100
  systemPrompt: "You are a helpful coding assistant.",
100
101
  })
101
- ```
102
102
 
103
- **3. Stream responses**
103
+ // 3. Start a task
104
+ await session.start("Create a hello world script")
104
105
 
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
106
+ // 4. Poll for events
107
+ while (await session.isRunning()) {
108
+ const { events } = await session.getEvents()
109
+ for (const event of events) {
110
+ if (event.type === "token") process.stdout.write(event.text)
111
+ if (event.type === "tool_start") console.log(`\n[Tool: ${event.name}]`)
112
+ if (event.type === "end") console.log("\nDone.")
113
+ }
114
+ await new Promise(r => setTimeout(r, 1000))
110
115
  }
111
- ```
112
-
113
- **4. Cleanup**
114
116
 
115
- ```typescript
117
+ // 5. Cleanup
116
118
  await sandbox.delete()
117
119
  ```
118
120
 
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
121
  ---
129
122
 
130
- ## Full example
123
+ ## Restart-tolerant workflows
131
124
 
132
- End-to-end example with event handling and cleanup:
125
+ The SDK is designed for long-running tasks that may outlive your server process. Persist `sandbox.id` and `session.id`, then reattach after restart.
133
126
 
134
127
  ```typescript
135
128
  import { Daytona } from "@daytonaio/sdk"
136
- import { createSession } from "background-agents"
129
+ import { createSession, getSession } from "background-agents"
137
130
 
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
- }
131
+ const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY! })
132
+ const sandbox = await daytona.create()
164
133
 
165
- main()
166
- ```
134
+ // Start a task
135
+ const session = await createSession("claude", {
136
+ sandbox,
137
+ env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
138
+ model: "sonnet",
139
+ })
140
+ await session.start("Do a long-running refactor...")
141
+
142
+ // Persist these IDs, then exit
143
+ const sandboxId = sandbox.id
144
+ const sessionId = session.id // Save this to reattach later
145
+
146
+ // --- After restart ---
167
147
 
168
- ### CLI commands (reference)
148
+ // Reattach to existing session
149
+ const sandbox = await daytona.get(sandboxId)
150
+ const session = await getSession(sessionId, { sandbox })
169
151
 
170
- Each provider is invoked via its CLI. Optional flags in brackets.
152
+ // Continue polling
153
+ const { events, running } = await session.getEvents()
154
+ for (const event of events) {
155
+ if (event.type === "token") process.stdout.write(event.text)
156
+ }
171
157
 
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>` |
158
+ // Cancel if needed
159
+ await session.cancel()
160
+ ```
178
161
 
179
162
  ---
180
163
 
@@ -182,180 +165,108 @@ Each provider is invoked via its CLI. Optional flags in brackets.
182
165
 
183
166
  ### `createSession(provider, options)`
184
167
 
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.
168
+ Creates a session. The provider CLI is installed automatically.
186
169
 
187
170
  ```typescript
188
171
  const session = await createSession("claude", {
189
- sandbox,
190
- model: "sonnet",
191
- timeout: 120,
172
+ sandbox, // Daytona sandbox
173
+ env: { ANTHROPIC_API_KEY: "sk-..." }, // Environment variables
174
+ model: "sonnet", // Optional: model name
175
+ systemPrompt: "You are helpful.", // Optional: system prompt
192
176
  })
193
177
  ```
194
178
 
195
- ### `session.run(prompt)`
179
+ ### `session.start(prompt)`
196
180
 
197
- Returns an async iterable of events. Stream and handle them uniformly across providers.
181
+ Starts a background task. Returns immediately with process info.
198
182
 
199
183
  ```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
- }
184
+ const { pid, outputFile } = await session.start("Your task here")
203
185
  ```
204
186
 
205
- ### Event stream
187
+ ### `session.getEvents()`
206
188
 
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) |
189
+ Polls for new events since last call.
216
190
 
217
191
  ```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 }
192
+ const { events, running } = await session.getEvents()
193
+ // events: Event[] - new events since last poll
194
+ // running: boolean - true if agent is still running
226
195
  ```
227
196
 
228
- ### Normalized tool names
197
+ ### `session.isRunning()`
229
198
 
230
- Tool names are normalized across providers. Each has a defined `tool_start` input and `tool_end` output.
199
+ Returns `true` while the agent is running.
231
200
 
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? }` | ✅ | ✅ | ✅ |
201
+ ### `session.cancel()`
240
202
 
241
- ---
203
+ Kills the running agent process.
242
204
 
243
- ## Model selection
205
+ ### `getSession(sessionId, options)`
244
206
 
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.
207
+ Reattaches to an existing session by ID.
266
208
 
267
209
  ```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)
210
+ const session = await getSession(
211
+ sessionId, // session.id from createSession()
212
+ { sandbox }
213
+ )
308
214
  ```
309
215
 
310
216
  ---
311
217
 
312
- ## Local mode (dangerous)
218
+ ## Event types
313
219
 
314
- Runs the provider CLI on your machine instead of a sandbox. Only use when you fully trust the code.
220
+ | Event | Description | Fields |
221
+ |-------|-------------|--------|
222
+ | `session` | Session started | `id: string` |
223
+ | `token` | Streamed text | `text: string` |
224
+ | `tool_start` | Tool invoked | `name: string`, `input?: unknown` |
225
+ | `tool_delta` | Tool streaming | `text: string` |
226
+ | `tool_end` | Tool finished | `output?: string` |
227
+ | `end` | Task complete | `error?: string` |
228
+ | `agent_crashed` | Process crashed | `message?: string`, `output?: string` |
315
229
 
316
230
  ```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
- }
231
+ type Event =
232
+ | { type: "session"; id: string }
233
+ | { type: "token"; text: string }
234
+ | { type: "tool_start"; name: string; input?: unknown }
235
+ | { type: "tool_delta"; text: string }
236
+ | { type: "tool_end"; output?: string }
237
+ | { type: "end"; error?: string }
238
+ | { type: "agent_crashed"; message?: string; output?: string }
321
239
  ```
322
240
 
323
241
  ---
324
242
 
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
- ```
243
+ ## Model selection
339
244
 
340
- ```bash
341
- npx tsx scripts/repl.ts -h # help; providers: claude, codex, opencode, gemini
342
- ```
245
+ | Provider | Example | Docs |
246
+ |----------|---------|------|
247
+ | **Claude** | `model: "sonnet"` | [Claude Code models](https://code.claude.com/docs/en/model-config) |
248
+ | **Codex** | `model: "gpt-4o"` | [Codex CLI models](https://developers.openai.com/codex/models) |
249
+ | **Goose** | `model: "gpt-4o"` | [Goose providers](https://block.github.io/goose/docs/getting-started/providers) |
250
+ | **OpenCode** | `model: "openai/gpt-4o"` | [OpenCode models](https://opencode.ai/docs/models/) |
251
+ | **Gemini** | `model: "gemini-2.0-flash"` | [Gemini CLI model](https://geminicli.com/docs/cli/model) |
252
+ | **Pi** | `model: "sonnet"` or `model: "openai/gpt-4o"` | [Pi CLI models](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent#providers--models) |
343
253
 
344
254
  ---
345
255
 
346
256
  ## How it works
347
257
 
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.
258
+ 1. **Sandbox** — Create a Daytona sandbox for isolated execution
259
+ 2. **CLI install** — Provider CLI is installed in the sandbox automatically
260
+ 3. **Background execution** — Agent runs via `nohup`, outputs to a log file
261
+ 4. **Polling** — SDK polls the log file for new JSON events
262
+ 5. **Completion** — A `.done` file signals when the agent finishes
263
+ 6. **Cleanup** — You call `sandbox.delete()` when done
353
264
 
354
265
  ```
355
266
  ┌─────────────┐ ┌──────────────────────────────────────┐
356
267
  │ Your App │────▶│ Daytona Sandbox │
357
- │◀────│ ┌─────────────┐ ┌─────────────┐ │
358
- │ │PTY Stream │◀──▶│ Agent CLI │ │
268
+ │ │ ┌─────────────┐ ┌─────────────┐ │
269
+ (polling) │◀────│ Log File │◀───│ Agent CLI │ │
359
270
  │ │ │ └─────────────┘ └─────────────┘ │
360
271
  └─────────────┘ └──────────────────────────────────────┘
361
272
  ```
@@ -364,36 +275,57 @@ npx tsx scripts/repl.ts -h # help; providers: claude, codex, opencode, gemini
364
275
 
365
276
  ## Debug mode
366
277
 
367
- Set `CODING_AGENTS_DEBUG=1` (or any non-empty value) to log debugging information to stderr:
278
+ Set `CODING_AGENTS_DEBUG=1` to enable debug logging:
279
+
280
+ ```bash
281
+ CODING_AGENTS_DEBUG=1 npx tsx your-script.ts
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Claude OAuth credentials
368
287
 
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)
288
+ Claude can authenticate via `ANTHROPIC_API_KEY` or `CLAUDE_CODE_CREDENTIALS`. The latter uses OAuth credentials from a Claude Pro/Max subscription.
289
+
290
+ First, sign in locally:
372
291
 
373
292
  ```bash
374
- CODING_AGENTS_DEBUG=1 npx tsx scripts/repl-polling.ts
293
+ claude auth login
375
294
  ```
376
295
 
296
+ Then retrieve your credentials:
297
+
298
+ | OS | Command |
299
+ |----|---------|
300
+ | macOS | `security find-generic-password -s "Claude Code-credentials" -w` |
301
+ | Linux | `cat ~/.claude/.credentials.json` |
302
+ | Windows | `type %USERPROFILE%\.claude\.credentials.json` |
303
+
304
+ Pass the output as `CLAUDE_CODE_CREDENTIALS`. The SDK automatically writes it to `~/.claude/.credentials.json` in the sandbox.
305
+
377
306
  ---
378
307
 
379
308
  ## Development
380
309
 
310
+ Build, test, and iterate locally. Start by installing dependencies and running the unit test suite:
311
+
381
312
  ```bash
382
313
  npm install
383
314
  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
315
+ npm test
388
316
  ```
389
317
 
318
+ For integration and end-to-end testing, see [TESTING.md](./TESTING.md).
319
+
320
+ For testing scenarios, you can use the deterministic Eliza agent, which requires no provider API key.
321
+
390
322
  ---
391
323
 
392
324
  ## Resources
393
325
 
394
326
  **Sandbox** — [Daytona Docs](https://www.daytona.io/docs/) · [Daytona GitHub](https://github.com/daytonaio/daytona)
395
327
 
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/)
328
+ **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/) · [Goose](https://block.github.io/goose/docs/) · [OpenCode](https://opencode.ai/docs/) · [Pi](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent)
397
329
 
398
330
  ---
399
331
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Claude Code CLI Agent Definition
3
+ */
4
+ import type { AgentDefinition } from "../../core/agent";
5
+ /**
6
+ * Claude Code CLI agent definition.
7
+ *
8
+ * Interacts with the Claude CLI tool which outputs JSON lines in stream-json format.
9
+ */
10
+ export declare const claudeAgent: AgentDefinition;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/claude/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAyC,MAAM,kBAAkB,CAAA;AAwC9F;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,eAqDzB,CAAA"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Claude Code CLI Agent Definition
3
+ */
4
+ import { parseClaudeLine } from "./parser";
5
+ import { CLAUDE_TOOL_MAPPINGS } from "./tools";
6
+ /** Claude credentials directory */
7
+ const CLAUDE_CREDENTIALS_DIR = "/home/daytona/.claude";
8
+ /** Claude credentials file */
9
+ const CLAUDE_CREDENTIALS_FILE = "/home/daytona/.claude/.credentials.json";
10
+ /** Environment variable name for Claude Code credentials */
11
+ const CLAUDE_CODE_CREDENTIALS_ENV = "CLAUDE_CODE_CREDENTIALS";
12
+ /**
13
+ * Claude agent-specific setup: write credentials from environment variable.
14
+ *
15
+ * When CLAUDE_CODE_CREDENTIALS environment variable is set, this function
16
+ * writes its contents to ~/.claude/.credentials.json. This allows credentials
17
+ * to be passed via environment variable instead of writing the file manually.
18
+ *
19
+ * The value should be the JSON content of the credentials file, e.g.:
20
+ * {"claudeAiOauth":{"accessToken":"sk-ant-oa..."}}
21
+ */
22
+ async function claudeSetup(sandbox, env) {
23
+ const credentialsJson = env[CLAUDE_CODE_CREDENTIALS_ENV];
24
+ if (!credentialsJson || !sandbox.executeCommand)
25
+ return;
26
+ // Escape single quotes for shell command
27
+ const safeCredentials = credentialsJson.replace(/'/g, "'\\''");
28
+ // Create directory and write credentials file with secure permissions
29
+ await sandbox.executeCommand(`mkdir -p '${CLAUDE_CREDENTIALS_DIR}' && echo '${safeCredentials}' > '${CLAUDE_CREDENTIALS_FILE}' && chmod 600 '${CLAUDE_CREDENTIALS_FILE}'`, 30);
30
+ }
31
+ /**
32
+ * Claude Code CLI agent definition.
33
+ *
34
+ * Interacts with the Claude CLI tool which outputs JSON lines in stream-json format.
35
+ */
36
+ export const claudeAgent = {
37
+ name: "claude",
38
+ toolMappings: CLAUDE_TOOL_MAPPINGS,
39
+ capabilities: {
40
+ supportsSystemPrompt: true,
41
+ supportsResume: true,
42
+ setup: claudeSetup,
43
+ },
44
+ buildCommand(options) {
45
+ const args = [];
46
+ // Print mode for non-interactive usage
47
+ args.push("-p");
48
+ // Add output format flag for JSON streaming (requires --verbose)
49
+ args.push("--output-format", "stream-json", "--verbose");
50
+ // Skip permission prompts when already running in a sandbox
51
+ args.push("--dangerously-skip-permissions");
52
+ // Apply system prompt via native CLI flag when provided
53
+ if (options.systemPrompt) {
54
+ args.push("--system-prompt", options.systemPrompt);
55
+ }
56
+ // Add model if specified (e.g., "sonnet", "opus", "claude-sonnet-4-5-20250929")
57
+ if (options.model) {
58
+ args.push("--model", options.model);
59
+ }
60
+ // Resume session if provided
61
+ if (options.sessionId) {
62
+ args.push("--resume", options.sessionId);
63
+ }
64
+ // Add the prompt if provided
65
+ if (options.prompt) {
66
+ args.push(options.prompt);
67
+ }
68
+ return {
69
+ cmd: "claude",
70
+ args,
71
+ env: options.env,
72
+ };
73
+ },
74
+ parse(line, _context) {
75
+ return parseClaudeLine(line, this.toolMappings);
76
+ },
77
+ };
78
+ //# sourceMappingURL=index.js.map