@ai-sdk/harness-claude-code 1.0.168 → 1.0.170
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/CHANGELOG.md +21 -0
- package/dist/bridge/index.mjs +9 -5
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/claude-code-system-prompt.ts +8 -1
- package/src/bridge/create-emit-stream-event.ts +8 -1
- package/src/bridge/index.ts +12 -1
- package/src/claude-code-bridge-protocol.ts +4 -0
- package/src/claude-code-harness.ts +60 -0
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
export function createClaudeCodeSystemPrompt(
|
|
1
|
+
export function createClaudeCodeSystemPrompt(
|
|
2
|
+
instructions?: string,
|
|
3
|
+
options?: { excludeDynamicSections?: boolean },
|
|
4
|
+
): {
|
|
2
5
|
type: 'preset';
|
|
3
6
|
preset: 'claude_code';
|
|
4
7
|
append?: string;
|
|
8
|
+
excludeDynamicSections?: boolean;
|
|
5
9
|
} {
|
|
6
10
|
return {
|
|
7
11
|
type: 'preset',
|
|
8
12
|
preset: 'claude_code',
|
|
9
13
|
...(instructions ? { append: instructions } : {}),
|
|
14
|
+
...(options?.excludeDynamicSections !== undefined
|
|
15
|
+
? { excludeDynamicSections: options.excludeDynamicSections }
|
|
16
|
+
: {}),
|
|
10
17
|
};
|
|
11
18
|
}
|
|
@@ -194,7 +194,14 @@ export function createEmitStreamEvent({
|
|
|
194
194
|
// Emit `stream-start` once, on the first message, carrying the model the
|
|
195
195
|
// CLI resolved to (the `system`/`init` message reports it — this is the
|
|
196
196
|
// default model when none was configured).
|
|
197
|
-
|
|
197
|
+
/*
|
|
198
|
+
* `command_lifecycle` frames are skipped here. The CLI's stdin reader
|
|
199
|
+
* forwards them (e.g. `queued` and `started` for the prompt) straight to
|
|
200
|
+
* the output stream, independently of the engine that yields
|
|
201
|
+
* `system`/`init` at the start of each turn, so they can arrive before
|
|
202
|
+
* `init`. They produce no stream parts.
|
|
203
|
+
*/
|
|
204
|
+
if (!streamStarted && type !== 'command_lifecycle') {
|
|
198
205
|
const initModel =
|
|
199
206
|
type === 'system' &&
|
|
200
207
|
msg.subtype === 'init' &&
|
package/src/bridge/index.ts
CHANGED
|
@@ -570,6 +570,12 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
570
570
|
options: {
|
|
571
571
|
...(start.model ? { model: start.model } : {}),
|
|
572
572
|
...(start.maxTurns !== undefined ? { maxTurns: start.maxTurns } : {}),
|
|
573
|
+
...(start.maxBudgetUsd !== undefined
|
|
574
|
+
? { maxBudgetUsd: start.maxBudgetUsd }
|
|
575
|
+
: {}),
|
|
576
|
+
...(start.strictMcpConfig !== undefined
|
|
577
|
+
? { strictMcpConfig: start.strictMcpConfig }
|
|
578
|
+
: {}),
|
|
573
579
|
...(start.agentProgressSummaries !== undefined
|
|
574
580
|
? { agentProgressSummaries: start.agentProgressSummaries }
|
|
575
581
|
: {}),
|
|
@@ -582,7 +588,9 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
582
588
|
...(inactiveNativeTools.length > 0
|
|
583
589
|
? { disallowedTools: inactiveNativeTools }
|
|
584
590
|
: {}),
|
|
585
|
-
systemPrompt: createClaudeCodeSystemPrompt(start.instructions
|
|
591
|
+
systemPrompt: createClaudeCodeSystemPrompt(start.instructions, {
|
|
592
|
+
excludeDynamicSections: start.excludeDynamicSections,
|
|
593
|
+
}),
|
|
586
594
|
thinking: start.thinking,
|
|
587
595
|
...(start.effort !== undefined ? { effort: start.effort } : {}),
|
|
588
596
|
...(start.responseFormat?.type === 'json' &&
|
|
@@ -603,6 +611,9 @@ async function runTurn(start: StartMessage, turn: BridgeTurn): Promise<void> {
|
|
|
603
611
|
{
|
|
604
612
|
matcher: 'AskUserQuestion',
|
|
605
613
|
hooks: [questionPreToolUseHook],
|
|
614
|
+
...(start.questionTimeoutMs !== undefined
|
|
615
|
+
? { timeout: Math.ceil(start.questionTimeoutMs / 1000) }
|
|
616
|
+
: {}),
|
|
606
617
|
},
|
|
607
618
|
],
|
|
608
619
|
PostCompact: [
|
|
@@ -37,6 +37,10 @@ export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
|
37
37
|
thinking: thinkingSchema,
|
|
38
38
|
effort: z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),
|
|
39
39
|
maxTurns: z.number().optional(),
|
|
40
|
+
maxBudgetUsd: z.number().optional(),
|
|
41
|
+
strictMcpConfig: z.boolean().optional(),
|
|
42
|
+
questionTimeoutMs: z.number().optional(),
|
|
43
|
+
excludeDynamicSections: z.boolean().optional(),
|
|
40
44
|
agentProgressSummaries: z.boolean().optional(),
|
|
41
45
|
forwardSubagentText: z.boolean().optional(),
|
|
42
46
|
env: z.record(z.string(), z.string()).optional(),
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
waitForBridgeReady,
|
|
47
47
|
writeSkills,
|
|
48
48
|
type BridgeHello,
|
|
49
|
+
type SandboxChannelDebugEvent,
|
|
49
50
|
type SandboxChannelReconnectOptions,
|
|
50
51
|
} from '@ai-sdk/harness/utils';
|
|
51
52
|
import {
|
|
@@ -103,6 +104,27 @@ export type ClaudeCodeHarnessSettings = {
|
|
|
103
104
|
* back to the caller. Unset means the CLI's default.
|
|
104
105
|
*/
|
|
105
106
|
readonly maxTurns?: number;
|
|
107
|
+
/**
|
|
108
|
+
* Maximum estimated spend in USD for each Claude query. When it is exceeded,
|
|
109
|
+
* the query stops and the turn ends with an error. Unset means no limit.
|
|
110
|
+
*/
|
|
111
|
+
readonly maxBudgetUsd?: number;
|
|
112
|
+
/**
|
|
113
|
+
* Only use the MCP servers configured with `mcpServers`, and ignore any other
|
|
114
|
+
* MCP configuration such as a project `.mcp.json` or user settings.
|
|
115
|
+
*/
|
|
116
|
+
readonly strictMcpConfig?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Maximum milliseconds Claude waits for an answer to an `AskUserQuestion`
|
|
119
|
+
* question before the question fails. Unset means the Claude Code default.
|
|
120
|
+
*/
|
|
121
|
+
readonly questionTimeoutMs?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Moves per-session sections (working directory, memory, git status) out of
|
|
124
|
+
* the Claude Code system prompt and into the first user message, so the
|
|
125
|
+
* system prompt can be cached across sessions.
|
|
126
|
+
*/
|
|
127
|
+
readonly excludeDynamicSections?: boolean;
|
|
106
128
|
/**
|
|
107
129
|
* Enables periodic AI-generated progress summaries for running subagents.
|
|
108
130
|
* The summaries are forwarded in raw `task_progress` stream parts.
|
|
@@ -149,6 +171,14 @@ export type ClaudeCodeHarnessSettings = {
|
|
|
149
171
|
* milliseconds up to 2 seconds.
|
|
150
172
|
*/
|
|
151
173
|
readonly reconnect?: SandboxChannelReconnectOptions;
|
|
174
|
+
/**
|
|
175
|
+
* Called with bridge connection lifecycle events: reconnect attempts,
|
|
176
|
+
* successful reconnects, and `reconnect-failed` once the connection is
|
|
177
|
+
* closed for good. Hosts that cache idle sessions can use it to reattach
|
|
178
|
+
* before sending the next prompt. The `cause` of a failed reconnect can
|
|
179
|
+
* contain connection details, so avoid logging it as is.
|
|
180
|
+
*/
|
|
181
|
+
readonly onDebug?: (event: SandboxChannelDebugEvent) => void;
|
|
152
182
|
/**
|
|
153
183
|
* Creates the authentication token used by the sandbox bridge. Defaults to
|
|
154
184
|
* a random 32-byte hexadecimal token.
|
|
@@ -1028,6 +1058,7 @@ export function createClaudeCode(
|
|
|
1028
1058
|
onDiagnostic,
|
|
1029
1059
|
onBridgeError,
|
|
1030
1060
|
reconnect: settings.reconnect,
|
|
1061
|
+
onDebug: settings.onDebug,
|
|
1031
1062
|
});
|
|
1032
1063
|
const finishListenerAttachment = isContinue
|
|
1033
1064
|
? attachChannel.beginListenerAttachment()
|
|
@@ -1048,6 +1079,10 @@ export function createClaudeCode(
|
|
|
1048
1079
|
// sandbox is left running, stopped, or destroyed.
|
|
1049
1080
|
proc: undefined,
|
|
1050
1081
|
maxTurns: settings.maxTurns,
|
|
1082
|
+
maxBudgetUsd: settings.maxBudgetUsd,
|
|
1083
|
+
strictMcpConfig: settings.strictMcpConfig,
|
|
1084
|
+
questionTimeoutMs: settings.questionTimeoutMs,
|
|
1085
|
+
excludeDynamicSections: settings.excludeDynamicSections,
|
|
1051
1086
|
agentProgressSummaries: settings.agentProgressSummaries,
|
|
1052
1087
|
forwardSubagentText: settings.forwardSubagentText,
|
|
1053
1088
|
env: sandboxClaudeEnvironment,
|
|
@@ -1191,6 +1226,7 @@ export function createClaudeCode(
|
|
|
1191
1226
|
onDiagnostic,
|
|
1192
1227
|
onBridgeError,
|
|
1193
1228
|
reconnect: settings.reconnect,
|
|
1229
|
+
onDebug: settings.onDebug,
|
|
1194
1230
|
// In replay mode the respawned bridge reloaded the finished turn from
|
|
1195
1231
|
// disk; seed the cursor and resume so it streams the tail (incl.
|
|
1196
1232
|
// `finish`) rather than starting empty.
|
|
@@ -1217,6 +1253,10 @@ export function createClaudeCode(
|
|
|
1217
1253
|
finishListenerAttachment,
|
|
1218
1254
|
proc,
|
|
1219
1255
|
maxTurns: settings.maxTurns,
|
|
1256
|
+
maxBudgetUsd: settings.maxBudgetUsd,
|
|
1257
|
+
strictMcpConfig: settings.strictMcpConfig,
|
|
1258
|
+
questionTimeoutMs: settings.questionTimeoutMs,
|
|
1259
|
+
excludeDynamicSections: settings.excludeDynamicSections,
|
|
1220
1260
|
agentProgressSummaries: settings.agentProgressSummaries,
|
|
1221
1261
|
forwardSubagentText: settings.forwardSubagentText,
|
|
1222
1262
|
env: sandboxClaudeEnvironment,
|
|
@@ -1255,6 +1295,10 @@ function createSession({
|
|
|
1255
1295
|
finishListenerAttachment,
|
|
1256
1296
|
proc,
|
|
1257
1297
|
maxTurns,
|
|
1298
|
+
maxBudgetUsd,
|
|
1299
|
+
strictMcpConfig,
|
|
1300
|
+
questionTimeoutMs,
|
|
1301
|
+
excludeDynamicSections,
|
|
1258
1302
|
agentProgressSummaries,
|
|
1259
1303
|
forwardSubagentText,
|
|
1260
1304
|
env,
|
|
@@ -1282,6 +1326,10 @@ function createSession({
|
|
|
1282
1326
|
/** Undefined on `attach` — the live bridge was spawned by another process. */
|
|
1283
1327
|
proc: Experimental_SandboxProcess | undefined;
|
|
1284
1328
|
maxTurns: number | undefined;
|
|
1329
|
+
maxBudgetUsd: number | undefined;
|
|
1330
|
+
strictMcpConfig: boolean | undefined;
|
|
1331
|
+
questionTimeoutMs: number | undefined;
|
|
1332
|
+
excludeDynamicSections: boolean | undefined;
|
|
1285
1333
|
agentProgressSummaries: boolean | undefined;
|
|
1286
1334
|
forwardSubagentText: boolean | undefined;
|
|
1287
1335
|
env: Readonly<Record<string, string>> | undefined;
|
|
@@ -1559,6 +1607,12 @@ function createSession({
|
|
|
1559
1607
|
: {}),
|
|
1560
1608
|
model: promptOpts.model,
|
|
1561
1609
|
maxTurns,
|
|
1610
|
+
...(maxBudgetUsd !== undefined ? { maxBudgetUsd } : {}),
|
|
1611
|
+
...(strictMcpConfig !== undefined ? { strictMcpConfig } : {}),
|
|
1612
|
+
...(questionTimeoutMs !== undefined ? { questionTimeoutMs } : {}),
|
|
1613
|
+
...(excludeDynamicSections !== undefined
|
|
1614
|
+
? { excludeDynamicSections }
|
|
1615
|
+
: {}),
|
|
1562
1616
|
...(agentProgressSummaries !== undefined
|
|
1563
1617
|
? { agentProgressSummaries }
|
|
1564
1618
|
: {}),
|
|
@@ -1630,6 +1684,12 @@ function createSession({
|
|
|
1630
1684
|
: {}),
|
|
1631
1685
|
model: continueOpts.model,
|
|
1632
1686
|
maxTurns,
|
|
1687
|
+
...(maxBudgetUsd !== undefined ? { maxBudgetUsd } : {}),
|
|
1688
|
+
...(strictMcpConfig !== undefined ? { strictMcpConfig } : {}),
|
|
1689
|
+
...(questionTimeoutMs !== undefined ? { questionTimeoutMs } : {}),
|
|
1690
|
+
...(excludeDynamicSections !== undefined
|
|
1691
|
+
? { excludeDynamicSections }
|
|
1692
|
+
: {}),
|
|
1633
1693
|
...(agentProgressSummaries !== undefined
|
|
1634
1694
|
? { agentProgressSummaries }
|
|
1635
1695
|
: {}),
|