@agent-harness-experimental/adapter-claude-code 0.0.0 → 0.0.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/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Copyright Vercel Inc. Pre-release. Not licensed as OSS yet.
package/README.md CHANGED
@@ -1,3 +1,103 @@
1
- # @agent-harness-experimental/adapter-claude-code
1
+ # `@agent-harness-experimental/adapter-claude-code`
2
2
 
3
- Placeholder package.
3
+ Adapter for running [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
4
+ as an agent inside `agent-harness-experimental`.
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npm install agent-harness-experimental @agent-harness-experimental/adapter-claude-code
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ ```ts
15
+ import { createAgentSession } from "agent-harness-experimental";
16
+ import { claudeCode } from "@agent-harness-experimental/adapter-claude-code";
17
+
18
+ const agent = createAgentSession({
19
+ adapter: claudeCode(),
20
+ });
21
+
22
+ const result = await agent.generate("Create a hello world Express server");
23
+ console.log(result.text);
24
+ await agent.close("stop");
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ ```ts
30
+ claudeCode({
31
+ // Claude model to use
32
+ model: "claude-sonnet-4",
33
+
34
+ // Maximum conversation turns
35
+ maxTurns: 20,
36
+
37
+ // Extended thinking mode
38
+ thinking: "adaptive", // or 'disabled' or { budgetTokens: 10000 }
39
+
40
+ // Reasoning effort level
41
+ effort: "high", // 'low' | 'medium' | 'high' | 'max'
42
+ });
43
+ ```
44
+
45
+ | Option | Type | Default | Description |
46
+ | --- | --- | --- | --- |
47
+ | `model` | `string` | — | Claude model ID |
48
+ | `maxTurns` | `number` | — | Max conversation turns |
49
+ | `thinking` | `'adaptive' \| 'disabled' \| { budgetTokens }` | — | Extended thinking mode |
50
+ | `effort` | `'low' \| 'medium' \| 'high' \| 'max'` | — | Reasoning effort |
51
+ | `auth` | `object` | — | Optional per-adapter auth override (`gateway` or `anthropic`) |
52
+
53
+ Sandbox runtime options such as `template`, `timeoutMs`, and `httpHandler`
54
+ belong on `createAgentSession({ sandbox })`.
55
+
56
+ ```ts
57
+ const agent = createAgentSession({
58
+ adapter: claudeCode({ model: "claude-sonnet-4" }),
59
+ sandbox: {
60
+ template: "snap_abc123",
61
+ timeoutMs: 60000,
62
+ httpHandler: async (request: Request) => fetch(request),
63
+ },
64
+ });
65
+ ```
66
+
67
+ ## Auth
68
+
69
+ `auth` is optional. If you omit it, Claude Code keeps the existing
70
+ gateway-first fallback.
71
+
72
+ ```ts
73
+ claudeCode({
74
+ model: "claude-sonnet-4",
75
+ auth: {
76
+ anthropic: {
77
+ apiKey: { env: "ANTHROPIC_TEAM_B_API_KEY" },
78
+ },
79
+ },
80
+ });
81
+ ```
82
+
83
+ ## Built-in Tools
84
+
85
+ Claude Code exposes standardized builtin names through `agent-harness-experimental`. The native runtime names are shown for reference:
86
+
87
+ | Tool | Native Tool | Description |
88
+ | --- | --- | --- |
89
+ | `read` | `Read` | Read file contents |
90
+ | `write` | `Write` | Write content to a file |
91
+ | `edit` | `Edit` | Edit a file by replacing text |
92
+ | `bash` | `Bash` | Execute a shell command |
93
+ | `glob` | `Glob` | Find files matching a glob pattern |
94
+ | `grep` | `Grep` | Search file contents with regex |
95
+
96
+ ## Features
97
+
98
+ - **Tool interception**: Built-in tools can be intercepted for approval via the
99
+ `permissions` option on `createAgentSession`
100
+ - **Skills**: Written to `.claude/skills/{name}.md` with YAML frontmatter
101
+ - **Subagents**: Full support for delegating to named subagents
102
+ - **Token-level streaming**: Real-time text and reasoning deltas
103
+ - **Session resume**: Persistent sandbox sessions across restarts
@@ -0,0 +1,29 @@
1
+ import type { AgentAdapter, AdapterContext, AnthropicAuthOptions, GatewayAuthOptions } from 'agent-harness-experimental';
2
+ export declare const CLAUDE_CODE_BUILTIN_TOOLS: {
3
+ name: string;
4
+ inputSchema: import("agent-harness-experimental").JsonSchema;
5
+ nativeName?: string | undefined;
6
+ description?: string | undefined;
7
+ }[], CLAUDE_CODE_BUILTIN_TOOL_MAPPINGS: Pick<{
8
+ name: string;
9
+ inputSchema: import("agent-harness-experimental").JsonSchema;
10
+ nativeName?: string | undefined;
11
+ description?: string | undefined;
12
+ }, "name" | "nativeName">[], CLAUDE_CODE_PERMISSION_TOOL_CATEGORIES: import("agent-harness-experimental").PermissionToolCategories;
13
+ export interface ClaudeCodeAdapterOptions {
14
+ model?: string;
15
+ maxTurns?: number;
16
+ /** Thinking mode: 'adaptive' (default), 'enabled' with budget, or 'disabled' */
17
+ thinking?: 'adaptive' | 'disabled' | {
18
+ budgetTokens: number;
19
+ };
20
+ /** Reasoning effort level */
21
+ effort?: 'low' | 'medium' | 'high' | 'max';
22
+ auth?: {
23
+ gateway?: GatewayAuthOptions;
24
+ anthropic?: AnthropicAuthOptions;
25
+ };
26
+ }
27
+ export declare function setupClaudeCodeEnv(ctx: AdapterContext, options?: ClaudeCodeAdapterOptions, env?: NodeJS.ProcessEnv): void;
28
+ export declare function claudeCode(options?: ClaudeCodeAdapterOptions): AgentAdapter;
29
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAGnB,MAAM,4BAA4B,CAAC;AAqBpC,eAAO,MACE,yBAAyB;;;;;KACtB,iCAAiC;;;;;6BACjB,sCAAsC,+DAYhE,CAAC;AAEH,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,6BAA6B;IAC7B,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;IAC3C,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,kBAAkB,CAAC;QAC7B,SAAS,CAAC,EAAE,oBAAoB,CAAC;KAClC,CAAC;CACH;AAqFD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,wBAAwB,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,IAAI,CAoCtI;AAED,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,wBAAwB,GAAG,YAAY,CAoG3E"}
@@ -0,0 +1,215 @@
1
+ import { normalizeAdapterError, defineAdapterBuiltinTools, detachSandboxRuntime, getSandboxRuntimeLayout, hasHttpPathRuleForBaseUrl, promptSandboxRuntime, resolveAnthropicHeaders, resolveBearerHeaders, resolveSecretInput, resolveUrlHost, selectConfiguredAuthBag, startSandboxRuntime, stopSandboxRuntime, toSandboxPlaceholderSecret, } from 'agent-harness-experimental';
2
+ import { getSandboxImageName, withVercelSandboxBackend } from '@agent-harness-experimental/sandbox-vercel';
3
+ import { CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW, getClaudeCodeSandboxSetup } from './setup.js';
4
+ export const { tools: CLAUDE_CODE_BUILTIN_TOOLS, mappings: CLAUDE_CODE_BUILTIN_TOOL_MAPPINGS, permissionToolCategories: CLAUDE_CODE_PERMISSION_TOOL_CATEGORIES, } = defineAdapterBuiltinTools([
5
+ { name: 'read', nativeName: 'Read' },
6
+ { name: 'write', nativeName: 'Write' },
7
+ { name: 'edit', nativeName: 'Edit' },
8
+ { name: 'bash', nativeName: 'Bash' },
9
+ { name: 'glob', nativeName: 'Glob' },
10
+ {
11
+ name: 'grep',
12
+ nativeName: 'Grep',
13
+ description: 'Search file contents with regex',
14
+ },
15
+ ]);
16
+ function setEnvValue(target, name, value) {
17
+ if (value !== undefined) {
18
+ target[name] = value;
19
+ }
20
+ }
21
+ function resolveClaudeCodeErrorProvider(options) {
22
+ const selectedAuth = selectConfiguredAuthBag(options?.auth, ['anthropic', 'gateway']);
23
+ if (selectedAuth === 'anthropic') {
24
+ return 'anthropic';
25
+ }
26
+ if (selectedAuth === 'gateway') {
27
+ return 'ai-gateway';
28
+ }
29
+ return undefined;
30
+ }
31
+ function resolveClaudeCodeCoreSandboxAccess(options, sandboxConfig, env = process.env) {
32
+ const selectedAuth = selectConfiguredAuthBag(options?.auth, ['anthropic', 'gateway']);
33
+ const forceProxy = Boolean(sandboxConfig?.httpHandler);
34
+ if (selectedAuth === 'anthropic') {
35
+ const auth = options?.auth?.anthropic;
36
+ const apiKey = resolveSecretInput(auth?.apiKey, env) ?? env.ANTHROPIC_API_KEY;
37
+ const authToken = resolveSecretInput(auth?.authToken, env) ?? env.ANTHROPIC_AUTH_TOKEN;
38
+ const baseUrl = auth?.baseURL ?? env.ANTHROPIC_BASE_URL;
39
+ const host = resolveUrlHost(baseUrl, 'https://api.anthropic.com');
40
+ if (!host) {
41
+ return undefined;
42
+ }
43
+ if (forceProxy || hasHttpPathRuleForBaseUrl(sandboxConfig?.network?.deny?.urlPrefixes, baseUrl, 'https://api.anthropic.com')) {
44
+ return {
45
+ proxiedHosts: [host],
46
+ injectedHeaders: [{ domain: host, headers: resolveAnthropicHeaders({ apiKey, authToken, headers: auth?.headers }) }],
47
+ };
48
+ }
49
+ return {
50
+ directHosts: [host],
51
+ injectedHeaders: [{ domain: host, headers: resolveAnthropicHeaders({ apiKey, authToken, headers: auth?.headers }) }],
52
+ };
53
+ }
54
+ if (selectedAuth === 'gateway') {
55
+ const auth = options?.auth?.gateway;
56
+ const gatewayKey = resolveSecretInput(auth?.apiKey, env) ?? env.AI_GATEWAY_API_KEY;
57
+ const host = resolveUrlHost(auth?.baseURL ?? env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh', 'https://ai-gateway.vercel.sh');
58
+ return {
59
+ ...(forceProxy ? { proxiedHosts: host ? [host] : [] } : { directHosts: host ? [host] : [] }),
60
+ injectedHeaders: host ? [{ domain: host, headers: resolveBearerHeaders(gatewayKey, auth?.headers) }] : [],
61
+ };
62
+ }
63
+ const gatewayKey = env.AI_GATEWAY_API_KEY || '';
64
+ if (gatewayKey) {
65
+ const host = resolveUrlHost(env.AI_GATEWAY_BASE_URL ?? env.ANTHROPIC_BASE_URL, 'https://ai-gateway.vercel.sh');
66
+ return {
67
+ ...(forceProxy ? { proxiedHosts: host ? [host] : [] } : { directHosts: host ? [host] : [] }),
68
+ injectedHeaders: host ? [{ domain: host, headers: resolveBearerHeaders(gatewayKey) }] : [],
69
+ };
70
+ }
71
+ const host = resolveUrlHost(env.ANTHROPIC_BASE_URL, 'https://api.anthropic.com');
72
+ const apiKey = env.ANTHROPIC_API_KEY;
73
+ const authToken = env.ANTHROPIC_AUTH_TOKEN;
74
+ if (!host) {
75
+ return undefined;
76
+ }
77
+ if (forceProxy || hasHttpPathRuleForBaseUrl(sandboxConfig?.network?.deny?.urlPrefixes, env.ANTHROPIC_BASE_URL, 'https://api.anthropic.com')) {
78
+ return {
79
+ proxiedHosts: [host],
80
+ injectedHeaders: [{ domain: host, headers: resolveAnthropicHeaders({ apiKey, authToken }) }],
81
+ };
82
+ }
83
+ return {
84
+ directHosts: [host],
85
+ injectedHeaders: [{ domain: host, headers: resolveAnthropicHeaders({ apiKey, authToken }) }],
86
+ };
87
+ }
88
+ export function setupClaudeCodeEnv(ctx, options, env = process.env) {
89
+ const selectedAuth = selectConfiguredAuthBag(options?.auth, ['anthropic', 'gateway']);
90
+ if (selectedAuth === 'anthropic') {
91
+ const auth = options?.auth?.anthropic;
92
+ const apiKey = resolveSecretInput(auth?.apiKey, env) ?? env.ANTHROPIC_API_KEY;
93
+ const authToken = resolveSecretInput(auth?.authToken, env) ?? env.ANTHROPIC_AUTH_TOKEN;
94
+ setEnvValue(ctx.env, 'ANTHROPIC_API_KEY', toSandboxPlaceholderSecret(apiKey));
95
+ setEnvValue(ctx.env, 'ANTHROPIC_AUTH_TOKEN', toSandboxPlaceholderSecret(authToken));
96
+ setEnvValue(ctx.env, 'ANTHROPIC_BASE_URL', auth?.baseURL ?? env.ANTHROPIC_BASE_URL);
97
+ }
98
+ else if (selectedAuth === 'gateway') {
99
+ const auth = options?.auth?.gateway;
100
+ const gatewayKey = resolveSecretInput(auth?.apiKey, env) ?? env.AI_GATEWAY_API_KEY;
101
+ setEnvValue(ctx.env, 'AI_GATEWAY_API_KEY', toSandboxPlaceholderSecret(gatewayKey));
102
+ setEnvValue(ctx.env, 'ANTHROPIC_BASE_URL', auth?.baseURL ?? env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh');
103
+ setEnvValue(ctx.env, 'ANTHROPIC_AUTH_TOKEN', toSandboxPlaceholderSecret(gatewayKey));
104
+ setEnvValue(ctx.env, 'ANTHROPIC_API_KEY', toSandboxPlaceholderSecret(gatewayKey));
105
+ }
106
+ else {
107
+ const gatewayKey = env.AI_GATEWAY_API_KEY || '';
108
+ if (gatewayKey) {
109
+ ctx.env.ANTHROPIC_BASE_URL = env.ANTHROPIC_BASE_URL || 'https://ai-gateway.vercel.sh';
110
+ ctx.env.ANTHROPIC_AUTH_TOKEN = toSandboxPlaceholderSecret(env.ANTHROPIC_AUTH_TOKEN || gatewayKey) ?? '';
111
+ ctx.env.ANTHROPIC_API_KEY = toSandboxPlaceholderSecret(gatewayKey) ?? '';
112
+ }
113
+ else if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_AUTH_TOKEN) {
114
+ if (env.ANTHROPIC_API_KEY) {
115
+ ctx.env.ANTHROPIC_API_KEY = toSandboxPlaceholderSecret(env.ANTHROPIC_API_KEY) ?? '';
116
+ }
117
+ if (env.ANTHROPIC_AUTH_TOKEN) {
118
+ ctx.env.ANTHROPIC_AUTH_TOKEN = toSandboxPlaceholderSecret(env.ANTHROPIC_AUTH_TOKEN) ?? '';
119
+ }
120
+ }
121
+ }
122
+ if (ctx.agentTelemetry !== 'allow') {
123
+ ctx.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = '1';
124
+ }
125
+ }
126
+ export function claudeCode(options) {
127
+ let state = null;
128
+ const sandboxSetup = getClaudeCodeSandboxSetup();
129
+ const sandboxImageName = getSandboxImageName('claude-code', sandboxSetup);
130
+ return {
131
+ name: 'claude-code',
132
+ supportsToolInterception: true,
133
+ supportsHostAccessRequests: true,
134
+ prepareStepSupport: 'continuation',
135
+ normalizeError(error) {
136
+ return normalizeAdapterError(error, {
137
+ adapter: 'claude-code',
138
+ provider: resolveClaudeCodeErrorProvider(options),
139
+ model: options?.model,
140
+ });
141
+ },
142
+ builtinTools: CLAUDE_CODE_BUILTIN_TOOLS,
143
+ defaultContextWindow: CLAUDE_CODE_DEFAULT_CONTEXT_WINDOW,
144
+ permissionToolCategories: CLAUDE_CODE_PERMISSION_TOOL_CATEGORIES,
145
+ getBridgeFiles: () => sandboxSetup.getBridgeFiles(),
146
+ getSandboxFiles: (ctx) => sandboxSetup.getSandboxFiles(ctx),
147
+ resolveSandboxConfig: (sandboxConfig) => withVercelSandboxBackend(sandboxConfig),
148
+ async start(ctx) {
149
+ const sandboxConfig = withVercelSandboxBackend(ctx.sandboxConfig);
150
+ const { workDir } = getSandboxRuntimeLayout('claude-code', ctx.sessionId, sandboxConfig);
151
+ state = await startSandboxRuntime(ctx, {
152
+ adapterName: 'claude-code',
153
+ sessionId: ctx.sessionId,
154
+ deps: sandboxSetup.deps,
155
+ lockfile: sandboxSetup.lockfile,
156
+ bridgeFiles: sandboxSetup.getBridgeFiles(),
157
+ sandboxFiles: sandboxSetup.getSandboxFiles({
158
+ workDir,
159
+ skills: ctx.skills,
160
+ agents: ctx.agents,
161
+ instructions: ctx.instructions,
162
+ }),
163
+ postInstallCommands: sandboxSetup.postInstallCommands,
164
+ setupEnv(innerCtx) {
165
+ setupClaudeCodeEnv(innerCtx, options);
166
+ },
167
+ buildConfig: () => ({
168
+ model: options?.model,
169
+ maxTurns: options?.maxTurns,
170
+ activeTools: ctx.activeTools,
171
+ interceptBuiltinTools: ctx.interceptBuiltinTools,
172
+ builtinToolMappings: CLAUDE_CODE_BUILTIN_TOOL_MAPPINGS,
173
+ thinking: options?.thinking,
174
+ effort: options?.effort,
175
+ agents: ctx.agents,
176
+ }),
177
+ imageName: sandboxImageName,
178
+ sandboxConfig,
179
+ coreAccess: resolveClaudeCodeCoreSandboxAccess(options, sandboxConfig),
180
+ });
181
+ },
182
+ async prompt(message, ctx) {
183
+ if (!state)
184
+ throw new Error('Adapter not started');
185
+ await promptSandboxRuntime(state, ctx, message, ctx.registeredTools, {
186
+ model: options?.model,
187
+ maxTurns: options?.maxTurns,
188
+ activeTools: ctx.activeTools,
189
+ interceptBuiltinTools: ctx.interceptBuiltinTools,
190
+ builtinToolMappings: CLAUDE_CODE_BUILTIN_TOOL_MAPPINGS,
191
+ thinking: options?.thinking,
192
+ effort: options?.effort,
193
+ contextWindow: ctx.contextWindow,
194
+ toolSearchMode: ctx.toolSearchMode,
195
+ traceContext: ctx.traceContext,
196
+ agents: ctx.agents,
197
+ }, { instructions: ctx.instructions });
198
+ },
199
+ async registerTools(tools, ctx) {
200
+ ctx.registeredTools = tools;
201
+ },
202
+ async stop() {
203
+ if (state) {
204
+ await stopSandboxRuntime(state);
205
+ state = null;
206
+ }
207
+ },
208
+ async detach() {
209
+ if (state) {
210
+ await detachSandboxRuntime(state);
211
+ }
212
+ },
213
+ };
214
+ }
215
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,GAE3B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAC3G,OAAO,EAAE,kCAAkC,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE3F,MAAM,CAAC,MAAM,EACX,KAAK,EAAE,yBAAyB,EAChC,QAAQ,EAAE,iCAAiC,EAC3C,wBAAwB,EAAE,sCAAsC,GACjE,GAAG,yBAAyB,CAAC;IAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE;IACtC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE;IACpC;QACE,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,iCAAiC;KAC/C;CACF,CAAC,CAAC;AAeH,SAAS,WAAW,CAAC,MAA8B,EAAE,IAAY,EAAE,KAAyB;IAC1F,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,8BAA8B,CAAC,OAAkC;IACxE,MAAM,YAAY,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,SAAS,CAAU,CAAC,CAAC;IAC/F,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,kCAAkC,CACzC,OAAkC,EAClC,aAA+C,EAC/C,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,YAAY,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,SAAS,CAAU,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAEvD,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;QACtC,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC;QAC9E,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,oBAAoB,CAAC;QACvF,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,kBAAkB,CAAC;QACxD,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,UAAU,IAAI,yBAAyB,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,2BAA2B,CAAC,EAAE,CAAC;YAC7H,OAAO;gBACL,YAAY,EAAE,CAAC,IAAI,CAAC;gBACpB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;aACrH,CAAC;QACJ,CAAC;QACD,OAAO;YACL,WAAW,EAAE,CAAC,IAAI,CAAC;YACnB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;SACrH,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC;QACpC,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,kBAAkB,CAAC;QACnF,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,mBAAmB,IAAI,8BAA8B,EAAE,8BAA8B,CAAC,CAAC;QACxI,OAAO;YACL,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5F,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;SAC1G,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;IAChD,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,kBAAkB,EAAE,8BAA8B,CAAC,CAAC;QAC/G,OAAO;YACL,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5F,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;SAC3F,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,kBAAkB,EAAE,2BAA2B,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,GAAG,CAAC,iBAAiB,CAAC;IACrC,MAAM,SAAS,GAAG,GAAG,CAAC,oBAAoB,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,UAAU,IAAI,yBAAyB,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,kBAAkB,EAAE,2BAA2B,CAAC,EAAE,CAAC;QAC5I,OAAO;YACL,YAAY,EAAE,CAAC,IAAI,CAAC;YACpB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;SAC7F,CAAC;IACJ,CAAC;IACD,OAAO;QACL,WAAW,EAAE,CAAC,IAAI,CAAC;QACnB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,uBAAuB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;KAC7F,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAmB,EAAE,OAAkC,EAAE,MAAyB,OAAO,CAAC,GAAG;IAC9H,MAAM,YAAY,GAAG,uBAAuB,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,SAAS,CAAU,CAAC,CAAC;IAE/F,IAAI,YAAY,KAAK,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC;QACtC,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,iBAAiB,CAAC;QAC9E,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,oBAAoB,CAAC;QACvF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,mBAAmB,EAAE,0BAA0B,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9E,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,sBAAsB,EAAE,0BAA0B,CAAC,SAAS,CAAC,CAAC,CAAC;QACpF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,EAAE,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACtF,CAAC;SAAM,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC;QACpC,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,kBAAkB,CAAC;QACnF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC,CAAC;QACnF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,oBAAoB,EAAE,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,mBAAmB,IAAI,8BAA8B,CAAC,CAAC;QACvH,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,sBAAsB,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC,CAAC;QACrF,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,mBAAmB,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC,CAAC;IACpF,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,GAAG,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAChD,IAAI,UAAU,EAAE,CAAC;YACf,GAAG,CAAC,GAAG,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,IAAI,8BAA8B,CAAC;YACtF,GAAG,CAAC,GAAG,CAAC,oBAAoB,GAAG,0BAA0B,CAAC,GAAG,CAAC,oBAAoB,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;YACxG,GAAG,CAAC,GAAG,CAAC,iBAAiB,GAAG,0BAA0B,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QAC3E,CAAC;aAAM,IAAI,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,oBAAoB,EAAE,CAAC;YAC7D,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;gBAC1B,GAAG,CAAC,GAAG,CAAC,iBAAiB,GAAG,0BAA0B,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;YACtF,CAAC;YACD,IAAI,GAAG,CAAC,oBAAoB,EAAE,CAAC;gBAC7B,GAAG,CAAC,GAAG,CAAC,oBAAoB,GAAG,0BAA0B,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC;YAC5F,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,GAAG,CAAC,cAAc,KAAK,OAAO,EAAE,CAAC;QACnC,GAAG,CAAC,GAAG,CAAC,wCAAwC,GAAG,GAAG,CAAC;IACzD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAkC;IAC3D,IAAI,KAAK,GAA+B,IAAI,CAAC;IAC7C,MAAM,YAAY,GAAG,yBAAyB,EAAE,CAAC;IACjD,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;IAE1E,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,wBAAwB,EAAE,IAAI;QAC9B,0BAA0B,EAAE,IAAI;QAChC,kBAAkB,EAAE,cAAc;QAClC,cAAc,CAAC,KAAc;YAC3B,OAAO,qBAAqB,CAAC,KAAK,EAAE;gBAClC,OAAO,EAAE,aAAa;gBACtB,QAAQ,EAAE,8BAA8B,CAAC,OAAO,CAAC;gBACjD,KAAK,EAAE,OAAO,EAAE,KAAK;aACtB,CAAC,CAAC;QACL,CAAC;QACD,YAAY,EAAE,yBAAyB;QACvC,oBAAoB,EAAE,kCAAkC;QACxD,wBAAwB,EAAE,sCAAsC;QAChE,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE;QACnD,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,YAAY,CAAC,eAAe,CAAC,GAAG,CAAC;QAC3D,oBAAoB,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,wBAAwB,CAAC,aAAa,CAAoC;QAEnH,KAAK,CAAC,KAAK,CAAC,GAAmB;YAC7B,MAAM,aAAa,GAAG,wBAAwB,CAAC,GAAG,CAAC,aAAa,CAAoC,CAAC;YACrG,MAAM,EAAE,OAAO,EAAE,GAAG,uBAAuB,CAAC,aAAa,EAAE,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;YACzF,KAAK,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE;gBACrC,WAAW,EAAE,aAAa;gBAC1B,SAAS,EAAE,GAAG,CAAC,SAAS;gBACxB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,QAAQ,EAAE,YAAY,CAAC,QAAQ;gBAC/B,WAAW,EAAE,YAAY,CAAC,cAAc,EAAE;gBAC1C,YAAY,EAAE,YAAY,CAAC,eAAe,CAAC;oBACzC,OAAO;oBACP,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;oBAClB,YAAY,EAAE,GAAG,CAAC,YAAY;iBAC/B,CAAC;gBACF,mBAAmB,EAAE,YAAY,CAAC,mBAAmB;gBACrD,QAAQ,CAAC,QAAQ;oBACf,kBAAkB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACxC,CAAC;gBACD,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;oBAClB,KAAK,EAAE,OAAO,EAAE,KAAK;oBACrB,QAAQ,EAAE,OAAO,EAAE,QAAQ;oBAC3B,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,qBAAqB,EAAE,GAAG,CAAC,qBAAqB;oBAChD,mBAAmB,EAAE,iCAAiC;oBACtD,QAAQ,EAAE,OAAO,EAAE,QAAQ;oBAC3B,MAAM,EAAE,OAAO,EAAE,MAAM;oBACvB,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC;gBACF,SAAS,EAAE,gBAAgB;gBAC3B,aAAa;gBACb,UAAU,EAAE,kCAAkC,CAAC,OAAO,EAAE,aAAa,CAAC;aACvE,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,GAAmB;YAC/C,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACnD,MAAM,oBAAoB,CACxB,KAAK,EACL,GAAG,EACH,OAAO,EACP,GAAG,CAAC,eAAe,EACnB;gBACE,KAAK,EAAE,OAAO,EAAE,KAAK;gBACrB,QAAQ,EAAE,OAAO,EAAE,QAAQ;gBAC3B,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,qBAAqB,EAAE,GAAG,CAAC,qBAAqB;gBAChD,mBAAmB,EAAE,iCAAiC;gBACtD,QAAQ,EAAE,OAAO,EAAE,QAAQ;gBAC3B,MAAM,EAAE,OAAO,EAAE,MAAM;gBACvB,aAAa,EAAE,GAAG,CAAC,aAAa;gBAChC,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,YAAY,EAAE,GAAG,CAAC,YAAY;gBAC9B,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,EACD,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,CACnC,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,KAAmB,EAAE,GAAmB;YAC1D,GAAG,CAAC,eAAe,GAAG,KAAK,CAAC;QAC9B,CAAC;QAED,KAAK,CAAC,IAAI;YACR,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBAChC,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;QACH,CAAC;QAED,KAAK,CAAC,MAAM;YACV,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export * from '@agent-harness-experimental/bridge/bridge-continuation';
@@ -0,0 +1 @@
1
+ export * from '@agent-harness-experimental/bridge/bridge-delegation';
@@ -0,0 +1,122 @@
1
+ import { isToolAllowed, shouldObserveBuiltinTool, toStandardBuiltinToolName } from './bridge-tool-policy.mts';
2
+ import type { emit } from './bridge-ws-server.mts';
3
+ import { msg as protocolMessage } from '@agent-harness-experimental/protocol';
4
+
5
+ type ClaudeBridgeConfig = {
6
+ workDir?: string;
7
+ interceptBuiltinTools?: boolean | string[];
8
+ activeTools?: string[];
9
+ builtinToolMappings?: Array<{
10
+ name: string;
11
+ nativeName?: string;
12
+ }>;
13
+ model?: string;
14
+ maxTurns?: number;
15
+ executableArgs?: string[];
16
+ instructions?: string;
17
+ thinking?: 'adaptive' | 'disabled' | Record<string, unknown>;
18
+ effort?: string;
19
+ agents?: Record<string, unknown>;
20
+ };
21
+
22
+ type ToolDecision = {
23
+ approved: boolean;
24
+ reason?: string;
25
+ };
26
+
27
+ type ToolDecisionRequester = (requestId: string) => Promise<ToolDecision>;
28
+ type BridgeEmitter = typeof emit;
29
+
30
+ type ClaudeQueryToolDecision =
31
+ | { behavior: 'allow'; updatedInput: Record<string, unknown> }
32
+ | {
33
+ behavior: 'deny';
34
+ message: string;
35
+ };
36
+
37
+ type ClaudeQueryToolOptions = {
38
+ permissionMode: 'default' | 'bypassPermissions';
39
+ allowDangerouslySkipPermissions: boolean;
40
+ canUseTool?: (toolName: string, input: Record<string, unknown>, opts: { toolUseID: string }) => Promise<ClaudeQueryToolDecision>;
41
+ };
42
+
43
+ export function createClaudeQueryToolOptions(
44
+ config: ClaudeBridgeConfig,
45
+ emit: BridgeEmitter,
46
+ requestToolDecision: ToolDecisionRequester,
47
+ allowedTools?: string[],
48
+ ): ClaudeQueryToolOptions {
49
+ if (!config.interceptBuiltinTools && !allowedTools?.length) {
50
+ return {
51
+ permissionMode: 'bypassPermissions',
52
+ allowDangerouslySkipPermissions: true,
53
+ };
54
+ }
55
+
56
+ return {
57
+ permissionMode: 'default',
58
+ allowDangerouslySkipPermissions: false,
59
+ async canUseTool(toolName, input, opts) {
60
+ const requestId = opts.toolUseID;
61
+ const standardToolName = toStandardBuiltinToolName(config, toolName);
62
+ if (!isToolAllowed(standardToolName, allowedTools) || !isToolAllowed(standardToolName, config.activeTools)) {
63
+ return { behavior: 'deny', message: `Tool "${standardToolName}" is not allowed for this run` };
64
+ }
65
+ if (shouldObserveBuiltinTool(config, toolName)) {
66
+ emit(protocolMessage.toolCall({ requestId, toolName: standardToolName, toolCallId: requestId, input, observeOnly: true }));
67
+ return { behavior: 'allow', updatedInput: input };
68
+ }
69
+
70
+ emit(protocolMessage.toolCall({ requestId, toolName: standardToolName, toolCallId: requestId, input }));
71
+ const decision = await requestToolDecision(requestId);
72
+ return decision.approved ? { behavior: 'allow', updatedInput: input } : { behavior: 'deny', message: decision.reason || 'Denied' };
73
+ },
74
+ };
75
+ }
76
+
77
+ function extractSubagentName(input: unknown): string | null {
78
+ if (!input || typeof input !== 'object') {
79
+ return null;
80
+ }
81
+
82
+ for (const key of ['agent', 'name', 'subagent', 'agentName', 'subagent_type', 'subagentType', 'agent_type', 'agentType']) {
83
+ const value = (input as Record<string, unknown>)[key];
84
+ if (typeof value === 'string' && value.length > 0) {
85
+ return value;
86
+ }
87
+ }
88
+
89
+ return null;
90
+ }
91
+
92
+ export function recordClaudeSubagentStart(
93
+ activeSubagents: Map<string, string>,
94
+ emit: BridgeEmitter,
95
+ toolName: string,
96
+ toolUseId: string,
97
+ input: unknown,
98
+ ): string | null {
99
+ if (toolName !== 'Agent' && toolName !== 'Task') {
100
+ return null;
101
+ }
102
+
103
+ const agentName = extractSubagentName(input);
104
+ if (!agentName) {
105
+ return null;
106
+ }
107
+
108
+ activeSubagents.set(toolUseId, agentName);
109
+ emit(protocolMessage.subagentStart({ agentName, parentToolCallId: toolUseId }));
110
+ return agentName;
111
+ }
112
+
113
+ export function recordClaudeSubagentFinish(activeSubagents: Map<string, string>, emit: BridgeEmitter, toolUseId: string, output?: unknown): string | null {
114
+ const agentName = activeSubagents.get(toolUseId);
115
+ if (!agentName) {
116
+ return null;
117
+ }
118
+
119
+ activeSubagents.delete(toolUseId);
120
+ emit(protocolMessage.subagentFinish({ agentName, parentToolCallId: toolUseId, ...(output !== undefined ? { output } : {}) }));
121
+ return agentName;
122
+ }
@@ -0,0 +1 @@
1
+ export * from '@agent-harness-experimental/bridge/bridge-tool-policy';
@@ -0,0 +1 @@
1
+ export * from '@agent-harness-experimental/bridge/bridge-ws-server';