coding-agents-sdk 0.0.1 → 0.2.0
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 +242 -0
- package/dist/Agent-D8WkUilj.mjs +262 -0
- package/dist/SdkAgent-B47mJiIE.mjs +38 -0
- package/dist/adapters/claude-code-cli/index.d.mts +2 -0
- package/dist/adapters/claude-code-cli/index.mjs +490 -0
- package/dist/adapters/claude-code-sdk/index.d.mts +2 -0
- package/dist/adapters/claude-code-sdk/index.mjs +483 -0
- package/dist/adapters/codex-cli/index.d.mts +2 -0
- package/dist/adapters/codex-cli/index.mjs +626 -0
- package/dist/adapters/codex-sdk/index.d.mts +2 -0
- package/dist/adapters/codex-sdk/index.mjs +286 -0
- package/dist/adapters/gemini-cli/index.d.mts +2 -0
- package/dist/adapters/gemini-cli/index.mjs +292 -0
- package/dist/classify-error-pL6jeu4T.mjs +456 -0
- package/dist/container/index.d.mts +2 -0
- package/dist/container/index.mjs +24 -0
- package/dist/container-2UmPZ0CI.mjs +22 -0
- package/dist/container-CHxKIonn.mjs +440 -0
- package/dist/container-D2Z0ITDJ.mjs +22 -0
- package/dist/diff-De8d3MVb.mjs +333 -0
- package/dist/errors-BAmHDQu8.mjs +45 -0
- package/dist/events-nxuRbYIu.d.mts +239 -0
- package/dist/index-B3YqrgIp.d.mts +45 -0
- package/dist/index-ByAOGMUM.d.mts +224 -0
- package/dist/index-C3ZxLAd0.d.mts +315 -0
- package/dist/index-CFpNOmdA.d.mts +145 -0
- package/dist/index-dRVpEAr8.d.mts +39 -0
- package/dist/index-nzo1sBiK.d.mts +110 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +61 -0
- package/dist/oci-DMZZQZ47.mjs +438 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +2 -0
- package/dist/schemas-DwD4pwJB.mjs +96 -0
- package/dist/spawner-Bw9UBEGX.mjs +54 -0
- package/dist/structured-output-BHtr_zpz.mjs +19 -0
- package/dist/types-Cb_EXIEe.d.mts +177 -0
- package/dist/types-aNMD8h3x.mjs +19 -0
- package/dist/util-B4RQZkKr.mjs +77 -0
- package/package.json +86 -9
- package/index.js +0 -7
package/README.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# coding-agents-sdk
|
|
2
|
+
|
|
3
|
+
This is a coding agent orchestration library.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add coding-agents-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
If you use an SDK adapter or the `e2b` container provider, install that optional peer too.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# for claude-code-sdk
|
|
15
|
+
bun add @anthropic-ai/claude-agent-sdk
|
|
16
|
+
|
|
17
|
+
# for codex-sdk
|
|
18
|
+
bun add @openai/codex-sdk
|
|
19
|
+
|
|
20
|
+
# for createContainer({ type: "e2b", ... })
|
|
21
|
+
bun add e2b
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Runtime setup
|
|
25
|
+
|
|
26
|
+
Before you call `await createAgent(...)`, make sure the runtime for that adapter is available.
|
|
27
|
+
|
|
28
|
+
- `claude-code-cli` runs Claude Code CLI.
|
|
29
|
+
- `claude-code-sdk` uses `@anthropic-ai/claude-agent-sdk` and launches Claude Code locally.
|
|
30
|
+
- `codex-cli` runs Codex CLI.
|
|
31
|
+
- `codex-sdk` uses `@openai/codex-sdk` and launches Codex locally.
|
|
32
|
+
- `gemini-cli` runs Gemini CLI.
|
|
33
|
+
|
|
34
|
+
SDK adapters and the `e2b` container provider are optional peer dependencies. Install only the ones you use.
|
|
35
|
+
|
|
36
|
+
If one is missing, awaiting `createAgent()` or `createContainer()` surfaces an error that tells you which package to install.
|
|
37
|
+
|
|
38
|
+
Set `cwd` when the agent should run somewhere other than the current working directory.
|
|
39
|
+
|
|
40
|
+
Use `agent.capabilities` when you need to branch on features at runtime.
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { createAgent } from "coding-agents-sdk";
|
|
46
|
+
|
|
47
|
+
await using agent = await createAgent("claude-code-cli");
|
|
48
|
+
|
|
49
|
+
const result = await agent.run({
|
|
50
|
+
input: "Read package.json and tell me what this project does.",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (result.status !== "completed") {
|
|
54
|
+
throw new Error(result.error.message);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(result.text);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Replace `"claude-code-cli"` with the adapter you want to use.
|
|
61
|
+
Unless noted otherwise, the rest of the snippets assume the same `agent` shape.
|
|
62
|
+
|
|
63
|
+
## Run results
|
|
64
|
+
|
|
65
|
+
`run()` returns a `RunResult` with `status: "completed" | "failed" | "cancelled"`.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const result = await agent.run({
|
|
69
|
+
input: "Review the last commit.",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
switch (result.status) {
|
|
73
|
+
case "completed":
|
|
74
|
+
console.log(result.text);
|
|
75
|
+
break;
|
|
76
|
+
case "failed":
|
|
77
|
+
console.error(result.error.kind, result.error.message);
|
|
78
|
+
break;
|
|
79
|
+
case "cancelled":
|
|
80
|
+
console.error(result.cancelReason, result.error.message);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Notes:
|
|
86
|
+
|
|
87
|
+
- `runOrThrow()` turns non-completed runs into `AgentRunError`
|
|
88
|
+
- `stop()`, `wait()`, `reset()`, and `dispose()` are available on every agent
|
|
89
|
+
|
|
90
|
+
TypeScript infers the completed-result shape from your request:
|
|
91
|
+
|
|
92
|
+
- Zod schema: `result.output` is fully typed
|
|
93
|
+
- raw JSON Schema: `result.output` is `unknown`
|
|
94
|
+
- no `schema`: use `result.text`; completed results do not include `output`
|
|
95
|
+
- `runOrThrow()` follows the same inference, but only returns the completed variant
|
|
96
|
+
|
|
97
|
+
## Input
|
|
98
|
+
|
|
99
|
+
Most calls just use a string. If you need richer input, pass parts instead.
|
|
100
|
+
|
|
101
|
+
Image input is currently supported only by `codex-sdk`.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
await using agent = await createAgent("codex-sdk");
|
|
105
|
+
|
|
106
|
+
await agent.run({
|
|
107
|
+
input: [
|
|
108
|
+
{ type: "text", text: "Describe this image." },
|
|
109
|
+
{ type: "image", path: "./ui.png" },
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Structured output
|
|
115
|
+
|
|
116
|
+
Pass `schema` when you want structured output.
|
|
117
|
+
|
|
118
|
+
If you want typed output, pass a Zod schema.
|
|
119
|
+
If you pass raw JSON Schema, `result.output` is `unknown`.
|
|
120
|
+
If you do not pass a schema, use `result.text`.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { z } from "zod/v4";
|
|
124
|
+
|
|
125
|
+
const result = await agent.run({
|
|
126
|
+
input: "Read package.json and return the package name and whether it has a test script.",
|
|
127
|
+
schema: z
|
|
128
|
+
.object({
|
|
129
|
+
name: z.string(),
|
|
130
|
+
hasTestScript: z.boolean(),
|
|
131
|
+
})
|
|
132
|
+
.strict(),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (result.status === "completed") {
|
|
136
|
+
console.log(result.output);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If you want to pass Zod schemas, depend on `zod` in your app.
|
|
141
|
+
|
|
142
|
+
`schema` accepts a raw JSON Schema object or a Zod schema. This wrapper validates only the Zod path. `gemini-cli` does not support structured output.
|
|
143
|
+
|
|
144
|
+
If you need to name these shapes in your own helpers, import `RunRequest`, `JsonSchemaRunRequest`, `ZodRunRequest`, `RunResult`, or `CompletedRunResult` from the package.
|
|
145
|
+
|
|
146
|
+
## Sessions
|
|
147
|
+
|
|
148
|
+
One agent instance keeps one conversation going. Reuse the same instance when you want the next turn to continue the same session.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
await agent.run({
|
|
152
|
+
input: "Remember this word: pineapple. Reply with only 'ok'.",
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const result = await agent.run({
|
|
156
|
+
input: "What word did I ask you to remember?",
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Useful bits:
|
|
161
|
+
|
|
162
|
+
- `agent.sessionId` is set once a session exists
|
|
163
|
+
- pass `sessionId` to `await createAgent(type, { sessionId })` to resume one explicitly
|
|
164
|
+
- `reset()` forgets the stored session
|
|
165
|
+
- Claude adapters support `fork()`
|
|
166
|
+
|
|
167
|
+
## Events
|
|
168
|
+
|
|
169
|
+
Use `onEvent()` to subscribe to the normalized event stream.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
const unsubscribe = agent.onEvent((event) => {
|
|
173
|
+
if (event.type === "tool-call") {
|
|
174
|
+
console.log(event.toolName);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
await agent.run({
|
|
179
|
+
input: "Explain the package layout.",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
unsubscribe();
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
All adapters emit `session-start` and `session-end`. Depending on the backend, you may also see `message`, `reasoning`, `tool-call`, `tool-result`, and `stderr`.
|
|
186
|
+
|
|
187
|
+
## MCP
|
|
188
|
+
|
|
189
|
+
MCP tool calls can show up in the event stream when the underlying runtime supports them.
|
|
190
|
+
|
|
191
|
+
This wrapper exposes MCP configuration directly on:
|
|
192
|
+
|
|
193
|
+
- `claude-code-cli`: `mcpConfig`, `mcpServers`
|
|
194
|
+
- `claude-code-sdk`: `mcpServers`
|
|
195
|
+
- `codex-cli`: `mcpConfig`, `mcpServers`
|
|
196
|
+
|
|
197
|
+
For `codex-sdk` and `gemini-cli`, use the runtime's own MCP setup. This wrapper does not add separate MCP config options for them.
|
|
198
|
+
|
|
199
|
+
## Containers
|
|
200
|
+
|
|
201
|
+
Containers are supported on the CLI adapters: `claude-code-cli`, `codex-cli`, and `gemini-cli`.
|
|
202
|
+
`docker` and `podman` do not need extra package dependencies. `e2b` requires the optional `e2b` peer dependency.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { createAgent, createContainer } from "coding-agents-sdk";
|
|
206
|
+
|
|
207
|
+
await using container = await createContainer({
|
|
208
|
+
type: "docker",
|
|
209
|
+
workdir: "/workspace",
|
|
210
|
+
image: "my-agent-image",
|
|
211
|
+
// or instead of image:
|
|
212
|
+
// build: {
|
|
213
|
+
// content: [
|
|
214
|
+
// "FROM ubuntu:24.04",
|
|
215
|
+
// "RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git && rm -rf /var/lib/apt/lists/*",
|
|
216
|
+
// "RUN useradd -m -s /bin/bash agent",
|
|
217
|
+
// "USER agent",
|
|
218
|
+
// "RUN curl -fsSL https://claude.ai/install.sh | bash",
|
|
219
|
+
// 'ENV PATH="/home/agent/.local/bin:${PATH}"',
|
|
220
|
+
// "WORKDIR /workspace",
|
|
221
|
+
// ].join("\n"),
|
|
222
|
+
// },
|
|
223
|
+
mounts: [{ source: "/absolute/path/to/project", target: "/workspace" }],
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
await using agent = await createAgent("claude-code-cli", {
|
|
227
|
+
container,
|
|
228
|
+
permissionMode: "bypassPermissions",
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const result = await agent.run({
|
|
232
|
+
input: "Run the tests and fix the failing test.",
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
if (result.status === "completed") {
|
|
236
|
+
console.log(result.text);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Your image needs the runtime for the adapter you picked available inside the container.
|
|
241
|
+
|
|
242
|
+
If you omit `cwd`, the agent uses `container.workdir`. The container is started automatically on the first run. Use `snapshotWorkdir()`, `diffWorkdir()`, and `releaseWorkdirSnapshot()` when you need a reliable before/after file diff.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { t as formatError } from "./util-B4RQZkKr.mjs";
|
|
2
|
+
import { a as buildBaseProcessEnv, i as hasMeaningfulEvent, n as AgentCore, o as createAgentEvent, t as classifyRunError } from "./classify-error-pL6jeu4T.mjs";
|
|
3
|
+
import { t as DEFAULT_SPAWNER } from "./spawner-Bw9UBEGX.mjs";
|
|
4
|
+
import { createWriteStream, mkdirSync } from "node:fs";
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
//#region src/core/process/read-lines.ts
|
|
7
|
+
async function* readDecodedLines(stream) {
|
|
8
|
+
const decoder = new TextDecoder();
|
|
9
|
+
let buffer = "";
|
|
10
|
+
for await (const chunk of stream) {
|
|
11
|
+
const text = decoder.decode(chunk, { stream: true });
|
|
12
|
+
buffer += text;
|
|
13
|
+
const lines = buffer.split("\n");
|
|
14
|
+
buffer = lines.pop() ?? "";
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const trimmed = line.trim();
|
|
17
|
+
if (trimmed) yield trimmed;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const tail = decoder.decode();
|
|
21
|
+
if (tail) buffer += tail;
|
|
22
|
+
const remaining = buffer.trim();
|
|
23
|
+
if (remaining) yield remaining;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/core/agent/Agent.ts
|
|
27
|
+
const SIGKILL_TIMEOUT_MS = 5e3;
|
|
28
|
+
const rejectedMessage = (result) => {
|
|
29
|
+
return result.status === "rejected" ? formatError(result.reason) : void 0;
|
|
30
|
+
};
|
|
31
|
+
const resolveFatalError = (run, settled) => {
|
|
32
|
+
if (run.stopReason) return void 0;
|
|
33
|
+
const stdoutError = rejectedMessage(settled.stdoutResult);
|
|
34
|
+
if (stdoutError) return {
|
|
35
|
+
kind: "process",
|
|
36
|
+
message: stdoutError
|
|
37
|
+
};
|
|
38
|
+
const stderrError = rejectedMessage(settled.stderrResult);
|
|
39
|
+
if (stderrError) return {
|
|
40
|
+
kind: "process",
|
|
41
|
+
message: stderrError
|
|
42
|
+
};
|
|
43
|
+
const spawnError = rejectedMessage(settled.processResult);
|
|
44
|
+
if (spawnError) return {
|
|
45
|
+
kind: "spawn",
|
|
46
|
+
message: spawnError
|
|
47
|
+
};
|
|
48
|
+
if (!run.status && !run.error) {
|
|
49
|
+
const processResult = run.processResult;
|
|
50
|
+
const stderrText = run.stderrLines.join("\n");
|
|
51
|
+
if (processResult && processResult.exitCode !== null && processResult.exitCode !== 0) return {
|
|
52
|
+
kind: "process",
|
|
53
|
+
message: stderrText || `Process exited with code ${processResult.exitCode}.`
|
|
54
|
+
};
|
|
55
|
+
if (!hasMeaningfulEvent(run) && run.stderrLines.length > 0) return {
|
|
56
|
+
kind: "process",
|
|
57
|
+
message: stderrText
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const classifyAgentRuntimeError = (error) => {
|
|
62
|
+
const classified = classifyRunError(error);
|
|
63
|
+
return classified.kind === "provider" ? {
|
|
64
|
+
kind: "process",
|
|
65
|
+
message: classified.message
|
|
66
|
+
} : classified;
|
|
67
|
+
};
|
|
68
|
+
var Agent = class extends AgentCore {
|
|
69
|
+
spawner;
|
|
70
|
+
defaults;
|
|
71
|
+
containerRef;
|
|
72
|
+
autoStartContainer;
|
|
73
|
+
autoStopContainer;
|
|
74
|
+
containerStopPromise;
|
|
75
|
+
logStream;
|
|
76
|
+
sigkillTimer;
|
|
77
|
+
constructor(options) {
|
|
78
|
+
super({
|
|
79
|
+
type: options.type,
|
|
80
|
+
capabilities: options.capabilities,
|
|
81
|
+
sessionId: options.defaults?.sessionId,
|
|
82
|
+
onEvent: options.onEvent
|
|
83
|
+
});
|
|
84
|
+
this.spawner = options.spawner ?? DEFAULT_SPAWNER;
|
|
85
|
+
this.defaults = options.defaults ?? {};
|
|
86
|
+
this.containerRef = options.container;
|
|
87
|
+
this.autoStartContainer = options.autoStartContainer ?? true;
|
|
88
|
+
this.autoStopContainer = options.autoStopContainer ?? false;
|
|
89
|
+
if (options.logPath) this.initLogStream(options.logPath);
|
|
90
|
+
}
|
|
91
|
+
onParseError(line, error) {
|
|
92
|
+
this.appendRawLog(`[parse-error] ${formatError(error)} ${line.slice(0, 200)}`);
|
|
93
|
+
}
|
|
94
|
+
buildDefaultEnv(propagateEnv) {
|
|
95
|
+
const env = buildBaseProcessEnv({ propagateEnv });
|
|
96
|
+
env.CI = env.CI ?? "true";
|
|
97
|
+
if (this.defaults.env) Object.assign(env, this.defaults.env);
|
|
98
|
+
return env;
|
|
99
|
+
}
|
|
100
|
+
async executeRunCore(run, request) {
|
|
101
|
+
const lifecycle = this.setupRunLifecycle(run);
|
|
102
|
+
try {
|
|
103
|
+
if (lifecycle.abortedBeforeStart) return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
104
|
+
try {
|
|
105
|
+
await this.onBeforeRun(run);
|
|
106
|
+
const mergedRequest = {
|
|
107
|
+
...request,
|
|
108
|
+
...run.normalizedRequest
|
|
109
|
+
};
|
|
110
|
+
const args = this.buildArgs(mergedRequest, run);
|
|
111
|
+
const env = this.buildEnv(mergedRequest, run);
|
|
112
|
+
const command = this.defaults.command?.[0] ?? "claude";
|
|
113
|
+
const commandArgs = [...this.defaults.command?.slice(1) ?? [], ...args];
|
|
114
|
+
if (run.stopReason) return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
115
|
+
this.emitSessionStart(run);
|
|
116
|
+
run.process = this.spawner.spawn(command, commandArgs, {
|
|
117
|
+
cwd: run.normalizedRequest.cwd,
|
|
118
|
+
env,
|
|
119
|
+
stdio: [
|
|
120
|
+
"pipe",
|
|
121
|
+
"pipe",
|
|
122
|
+
"pipe"
|
|
123
|
+
]
|
|
124
|
+
});
|
|
125
|
+
run.process.stdin?.end();
|
|
126
|
+
const [stdoutResult, stderrResult, processResult] = await Promise.allSettled([
|
|
127
|
+
this.watchStdout(run),
|
|
128
|
+
this.watchStderr(run),
|
|
129
|
+
run.process.wait()
|
|
130
|
+
]);
|
|
131
|
+
if (processResult.status === "fulfilled") run.processResult = processResult.value;
|
|
132
|
+
const fatalError = resolveFatalError(run, {
|
|
133
|
+
stdoutResult,
|
|
134
|
+
stderrResult,
|
|
135
|
+
processResult
|
|
136
|
+
});
|
|
137
|
+
if (fatalError) run.error = fatalError;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (!run.stopReason && !run.error) run.error = classifyAgentRuntimeError(error);
|
|
140
|
+
}
|
|
141
|
+
return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
142
|
+
} finally {
|
|
143
|
+
lifecycle.cleanup();
|
|
144
|
+
if (this.sigkillTimer) {
|
|
145
|
+
clearTimeout(this.sigkillTimer);
|
|
146
|
+
this.sigkillTimer = void 0;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
await this.onRunFinished(run);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
this.appendRawLog(`[cleanup-error] ${formatError(error)}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async watchStdout(run) {
|
|
156
|
+
const stdout = run.process?.stdout;
|
|
157
|
+
if (!stdout) return;
|
|
158
|
+
for await (const line of readDecodedLines(stdout)) {
|
|
159
|
+
this.appendLog("stdout", line);
|
|
160
|
+
this.processLine(run, line);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async watchStderr(run) {
|
|
164
|
+
const stderr = run.process?.stderr;
|
|
165
|
+
if (!stderr) return;
|
|
166
|
+
for await (const line of readDecodedLines(stderr)) {
|
|
167
|
+
this.appendLog("stderr", line);
|
|
168
|
+
run.stderrLines.push(line);
|
|
169
|
+
this.emit(run, createAgentEvent(run.runId, "stderr", {
|
|
170
|
+
sessionId: run.sessionId,
|
|
171
|
+
text: line
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
processLine(run, line) {
|
|
176
|
+
let parsed;
|
|
177
|
+
try {
|
|
178
|
+
parsed = JSON.parse(line);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
this.onParseError(line, error);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
let batch;
|
|
184
|
+
try {
|
|
185
|
+
batch = this.mapRawEvent(parsed, {
|
|
186
|
+
runId: run.runId,
|
|
187
|
+
requestedSessionId: run.requestedSessionId,
|
|
188
|
+
sessionId: run.sessionId,
|
|
189
|
+
schemaRequested: run.normalizedRequest.schema.kind !== "none",
|
|
190
|
+
toolCalls: run.toolCalls
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
this.onParseError(line, error);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
this.applyBatch(run, batch);
|
|
197
|
+
}
|
|
198
|
+
get runRequestDefaults() {
|
|
199
|
+
return this.defaults;
|
|
200
|
+
}
|
|
201
|
+
onHandlerError(error) {
|
|
202
|
+
this.appendRawLog(`[handler-error] ${formatError(error)}`);
|
|
203
|
+
}
|
|
204
|
+
async onDispose() {
|
|
205
|
+
const logStream = this.logStream;
|
|
206
|
+
this.logStream = void 0;
|
|
207
|
+
if (!logStream) return;
|
|
208
|
+
await new Promise((resolve) => {
|
|
209
|
+
logStream.end(resolve);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
onStopRequested(run) {
|
|
213
|
+
run.process?.kill();
|
|
214
|
+
this.sigkillTimer = setTimeout(() => {
|
|
215
|
+
run.process?.kill("SIGKILL");
|
|
216
|
+
}, SIGKILL_TIMEOUT_MS);
|
|
217
|
+
this.sigkillTimer.unref?.();
|
|
218
|
+
}
|
|
219
|
+
onBeforeRun(_run) {
|
|
220
|
+
return this.ensureContainer();
|
|
221
|
+
}
|
|
222
|
+
async onRunFinished(_run) {
|
|
223
|
+
if (this.autoStopContainer && this.containerRef && this.containerRef.status === "running") {
|
|
224
|
+
this.containerStopPromise = this.containerRef.stop().catch((error) => {
|
|
225
|
+
this.appendRawLog(`[auto-stop-error] ${formatError(error)}`);
|
|
226
|
+
});
|
|
227
|
+
await this.containerStopPromise;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
appendRawLog(data) {
|
|
231
|
+
if (!this.logStream) return;
|
|
232
|
+
const text = typeof data === "string" ? data : JSON.stringify(data);
|
|
233
|
+
this.logStream.write(`${text}\n`);
|
|
234
|
+
}
|
|
235
|
+
initLogStream(logPath) {
|
|
236
|
+
try {
|
|
237
|
+
mkdirSync(dirname(logPath), { recursive: true });
|
|
238
|
+
this.logStream = createWriteStream(logPath, { flags: "a" });
|
|
239
|
+
this.logStream.write(`\n--- ${(/* @__PURE__ */ new Date()).toISOString()} ---\n`);
|
|
240
|
+
} catch {
|
|
241
|
+
this.logStream = void 0;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
appendLog(source, chunk) {
|
|
245
|
+
if (!this.logStream || !chunk) return;
|
|
246
|
+
const label = source === "stderr" ? "STDERR" : "STDOUT";
|
|
247
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
248
|
+
for (const line of chunk.split("\n")) {
|
|
249
|
+
if (!line) continue;
|
|
250
|
+
this.logStream.write(`[${ts}] ${label} ${line}\n`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async ensureContainer() {
|
|
254
|
+
if (this.containerStopPromise) {
|
|
255
|
+
await this.containerStopPromise;
|
|
256
|
+
this.containerStopPromise = void 0;
|
|
257
|
+
}
|
|
258
|
+
if (this.autoStartContainer && this.containerRef && this.containerRef.status !== "running") await this.containerRef.start();
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
//#endregion
|
|
262
|
+
export { Agent as t };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { n as AgentCore, t as classifyRunError } from "./classify-error-pL6jeu4T.mjs";
|
|
2
|
+
//#region src/core/agent/SdkAgent.ts
|
|
3
|
+
/**
|
|
4
|
+
* Base class for SDK-based agent adapters (claude-code-sdk, codex-sdk).
|
|
5
|
+
* Provides the shared run lifecycle: abort/timeout wiring, session-start/end emission,
|
|
6
|
+
* error classification, and cleanup. Subclasses implement only the SDK-specific iteration.
|
|
7
|
+
*/
|
|
8
|
+
var SdkAgent = class extends AgentCore {
|
|
9
|
+
currentAbortController;
|
|
10
|
+
/** optional cleanup called in finally block (e.g. close SDK query) */
|
|
11
|
+
cleanupSdkResources() {}
|
|
12
|
+
onStopRequested(_run) {
|
|
13
|
+
this.currentAbortController?.abort();
|
|
14
|
+
}
|
|
15
|
+
async executeRunCore(run, request) {
|
|
16
|
+
const runAbortController = new AbortController();
|
|
17
|
+
this.currentAbortController = runAbortController;
|
|
18
|
+
const lifecycle = this.setupRunLifecycle(run);
|
|
19
|
+
try {
|
|
20
|
+
if (lifecycle.abortedBeforeStart) return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
21
|
+
if (run.stopReason) return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
22
|
+
this.emitSessionStart(run);
|
|
23
|
+
await this.executeSdkRun(run, request, runAbortController);
|
|
24
|
+
return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (!run.stopReason && !run.error) run.error = classifyRunError(error);
|
|
27
|
+
return this.buildResult(run, /* @__PURE__ */ new Date());
|
|
28
|
+
} finally {
|
|
29
|
+
lifecycle.cleanup();
|
|
30
|
+
try {
|
|
31
|
+
await this.cleanupSdkResources();
|
|
32
|
+
} catch {}
|
|
33
|
+
if (this.currentAbortController === runAbortController) this.currentAbortController = void 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { SdkAgent as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as ClaudeCodeCliRunOptions, c as ClaudeRateLimitEvent, d as ClaudeUserEvent, i as ClaudeCodeCliPermissionMode, l as ClaudeResultEvent, n as ClaudeCodeCliAgent, o as ClaudeAssistantEvent, r as ClaudeCodeCliAgentOptions, s as ClaudeEvent, t as createClaudeCodeCliAgent, u as ClaudeSystemEvent } from "../../index-C3ZxLAd0.mjs";
|
|
2
|
+
export { ClaudeAssistantEvent, ClaudeCodeCliAgent, ClaudeCodeCliAgentOptions, ClaudeCodeCliPermissionMode, ClaudeCodeCliRunOptions, ClaudeEvent, ClaudeRateLimitEvent, ClaudeResultEvent, ClaudeSystemEvent, ClaudeUserEvent, createClaudeCodeCliAgent };
|