@ai-sdk/harness-claude-code 1.0.65 → 1.0.67
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 +19 -0
- package/README.md +13 -0
- package/dist/bridge/index.mjs +49 -36
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +24674 -397
- package/dist/index.js +361 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +18 -1
- package/src/bridge/index.ts +11 -63
- package/src/bridge/tool-filtering.ts +58 -0
- package/src/claude-code-bridge-protocol.ts +2 -0
- package/src/claude-code-harness.ts +401 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @ai-sdk/harness-claude-code
|
|
2
2
|
|
|
3
|
+
## 1.0.67
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a03ff6c: feat(harness): add support for per-harness MCP servers
|
|
8
|
+
- fc3baaf: feat(harness): add optional `mintBridgeToken(sandboxId)` to harness settings to control the bridge token value
|
|
9
|
+
- cfc587b: fix(harness-claude-code): add missing Claude Code built-in tools
|
|
10
|
+
- Updated dependencies [401a4ba]
|
|
11
|
+
- Updated dependencies [a03ff6c]
|
|
12
|
+
- @ai-sdk/provider-utils@5.0.26
|
|
13
|
+
- @ai-sdk/harness@1.0.65
|
|
14
|
+
|
|
15
|
+
## 1.0.66
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 8c95b3f: fix(harness-claude-code): fix built-in tool filtering by using actual denylist when passing `inactiveTools`
|
|
20
|
+
- a65bbb2: feat(harness-claude-code): add optional `env` property to `createClaudeCode()` for custom env vars
|
|
21
|
+
|
|
3
22
|
## 1.0.65
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -62,3 +62,16 @@ try {
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
The adapter requires a `HarnessV1SandboxProvider` whose handles expose at least one port — `@ai-sdk/sandbox-vercel` is the supported choice today. The agent calls `provider.createSession()` when a session starts. Use `session.detach()` to park the bridge and sandbox, `session.stop()` to save state and stop the sandbox, or `session.destroy()` to clean up without keeping resume state.
|
|
65
|
+
|
|
66
|
+
## Runtime configuration
|
|
67
|
+
|
|
68
|
+
Use `env` to add environment variables to the Claude Code process. Configured
|
|
69
|
+
values override variables inherited from the sandbox bridge process.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const harness = createClaudeCode({
|
|
73
|
+
env: {
|
|
74
|
+
DEPLOYMENT_ENV: 'staging',
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -491,7 +491,7 @@ function createCompactionLatch(emit) {
|
|
|
491
491
|
|
|
492
492
|
// src/bridge/index.ts
|
|
493
493
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
494
|
-
import { argv, stdout as stdout2 } from "process";
|
|
494
|
+
import { argv, env as procEnv2, stdout as stdout2 } from "process";
|
|
495
495
|
import * as claudeAgentSdk from "@anthropic-ai/claude-agent-sdk";
|
|
496
496
|
import * as mcpServerModule from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
497
497
|
|
|
@@ -512,6 +512,7 @@ function createClaudeStreamEventState() {
|
|
|
512
512
|
pendingStepUsage: void 0,
|
|
513
513
|
stepOpen: false,
|
|
514
514
|
mcpToolUseIds: /* @__PURE__ */ new Set(),
|
|
515
|
+
externalMcpToolUseIds: /* @__PURE__ */ new Set(),
|
|
515
516
|
observedTerminalError: void 0
|
|
516
517
|
};
|
|
517
518
|
}
|
|
@@ -586,6 +587,8 @@ function createEmitStreamEvent({
|
|
|
586
587
|
continue;
|
|
587
588
|
}
|
|
588
589
|
state.nativeToolCallNames.set(block.id, block.name);
|
|
590
|
+
const dynamic = block.name.startsWith("mcp__");
|
|
591
|
+
if (dynamic) state.externalMcpToolUseIds.add(block.id);
|
|
589
592
|
if (state.approvalRequestedToolUseIds.has(block.id)) {
|
|
590
593
|
continue;
|
|
591
594
|
}
|
|
@@ -597,7 +600,8 @@ function createEmitStreamEvent({
|
|
|
597
600
|
toolName: toCommonName2(block.name),
|
|
598
601
|
nativeName: block.name,
|
|
599
602
|
input: JSON.stringify(block.input ?? {}),
|
|
600
|
-
providerExecuted: true
|
|
603
|
+
providerExecuted: true,
|
|
604
|
+
...dynamic ? { dynamic: true } : {}
|
|
601
605
|
});
|
|
602
606
|
}
|
|
603
607
|
}
|
|
@@ -619,15 +623,17 @@ function createEmitStreamEvent({
|
|
|
619
623
|
const nativeName = state.nativeToolCallNames.get(block.tool_use_id) ?? "unknown";
|
|
620
624
|
state.nativeToolCallNames.delete(block.tool_use_id);
|
|
621
625
|
const toolName = toCommonName2(nativeName);
|
|
626
|
+
const dynamic = state.externalMcpToolUseIds.delete(block.tool_use_id);
|
|
622
627
|
const isError = !!block.is_error;
|
|
623
628
|
const content = stringifyContent(block.content);
|
|
624
|
-
const result = toolName === "bash" ? { exitCode: isError ? 1 : 0, stdout: content } : content;
|
|
629
|
+
const result = toolName === "bash" ? { exitCode: isError ? 1 : 0, stdout: content } : dynamic ? parseMcpToolResult(content) : content;
|
|
625
630
|
emit({
|
|
626
631
|
type: "tool-result",
|
|
627
632
|
toolCallId: block.tool_use_id,
|
|
628
633
|
toolName,
|
|
629
634
|
result,
|
|
630
|
-
isError
|
|
635
|
+
isError,
|
|
636
|
+
...dynamic ? { dynamic: true } : {}
|
|
631
637
|
});
|
|
632
638
|
state.pendingStepToolUseIds.delete(block.tool_use_id);
|
|
633
639
|
}
|
|
@@ -734,6 +740,13 @@ function stringifyContent(content) {
|
|
|
734
740
|
}
|
|
735
741
|
return JSON.stringify(content);
|
|
736
742
|
}
|
|
743
|
+
function parseMcpToolResult(content) {
|
|
744
|
+
try {
|
|
745
|
+
return JSON.parse(content);
|
|
746
|
+
} catch {
|
|
747
|
+
return content;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
737
750
|
function mapUsage(usage) {
|
|
738
751
|
if (!usage || typeof usage !== "object") return void 0;
|
|
739
752
|
const u = usage;
|
|
@@ -848,16 +861,7 @@ function isJsonLiteral(value) {
|
|
|
848
861
|
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
849
862
|
}
|
|
850
863
|
|
|
851
|
-
// src/bridge/
|
|
852
|
-
var NATIVE_TO_COMMON = {
|
|
853
|
-
Read: "read",
|
|
854
|
-
Write: "write",
|
|
855
|
-
Edit: "edit",
|
|
856
|
-
Bash: "bash",
|
|
857
|
-
Glob: "glob",
|
|
858
|
-
Grep: "grep",
|
|
859
|
-
WebSearch: "webSearch"
|
|
860
|
-
};
|
|
864
|
+
// src/bridge/tool-filtering.ts
|
|
861
865
|
var PUBLIC_TO_NATIVE = {
|
|
862
866
|
read: "Read",
|
|
863
867
|
write: "Write",
|
|
@@ -887,6 +891,31 @@ var PUBLIC_TO_NATIVE = {
|
|
|
887
891
|
ToolSearch: "ToolSearch"
|
|
888
892
|
};
|
|
889
893
|
var PUBLIC_TOOL_NAMES = Object.keys(PUBLIC_TO_NATIVE);
|
|
894
|
+
function toNativeName(toolName) {
|
|
895
|
+
return PUBLIC_TO_NATIVE[toolName] ?? toolName;
|
|
896
|
+
}
|
|
897
|
+
function resolveNativeTools(toolFiltering) {
|
|
898
|
+
if (toolFiltering == null || toolFiltering.mode === "deny") return void 0;
|
|
899
|
+
return toolFiltering.toolNames.map((name) => toNativeName(name));
|
|
900
|
+
}
|
|
901
|
+
function resolveInactiveNativeTools(toolFiltering) {
|
|
902
|
+
if (toolFiltering == null) return [];
|
|
903
|
+
const inactiveToolNames = toolFiltering.mode === "allow" ? PUBLIC_TOOL_NAMES.filter(
|
|
904
|
+
(name) => !toolFiltering.toolNames.includes(name)
|
|
905
|
+
) : toolFiltering.toolNames;
|
|
906
|
+
return inactiveToolNames.map((name) => toNativeName(name));
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/bridge/index.ts
|
|
910
|
+
var NATIVE_TO_COMMON = {
|
|
911
|
+
Read: "read",
|
|
912
|
+
Write: "write",
|
|
913
|
+
Edit: "edit",
|
|
914
|
+
Bash: "bash",
|
|
915
|
+
Glob: "glob",
|
|
916
|
+
Grep: "grep",
|
|
917
|
+
WebSearch: "webSearch"
|
|
918
|
+
};
|
|
890
919
|
var NATIVE_TOOL_KINDS = {
|
|
891
920
|
Read: "readonly",
|
|
892
921
|
Glob: "readonly",
|
|
@@ -917,25 +946,6 @@ var NATIVE_TOOL_KINDS = {
|
|
|
917
946
|
function toCommonName(nativeName) {
|
|
918
947
|
return NATIVE_TO_COMMON[nativeName] ?? nativeName;
|
|
919
948
|
}
|
|
920
|
-
function toNativeName(toolName) {
|
|
921
|
-
return PUBLIC_TO_NATIVE[toolName] ?? toolName;
|
|
922
|
-
}
|
|
923
|
-
function resolveNativeTools(start) {
|
|
924
|
-
const toolFiltering = start.builtinToolFiltering;
|
|
925
|
-
if (toolFiltering == null) return void 0;
|
|
926
|
-
const activeToolNames = toolFiltering.mode === "allow" ? toolFiltering.toolNames : PUBLIC_TOOL_NAMES.filter(
|
|
927
|
-
(name) => !toolFiltering.toolNames.includes(name)
|
|
928
|
-
);
|
|
929
|
-
return activeToolNames.map((name) => toNativeName(name));
|
|
930
|
-
}
|
|
931
|
-
function resolveInactiveNativeTools(start) {
|
|
932
|
-
const toolFiltering = start.builtinToolFiltering;
|
|
933
|
-
if (toolFiltering == null) return [];
|
|
934
|
-
const inactiveToolNames = toolFiltering.mode === "allow" ? PUBLIC_TOOL_NAMES.filter(
|
|
935
|
-
(name) => !toolFiltering.toolNames.includes(name)
|
|
936
|
-
) : toolFiltering.toolNames;
|
|
937
|
-
return inactiveToolNames.map((name) => toNativeName(name));
|
|
938
|
-
}
|
|
939
949
|
var args = parseArgs(argv.slice(2));
|
|
940
950
|
var workdir = args.workdir;
|
|
941
951
|
var bridgeStateDir = args.bridgeStateDir;
|
|
@@ -1038,7 +1048,7 @@ async function runTurn(start, turn) {
|
|
|
1038
1048
|
});
|
|
1039
1049
|
}
|
|
1040
1050
|
const streamEventState = createClaudeStreamEventState();
|
|
1041
|
-
const mcpServers = {};
|
|
1051
|
+
const mcpServers = { ...start.mcpServers ?? {} };
|
|
1042
1052
|
if (start.tools && start.tools.length > 0) {
|
|
1043
1053
|
const server = new mcpModule.McpServer({
|
|
1044
1054
|
name: "harness-tools",
|
|
@@ -1087,8 +1097,10 @@ async function runTurn(start, turn) {
|
|
|
1087
1097
|
abortSignal: abortCtl.signal
|
|
1088
1098
|
});
|
|
1089
1099
|
const skillsOption = toClaudeSkillsOption(start.skills);
|
|
1090
|
-
const nativeTools = resolveNativeTools(start);
|
|
1091
|
-
const inactiveNativeTools = resolveInactiveNativeTools(
|
|
1100
|
+
const nativeTools = resolveNativeTools(start.builtinToolFiltering);
|
|
1101
|
+
const inactiveNativeTools = resolveInactiveNativeTools(
|
|
1102
|
+
start.builtinToolFiltering
|
|
1103
|
+
);
|
|
1092
1104
|
const permissionOptions = createPermissionOptions({
|
|
1093
1105
|
start,
|
|
1094
1106
|
inactiveNativeTools,
|
|
@@ -1105,6 +1117,7 @@ async function runTurn(start, turn) {
|
|
|
1105
1117
|
options: {
|
|
1106
1118
|
...start.model ? { model: start.model } : {},
|
|
1107
1119
|
...start.maxTurns !== void 0 ? { maxTurns: start.maxTurns } : {},
|
|
1120
|
+
...start.env !== void 0 ? { env: { ...procEnv2, ...start.env } } : {},
|
|
1108
1121
|
...skillsOption ? { skills: skillsOption } : {},
|
|
1109
1122
|
...nativeTools !== void 0 ? { tools: nativeTools } : {},
|
|
1110
1123
|
...inactiveNativeTools.length > 0 ? { disallowedTools: inactiveNativeTools } : {},
|