@agentproto/adapter-claude-sdk 0.4.1 → 0.5.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 CHANGED
@@ -50,8 +50,8 @@ arm.
50
50
  `base_url` + `auth_token` point one spawn at an Anthropic-compatible gateway
51
51
  with a per-spawn Bearer key (the ambient `ANTHROPIC_API_KEY` is for real
52
52
  Anthropic). `auth_token` becomes `ANTHROPIC_AUTH_TOKEN`, which the SDK sends as
53
- `Authorization: Bearer <token>` — accepted by Moonshot, OpenRouter, and DeepSeek.
54
- The token value is never logged.
53
+ `Authorization: Bearer <token>` — accepted by Moonshot, OpenRouter, DeepSeek,
54
+ and the local `llm-endpoint` proxy. The token value is never logged.
55
55
 
56
56
  When `base_url` is set the adapter enters **gateway mode**: it pins every model
57
57
  tier the harness might internally request — `ANTHROPIC_MODEL`,
@@ -61,39 +61,16 @@ tier the harness might internally request — `ANTHROPIC_MODEL`,
61
61
  `kimi-k2.7-code`) rejects the harness's background `claude-haiku-*` requests.
62
62
  Native Anthropic (no `base_url`) leaves tier routing untouched.
63
63
 
64
- Verified live: Moonshot `https://api.moonshot.ai/anthropic` +
65
- `model=kimi-k2.7-code`, OpenRouter `https://openrouter.ai/api`, and Requesty
66
- `https://router.requesty.ai` all return valid Anthropic Messages format under
67
- `Authorization: Bearer`.
68
-
69
- Note the base URLs carry no `/v1`: the SDK appends `/v1/messages` itself, so a
70
- `/v1` in the preset yields `…/v1/v1/messages` → 404. Verify a gateway by
71
- POSTing to `<base_url>/v1/messages` — NOT by curling the endpoint you think it
72
- serves. An earlier "verified live" note recorded OpenRouter as `…/api/v1` on
73
- the strength of a direct curl to `/api/v1/messages`, which left every
74
- openrouter-mode spawn 404ing behind the misleading gateway error "model may not
75
- exist or you may not have access to it".
76
-
77
- ### Gateway presets (modes)
78
-
79
- So you don't hand-type the base URL each spawn, four modes pre-wire the gateway
80
- endpoint (`base_url`/`auth_token`/`thinking` still work manually for anything
81
- else):
82
-
83
- | mode | pre-wires | you supply |
84
- | ----------- | --------------------------------------------------------------- | ----------------------------------- |
85
- | `default` | nothing — native Anthropic | `ANTHROPIC_API_KEY` |
86
- | `moonshot` | `ANTHROPIC_BASE_URL` + `model=kimi-k2.7-code` + `--thinking` | `auth_token` (Moonshot key) |
87
- | `openrouter`| `ANTHROPIC_BASE_URL` | `model` (slug) + `auth_token` (key) |
88
- | `requesty` | `ANTHROPIC_BASE_URL` | `model` (slug) + `auth_token` (key) |
89
- | `deepseek` | `ANTHROPIC_BASE_URL` + `model=deepseek-v4-pro` | `auth_token` (DeepSeek key) |
90
-
91
- `mode: moonshot` is a one-pick Kimi run; override `model` for another Moonshot
92
- model. `mode: openrouter` still needs a `model` (e.g. `z-ai/glm-5.2`,
93
- `deepseek/deepseek-v4-pro`, `moonshotai/kimi-k2`). `mode: deepseek` defaults to
94
- `deepseek-v4-pro`; override `model` for `deepseek-v4-flash`. The `auth_token`
95
- is the gateway key — the ambient `ANTHROPIC_API_KEY` stays for real Anthropic.
96
- DeepSeek isn't thinking-gated, so unlike `moonshot` no `--thinking` is forced.
64
+ The runtime resolver injects the correct `ANTHROPIC_BASE_URL` and credential for
65
+ registered gateway providers (Moonshot, OpenRouter, Requesty, DeepSeek,
66
+ `llm-endpoint`, etc.), so the adapter no longer hard-codes gateway URLs or modes.
67
+ You can still override manually with `base_url` + `auth_token` for a gateway that
68
+ is not yet in the catalog.
69
+
70
+ Note the Anthropic-flavored base URLs carry no `/v1`: the SDK appends
71
+ `/v1/messages` itself, so a `/v1` in the preset yields `…/v1/v1/messages` → 404.
72
+ Verify a gateway by POSTing to `<base_url>/v1/messages` — NOT by curling the
73
+ endpoint you think it serves.
97
74
 
98
75
  ### Extended thinking
99
76
 
package/claude-sdk.ACP.md CHANGED
@@ -62,6 +62,11 @@ single-model gateway (e.g. Moonshot serving only `kimi-k2.7-code`) from
62
62
  receiving a background `claude-haiku-*` request it can't serve. Native Anthropic
63
63
  (no `base_url`) leaves tier routing untouched.
64
64
 
65
+ Gateway routing is no longer hard-coded in this adapter. The runtime resolver
66
+ injects the correct `ANTHROPIC_BASE_URL` and credential for registered gateway
67
+ providers. You can still override manually with `base_url` + `auth_token` for an
68
+ unregistered gateway.
69
+
65
70
  ## Auth / secrets
66
71
 
67
72
  `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` on the spawn env (direct or via an
@@ -69,7 +74,8 @@ Anthropic-compatible gateway), or the cloud-provider toggles above. No ACP-level
69
74
  auth handshake. The `auth_token` option sets `ANTHROPIC_AUTH_TOKEN` in the child
70
75
  env (manifest `auth_token` option's `env` template) — the SDK sends it as
71
76
  `Authorization: Bearer <token>`, letting one spawn target a gateway (Moonshot,
72
- OpenRouter, DeepSeek) with a per-spawn Bearer key. The token value is never logged.
77
+ OpenRouter, DeepSeek, `llm-endpoint`) with a per-spawn Bearer key. The token
78
+ value is never logged.
73
79
 
74
80
  ## Thinking
75
81
 
@@ -18,6 +18,7 @@ var CLOUD_PROVIDER_REDIRECT_TOGGLES = [
18
18
  "CLAUDE_CODE_USE_GATEWAY"
19
19
  ];
20
20
  var DEFAULT_IDLE_TIMEOUT_MS = 9e4;
21
+ var DEFAULT_TOOL_IDLE_TIMEOUT_MS = 6e5;
21
22
  function mapAcpMcpServers(servers) {
22
23
  const out = {};
23
24
  for (const server of servers ?? []) {
@@ -56,8 +57,7 @@ function buildQueryOptions(args) {
56
57
  const env = { ...baseEnv };
57
58
  if (config.baseUrl) {
58
59
  env.ANTHROPIC_BASE_URL = config.baseUrl;
59
- const gatewayKeyEnv = baseEnv.CLAUDE_SDK_GATEWAY_KEY_ENV;
60
- const bearer = config.authToken ?? baseEnv.ANTHROPIC_AUTH_TOKEN ?? (gatewayKeyEnv ? baseEnv[gatewayKeyEnv] : void 0);
60
+ const bearer = config.authToken ?? baseEnv.ANTHROPIC_AUTH_TOKEN;
61
61
  delete env.ANTHROPIC_API_KEY;
62
62
  if (bearer) env.ANTHROPIC_AUTH_TOKEN = bearer;
63
63
  else delete env.ANTHROPIC_AUTH_TOKEN;
@@ -368,16 +368,29 @@ var ClaudeSdkAcpAgent = class {
368
368
  * never fires. */
369
369
  async #drive(session, text, options, ac) {
370
370
  const idleMs = this.#config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
371
+ const toolIdleMs = this.#config.toolIdleTimeoutMs ?? DEFAULT_TOOL_IDLE_TIMEOUT_MS;
371
372
  const iterator = this.#query({ prompt: text, options })[Symbol.asyncIterator]();
372
373
  let sawPartial = false;
374
+ let pendingTool = false;
373
375
  try {
374
376
  while (!ac.signal.aborted) {
375
- const next = await this.#nextMessage(iterator, idleMs, ac);
377
+ const nextIdleMs = pendingTool ? toolIdleMs : idleMs;
378
+ const next = await this.#nextMessage(iterator, nextIdleMs, ac);
376
379
  if (next.done) break;
377
380
  const msg = next.value;
378
381
  const sdkId = systemInitSessionId(msg);
379
382
  if (sdkId) session.sdkSessionId = sdkId;
380
383
  if (msg.type === "stream_event") sawPartial = true;
384
+ if (msg.type === "assistant") {
385
+ for (const block of msg.message.content) {
386
+ if (block.type === "tool_use") pendingTool = true;
387
+ }
388
+ } else if (msg.type === "user") {
389
+ const content = msg.message.content;
390
+ if (Array.isArray(content) && content.some((block) => block.type === "tool_result")) {
391
+ pendingTool = false;
392
+ }
393
+ }
381
394
  for (const update of sdkMessageToUpdates(msg, {
382
395
  suppressAssistantText: sawPartial
383
396
  })) {
@@ -426,5 +439,5 @@ function runAcpOverStdio(config = {}) {
426
439
  }
427
440
 
428
441
  export { ClaudeSdkAcpAgent, DEFAULT_MODEL, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates };
429
- //# sourceMappingURL=chunk-DW2G2NIH.mjs.map
430
- //# sourceMappingURL=chunk-DW2G2NIH.mjs.map
442
+ //# sourceMappingURL=chunk-2LNYIR6L.mjs.map
443
+ //# sourceMappingURL=chunk-2LNYIR6L.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/options.ts","../src/message-map.ts","../src/acp-host.ts","../src/run.ts"],"names":["query","sdkQuery"],"mappings":"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","file":"chunk-2LNYIR6L.mjs","sourcesContent":["/**\n * Build the Claude Agent SDK `Options` for a turn, and map ACP-side inputs\n * (session id, injected MCP servers) onto it. Isolated from the ACP host so\n * the option-shaping is unit-testable without a live SDK.\n */\n\nimport type { McpServer } from \"@agentclientprotocol/sdk\"\nimport type {\n McpServerConfig,\n Options,\n PermissionMode,\n} from \"@anthropic-ai/claude-agent-sdk\"\n\n/** A cheap Claude by default — this is a budget first-party arm. */\nexport const DEFAULT_MODEL = \"claude-haiku-4-5-20251001\"\n\n/**\n * Boolean provider-select toggles the SDK's own `claude` binary groups\n * together with `CLAUDE_CODE_USE_BEDROCK`/`CLAUDE_CODE_USE_VERTEX` (same\n * array, `ac4f1e4` build of `@anthropic-ai/claude-agent-sdk`) to pick a\n * cloud-provider endpoint ahead of `ANTHROPIC_BASE_URL`. Leaking any of these\n * from a Claude-Code parent shell wedges a gateway turn against the wrong\n * provider. Deliberately excludes the non-boolean config members of that same\n * array (`ANTHROPIC_VERTEX_PROJECT_ID`, `ANTHROPIC_AWS_WORKSPACE_ID`,\n * `ANTHROPIC_FOUNDRY_RESOURCE`, `CLOUD_ML_REGION`) and the provider\n * credential/skip-auth vars — both are inert once the toggle that gates them\n * is gone.\n */\nconst CLOUD_PROVIDER_REDIRECT_TOGGLES = [\n \"CLAUDE_CODE_USE_BEDROCK\",\n \"CLAUDE_CODE_USE_VERTEX\",\n \"CLAUDE_CODE_USE_FOUNDRY\",\n \"CLAUDE_CODE_USE_ANTHROPIC_AWS\",\n \"CLAUDE_CODE_USE_MANTLE\",\n \"CLAUDE_CODE_USE_GATEWAY\",\n] as const\n\n/**\n * Default idle watchdog for a turn (ms). If `query()` yields no message for\n * this long, {@link ClaudeSdkConfig.idleTimeoutMs} aborts the turn instead of\n * hanging forever. Ninety seconds: the watchdog is IDLE-based (reset on every\n * SDK message), and a healthy streaming turn — native or gateway — emits\n * messages continuously with sub-second gaps, so a 90s silence means the SDK\n * child is genuinely wedged. The prior 5-minute ceiling was needlessly slow to\n * surface a wedged child; 90s stays well clear of any real inter-message gap\n * while turning a wedged turn around quickly. `0` disables. See\n * {@link ClaudeSdkConfig.idleTimeoutMs}.\n */\nexport const DEFAULT_IDLE_TIMEOUT_MS = 90_000\n\n/**\n * Default watchdog while one or more tool calls are pending (ms). Tool\n * execution is legitimately silent between the SDK's `tool_use` and the\n * matching `tool_result`, so the generation watchdog would otherwise abort a\n * healthy turn. This budget is used only while at least one tool is in flight;\n * once the last tool_result arrives the adapter falls back to\n * {@link DEFAULT_IDLE_TIMEOUT_MS} for the model's next generation. `0`\n * disables the tool-pending watchdog.\n */\nexport const DEFAULT_TOOL_IDLE_TIMEOUT_MS = 600_000\n\n/** Static config for the adapter, parsed from CLI args / env at boot. */\nexport interface ClaudeSdkConfig {\n /** SDK `options.model`. Defaults to {@link DEFAULT_MODEL}. */\n model?: string\n /** Sets `ANTHROPIC_BASE_URL` in the child env — points the harness at real\n * Anthropic, Bedrock/Vertex/Azure, or an Anthropic-compatible gateway. */\n baseUrl?: string\n /** Sets `ANTHROPIC_AUTH_TOKEN` in the child env — the SDK sends it as\n * `Authorization: Bearer`. Pair with {@link baseUrl} to target a gateway\n * (Moonshot / OpenRouter) with a per-spawn key instead of the ambient\n * `ANTHROPIC_API_KEY`. Never logged. */\n authToken?: string\n /**\n * Enable extended thinking (SDK `options.thinking = { type: \"enabled\" }`).\n * Required by some gateway models (e.g. Moonshot's `kimi-k2.7-code`, which\n * rejects a request without it). Off by default — native Claude models pick\n * their own thinking behaviour.\n */\n thinking?: boolean\n /** Working directory for the session (tools are confined here). */\n cwd?: string\n /**\n * Idle watchdog for a turn, in milliseconds. If the SDK's `query()` iterator\n * produces no message for this long, the turn is aborted with a surfaced\n * error instead of hanging forever. This is a defensive guard against a\n * wedged SDK child — one that stops yielding messages and never delivers the\n * SDK's terminal `result`, nor closes — which would otherwise leave the turn\n * stuck `busy` with zero output (the worst failure mode). The observed cause\n * is environmental, NOT the model or its response shape: a conflicting host\n * env leaking into the spawned SDK subprocess (e.g. a stray\n * `ANTHROPIC_BASE_URL`, or a `CLAUDE_CODE_USE_BEDROCK`/`_VERTEX` auth toggle\n * inherited from a Claude Code shell) can send the child down a path that\n * never completes. Moonshot's own Anthropic-compatible responses (empty\n * `thinking.signature`, a non-`msg_` `chatcmpl-…` id, a `message_delta`-\n * terminated stream) are consumed and finalised correctly by the SDK —\n * verified live end-to-end under a clean env — so the guard is a safety net\n * for a wedged child, not a gateway/response defect. Idle-based (reset on\n * every message), so a legitimately long generation or tool run is\n * unaffected. `0` disables the watchdog. Defaults to\n * {@link DEFAULT_IDLE_TIMEOUT_MS}. Overridable at the CLI via\n * `CLAUDE_SDK_IDLE_TIMEOUT_MS`.\n */\n idleTimeoutMs?: number\n /**\n * Extended idle watchdog used while one or more tool calls are pending. Tool\n * execution is silent between the SDK's `tool_use` and the matching\n * `tool_result`, so the normal generation watchdog would abort a healthy\n * turn. This budget is used only while at least one tool is in flight; once\n * the last tool_result arrives the adapter falls back to\n * {@link DEFAULT_IDLE_TIMEOUT_MS}. `0` disables. Defaults to\n * {@link DEFAULT_TOOL_IDLE_TIMEOUT_MS}. Overridable via\n * `CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS`.\n */\n toolIdleTimeoutMs?: number\n /**\n * How the harness handles tool-permission prompts. Defaults to\n * `bypassPermissions` (with the required danger flag) so the arm can act\n * autonomously inside the daemon's sandbox, mirroring how the claude-code\n * arm is spawned. Override via `CLAUDE_SDK_PERMISSION_MODE`.\n */\n permissionMode?: PermissionMode\n}\n\n/**\n * Map ACP `session/new` MCP server declarations to the SDK's\n * `mcpServers` record (keyed by name). Lets the daemon inject a scoped toolset\n * into the harness exactly like any other arm. Env pairs / headers arrive as\n * `{ name, value }` lists on the wire; flatten them to the record shape the\n * SDK expects.\n */\nexport function mapAcpMcpServers(\n servers: McpServer[] | undefined,\n): Record<string, McpServerConfig> {\n const out: Record<string, McpServerConfig> = {}\n for (const server of servers ?? []) {\n if (\"type\" in server && server.type === \"http\") {\n out[server.name] = {\n type: \"http\",\n url: server.url,\n headers: flattenPairs(server.headers),\n }\n } else if (\"type\" in server && server.type === \"sse\") {\n out[server.name] = {\n type: \"sse\",\n url: server.url,\n headers: flattenPairs(server.headers),\n }\n } else {\n // Stdio is the default (untagged) ACP MCP variant.\n out[server.name] = {\n type: \"stdio\",\n command: server.command,\n args: server.args,\n env: flattenPairs(server.env),\n }\n }\n }\n return out\n}\n\n/** Flatten an ACP `{ name, value }[]` list to a `Record<string, string>`. */\nfunction flattenPairs(\n pairs: Array<{ name: string; value: string }> | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const pair of pairs ?? []) out[pair.name] = pair.value\n return out\n}\n\n/**\n * Assemble the SDK `Options` for a single `query()` call.\n *\n * - `sessionId` pins a stable UUID on the FIRST turn so the ACP session id and\n * the SDK session id match (enabling resume).\n * - `resume` continues that same session on later turns.\n * - Native mode (no `base_url`): the ambient env — `ANTHROPIC_API_KEY` or the\n * Claude Code subscription/OAuth login — is passed through unchanged; an\n * explicit `auth_token` still wins as `ANTHROPIC_AUTH_TOKEN`.\n * - Gateway mode (`base_url` set → a non-Anthropic host): the ambient\n * `ANTHROPIC_API_KEY` is SCRUBBED (it must never be sent to a third-party\n * gateway — that both 401s and leaks the real key). The gateway bearer is\n * resolved from the explicit `auth_token` or `ANTHROPIC_AUTH_TOKEN` in the\n * spawn env; if neither resolves, no credential is presented (fail clean,\n * never leak). Every internal model tier is also pinned to the resolved\n * model so a single-model gateway never receives a tier it can't serve\n * (e.g. Moonshot rejecting `claude-haiku-*`). The\n * {@link CLOUD_PROVIDER_REDIRECT_TOGGLES} leaked from a Claude-Code parent\n * shell are also scrubbed so the gateway `base_url` isn't overridden.\n */\nexport function buildQueryOptions(args: {\n config: ClaudeSdkConfig\n abortController: AbortController\n /** Set on the first turn to fix the session UUID. */\n sessionId?: string\n /** Set on resuming turns. */\n resume?: string\n mcpServers?: McpServer[]\n env?: Record<string, string | undefined>\n}): Options {\n const { config, abortController, sessionId, resume, mcpServers } = args\n const model = config.model ?? DEFAULT_MODEL\n const baseEnv = args.env ?? process.env\n const env: Record<string, string | undefined> = { ...baseEnv }\n if (config.baseUrl) {\n // Gateway mode (non-Anthropic host). Auth hygiene: an ambient\n // ANTHROPIC_API_KEY must NEVER reach a third-party gateway (it 401s AND\n // leaks the real Anthropic key). Resolve the gateway bearer from the\n // explicit auth_token or ANTHROPIC_AUTH_TOKEN in the spawn env, then scrub\n // the Anthropic key so exactly the gateway's own credential is presented;\n // if neither resolves, present no credential (fail clean, never leak).\n env.ANTHROPIC_BASE_URL = config.baseUrl\n const bearer = config.authToken ?? baseEnv.ANTHROPIC_AUTH_TOKEN\n delete env.ANTHROPIC_API_KEY\n if (bearer) env.ANTHROPIC_AUTH_TOKEN = bearer\n else delete env.ANTHROPIC_AUTH_TOKEN\n // A Claude-Code parent shell may leak CLAUDE_CODE_USE_BEDROCK / _VERTEX\n // (etc.) into this child's env; the SDK honours those ahead of\n // ANTHROPIC_BASE_URL, silently sending the turn to the wrong provider\n // instead of the gateway (the confirmed cause of turns wedging forever).\n // Scrub so exactly the gateway base_url + bearer are presented.\n for (const key of CLOUD_PROVIDER_REDIRECT_TOGGLES) delete env[key]\n // Pin every tier the harness might request (opus/sonnet/haiku defaults + the\n // small/fast background model) to the one model the gateway serves.\n env.ANTHROPIC_MODEL = model\n env.ANTHROPIC_DEFAULT_OPUS_MODEL = model\n env.ANTHROPIC_DEFAULT_SONNET_MODEL = model\n env.ANTHROPIC_DEFAULT_HAIKU_MODEL = model\n env.ANTHROPIC_SMALL_FAST_MODEL = model\n } else if (config.authToken) {\n // Native Anthropic: an explicit bearer (e.g. a subscription/OAuth token)\n // still wins; otherwise the SDK uses the ambient ANTHROPIC_API_KEY or the\n // Claude Code login (subscription), left untouched.\n env.ANTHROPIC_AUTH_TOKEN = config.authToken\n }\n\n const options: Options = {\n model,\n abortController,\n permissionMode: config.permissionMode ?? \"bypassPermissions\",\n // Required companion to bypassPermissions — this arm runs unattended.\n allowDangerouslySkipPermissions: true,\n // Hermetic embed: don't silently pull in filesystem settings / CLAUDE.md;\n // the daemon owns the configuration surface.\n settingSources: [],\n // Stream partial (`stream_event`) messages so a long thinking / generation\n // stretch is observable live instead of surfacing only at message\n // boundaries. Two things depend on it: (1) the daemon's output ring — the\n // mapped text/thinking deltas keep `lastOutputAt` advancing during a long\n // busy turn instead of freezing until the next tool boundary; and (2) the\n // turn watchdog (acp-host `#nextMessage`), which resets on every SDK\n // message — without partials, a >90s thinking block (kimi-k2.7-code with\n // `--thinking`) yields NO message and the idle watchdog wrongly aborts a\n // healthy turn. See message-map's `streamEventUpdates`.\n includePartialMessages: true,\n env,\n ...(config.cwd ? { cwd: config.cwd } : {}),\n ...(sessionId ? { sessionId } : {}),\n ...(resume ? { resume } : {}),\n }\n // Extended thinking, opt-in. Required by thinking-gated gateway models such\n // as kimi-k2.7-code (rejects a request with no `thinking`). The property's\n // type contextualises the literal, so no cast is needed.\n if (config.thinking) options.thinking = { type: \"enabled\" }\n const mapped = mapAcpMcpServers(mcpServers)\n if (Object.keys(mapped).length > 0) options.mcpServers = mapped\n return options\n}\n","/**\n * Pure mapping from the Claude Agent SDK's message stream (`SDKMessage`, the\n * values `query()` yields) to AIP-44 ACP `session/update` payloads. Kept\n * side-effect free and dependency-light (types only) so it is straightforward\n * to unit-test; the ACP host (acp-host.ts) owns the wire/IO and forwards\n * whatever this returns.\n *\n * I/O stays 100% Anthropic-native: we read the SDK's real message shapes and\n * translate them to ACP updates — no format translation of the model I/O.\n *\n * The SDK emits a typed union on `query()`. We surface:\n * - `stream_event` text delta → ACP `agent_message_chunk` (streamed prose)\n * - `stream_event` thinking delta → ACP `agent_thought_chunk` (streamed reasoning)\n * - `assistant` text blocks → ACP `agent_message_chunk` (assistant prose)\n * - `assistant` tool_use → ACP `tool_call` (a tool started)\n * - `user` tool_result → ACP `tool_call_update` (that tool finished/failed)\n * - `result` → ACP `usage_update` (tokens + cost)\n * The `system`/`init` message carries the SDK `session_id`, handled separately\n * by the host (see {@link systemInitSessionId}).\n *\n * With `includePartialMessages` on (see options.ts), assistant prose arrives\n * TWICE: first as streamed `stream_event` text deltas, then again in the\n * terminal complete `assistant` message. The host tracks whether it saw any\n * partial and asks {@link sdkMessageToUpdates} to suppress the complete\n * message's text so the ring isn't double-fed (see `suppressAssistantText`).\n * `thinking` is only ever surfaced via the streamed deltas — the complete\n * `assistant` message's thinking block is intentionally not mapped.\n */\n\nimport type {\n SDKAssistantMessage,\n SDKMessage,\n SDKPartialAssistantMessage,\n SDKResultMessage,\n SDKSystemMessage,\n SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\"\nimport type { SessionUpdate, ToolKind, UsageUpdate } from \"@agentclientprotocol/sdk\"\n\n/**\n * A `usage_update` session update. ACP's `UsageUpdate` models `size`/`used`/\n * `cost`; we widen it with the optional `tokensIn`/`tokensOut` the agentproto\n * runtime also reads (see packages/acp translateSessionUpdate + runtime\n * sessions.ts), so a session whose adapter reports tokens can be priced even\n * without a `cost`. Assignable to `SessionUpdate` structurally (extra fields\n * are allowed), so no cast is needed.\n */\nexport type UsageSessionUpdate = UsageUpdate & {\n sessionUpdate: \"usage_update\"\n tokensIn?: number\n tokensOut?: number\n}\n\n/** Map a Claude Code built-in tool name to the ACP {@link ToolKind} that\n * drives client icon/UI treatment. Unknown/MCP tools fall back to \"other\". */\nexport function toolKindForClaudeTool(name: string): ToolKind {\n switch (name) {\n case \"Read\":\n case \"NotebookRead\":\n return \"read\"\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return \"edit\"\n case \"Bash\":\n case \"BashOutput\":\n case \"KillBash\":\n return \"execute\"\n case \"Grep\":\n case \"Glob\":\n return \"search\"\n case \"WebFetch\":\n case \"WebSearch\":\n return \"fetch\"\n case \"Task\":\n return \"think\"\n default:\n return \"other\"\n }\n}\n\n/** Read a string-valued property from an unknown value without an unsafe\n * cast — narrows via `in` and a `typeof` guard. */\nfunction stringField(input: unknown, key: string): string | undefined {\n if (input && typeof input === \"object\" && key in input) {\n const value: unknown = Reflect.get(input, key)\n if (typeof value === \"string\") return value\n }\n return undefined\n}\n\n/** A short, human-readable title for a tool call, e.g. `Bash: ls -la` or\n * `Read: src/index.ts`. Falls back to the bare tool name. */\nexport function toolCallTitle(name: string, input: unknown): string {\n const hint =\n stringField(input, \"command\") ??\n stringField(input, \"file_path\") ??\n stringField(input, \"path\") ??\n stringField(input, \"pattern\") ??\n stringField(input, \"url\")\n return hint ? `${name}: ${hint}` : name\n}\n\n/** Translate one complete `assistant` message into ACP updates: one per text\n * block (agent_message_chunk) and one per tool_use block (tool_call).\n *\n * `suppressText` drops the text blocks — set by the host once it has seen\n * `stream_event` deltas this turn, since the prose already streamed and\n * re-emitting the complete copy would double-feed the ring. tool_use blocks\n * are always emitted (they carry the full input the daemon needs and never\n * arrive as a usable partial). */\nexport function assistantMessageUpdates(\n msg: SDKAssistantMessage,\n suppressText = false,\n): SessionUpdate[] {\n const updates: SessionUpdate[] = []\n for (const block of msg.message.content) {\n if (block.type === \"text\") {\n if (suppressText || !block.text) continue\n updates.push({\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text: block.text },\n })\n } else if (block.type === \"tool_use\") {\n updates.push({\n sessionUpdate: \"tool_call\",\n toolCallId: block.id,\n title: toolCallTitle(block.name, block.input),\n kind: toolKindForClaudeTool(block.name),\n status: \"in_progress\",\n rawInput: block.input,\n })\n }\n }\n return updates\n}\n\n/**\n * Translate a `stream_event` (partial-assistant) message into ACP deltas.\n * Only `content_block_delta` text / thinking deltas carry user-visible content:\n * - `text_delta` → `agent_message_chunk` (streamed assistant prose)\n * - `thinking_delta` → `agent_thought_chunk` (streamed extended-thinking)\n * Every other frame (block start/stop, `input_json_delta`, `signature_delta`,\n * message-level `message_start`/`message_delta`/`message_stop`) produces\n * nothing here — but still counts as an SDK message to the host's turn\n * watchdog, which is exactly why partial streaming keeps a long thinking turn\n * from being mistaken for a stall.\n *\n * Read structurally (via typed field guards) rather than importing the beta\n * `RawContentBlockDelta` union — this file stays dependency-light per its\n * header, and the two delta shapes we care about are tiny and stable\n * (`{ type: \"text_delta\", text }` / `{ type: \"thinking_delta\", thinking }`).\n */\nexport function streamEventUpdates(\n msg: SDKPartialAssistantMessage,\n): SessionUpdate[] {\n const event: unknown = msg.event\n if (stringField(event, \"type\") !== \"content_block_delta\") return []\n const delta =\n event && typeof event === \"object\" ? Reflect.get(event, \"delta\") : undefined\n switch (stringField(delta, \"type\")) {\n case \"text_delta\": {\n const text = stringField(delta, \"text\")\n return text\n ? [\n {\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text },\n },\n ]\n : []\n }\n case \"thinking_delta\": {\n const thinking = stringField(delta, \"thinking\")\n return thinking\n ? [\n {\n sessionUpdate: \"agent_thought_chunk\",\n content: { type: \"text\", text: thinking },\n },\n ]\n : []\n }\n default:\n return []\n }\n}\n\n/** Translate a `user` message's tool_result blocks into ACP\n * `tool_call_update`s. Non-tool user echoes (a plain string, or the initial\n * prompt) produce nothing. */\nexport function userMessageUpdates(msg: SDKUserMessage): SessionUpdate[] {\n const content = msg.message.content\n if (typeof content === \"string\") return []\n const updates: SessionUpdate[] = []\n for (const block of content) {\n if (block.type !== \"tool_result\") continue\n updates.push({\n sessionUpdate: \"tool_call_update\",\n toolCallId: block.tool_use_id,\n status: block.is_error ? \"failed\" : \"completed\",\n rawOutput: block.content,\n })\n }\n return updates\n}\n\n/** The largest reported context-window size across the turn's models, or 0. */\nfunction contextWindowOf(msg: SDKResultMessage): number {\n let size = 0\n for (const usage of Object.values(msg.modelUsage)) {\n if (usage.contextWindow > size) size = usage.contextWindow\n }\n return size\n}\n\n/** Translate a `result` message into an ACP `usage_update`. Native Anthropic\n * usage → the shape the runtime already consumes: `size` (context window),\n * `used` (tokens in context), `cost` (from `total_cost_usd`), and the\n * `tokensIn`/`tokensOut` extension. */\nexport function resultUsageUpdate(msg: SDKResultMessage): UsageSessionUpdate {\n const u = msg.usage\n const cacheRead = u.cache_read_input_tokens ?? 0\n const cacheCreate = u.cache_creation_input_tokens ?? 0\n const tokensIn = u.input_tokens + cacheRead + cacheCreate\n const tokensOut = u.output_tokens\n return {\n sessionUpdate: \"usage_update\",\n size: contextWindowOf(msg),\n used: tokensIn + tokensOut,\n cost: { amount: msg.total_cost_usd, currency: \"USD\" },\n tokensIn,\n tokensOut,\n }\n}\n\n/**\n * Dispatch one SDK message to the ACP updates it produces (possibly none).\n * `system`/`init` is intentionally not mapped here — its `session_id` is read\n * by the host via {@link systemInitSessionId}, not surfaced as an update.\n *\n * `suppressAssistantText` is forwarded to {@link assistantMessageUpdates}: the\n * host sets it once a `stream_event` has streamed this turn's prose, so the\n * terminal complete `assistant` message doesn't re-emit the same text.\n */\nexport function sdkMessageToUpdates(\n msg: SDKMessage,\n opts: { suppressAssistantText?: boolean } = {},\n): SessionUpdate[] {\n switch (msg.type) {\n case \"stream_event\":\n return streamEventUpdates(msg)\n case \"assistant\":\n return assistantMessageUpdates(msg, opts.suppressAssistantText ?? false)\n case \"user\":\n return userMessageUpdates(msg)\n case \"result\":\n return [resultUsageUpdate(msg)]\n default:\n return []\n }\n}\n\n/** Extract the SDK `session_id` from the `system`/`init` message, else null. */\nexport function systemInitSessionId(msg: SDKMessage): string | null {\n if (msg.type === \"system\" && isInit(msg)) return msg.session_id\n return null\n}\n\n/** Narrow a `system` message to its `init` subtype (which carries the\n * authoritative `session_id` and model). */\nfunction isInit(msg: SDKMessage & { type: \"system\" }): msg is SDKSystemMessage {\n return msg.subtype === \"init\"\n}\n","/**\n * The agent side of AIP-44 ACP, backed by the Claude Agent SDK's headless\n * `query()`.\n *\n * Implements the `@agentclientprotocol/sdk` `Agent` interface: on\n * `session/prompt` it drives `query({ prompt, options })` and relays the SDK's\n * native message stream as ACP `session/update`s (assistant text, tool calls,\n * usage). I/O stays 100% Anthropic-native — no format translation of the model\n * I/O — so the daemon spawns this like any other ACP arm.\n *\n * Session identity: ACP requires a session id at `session/new`, before any\n * `query()` has run. We generate a UUID there and PIN it via the SDK's\n * `options.sessionId` on the first turn, so our ACP session id and the SDK's\n * `session_id` are the same value — which then feeds `options.resume` on later\n * turns (agentproto resume).\n */\n\nimport type {\n AgentSideConnection,\n Agent as AcpAgent,\n AuthenticateRequest,\n CancelNotification,\n InitializeRequest,\n InitializeResponse,\n McpServer,\n NewSessionRequest,\n NewSessionResponse,\n PromptRequest,\n PromptResponse,\n SetSessionConfigOptionRequest,\n SetSessionConfigOptionResponse,\n SetSessionModeRequest,\n} from \"@agentclientprotocol/sdk\"\nimport { PROTOCOL_VERSION } from \"@agentclientprotocol/sdk\"\nimport {\n query as sdkQuery,\n type Options,\n type SDKMessage,\n type SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\"\nimport { sdkMessageToUpdates, systemInitSessionId } from \"./message-map.js\"\nimport {\n buildQueryOptions,\n DEFAULT_IDLE_TIMEOUT_MS,\n DEFAULT_TOOL_IDLE_TIMEOUT_MS,\n type ClaudeSdkConfig,\n} from \"./options.js\"\n\n/** The single SDK entry point we depend on — the headless async generator.\n * Typed structurally and injectable so tests can drive the host with a faked\n * message stream (no live Anthropic key required). */\nexport type QueryFn = (params: {\n prompt: string | AsyncIterable<SDKUserMessage>\n options?: Options\n}) => AsyncIterable<SDKMessage>\n\ninterface SessionState {\n /** The pinned ACP/SDK session id. */\n readonly id: string\n /** MCP servers injected by the daemon at `session/new`. */\n readonly mcpServers: McpServer[]\n /** null until the first turn has pinned the SDK session. */\n started: boolean\n /** The SDK's own session id, adopted from the `init` message. */\n sdkSessionId: string | null\n /** In-flight turn, for cancellation. */\n prompt: AbortController | null\n}\n\n/** A message from an unknown thrown value, without an unsafe cast. */\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\n/**\n * Thrown by the {@link ClaudeSdkAcpAgent}'s turn watchdog when `query()` stops\n * yielding messages: the SDK child wedged and never delivered the terminal\n * `result`, so the async iterator would otherwise never terminate. A defensive\n * safety net for an environmentally wedged child (e.g. a conflicting host env\n * leaked into the SDK subprocess), not a response-shape problem — a healthy\n * turn always reaches `result`. Distinct from a user cancel so the host\n * surfaces it as an error rather than silently reporting the turn as cancelled.\n */\nexport class TurnStalledError extends Error {\n constructor(public readonly idleMs: number) {\n super(\n `claude-sdk: query() produced no message for ${idleMs}ms — the model ` +\n `stream stalled and never delivered a terminal result. Aborting the ` +\n `turn to avoid a silent, zero-output hang. If this was a slow but ` +\n `healthy turn, raise CLAUDE_SDK_IDLE_TIMEOUT_MS.`,\n )\n this.name = \"TurnStalledError\"\n }\n}\n\n/** Pull the user's text out of an ACP prompt (its `text` content blocks). */\nexport function promptText(params: PromptRequest): string {\n return params.prompt\n .filter((b) => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\")\n .trim()\n}\n\nexport class ClaudeSdkAcpAgent implements AcpAgent {\n readonly #conn: AgentSideConnection\n readonly #config: ClaudeSdkConfig\n readonly #query: QueryFn\n readonly #sessions = new Map<string, SessionState>()\n\n constructor(\n conn: AgentSideConnection,\n config: ClaudeSdkConfig = {},\n query: QueryFn = sdkQuery,\n ) {\n this.#conn = conn\n this.#config = config\n this.#query = query\n }\n\n async initialize(_params: InitializeRequest): Promise<InitializeResponse> {\n return {\n protocolVersion: PROTOCOL_VERSION,\n agentCapabilities: {\n // Turns resume via the SDK's session store (options.resume), keyed by\n // the pinned session id — but there is no ACP `session/load` replay\n // surface, so we advertise loadSession: false.\n loadSession: false,\n },\n }\n }\n\n async authenticate(\n _params: AuthenticateRequest,\n ): Promise<Record<string, never>> {\n // Auth (ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, or Bedrock/Vertex/Foundry\n // env) is read from the spawn env by the SDK — no ACP-level handshake.\n return {}\n }\n\n async newSession(params: NewSessionRequest): Promise<NewSessionResponse> {\n const id = crypto.randomUUID()\n this.#sessions.set(id, {\n id,\n mcpServers: params.mcpServers ?? [],\n started: false,\n sdkSessionId: null,\n prompt: null,\n })\n return { sessionId: id }\n }\n\n async prompt(params: PromptRequest): Promise<PromptResponse> {\n const session = this.#sessions.get(params.sessionId)\n if (!session) throw new Error(`unknown session ${params.sessionId}`)\n\n // Cancel any in-flight turn for this session before starting a new one.\n session.prompt?.abort()\n const ac = new AbortController()\n session.prompt = ac\n\n const text = promptText(params)\n try {\n const options = buildQueryOptions({\n config: this.#config,\n abortController: ac,\n // First turn pins the id; later turns resume the SDK session.\n ...(session.started\n ? { resume: session.sdkSessionId ?? session.id }\n : { sessionId: session.id }),\n mcpServers: session.mcpServers,\n })\n session.started = true\n\n await this.#drive(session, text, options, ac)\n } catch (err) {\n // A watchdog stall aborts `ac` to tear down the SDK subprocess, so check\n // the stall FIRST — otherwise it would masquerade as a user cancel and be\n // silently swallowed, which is exactly the zero-output failure we fix.\n if (ac.signal.aborted && !(err instanceof TurnStalledError)) {\n session.prompt = null\n return { stopReason: \"cancelled\" }\n }\n // Surface the failure as a message chunk, then end the turn — better UX\n // than a bare JSON-RPC error the host may swallow.\n await this.#conn.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: {\n type: \"text\",\n text: `\\n[claude-sdk error] ${errorMessage(err)}\\n`,\n },\n },\n })\n session.prompt = null\n return { stopReason: \"refusal\" }\n }\n\n const cancelled = ac.signal.aborted\n session.prompt = null\n return { stopReason: cancelled ? \"cancelled\" : \"end_turn\" }\n }\n\n async cancel(params: CancelNotification): Promise<void> {\n this.#sessions.get(params.sessionId)?.prompt?.abort()\n }\n\n /**\n * The daemon applies operator options (model, base_url) at spawn — via the\n * manifest's `bin_args_template` / `env` — then also calls this ACP config\n * hook (its default \"config apply\" path). Everything is already in effect,\n * so this reports our (empty) runtime-configurable set. Without it the spawn\n * fails with \"Method not found: session/set_config_option\".\n */\n async setSessionConfigOption(\n _params: SetSessionConfigOptionRequest,\n ): Promise<SetSessionConfigOptionResponse> {\n return { configOptions: [] }\n }\n\n /** No agent-specific modes; accept and ignore so a host that sets one\n * doesn't error. */\n async setSessionMode(\n _params: SetSessionModeRequest,\n ): Promise<Record<string, never>> {\n return {}\n }\n\n /** Drive one `query()` turn: adopt the SDK session id from `init`, then map\n * each SDK message to ACP updates and relay them.\n *\n * Iteration is driven manually (rather than `for await`) so an idle watchdog\n * can bound the wait for each next message. If the SDK child wedges mid-turn\n * — stops yielding messages without delivering the terminal `result` and\n * without closing (e.g. a conflicting host env leaked into the subprocess) —\n * the watchdog aborts the turn with a {@link TurnStalledError} instead of\n * awaiting forever with zero output. A defensive safety net; a well-behaved\n * turn (Moonshot included, under a clean env) reaches `result` and this\n * never fires. */\n async #drive(\n session: SessionState,\n text: string,\n options: Options,\n ac: AbortController,\n ): Promise<void> {\n const idleMs = this.#config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS\n const toolIdleMs = this.#config.toolIdleTimeoutMs ?? DEFAULT_TOOL_IDLE_TIMEOUT_MS\n const iterator = this.#query({ prompt: text, options })[\n Symbol.asyncIterator\n ]()\n // Once a `stream_event` has streamed this turn's prose, the terminal\n // complete `assistant` message repeats it — suppress its text so the ring\n // isn't fed the same prose twice (see message-map's suppressAssistantText).\n let sawPartial = false\n // Tool execution is silent between the SDK's `tool_use` and the matching\n // `tool_result`. While any tool is pending, use the longer toolIdleMs\n // watchdog instead of the generation watchdog so healthy tool runs are not\n // aborted after 90s.\n let pendingTool = false\n try {\n while (!ac.signal.aborted) {\n const nextIdleMs = pendingTool ? toolIdleMs : idleMs\n const next = await this.#nextMessage(iterator, nextIdleMs, ac)\n if (next.done) break\n const msg = next.value\n const sdkId = systemInitSessionId(msg)\n if (sdkId) session.sdkSessionId = sdkId\n if (msg.type === \"stream_event\") sawPartial = true\n\n if (msg.type === \"assistant\") {\n for (const block of msg.message.content) {\n if (block.type === \"tool_use\") pendingTool = true\n }\n } else if (msg.type === \"user\") {\n const content = msg.message.content\n if (\n Array.isArray(content) &&\n content.some((block) => block.type === \"tool_result\")\n ) {\n pendingTool = false\n }\n }\n\n for (const update of sdkMessageToUpdates(msg, {\n suppressAssistantText: sawPartial,\n })) {\n await this.#conn.sessionUpdate({ sessionId: session.id, update })\n }\n }\n } finally {\n // Best-effort generator close on any exit (stall, cancel, error). Do NOT\n // await it: on a stall the generator is suspended mid-`await` and its\n // `.return()` never settles, so awaiting here would re-introduce the very\n // hang we guard against. The turn's AbortController — already aborted on\n // a stall or a cancel — is what actually tears the SDK subprocess down.\n void Promise.resolve(iterator.return?.(undefined)).catch(() => undefined)\n }\n }\n\n /**\n * Await the next SDK message, but no longer than `idleMs`. On timeout the\n * turn is treated as stalled: abort the shared controller (tearing down the\n * SDK subprocess) and reject with {@link TurnStalledError}. `idleMs <= 0`\n * disables the watchdog and awaits indefinitely (legacy behaviour).\n */\n async #nextMessage(\n iterator: AsyncIterator<SDKMessage>,\n idleMs: number,\n ac: AbortController,\n ): Promise<IteratorResult<SDKMessage>> {\n const next = iterator.next()\n if (idleMs <= 0) return next\n // If the watchdog wins the race, `next` settles later with nobody awaiting\n // it; pre-attach a no-op handler so a late rejection isn't \"unhandled\".\n void next.catch(() => undefined)\n let timer: ReturnType<typeof setTimeout> | undefined\n const watchdog = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n ac.abort()\n reject(new TurnStalledError(idleMs))\n }, idleMs)\n // Don't let the watchdog alone keep the event loop alive.\n timer.unref()\n })\n try {\n return await Promise.race([next, watchdog])\n } finally {\n if (timer) clearTimeout(timer)\n }\n }\n}\n","/**\n * Boots the ACP server over stdio — the standard wiring for a spawned ACP\n * agent (mirrors the @agentclientprotocol/sdk agent example): the agent writes\n * JSON-RPC to stdout and reads from stdin.\n */\n\nimport { Readable, Writable } from \"node:stream\"\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\"\nimport { ClaudeSdkAcpAgent } from \"./acp-host.js\"\nimport type { ClaudeSdkConfig } from \"./options.js\"\n\nexport function runAcpOverStdio(\n config: ClaudeSdkConfig = {},\n): AgentSideConnection {\n // ndJsonStream(writable, readable): outgoing bytes -> stdout, incoming <- stdin.\n const toClient = Writable.toWeb(process.stdout) as WritableStream<Uint8Array>\n const fromClient = Readable.toWeb(\n process.stdin,\n ) as unknown as ReadableStream<Uint8Array>\n const stream = ndJsonStream(toClient, fromClient)\n return new AgentSideConnection(\n (conn) => new ClaudeSdkAcpAgent(conn, config),\n stream,\n )\n}\n"]}
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { runAcpOverStdio } from './chunk-DW2G2NIH.mjs';
2
+ import { runAcpOverStdio } from './chunk-2LNYIR6L.mjs';
3
3
 
4
4
  /**
5
5
  * @agentproto/adapter-claude-sdk v0.1.0-alpha
@@ -55,7 +55,10 @@ function main() {
55
55
  ...permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE) ? { permissionMode: permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE) } : {},
56
56
  // Idle-stall watchdog override (ms); guards against a gateway whose stream
57
57
  // never terminates (e.g. Moonshot). Unset → the adapter default applies.
58
- ...idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) !== void 0 ? { idleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) } : {}
58
+ ...idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) !== void 0 ? { idleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) } : {},
59
+ // Extended watchdog while tool calls are pending. Prevents the generation
60
+ // watchdog from aborting a healthy turn during long tool execution.
61
+ ...idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS) !== void 0 ? { toolIdleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS) } : {}
59
62
  };
60
63
  runAcpOverStdio(config);
61
64
  }
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;AAyBA,SAAS,UAAU,IAAA,EAA4B;AAC7C,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACzB,EAAA,MAAM,GAAA,GAAkB,EAAE,GAAA,EAAK,IAAA,CAAK,CAAC,CAAA,EAAE;AACvC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,IAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAClB,IAAA,IAAI,QAAQ,SAAA,EAAW,GAAA,CAAI,KAAA,GAAQ,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,SAAA,IAClC,QAAQ,YAAA,EAAc,GAAA,CAAI,OAAA,GAAU,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,SAAA,IAC5C,QAAQ,cAAA,EAAgB,GAAA,CAAI,SAAA,GAAY,IAAA,CAAK,EAAE,CAAC,CAAA;AAAA,SAAA,IAChD,GAAA,KAAQ,YAAA,EAAc,GAAA,CAAI,QAAA,GAAW,IAAA;AAAA,EAChD;AACA,EAAA,OAAO,GAAA;AACT;AAEA,IAAM,KAAA,GACJ,oHAAA;AAIF,IAAM,gBAAA,GAA8C;AAAA,EAClD,SAAA;AAAA,EACA,aAAA;AAAA,EACA,mBAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAEA,SAAS,sBACP,GAAA,EAC4B;AAC5B,EAAA,OAAO,gBAAA,CAAiB,IAAA,CAAK,CAAC,IAAA,KAAS,SAAS,GAAG,CAAA;AACrD;AAKA,SAAS,qBAAqB,GAAA,EAA6C;AACzE,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,MAAA;AAC9B,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AAClC,EAAA,OAAO,OAAO,SAAA,CAAU,EAAE,CAAA,IAAK,EAAA,IAAM,IAAI,EAAA,GAAK,MAAA;AAChD;AAEA,SAAS,IAAA,GAAa;AACpB,EAAA,MAAM,EAAE,KAAK,KAAA,EAAO,OAAA,EAAS,WAAW,QAAA,EAAS,GAAI,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAC3E,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,KAAK,CAAA;AAC1B,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAA,GAAM,CAAA,GAAI,CAAC,CAAA;AAAA,EAC1B;AACA,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC9B,KAAA,EAAO,KAAA,IAAS,OAAA,CAAQ,GAAA,CAAI,gBAAA;AAAA,IAC5B,OAAA,EAAS,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,kBAAA;AAAA;AAAA;AAAA,IAGhC,SAAA,EAAW,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,oBAAA;AAAA;AAAA,IAEpC,GAAI,QAAA,GAAW,EAAE,QAAA,EAAU,IAAA,KAAS,EAAC;AAAA;AAAA,IAErC,GAAA,EAAK,QAAQ,GAAA,EAAI;AAAA,IACjB,GAAI,qBAAA,CAAsB,OAAA,CAAQ,GAAA,CAAI,0BAA0B,CAAA,GAC5D,EAAE,cAAA,EAAgB,qBAAA,CAAsB,OAAA,CAAQ,GAAA,CAAI,0BAA0B,CAAA,KAC9E,EAAC;AAAA;AAAA;AAAA,IAGL,GAAI,oBAAA,CAAqB,OAAA,CAAQ,GAAA,CAAI,0BAA0B,CAAA,KAAM,MAAA,GACjE,EAAE,aAAA,EAAe,qBAAqB,OAAA,CAAQ,GAAA,CAAI,0BAA0B,CAAA,KAC5E;AAAC,GACP;AAGA,EAAA,eAAA,CAAgB,MAAM,CAAA;AACxB;AAEA,IAAA,EAAK","file":"cli.mjs","sourcesContent":["#!/usr/bin/env node\n/**\n * Standalone CLI for the first-party Claude Agent SDK adapter.\n *\n * agentproto-claude-sdk acp [--model <id>] [--base-url <url>] \\\n * [--auth-token <token>] [--thinking]\n *\n * `acp` boots the ACP server over stdio — this is both what the agentproto\n * daemon spawns (as the `claude-sdk` arm) and what a user runs directly to\n * drive Claude Code's headless harness from any ACP-speaking host. I/O stays\n * 100% Anthropic-native.\n */\n\nimport { runAcpOverStdio } from \"./run.js\"\nimport type { ClaudeSdkConfig } from \"./options.js\"\nimport type { PermissionMode } from \"@anthropic-ai/claude-agent-sdk\"\n\ninterface ParsedArgs {\n cmd?: string\n model?: string\n baseUrl?: string\n authToken?: string\n thinking?: boolean\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const rest = argv.slice(2)\n const out: ParsedArgs = { cmd: rest[0] }\n for (let i = 1; i < rest.length; i++) {\n const arg = rest[i]\n if (arg === \"--model\") out.model = rest[++i]\n else if (arg === \"--base-url\") out.baseUrl = rest[++i]\n else if (arg === \"--auth-token\") out.authToken = rest[++i]\n else if (arg === \"--thinking\") out.thinking = true\n }\n return out\n}\n\nconst USAGE =\n \"usage: agentproto-claude-sdk acp [--model <claude-model>] \" +\n \"[--base-url <url>] [--auth-token <token>] [--thinking]\\n\"\n\n/** Recognised permission-mode overrides (env `CLAUDE_SDK_PERMISSION_MODE`). */\nconst PERMISSION_MODES: readonly PermissionMode[] = [\n \"default\",\n \"acceptEdits\",\n \"bypassPermissions\",\n \"plan\",\n \"dontAsk\",\n \"auto\",\n]\n\nfunction permissionModeFromEnv(\n raw: string | undefined,\n): PermissionMode | undefined {\n return PERMISSION_MODES.find((mode) => mode === raw)\n}\n\n/** Parse the idle-stall watchdog override. A non-negative integer (ms); `0`\n * disables the watchdog. Anything else (unset, negative, non-numeric) → the\n * adapter default. */\nfunction idleTimeoutMsFromEnv(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined\n const ms = Number.parseInt(raw, 10)\n return Number.isInteger(ms) && ms >= 0 ? ms : undefined\n}\n\nfunction main(): void {\n const { cmd, model, baseUrl, authToken, thinking } = parseArgs(process.argv)\n if (cmd !== \"acp\") {\n process.stderr.write(USAGE)\n process.exit(cmd ? 1 : 0)\n }\n const config: ClaudeSdkConfig = {\n model: model ?? process.env.CLAUDE_SDK_MODEL,\n baseUrl: baseUrl ?? process.env.ANTHROPIC_BASE_URL,\n // The daemon injects the manifest `auth_token` option as ANTHROPIC_AUTH_TOKEN\n // (env template); the flag is the standalone equivalent. Never logged.\n authToken: authToken ?? process.env.ANTHROPIC_AUTH_TOKEN,\n // `--thinking` (manifest bin_args_append_when_true) → options.thinking.\n ...(thinking ? { thinking: true } : {}),\n // Tools are confined to the dir the daemon spawned us in.\n cwd: process.cwd(),\n ...(permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE)\n ? { permissionMode: permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE) }\n : {}),\n // Idle-stall watchdog override (ms); guards against a gateway whose stream\n // never terminates (e.g. Moonshot). Unset → the adapter default applies.\n ...(idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) !== undefined\n ? { idleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) }\n : {}),\n }\n // The connection keeps the process alive (it holds stdin open); no explicit\n // wait loop needed.\n runAcpOverStdio(config)\n}\n\nmain()\n"]}
1
+ {"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":"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","file":"cli.mjs","sourcesContent":["#!/usr/bin/env node\n/**\n * Standalone CLI for the first-party Claude Agent SDK adapter.\n *\n * agentproto-claude-sdk acp [--model <id>] [--base-url <url>] \\\n * [--auth-token <token>] [--thinking]\n *\n * `acp` boots the ACP server over stdio — this is both what the agentproto\n * daemon spawns (as the `claude-sdk` arm) and what a user runs directly to\n * drive Claude Code's headless harness from any ACP-speaking host. I/O stays\n * 100% Anthropic-native.\n */\n\nimport { runAcpOverStdio } from \"./run.js\"\nimport type { ClaudeSdkConfig } from \"./options.js\"\nimport type { PermissionMode } from \"@anthropic-ai/claude-agent-sdk\"\n\ninterface ParsedArgs {\n cmd?: string\n model?: string\n baseUrl?: string\n authToken?: string\n thinking?: boolean\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const rest = argv.slice(2)\n const out: ParsedArgs = { cmd: rest[0] }\n for (let i = 1; i < rest.length; i++) {\n const arg = rest[i]\n if (arg === \"--model\") out.model = rest[++i]\n else if (arg === \"--base-url\") out.baseUrl = rest[++i]\n else if (arg === \"--auth-token\") out.authToken = rest[++i]\n else if (arg === \"--thinking\") out.thinking = true\n }\n return out\n}\n\nconst USAGE =\n \"usage: agentproto-claude-sdk acp [--model <claude-model>] \" +\n \"[--base-url <url>] [--auth-token <token>] [--thinking]\\n\"\n\n/** Recognised permission-mode overrides (env `CLAUDE_SDK_PERMISSION_MODE`). */\nconst PERMISSION_MODES: readonly PermissionMode[] = [\n \"default\",\n \"acceptEdits\",\n \"bypassPermissions\",\n \"plan\",\n \"dontAsk\",\n \"auto\",\n]\n\nfunction permissionModeFromEnv(\n raw: string | undefined,\n): PermissionMode | undefined {\n return PERMISSION_MODES.find((mode) => mode === raw)\n}\n\n/** Parse the idle-stall watchdog override. A non-negative integer (ms); `0`\n * disables the watchdog. Anything else (unset, negative, non-numeric) → the\n * adapter default. */\nfunction idleTimeoutMsFromEnv(raw: string | undefined): number | undefined {\n if (raw === undefined) return undefined\n const ms = Number.parseInt(raw, 10)\n return Number.isInteger(ms) && ms >= 0 ? ms : undefined\n}\n\nfunction main(): void {\n const { cmd, model, baseUrl, authToken, thinking } = parseArgs(process.argv)\n if (cmd !== \"acp\") {\n process.stderr.write(USAGE)\n process.exit(cmd ? 1 : 0)\n }\n const config: ClaudeSdkConfig = {\n model: model ?? process.env.CLAUDE_SDK_MODEL,\n baseUrl: baseUrl ?? process.env.ANTHROPIC_BASE_URL,\n // The daemon injects the manifest `auth_token` option as ANTHROPIC_AUTH_TOKEN\n // (env template); the flag is the standalone equivalent. Never logged.\n authToken: authToken ?? process.env.ANTHROPIC_AUTH_TOKEN,\n // `--thinking` (manifest bin_args_append_when_true) → options.thinking.\n ...(thinking ? { thinking: true } : {}),\n // Tools are confined to the dir the daemon spawned us in.\n cwd: process.cwd(),\n ...(permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE)\n ? { permissionMode: permissionModeFromEnv(process.env.CLAUDE_SDK_PERMISSION_MODE) }\n : {}),\n // Idle-stall watchdog override (ms); guards against a gateway whose stream\n // never terminates (e.g. Moonshot). Unset → the adapter default applies.\n ...(idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) !== undefined\n ? { idleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_IDLE_TIMEOUT_MS) }\n : {}),\n // Extended watchdog while tool calls are pending. Prevents the generation\n // watchdog from aborting a healthy turn during long tool execution.\n ...(idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS) !== undefined\n ? { toolIdleTimeoutMs: idleTimeoutMsFromEnv(process.env.CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS) }\n : {}),\n }\n // The connection keeps the process alive (it holds stdin open); no explicit\n // wait loop needed.\n runAcpOverStdio(config)\n}\n\nmain()\n"]}
package/dist/index.d.ts CHANGED
@@ -54,6 +54,17 @@ interface ClaudeSdkConfig {
54
54
  * `CLAUDE_SDK_IDLE_TIMEOUT_MS`.
55
55
  */
56
56
  idleTimeoutMs?: number;
57
+ /**
58
+ * Extended idle watchdog used while one or more tool calls are pending. Tool
59
+ * execution is silent between the SDK's `tool_use` and the matching
60
+ * `tool_result`, so the normal generation watchdog would abort a healthy
61
+ * turn. This budget is used only while at least one tool is in flight; once
62
+ * the last tool_result arrives the adapter falls back to
63
+ * {@link DEFAULT_IDLE_TIMEOUT_MS}. `0` disables. Defaults to
64
+ * {@link DEFAULT_TOOL_IDLE_TIMEOUT_MS}. Overridable via
65
+ * `CLAUDE_SDK_TOOL_IDLE_TIMEOUT_MS`.
66
+ */
67
+ toolIdleTimeoutMs?: number;
57
68
  /**
58
69
  * How the harness handles tool-permission prompts. Defaults to
59
70
  * `bypassPermissions` (with the required danger flag) so the arm can act
@@ -82,14 +93,13 @@ declare function mapAcpMcpServers(servers: McpServer[] | undefined): Record<stri
82
93
  * - Gateway mode (`base_url` set → a non-Anthropic host): the ambient
83
94
  * `ANTHROPIC_API_KEY` is SCRUBBED (it must never be sent to a third-party
84
95
  * gateway — that both 401s and leaks the real key). The gateway bearer is
85
- * resolved from, in order, the explicit `auth_token`, an explicit
86
- * `ANTHROPIC_AUTH_TOKEN`, or the gateway's conventional key env named by the
87
- * mode via `CLAUDE_SDK_GATEWAY_KEY_ENV` (e.g. `MOONSHOT_API_KEY`). Every
88
- * internal model tier is also pinned to the resolved model so a single-model
89
- * gateway never gets a tier it can't serve (e.g. Moonshot rejecting
90
- * `claude-haiku-*`). The {@link CLOUD_PROVIDER_REDIRECT_TOGGLES} leaked from
91
- * a Claude-Code parent shell are also scrubbed so the gateway `base_url`
92
- * isn't overridden.
96
+ * resolved from the explicit `auth_token` or `ANTHROPIC_AUTH_TOKEN` in the
97
+ * spawn env; if neither resolves, no credential is presented (fail clean,
98
+ * never leak). Every internal model tier is also pinned to the resolved
99
+ * model so a single-model gateway never receives a tier it can't serve
100
+ * (e.g. Moonshot rejecting `claude-haiku-*`). The
101
+ * {@link CLOUD_PROVIDER_REDIRECT_TOGGLES} leaked from a Claude-Code parent
102
+ * shell are also scrubbed so the gateway `base_url` isn't overridden.
93
103
  */
94
104
  declare function buildQueryOptions(args: {
95
105
  config: ClaudeSdkConfig;
package/dist/index.mjs CHANGED
@@ -1,8 +1,7 @@
1
- import { DEFAULT_MODEL } from './chunk-DW2G2NIH.mjs';
2
- export { ClaudeSdkAcpAgent, DEFAULT_MODEL, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates } from './chunk-DW2G2NIH.mjs';
1
+ import { DEFAULT_MODEL } from './chunk-2LNYIR6L.mjs';
2
+ export { ClaudeSdkAcpAgent, DEFAULT_MODEL, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates } from './chunk-2LNYIR6L.mjs';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { defineAgentCli, createAgentCliRuntime } from '@agentproto/driver-agent-cli';
5
- import { ANTHROPIC_GATEWAY_PRESETS } from '@agentproto/provider-presets';
6
5
 
7
6
  /**
8
7
  * @agentproto/adapter-claude-sdk v0.1.0-alpha
@@ -53,10 +52,23 @@ var claudeSdk = defineAgentCli({
53
52
  // options.ts / cli.ts) — so that's this adapter's authSubscription.setEnv,
54
53
  // with the CLI's CLAUDE_CODE_OAUTH_TOKEN scrubbed as the sibling credential.
55
54
  provider: "anthropic",
55
+ // A model's route is an independent choice here: gateway routing is
56
+ // injected at runtime via `base_url`, so the same model can go
57
+ // direct-Anthropic or via any gateway → free route selection.
58
+ routeSelection: "free",
56
59
  authSubscription: {
57
60
  setEnv: "ANTHROPIC_AUTH_TOKEN",
58
61
  conflictEnv: ["CLAUDE_CODE_OAUTH_TOKEN"]
59
62
  },
63
+ // How this adapter receives a GATEWAY-routed bearer credential (D4) —
64
+ // ANTHROPIC_AUTH_TOKEN, the SAME var as the `auth_token` option below
65
+ // (env: { ANTHROPIC_AUTH_TOKEN: "{value}" }) and the one the Claude Agent
66
+ // SDK actually sends as `Authorization: Bearer`. Distinct from a gateway
67
+ // preset's own `keyEnv` (OPENROUTER_API_KEY, MOONSHOT_API_KEY, …) — that's
68
+ // merely where the operator's providers.json stores the key; the runtime's
69
+ // resolveAuthSpec now injects the resolved credential HERE for a gateway
70
+ // route instead, so it lands in a var the SDK actually reads.
71
+ gatewayAuth: { setEnv: "ANTHROPIC_AUTH_TOKEN" },
60
72
  sandbox: "In-process: the SDK harness runs inside the spawned node process, scoped to the daemon's cwd. Tool-permission handling defaults to bypassPermissions (override via CLAUDE_SDK_PERMISSION_MODE); the daemon owns the surrounding sandbox.",
61
73
  protocol: "acp",
62
74
  acp: "./claude-sdk.ACP.md",
@@ -68,25 +80,53 @@ var claudeSdk = defineAgentCli({
68
80
  models: {
69
81
  // A cheap Claude by default — this is the budget first-party arm.
70
82
  default: DEFAULT_MODEL,
71
- // Each entry states who serves it (`provider`) and, for a gateway model,
72
- // which mode below routes there (`mode`) — the mode pre-wires
73
- // ANTHROPIC_BASE_URL, so picking the model without it would send a
74
- // gateway id straight to real Anthropic. Native models need no mode:
75
- // `mode: default` is already this adapter's baseline. The `model`
76
- // option stays free-form, so any gateway id works even if it isn't
77
- // listed here.
83
+ // Curated model menu. `provider` states who serves/bills the model; the
84
+ // runtime resolver supplies the matching ANTHROPIC_BASE_URL + credential
85
+ // for gateway providers. This adapter no longer hard-codes gateway URLs
86
+ // or modes — it declares routes/capabilities and consumes runtime-injected
87
+ // ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN. The `model` option remains
88
+ // free-form, so any gateway id works even if it is not listed here.
78
89
  allowed: [
79
- // Native Anthropic — no mode switch needed
90
+ // Native Anthropic
80
91
  { id: "claude-haiku-4-5-20251001", provider: "anthropic" },
81
92
  { id: "claude-sonnet-5", provider: "anthropic" },
82
93
  { id: "claude-opus-4-8", provider: "anthropic" },
83
94
  { id: "claude-fable-5", provider: "anthropic" },
84
- // Moonshot (Kimi) — mode: moonshot
85
- { id: "kimi-k2.7-code", provider: "moonshot", mode: "moonshot" },
86
- // OpenRouter — mode: openrouter
87
- { id: "z-ai/glm-5.2", provider: "openrouter", mode: "openrouter" },
88
- { id: "deepseek/deepseek-v4-pro", provider: "openrouter", mode: "openrouter" },
89
- { id: "moonshotai/kimi-k2", provider: "openrouter", mode: "openrouter" }
95
+ // Gateway providers — routing is resolved by the runtime. OpenRouter ids
96
+ // carry the `@openrouter` route-identity suffix so the catalog join pins
97
+ // the gateway route (a bare 2-segment id resolves to the dead direct
98
+ // vendor route instead).
99
+ { id: "kimi-k2.7-code", provider: "moonshot" },
100
+ { id: "z-ai/glm-5.2@openrouter", provider: "openrouter" },
101
+ { id: "deepseek/deepseek-v4-pro@openrouter", provider: "openrouter" },
102
+ { id: "moonshotai/kimi-k2@openrouter", provider: "openrouter" },
103
+ { id: "x-ai/grok-4.5@openrouter", provider: "openrouter" },
104
+ { id: "x-ai/grok-4.20@openrouter", provider: "openrouter" },
105
+ { id: "x-ai/grok-4.3@openrouter", provider: "openrouter" },
106
+ { id: "google/gemini-3.1-pro-preview@openrouter", provider: "openrouter" },
107
+ { id: "google/gemini-3.5-flash@openrouter", provider: "openrouter" },
108
+ { id: "google/gemini-2.5-flash@openrouter", provider: "openrouter" },
109
+ { id: "google/gemini-2.5-pro@openrouter", provider: "openrouter" },
110
+ { id: "moonshotai/kimi-k2.7-code@openrouter", provider: "openrouter" },
111
+ // OpenAI gpt-5.6 series via OpenRouter — reachable via ANTHROPIC_BASE_URL
112
+ // + ANTHROPIC_AUTH_TOKEN (the gatewayAuth setEnv above) like the other
113
+ // gateway rows. The `@openrouter` suffix pins the catalog join to the
114
+ // OpenRouter gateway (the bare id would resolve to the direct-OpenAI
115
+ // route, which the SDK's Anthropic surface can't speak). Real,
116
+ // already-priced OpenRouter chat models, not invented specialist ids.
117
+ { id: "openai/gpt-5.6-luna@openrouter", provider: "openrouter" },
118
+ { id: "openai/gpt-5.6-sol@openrouter", provider: "openrouter" },
119
+ // Local llm-endpoint proxy — the `@llm-endpoint` suffix pins the catalog
120
+ // join to the runtime-registered custom route (Anthropic surface at
121
+ // localhost:18090). A SMALL curated set from the proxy's own `default`
122
+ // pack (packages/llm-endpoint/src/packs.ts); the vendor prefix is the
123
+ // proxy's transparent-provider name so the boundary-stripped
124
+ // `vendor/product` upstream id transparently routes.
125
+ { id: "moonshot/kimi-k2.7-code@llm-endpoint", provider: "llm-endpoint" },
126
+ { id: "moonshot/kimi-k2.6@llm-endpoint", provider: "llm-endpoint" },
127
+ { id: "zai/glm-5.2@llm-endpoint", provider: "llm-endpoint" },
128
+ { id: "openai/gpt-4.1@llm-endpoint", provider: "llm-endpoint" },
129
+ { id: "openai/gpt-4o-mini@llm-endpoint", provider: "llm-endpoint" }
90
130
  ],
91
131
  env: {
92
132
  anthropic: "ANTHROPIC_API_KEY"
@@ -106,60 +146,14 @@ var claudeSdk = defineAgentCli({
106
146
  resumable: true,
107
147
  bidirectional: true
108
148
  },
109
- // Gateway presets. The base_url/auth_token/thinking options already let a
110
- // caller front any Anthropic-compatible gateway by hand; these modes just
111
- // pre-wire the endpoint (and, for Moonshot, the model + --thinking) so the
112
- // caller only has to supply the key. The `model` option still overrides.
149
+ // Operation modes. Only the native "default" profile remains as a manifest
150
+ // mode — gateway routing is now resolved by the runtime and injected via
151
+ // ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN. The adapter declares the
152
+ // providers/models it can consume, but it no longer hard-codes gateway URLs.
113
153
  modes: [
114
154
  {
115
155
  id: "default",
116
- description: "Native Anthropic \u2014 the real Anthropic API (or whatever ANTHROPIC_BASE_URL / cloud toggles the environment already sets). Uses the native Claude models in `allowed`."
117
- },
118
- {
119
- id: ANTHROPIC_GATEWAY_PRESETS.moonshot.id,
120
- description: "Moonshot (Kimi) gateway. Pre-wires ANTHROPIC_BASE_URL to Moonshot's Anthropic-compatible endpoint, defaults the model to kimi-k2.7-code, and enables --thinking (Kimi rejects a request without it). Supply the Moonshot key via the `auth_token` option (or ANTHROPIC_AUTH_TOKEN); override `model` for another Moonshot model.",
121
- env: {
122
- ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.moonshot.baseUrl,
123
- // cli.ts reads CLAUDE_SDK_MODEL as the model fallback (a `--model`
124
- // option still wins), so the mode ships a working default model.
125
- CLAUDE_SDK_MODEL: ANTHROPIC_GATEWAY_PRESETS.moonshot.defaultModel,
126
- // Declares this gateway's conventional credential source.
127
- // buildQueryOptions resolves the bearer from this env when no explicit
128
- // auth_token / ANTHROPIC_AUTH_TOKEN is set, and always scrubs the
129
- // ambient ANTHROPIC_API_KEY so it never reaches a non-Anthropic host.
130
- CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.moonshot.keyEnv
131
- },
132
- bin_args_append: ["--thinking"]
133
- },
134
- {
135
- id: ANTHROPIC_GATEWAY_PRESETS.openrouter.id,
136
- description: "OpenRouter gateway. Pre-wires ANTHROPIC_BASE_URL to OpenRouter's Anthropic-compatible endpoint. Pick a model via the `model` option (e.g. 'z-ai/glm-5.2', 'deepseek/deepseek-v4-pro', 'moonshotai/kimi-k2') and supply the OpenRouter key via `auth_token` (or ANTHROPIC_AUTH_TOKEN).",
137
- env: {
138
- ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.openrouter.baseUrl,
139
- // Conventional credential source for this gateway (see moonshot above).
140
- CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.openrouter.keyEnv
141
- }
142
- },
143
- {
144
- id: ANTHROPIC_GATEWAY_PRESETS.requesty.id,
145
- description: "Requesty gateway. Pre-wires ANTHROPIC_BASE_URL to Requesty's Anthropic-compatible endpoint. Pick a model via the `model` option (e.g. 'sference/thinkingcap-qwen3.6-27b', 'sference/glm-5.2') and supply the Requesty key via `auth_token` (or ANTHROPIC_AUTH_TOKEN). buildQueryOptions pins every model tier \u2014 including ANTHROPIC_SMALL_FAST_MODEL \u2014 to that one model, since Requesty serves no Claude-named tiers.",
146
- env: {
147
- ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.requesty.baseUrl,
148
- // Conventional credential source for this gateway (see moonshot above).
149
- CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.requesty.keyEnv
150
- }
151
- },
152
- {
153
- id: ANTHROPIC_GATEWAY_PRESETS.deepseek.id,
154
- description: "DeepSeek gateway. Pre-wires ANTHROPIC_BASE_URL to DeepSeek's Anthropic-compatible endpoint and defaults the model to deepseek-v4-pro. Supply the DeepSeek key via the `auth_token` option (or ANTHROPIC_AUTH_TOKEN); override `model` for deepseek-v4-flash. Thinking is opt-in (DeepSeek accepts requests without it, unlike Kimi).",
155
- env: {
156
- ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.deepseek.baseUrl,
157
- // cli.ts reads CLAUDE_SDK_MODEL as the model fallback (a `--model`
158
- // option still wins), so the mode ships a working default model.
159
- CLAUDE_SDK_MODEL: ANTHROPIC_GATEWAY_PRESETS.deepseek.defaultModel,
160
- // Conventional credential source for this gateway (see moonshot above).
161
- CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.deepseek.keyEnv
162
- }
156
+ description: "Native Anthropic \u2014 the real Anthropic API (or whatever ANTHROPIC_BASE_URL / cloud toggles the environment or runtime resolver already sets). Uses the native Claude models in `allowed`."
163
157
  }
164
158
  ],
165
159
  options: [
@@ -169,7 +163,7 @@ var claudeSdk = defineAgentCli({
169
163
  // Claude ids, or a gateway id when a gateway mode is selected. Applied as
170
164
  // a `--model <id>` spawn arg → SDK options.model.
171
165
  type: "string",
172
- description: "Model id \u2192 SDK options.model, applied as a `--model` arg at spawn. Native Claude (e.g. 'claude-opus-4-8', 'claude-sonnet-5') in the default mode, or a gateway id when mode is moonshot/openrouter (e.g. 'kimi-k2.7-code', 'z-ai/glm-5.2'). Omit for the mode's default.",
166
+ description: "Model id \u2192 SDK options.model, applied as a `--model` arg at spawn. Native Claude (e.g. 'claude-opus-4-8', 'claude-sonnet-5') in the default mode, or any gateway id when base_url is set (e.g. 'kimi-k2.7-code', 'z-ai/glm-5.2@openrouter'). Omit for the adapter's default.",
173
167
  bin_args_template: ["--model", "{value}"]
174
168
  },
175
169
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @agentproto/adapter-claude-sdk — first-party adapter that runs Claude Code's\n * agent harness as a LIBRARY.\n *\n * Unlike `@agentproto/adapter-claude-code` (which wraps the third-party\n * `@agentclientprotocol/claude-agent-acp` bridge), this adapter drives the\n * Claude Agent SDK's headless `query()` directly behind an AIP-44 ACP server\n * (see ./acp-host.ts), shipped as a CLI bin (`agentproto-claude-sdk acp`). The\n * daemon spawns it like any other arm; a user can launch it standalone.\n *\n * Driving the SDK directly buys us clean model pinning (`options.model`, no\n * spawn-arg rejection — issue #186), native usage telemetry (a `usage_update`\n * per turn — #186 P3), and a custom `base_url` (`ANTHROPIC_BASE_URL`) that\n * points the same Anthropic-native harness at real Anthropic, Bedrock/Vertex/\n * Azure, or an Anthropic-compatible gateway.\n *\n * import { claudeSdk, claudeSdkRuntime } from \"@agentproto/adapter-claude-sdk\"\n */\n\nimport { fileURLToPath } from \"node:url\"\nimport {\n createAgentCliRuntime,\n defineAgentCli,\n type AgentCliHandle,\n type AgentCliRuntime,\n} from \"@agentproto/driver-agent-cli\"\nimport { ANTHROPIC_GATEWAY_PRESETS } from \"@agentproto/provider-presets\"\nimport { DEFAULT_MODEL } from \"./options.js\"\n\n// Self-locating: the built handle spawns `node <this-dist>/cli.mjs acp`.\n// import.meta.url resolves into dist/ at runtime, where cli.mjs sits next to\n// index.mjs — so the same build works whether the daemon spawns it (resolved\n// from node_modules) or a user runs the published bin.\nconst cliEntry = fileURLToPath(new URL(\"./cli.mjs\", import.meta.url))\n\nexport const claudeSdk: AgentCliHandle = defineAgentCli({\n name: \"claude-sdk\",\n id: \"claude-sdk\",\n description:\n \"First-party agentproto adapter — Claude Code's agent harness run as a \" +\n \"library via the Claude Agent SDK's headless query(), behind an AIP-44 ACP \" +\n \"server. 100% Anthropic-native I/O: clean model pinning (options.model), \" +\n \"native per-turn usage (tokens + cost), and a custom base_url \" +\n \"(ANTHROPIC_BASE_URL) to front real Anthropic, Bedrock/Vertex/Azure, or an \" +\n \"Anthropic-compatible gateway. Spawned as `node cli.mjs acp` over stdio \" +\n \"JSON-RPC, or launched standalone via `agentproto-claude-sdk acp`.\",\n version: \"0.1.0\",\n bin: \"node\",\n bin_args: [cliEntry, \"acp\"],\n install: [\n {\n method: \"npm\",\n package: \"@agentproto/adapter-claude-sdk\",\n global: true,\n },\n ],\n // No external runtime to probe — the SDK's harness runs in the spawned node\n // process. A node version gate is enough to mark the arm ready.\n version_check: {\n cmd: \"node --version\",\n parse: \"(\\\\d+\\\\.\\\\d+\\\\.\\\\d+)\",\n range: \">=20.9.0\",\n timeout_ms: 5000,\n },\n auth: {\n ref: \"./claude-sdk.ACP.md\",\n // Auth is read from the spawn env by the SDK. Either an Anthropic key/token\n // (direct or via an Anthropic-compatible gateway), or the cloud-provider\n // toggles below.\n state: {\n env: [\n \"ANTHROPIC_API_KEY\",\n \"ANTHROPIC_AUTH_TOKEN\",\n \"CLAUDE_CODE_USE_BEDROCK\",\n \"CLAUDE_CODE_USE_VERTEX\",\n \"CLAUDE_CODE_USE_FOUNDRY\",\n ],\n },\n },\n // Billing-auth (opt-in — authEnforce defaults to \"when-configured\", so an\n // unconfigured spawn stays ambient/unchanged). provider \"anthropic\" ⇒\n // api-key mode SETS ANTHROPIC_API_KEY. Unlike the claude-code CLI wrapper,\n // the SDK's subscription/bearer var is ANTHROPIC_AUTH_TOKEN (see\n // options.ts / cli.ts) — so that's this adapter's authSubscription.setEnv,\n // with the CLI's CLAUDE_CODE_OAUTH_TOKEN scrubbed as the sibling credential.\n provider: \"anthropic\",\n authSubscription: {\n setEnv: \"ANTHROPIC_AUTH_TOKEN\",\n conflictEnv: [\"CLAUDE_CODE_OAUTH_TOKEN\"],\n },\n sandbox:\n \"In-process: the SDK harness runs inside the spawned node process, scoped \" +\n \"to the daemon's cwd. Tool-permission handling defaults to \" +\n \"bypassPermissions (override via CLAUDE_SDK_PERMISSION_MODE); the daemon \" +\n \"owns the surrounding sandbox.\",\n protocol: \"acp\",\n acp: \"./claude-sdk.ACP.md\",\n session: {\n mode: \"persistent\",\n idle_timeout_ms: 1_800_000,\n context_carryover: true,\n },\n models: {\n // A cheap Claude by default — this is the budget first-party arm.\n default: DEFAULT_MODEL,\n // Each entry states who serves it (`provider`) and, for a gateway model,\n // which mode below routes there (`mode`) — the mode pre-wires\n // ANTHROPIC_BASE_URL, so picking the model without it would send a\n // gateway id straight to real Anthropic. Native models need no mode:\n // `mode: default` is already this adapter's baseline. The `model`\n // option stays free-form, so any gateway id works even if it isn't\n // listed here.\n allowed: [\n // Native Anthropic — no mode switch needed\n { id: \"claude-haiku-4-5-20251001\", provider: \"anthropic\" },\n { id: \"claude-sonnet-5\", provider: \"anthropic\" },\n { id: \"claude-opus-4-8\", provider: \"anthropic\" },\n { id: \"claude-fable-5\", provider: \"anthropic\" },\n // Moonshot (Kimi) — mode: moonshot\n { id: \"kimi-k2.7-code\", provider: \"moonshot\", mode: \"moonshot\" },\n // OpenRouter — mode: openrouter\n { id: \"z-ai/glm-5.2\", provider: \"openrouter\", mode: \"openrouter\" },\n { id: \"deepseek/deepseek-v4-pro\", provider: \"openrouter\", mode: \"openrouter\" },\n { id: \"moonshotai/kimi-k2\", provider: \"openrouter\", mode: \"openrouter\" },\n ],\n env: {\n anthropic: \"ANTHROPIC_API_KEY\",\n },\n },\n capabilities: {\n streaming: true,\n // Claude Code's built-in tools (Read/Edit/Bash/…) and any injected MCP\n // tools run inside the harness and are relayed to the host as ACP\n // tool_call / tool_call_update updates (see acp-host.ts + message-map.ts).\n tool_calls: true,\n sub_agents: true,\n file_io: true,\n multimodal: false,\n // Turns resume via the SDK session store (options.resume), keyed by the\n // pinned session id.\n resumable: true,\n bidirectional: true,\n },\n // Gateway presets. The base_url/auth_token/thinking options already let a\n // caller front any Anthropic-compatible gateway by hand; these modes just\n // pre-wire the endpoint (and, for Moonshot, the model + --thinking) so the\n // caller only has to supply the key. The `model` option still overrides.\n modes: [\n {\n id: \"default\",\n description:\n \"Native Anthropic — the real Anthropic API (or whatever \" +\n \"ANTHROPIC_BASE_URL / cloud toggles the environment already sets). \" +\n \"Uses the native Claude models in `allowed`.\",\n },\n {\n id: ANTHROPIC_GATEWAY_PRESETS.moonshot.id,\n description:\n \"Moonshot (Kimi) gateway. Pre-wires ANTHROPIC_BASE_URL to Moonshot's \" +\n \"Anthropic-compatible endpoint, defaults the model to kimi-k2.7-code, \" +\n \"and enables --thinking (Kimi rejects a request without it). Supply the \" +\n \"Moonshot key via the `auth_token` option (or ANTHROPIC_AUTH_TOKEN); \" +\n \"override `model` for another Moonshot model.\",\n env: {\n ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.moonshot.baseUrl,\n // cli.ts reads CLAUDE_SDK_MODEL as the model fallback (a `--model`\n // option still wins), so the mode ships a working default model.\n CLAUDE_SDK_MODEL: ANTHROPIC_GATEWAY_PRESETS.moonshot.defaultModel,\n // Declares this gateway's conventional credential source.\n // buildQueryOptions resolves the bearer from this env when no explicit\n // auth_token / ANTHROPIC_AUTH_TOKEN is set, and always scrubs the\n // ambient ANTHROPIC_API_KEY so it never reaches a non-Anthropic host.\n CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.moonshot.keyEnv,\n },\n bin_args_append: [\"--thinking\"],\n },\n {\n id: ANTHROPIC_GATEWAY_PRESETS.openrouter.id,\n description:\n \"OpenRouter gateway. Pre-wires ANTHROPIC_BASE_URL to OpenRouter's \" +\n \"Anthropic-compatible endpoint. Pick a model via the `model` option \" +\n \"(e.g. 'z-ai/glm-5.2', 'deepseek/deepseek-v4-pro', 'moonshotai/kimi-k2') \" +\n \"and supply the OpenRouter key via `auth_token` (or ANTHROPIC_AUTH_TOKEN).\",\n env: {\n ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.openrouter.baseUrl,\n // Conventional credential source for this gateway (see moonshot above).\n CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.openrouter.keyEnv,\n },\n },\n {\n id: ANTHROPIC_GATEWAY_PRESETS.requesty.id,\n description:\n \"Requesty gateway. Pre-wires ANTHROPIC_BASE_URL to Requesty's \" +\n \"Anthropic-compatible endpoint. Pick a model via the `model` option \" +\n \"(e.g. 'sference/thinkingcap-qwen3.6-27b', 'sference/glm-5.2') and \" +\n \"supply the Requesty key via `auth_token` (or ANTHROPIC_AUTH_TOKEN). \" +\n \"buildQueryOptions pins every model tier — including \" +\n \"ANTHROPIC_SMALL_FAST_MODEL — to that one model, since Requesty serves \" +\n \"no Claude-named tiers.\",\n env: {\n ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.requesty.baseUrl,\n // Conventional credential source for this gateway (see moonshot above).\n CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.requesty.keyEnv,\n },\n },\n {\n id: ANTHROPIC_GATEWAY_PRESETS.deepseek.id,\n description:\n \"DeepSeek gateway. Pre-wires ANTHROPIC_BASE_URL to DeepSeek's \" +\n \"Anthropic-compatible endpoint and defaults the model to \" +\n \"deepseek-v4-pro. Supply the DeepSeek key via the `auth_token` option \" +\n \"(or ANTHROPIC_AUTH_TOKEN); override `model` for deepseek-v4-flash. \" +\n \"Thinking is opt-in (DeepSeek accepts requests without it, unlike Kimi).\",\n env: {\n ANTHROPIC_BASE_URL: ANTHROPIC_GATEWAY_PRESETS.deepseek.baseUrl,\n // cli.ts reads CLAUDE_SDK_MODEL as the model fallback (a `--model`\n // option still wins), so the mode ships a working default model.\n CLAUDE_SDK_MODEL: ANTHROPIC_GATEWAY_PRESETS.deepseek.defaultModel,\n // Conventional credential source for this gateway (see moonshot above).\n CLAUDE_SDK_GATEWAY_KEY_ENV: ANTHROPIC_GATEWAY_PRESETS.deepseek.keyEnv,\n },\n },\n ],\n options: [\n {\n id: \"model\",\n // string (not enum) so any model id works without a code change — native\n // Claude ids, or a gateway id when a gateway mode is selected. Applied as\n // a `--model <id>` spawn arg → SDK options.model.\n type: \"string\" as const,\n description:\n \"Model id → SDK options.model, applied as a `--model` arg at spawn. \" +\n \"Native Claude (e.g. 'claude-opus-4-8', 'claude-sonnet-5') in the \" +\n \"default mode, or a gateway id when mode is moonshot/openrouter \" +\n \"(e.g. 'kimi-k2.7-code', 'z-ai/glm-5.2'). Omit for the mode's default.\",\n bin_args_template: [\"--model\", \"{value}\"],\n },\n {\n id: \"base_url\",\n // Injected into the child env as ANTHROPIC_BASE_URL — keeps the harness\n // Anthropic-native while fronting real Anthropic, a cloud provider, or an\n // Anthropic-compatible gateway (LiteLLM / claude-code-router). When set,\n // buildQueryOptions also pins every model tier to `model` (gateway mode).\n type: \"string\" as const,\n description:\n \"Custom Anthropic base URL. Injected as ANTHROPIC_BASE_URL in the \" +\n \"child env — front real Anthropic, Bedrock/Vertex/Azure, or an \" +\n \"Anthropic-compatible gateway. When set, every internal model tier \" +\n \"(opus/sonnet/haiku/small-fast) is pinned to `model` so a single-model \" +\n \"gateway never gets an unservable tier. Omit to use the default endpoint.\",\n env: { ANTHROPIC_BASE_URL: \"{value}\" },\n },\n {\n id: \"auth_token\",\n // Injected into the child env as ANTHROPIC_AUTH_TOKEN — the SDK sends it\n // as `Authorization: Bearer <token>`, which Anthropic-compatible gateways\n // (Moonshot, OpenRouter) accept. Pair with base_url for a per-spawn key.\n type: \"string\" as const,\n description:\n \"Bearer token for the Anthropic API or a compatible gateway. Injected \" +\n \"as ANTHROPIC_AUTH_TOKEN in the child env (sent as `Authorization: \" +\n \"Bearer`). Pair with base_url to target a gateway (e.g. Moonshot, \" +\n \"OpenRouter) with a per-spawn key instead of the ambient \" +\n \"ANTHROPIC_API_KEY. Omit to use ANTHROPIC_API_KEY from the environment.\",\n env: { ANTHROPIC_AUTH_TOKEN: \"{value}\" },\n },\n {\n id: \"thinking\",\n // Bare flag → cli.ts parses `--thinking` → SDK options.thinking =\n // { type: \"enabled\" }. Needed by thinking-gated gateway models such as\n // kimi-k2.7-code, which reject a request that omits `thinking`.\n type: \"boolean\" as const,\n description:\n \"Enable extended thinking (SDK options.thinking = { type: 'enabled' }). \" +\n \"Required by thinking-gated gateway models such as Moonshot's \" +\n \"kimi-k2.7-code, which reject a request without it. Off by default — \" +\n \"native Claude models choose their own thinking behaviour.\",\n bin_args_append_when_true: [\"--thinking\"],\n },\n ],\n tags: [\"anthropic\", \"claude\", \"claude-agent-sdk\", \"agentproto\", \"acp\", \"first-party\"],\n})\n\nexport function claudeSdkRuntime(): AgentCliRuntime {\n return createAgentCliRuntime(claudeSdk)\n}\n\nexport {\n ClaudeSdkAcpAgent,\n promptText,\n type QueryFn,\n} from \"./acp-host.js\"\nexport {\n buildQueryOptions,\n mapAcpMcpServers,\n DEFAULT_MODEL,\n type ClaudeSdkConfig,\n} from \"./options.js\"\nexport {\n sdkMessageToUpdates,\n assistantMessageUpdates,\n userMessageUpdates,\n resultUsageUpdate,\n systemInitSessionId,\n toolKindForClaudeTool,\n toolCallTitle,\n type UsageSessionUpdate,\n} from \"./message-map.js\"\nexport { runAcpOverStdio } from \"./run.js\"\nexport type { AgentCliHandle, AgentCliRuntime }\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;AAgCA,IAAM,WAAW,aAAA,CAAc,IAAI,IAAI,WAAA,EAAa,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAE7D,IAAM,YAA4B,cAAA,CAAe;AAAA,EACtD,IAAA,EAAM,YAAA;AAAA,EACN,EAAA,EAAI,YAAA;AAAA,EACJ,WAAA,EACE,8eAAA;AAAA,EAOF,OAAA,EAAS,OAAA;AAAA,EACT,GAAA,EAAK,MAAA;AAAA,EACL,QAAA,EAAU,CAAC,QAAA,EAAU,KAAK,CAAA;AAAA,EAC1B,OAAA,EAAS;AAAA,IACP;AAAA,MACE,MAAA,EAAQ,KAAA;AAAA,MACR,OAAA,EAAS,gCAAA;AAAA,MACT,MAAA,EAAQ;AAAA;AACV,GACF;AAAA;AAAA;AAAA,EAGA,aAAA,EAAe;AAAA,IACb,GAAA,EAAK,gBAAA;AAAA,IACL,KAAA,EAAO,sBAAA;AAAA,IACP,KAAA,EAAO,UAAA;AAAA,IACP,UAAA,EAAY;AAAA,GACd;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,GAAA,EAAK,qBAAA;AAAA;AAAA;AAAA;AAAA,IAIL,KAAA,EAAO;AAAA,MACL,GAAA,EAAK;AAAA,QACH,mBAAA;AAAA,QACA,sBAAA;AAAA,QACA,yBAAA;AAAA,QACA,wBAAA;AAAA,QACA;AAAA;AACF;AACF,GACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,QAAA,EAAU,WAAA;AAAA;AAAA;AAAA;AAAA,EAIV,cAAA,EAAgB,MAAA;AAAA,EAChB,gBAAA,EAAkB;AAAA,IAChB,MAAA,EAAQ,sBAAA;AAAA,IACR,WAAA,EAAa,CAAC,yBAAyB;AAAA,GACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAA,EAAa,EAAE,MAAA,EAAQ,sBAAA,EAAuB;AAAA,EAC9C,OAAA,EACE,0OAAA;AAAA,EAIF,QAAA,EAAU,KAAA;AAAA,EACV,GAAA,EAAK,qBAAA;AAAA,EACL,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,YAAA;AAAA,IACN,eAAA,EAAiB,IAAA;AAAA,IACjB,iBAAA,EAAmB;AAAA,GACrB;AAAA,EACA,MAAA,EAAQ;AAAA;AAAA,IAEN,OAAA,EAAS,aAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOT,OAAA,EAAS;AAAA;AAAA,MAEP,EAAE,EAAA,EAAI,2BAAA,EAA6B,QAAA,EAAU,WAAA,EAAY;AAAA,MACzD,EAAE,EAAA,EAAI,iBAAA,EAAmB,QAAA,EAAU,WAAA,EAAY;AAAA,MAC/C,EAAE,EAAA,EAAI,iBAAA,EAAmB,QAAA,EAAU,WAAA,EAAY;AAAA,MAC/C,EAAE,EAAA,EAAI,gBAAA,EAAkB,QAAA,EAAU,WAAA,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAK9C,EAAE,EAAA,EAAI,gBAAA,EAAkB,QAAA,EAAU,UAAA,EAAW;AAAA,MAC7C,EAAE,EAAA,EAAI,yBAAA,EAA2B,QAAA,EAAU,YAAA,EAAa;AAAA,MACxD,EAAE,EAAA,EAAI,qCAAA,EAAuC,QAAA,EAAU,YAAA,EAAa;AAAA,MACpE,EAAE,EAAA,EAAI,+BAAA,EAAiC,QAAA,EAAU,YAAA,EAAa;AAAA,MAC9D,EAAE,EAAA,EAAI,0BAAA,EAA4B,QAAA,EAAU,YAAA,EAAa;AAAA,MACzD,EAAE,EAAA,EAAI,2BAAA,EAA6B,QAAA,EAAU,YAAA,EAAa;AAAA,MAC1D,EAAE,EAAA,EAAI,0BAAA,EAA4B,QAAA,EAAU,YAAA,EAAa;AAAA,MACzD,EAAE,EAAA,EAAI,0CAAA,EAA4C,QAAA,EAAU,YAAA,EAAa;AAAA,MACzE,EAAE,EAAA,EAAI,oCAAA,EAAsC,QAAA,EAAU,YAAA,EAAa;AAAA,MACnE,EAAE,EAAA,EAAI,oCAAA,EAAsC,QAAA,EAAU,YAAA,EAAa;AAAA,MACnE,EAAE,EAAA,EAAI,kCAAA,EAAoC,QAAA,EAAU,YAAA,EAAa;AAAA,MACjE,EAAE,EAAA,EAAI,sCAAA,EAAwC,QAAA,EAAU,YAAA,EAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOrE,EAAE,EAAA,EAAI,gCAAA,EAAkC,QAAA,EAAU,YAAA,EAAa;AAAA,MAC/D,EAAE,EAAA,EAAI,+BAAA,EAAiC,QAAA,EAAU,YAAA,EAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAO9D,EAAE,EAAA,EAAI,sCAAA,EAAwC,QAAA,EAAU,cAAA,EAAe;AAAA,MACvE,EAAE,EAAA,EAAI,iCAAA,EAAmC,QAAA,EAAU,cAAA,EAAe;AAAA,MAClE,EAAE,EAAA,EAAI,0BAAA,EAA4B,QAAA,EAAU,cAAA,EAAe;AAAA,MAC3D,EAAE,EAAA,EAAI,6BAAA,EAA+B,QAAA,EAAU,cAAA,EAAe;AAAA,MAC9D,EAAE,EAAA,EAAI,iCAAA,EAAmC,QAAA,EAAU,cAAA;AAAe,KACpE;AAAA,IACA,GAAA,EAAK;AAAA,MACH,SAAA,EAAW;AAAA;AACb,GACF;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,SAAA,EAAW,IAAA;AAAA;AAAA;AAAA;AAAA,IAIX,UAAA,EAAY,IAAA;AAAA,IACZ,UAAA,EAAY,IAAA;AAAA,IACZ,OAAA,EAAS,IAAA;AAAA,IACT,UAAA,EAAY,KAAA;AAAA;AAAA;AAAA,IAGZ,SAAA,EAAW,IAAA;AAAA,IACX,aAAA,EAAe;AAAA,GACjB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,EAAO;AAAA,IACL;AAAA,MACE,EAAA,EAAI,SAAA;AAAA,MACJ,WAAA,EACE;AAAA;AAGJ,GACF;AAAA,EACA,OAAA,EAAS;AAAA,IACP;AAAA,MACE,EAAA,EAAI,OAAA;AAAA;AAAA;AAAA;AAAA,MAIJ,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EACE,mRAAA;AAAA,MAIF,iBAAA,EAAmB,CAAC,SAAA,EAAW,SAAS;AAAA,KAC1C;AAAA,IACA;AAAA,MACE,EAAA,EAAI,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAKJ,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EACE,sVAAA;AAAA,MAKF,GAAA,EAAK,EAAE,kBAAA,EAAoB,SAAA;AAAU,KACvC;AAAA,IACA;AAAA,MACE,EAAA,EAAI,YAAA;AAAA;AAAA;AAAA;AAAA,MAIJ,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EACE,wUAAA;AAAA,MAKF,GAAA,EAAK,EAAE,oBAAA,EAAsB,SAAA;AAAU,KACzC;AAAA,IACA;AAAA,MACE,EAAA,EAAI,UAAA;AAAA;AAAA;AAAA;AAAA,MAIJ,IAAA,EAAM,SAAA;AAAA,MACN,WAAA,EACE,wQAAA;AAAA,MAIF,yBAAA,EAA2B,CAAC,YAAY;AAAA;AAC1C,GACF;AAAA,EACA,MAAM,CAAC,WAAA,EAAa,UAAU,kBAAA,EAAoB,YAAA,EAAc,OAAO,aAAa;AACtF,CAAC;AAEM,SAAS,gBAAA,GAAoC;AAClD,EAAA,OAAO,sBAAsB,SAAS,CAAA;AACxC","file":"index.mjs","sourcesContent":["/**\n * @agentproto/adapter-claude-sdk — first-party adapter that runs Claude Code's\n * agent harness as a LIBRARY.\n *\n * Unlike `@agentproto/adapter-claude-code` (which wraps the third-party\n * `@agentclientprotocol/claude-agent-acp` bridge), this adapter drives the\n * Claude Agent SDK's headless `query()` directly behind an AIP-44 ACP server\n * (see ./acp-host.ts), shipped as a CLI bin (`agentproto-claude-sdk acp`). The\n * daemon spawns it like any other arm; a user can launch it standalone.\n *\n * Driving the SDK directly buys us clean model pinning (`options.model`, no\n * spawn-arg rejection — issue #186), native usage telemetry (a `usage_update`\n * per turn — #186 P3), and a custom `base_url` (`ANTHROPIC_BASE_URL`) that\n * points the same Anthropic-native harness at real Anthropic, Bedrock/Vertex/\n * Azure, or an Anthropic-compatible gateway.\n *\n * import { claudeSdk, claudeSdkRuntime } from \"@agentproto/adapter-claude-sdk\"\n */\n\nimport { fileURLToPath } from \"node:url\"\nimport {\n createAgentCliRuntime,\n defineAgentCli,\n type AgentCliHandle,\n type AgentCliRuntime,\n} from \"@agentproto/driver-agent-cli\"\nimport { DEFAULT_MODEL } from \"./options.js\"\n\n// Self-locating: the built handle spawns `node <this-dist>/cli.mjs acp`.\n// import.meta.url resolves into dist/ at runtime, where cli.mjs sits next to\n// index.mjs — so the same build works whether the daemon spawns it (resolved\n// from node_modules) or a user runs the published bin.\nconst cliEntry = fileURLToPath(new URL(\"./cli.mjs\", import.meta.url))\n\nexport const claudeSdk: AgentCliHandle = defineAgentCli({\n name: \"claude-sdk\",\n id: \"claude-sdk\",\n description:\n \"First-party agentproto adapter — Claude Code's agent harness run as a \" +\n \"library via the Claude Agent SDK's headless query(), behind an AIP-44 ACP \" +\n \"server. 100% Anthropic-native I/O: clean model pinning (options.model), \" +\n \"native per-turn usage (tokens + cost), and a custom base_url \" +\n \"(ANTHROPIC_BASE_URL) to front real Anthropic, Bedrock/Vertex/Azure, or an \" +\n \"Anthropic-compatible gateway. Spawned as `node cli.mjs acp` over stdio \" +\n \"JSON-RPC, or launched standalone via `agentproto-claude-sdk acp`.\",\n version: \"0.1.0\",\n bin: \"node\",\n bin_args: [cliEntry, \"acp\"],\n install: [\n {\n method: \"npm\",\n package: \"@agentproto/adapter-claude-sdk\",\n global: true,\n },\n ],\n // No external runtime to probe — the SDK's harness runs in the spawned node\n // process. A node version gate is enough to mark the arm ready.\n version_check: {\n cmd: \"node --version\",\n parse: \"(\\\\d+\\\\.\\\\d+\\\\.\\\\d+)\",\n range: \">=20.9.0\",\n timeout_ms: 5000,\n },\n auth: {\n ref: \"./claude-sdk.ACP.md\",\n // Auth is read from the spawn env by the SDK. Either an Anthropic key/token\n // (direct or via an Anthropic-compatible gateway), or the cloud-provider\n // toggles below.\n state: {\n env: [\n \"ANTHROPIC_API_KEY\",\n \"ANTHROPIC_AUTH_TOKEN\",\n \"CLAUDE_CODE_USE_BEDROCK\",\n \"CLAUDE_CODE_USE_VERTEX\",\n \"CLAUDE_CODE_USE_FOUNDRY\",\n ],\n },\n },\n // Billing-auth (opt-in — authEnforce defaults to \"when-configured\", so an\n // unconfigured spawn stays ambient/unchanged). provider \"anthropic\" ⇒\n // api-key mode SETS ANTHROPIC_API_KEY. Unlike the claude-code CLI wrapper,\n // the SDK's subscription/bearer var is ANTHROPIC_AUTH_TOKEN (see\n // options.ts / cli.ts) — so that's this adapter's authSubscription.setEnv,\n // with the CLI's CLAUDE_CODE_OAUTH_TOKEN scrubbed as the sibling credential.\n provider: \"anthropic\",\n // A model's route is an independent choice here: gateway routing is\n // injected at runtime via `base_url`, so the same model can go\n // direct-Anthropic or via any gateway → free route selection.\n routeSelection: \"free\",\n authSubscription: {\n setEnv: \"ANTHROPIC_AUTH_TOKEN\",\n conflictEnv: [\"CLAUDE_CODE_OAUTH_TOKEN\"],\n },\n // How this adapter receives a GATEWAY-routed bearer credential (D4) —\n // ANTHROPIC_AUTH_TOKEN, the SAME var as the `auth_token` option below\n // (env: { ANTHROPIC_AUTH_TOKEN: \"{value}\" }) and the one the Claude Agent\n // SDK actually sends as `Authorization: Bearer`. Distinct from a gateway\n // preset's own `keyEnv` (OPENROUTER_API_KEY, MOONSHOT_API_KEY, …) — that's\n // merely where the operator's providers.json stores the key; the runtime's\n // resolveAuthSpec now injects the resolved credential HERE for a gateway\n // route instead, so it lands in a var the SDK actually reads.\n gatewayAuth: { setEnv: \"ANTHROPIC_AUTH_TOKEN\" },\n sandbox:\n \"In-process: the SDK harness runs inside the spawned node process, scoped \" +\n \"to the daemon's cwd. Tool-permission handling defaults to \" +\n \"bypassPermissions (override via CLAUDE_SDK_PERMISSION_MODE); the daemon \" +\n \"owns the surrounding sandbox.\",\n protocol: \"acp\",\n acp: \"./claude-sdk.ACP.md\",\n session: {\n mode: \"persistent\",\n idle_timeout_ms: 1_800_000,\n context_carryover: true,\n },\n models: {\n // A cheap Claude by default — this is the budget first-party arm.\n default: DEFAULT_MODEL,\n // Curated model menu. `provider` states who serves/bills the model; the\n // runtime resolver supplies the matching ANTHROPIC_BASE_URL + credential\n // for gateway providers. This adapter no longer hard-codes gateway URLs\n // or modes — it declares routes/capabilities and consumes runtime-injected\n // ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN. The `model` option remains\n // free-form, so any gateway id works even if it is not listed here.\n allowed: [\n // Native Anthropic\n { id: \"claude-haiku-4-5-20251001\", provider: \"anthropic\" },\n { id: \"claude-sonnet-5\", provider: \"anthropic\" },\n { id: \"claude-opus-4-8\", provider: \"anthropic\" },\n { id: \"claude-fable-5\", provider: \"anthropic\" },\n // Gateway providers — routing is resolved by the runtime. OpenRouter ids\n // carry the `@openrouter` route-identity suffix so the catalog join pins\n // the gateway route (a bare 2-segment id resolves to the dead direct\n // vendor route instead).\n { id: \"kimi-k2.7-code\", provider: \"moonshot\" },\n { id: \"z-ai/glm-5.2@openrouter\", provider: \"openrouter\" },\n { id: \"deepseek/deepseek-v4-pro@openrouter\", provider: \"openrouter\" },\n { id: \"moonshotai/kimi-k2@openrouter\", provider: \"openrouter\" },\n { id: \"x-ai/grok-4.5@openrouter\", provider: \"openrouter\" },\n { id: \"x-ai/grok-4.20@openrouter\", provider: \"openrouter\" },\n { id: \"x-ai/grok-4.3@openrouter\", provider: \"openrouter\" },\n { id: \"google/gemini-3.1-pro-preview@openrouter\", provider: \"openrouter\" },\n { id: \"google/gemini-3.5-flash@openrouter\", provider: \"openrouter\" },\n { id: \"google/gemini-2.5-flash@openrouter\", provider: \"openrouter\" },\n { id: \"google/gemini-2.5-pro@openrouter\", provider: \"openrouter\" },\n { id: \"moonshotai/kimi-k2.7-code@openrouter\", provider: \"openrouter\" },\n // OpenAI gpt-5.6 series via OpenRouter — reachable via ANTHROPIC_BASE_URL\n // + ANTHROPIC_AUTH_TOKEN (the gatewayAuth setEnv above) like the other\n // gateway rows. The `@openrouter` suffix pins the catalog join to the\n // OpenRouter gateway (the bare id would resolve to the direct-OpenAI\n // route, which the SDK's Anthropic surface can't speak). Real,\n // already-priced OpenRouter chat models, not invented specialist ids.\n { id: \"openai/gpt-5.6-luna@openrouter\", provider: \"openrouter\" },\n { id: \"openai/gpt-5.6-sol@openrouter\", provider: \"openrouter\" },\n // Local llm-endpoint proxy — the `@llm-endpoint` suffix pins the catalog\n // join to the runtime-registered custom route (Anthropic surface at\n // localhost:18090). A SMALL curated set from the proxy's own `default`\n // pack (packages/llm-endpoint/src/packs.ts); the vendor prefix is the\n // proxy's transparent-provider name so the boundary-stripped\n // `vendor/product` upstream id transparently routes.\n { id: \"moonshot/kimi-k2.7-code@llm-endpoint\", provider: \"llm-endpoint\" },\n { id: \"moonshot/kimi-k2.6@llm-endpoint\", provider: \"llm-endpoint\" },\n { id: \"zai/glm-5.2@llm-endpoint\", provider: \"llm-endpoint\" },\n { id: \"openai/gpt-4.1@llm-endpoint\", provider: \"llm-endpoint\" },\n { id: \"openai/gpt-4o-mini@llm-endpoint\", provider: \"llm-endpoint\" },\n ],\n env: {\n anthropic: \"ANTHROPIC_API_KEY\",\n },\n },\n capabilities: {\n streaming: true,\n // Claude Code's built-in tools (Read/Edit/Bash/…) and any injected MCP\n // tools run inside the harness and are relayed to the host as ACP\n // tool_call / tool_call_update updates (see acp-host.ts + message-map.ts).\n tool_calls: true,\n sub_agents: true,\n file_io: true,\n multimodal: false,\n // Turns resume via the SDK session store (options.resume), keyed by the\n // pinned session id.\n resumable: true,\n bidirectional: true,\n },\n // Operation modes. Only the native \"default\" profile remains as a manifest\n // mode — gateway routing is now resolved by the runtime and injected via\n // ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN. The adapter declares the\n // providers/models it can consume, but it no longer hard-codes gateway URLs.\n modes: [\n {\n id: \"default\",\n description:\n \"Native Anthropic — the real Anthropic API (or whatever \" +\n \"ANTHROPIC_BASE_URL / cloud toggles the environment or runtime \" +\n \"resolver already sets). Uses the native Claude models in `allowed`.\",\n },\n ],\n options: [\n {\n id: \"model\",\n // string (not enum) so any model id works without a code change — native\n // Claude ids, or a gateway id when a gateway mode is selected. Applied as\n // a `--model <id>` spawn arg → SDK options.model.\n type: \"string\" as const,\n description:\n \"Model id → SDK options.model, applied as a `--model` arg at spawn. \" +\n \"Native Claude (e.g. 'claude-opus-4-8', 'claude-sonnet-5') in the \" +\n \"default mode, or any gateway id when base_url is set (e.g. \" +\n \"'kimi-k2.7-code', 'z-ai/glm-5.2@openrouter'). Omit for the adapter's default.\",\n bin_args_template: [\"--model\", \"{value}\"],\n },\n {\n id: \"base_url\",\n // Injected into the child env as ANTHROPIC_BASE_URL — keeps the harness\n // Anthropic-native while fronting real Anthropic, a cloud provider, or an\n // Anthropic-compatible gateway (LiteLLM / claude-code-router). When set,\n // buildQueryOptions also pins every model tier to `model` (gateway mode).\n type: \"string\" as const,\n description:\n \"Custom Anthropic base URL. Injected as ANTHROPIC_BASE_URL in the \" +\n \"child env — front real Anthropic, Bedrock/Vertex/Azure, or an \" +\n \"Anthropic-compatible gateway. When set, every internal model tier \" +\n \"(opus/sonnet/haiku/small-fast) is pinned to `model` so a single-model \" +\n \"gateway never gets an unservable tier. Omit to use the default endpoint.\",\n env: { ANTHROPIC_BASE_URL: \"{value}\" },\n },\n {\n id: \"auth_token\",\n // Injected into the child env as ANTHROPIC_AUTH_TOKEN — the SDK sends it\n // as `Authorization: Bearer <token>`, which Anthropic-compatible gateways\n // (Moonshot, OpenRouter) accept. Pair with base_url for a per-spawn key.\n type: \"string\" as const,\n description:\n \"Bearer token for the Anthropic API or a compatible gateway. Injected \" +\n \"as ANTHROPIC_AUTH_TOKEN in the child env (sent as `Authorization: \" +\n \"Bearer`). Pair with base_url to target a gateway (e.g. Moonshot, \" +\n \"OpenRouter) with a per-spawn key instead of the ambient \" +\n \"ANTHROPIC_API_KEY. Omit to use ANTHROPIC_API_KEY from the environment.\",\n env: { ANTHROPIC_AUTH_TOKEN: \"{value}\" },\n },\n {\n id: \"thinking\",\n // Bare flag → cli.ts parses `--thinking` → SDK options.thinking =\n // { type: \"enabled\" }. Needed by thinking-gated gateway models such as\n // kimi-k2.7-code, which reject a request that omits `thinking`.\n type: \"boolean\" as const,\n description:\n \"Enable extended thinking (SDK options.thinking = { type: 'enabled' }). \" +\n \"Required by thinking-gated gateway models such as Moonshot's \" +\n \"kimi-k2.7-code, which reject a request without it. Off by default — \" +\n \"native Claude models choose their own thinking behaviour.\",\n bin_args_append_when_true: [\"--thinking\"],\n },\n ],\n tags: [\"anthropic\", \"claude\", \"claude-agent-sdk\", \"agentproto\", \"acp\", \"first-party\"],\n})\n\nexport function claudeSdkRuntime(): AgentCliRuntime {\n return createAgentCliRuntime(claudeSdk)\n}\n\nexport {\n ClaudeSdkAcpAgent,\n promptText,\n type QueryFn,\n} from \"./acp-host.js\"\nexport {\n buildQueryOptions,\n mapAcpMcpServers,\n DEFAULT_MODEL,\n type ClaudeSdkConfig,\n} from \"./options.js\"\nexport {\n sdkMessageToUpdates,\n assistantMessageUpdates,\n userMessageUpdates,\n resultUsageUpdate,\n systemInitSessionId,\n toolKindForClaudeTool,\n toolCallTitle,\n type UsageSessionUpdate,\n} from \"./message-map.js\"\nexport { runAcpOverStdio } from \"./run.js\"\nexport type { AgentCliHandle, AgentCliRuntime }\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentproto/adapter-claude-sdk",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "@agentproto/adapter-claude-sdk — first-party agentproto adapter that runs Claude Code's agent harness as a library via the Claude Agent SDK headless query(), behind an AIP-44 ACP server. 100% Anthropic-native I/O; clean model pinning + base_url; native usage telemetry.",
5
5
  "keywords": [
6
6
  "agentproto",
@@ -48,9 +48,9 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@agentclientprotocol/sdk": "^0.21.0",
51
- "@anthropic-ai/claude-agent-sdk": "^0.3.200",
52
- "@agentproto/driver-agent-cli": "2.0.0",
53
- "@agentproto/provider-presets": "0.4.1"
51
+ "@anthropic-ai/claude-agent-sdk": "^0.3.220",
52
+ "@agentproto/driver-agent-cli": "2.1.0",
53
+ "@agentproto/provider-presets": "0.5.0"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/node": "^25.6.2",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/options.ts","../src/message-map.ts","../src/acp-host.ts","../src/run.ts"],"names":["query","sdkQuery"],"mappings":"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","file":"chunk-DW2G2NIH.mjs","sourcesContent":["/**\n * Build the Claude Agent SDK `Options` for a turn, and map ACP-side inputs\n * (session id, injected MCP servers) onto it. Isolated from the ACP host so\n * the option-shaping is unit-testable without a live SDK.\n */\n\nimport type { McpServer } from \"@agentclientprotocol/sdk\"\nimport type {\n McpServerConfig,\n Options,\n PermissionMode,\n} from \"@anthropic-ai/claude-agent-sdk\"\n\n/** A cheap Claude by default — this is a budget first-party arm. */\nexport const DEFAULT_MODEL = \"claude-haiku-4-5-20251001\"\n\n/**\n * Boolean provider-select toggles the SDK's own `claude` binary groups\n * together with `CLAUDE_CODE_USE_BEDROCK`/`CLAUDE_CODE_USE_VERTEX` (same\n * array, `ac4f1e4` build of `@anthropic-ai/claude-agent-sdk`) to pick a\n * cloud-provider endpoint ahead of `ANTHROPIC_BASE_URL`. Leaking any of these\n * from a Claude-Code parent shell wedges a gateway turn against the wrong\n * provider. Deliberately excludes the non-boolean config members of that same\n * array (`ANTHROPIC_VERTEX_PROJECT_ID`, `ANTHROPIC_AWS_WORKSPACE_ID`,\n * `ANTHROPIC_FOUNDRY_RESOURCE`, `CLOUD_ML_REGION`) and the provider\n * credential/skip-auth vars — both are inert once the toggle that gates them\n * is gone.\n */\nconst CLOUD_PROVIDER_REDIRECT_TOGGLES = [\n \"CLAUDE_CODE_USE_BEDROCK\",\n \"CLAUDE_CODE_USE_VERTEX\",\n \"CLAUDE_CODE_USE_FOUNDRY\",\n \"CLAUDE_CODE_USE_ANTHROPIC_AWS\",\n \"CLAUDE_CODE_USE_MANTLE\",\n \"CLAUDE_CODE_USE_GATEWAY\",\n] as const\n\n/**\n * Default idle watchdog for a turn (ms). If `query()` yields no message for\n * this long, {@link ClaudeSdkConfig.idleTimeoutMs} aborts the turn instead of\n * hanging forever. Ninety seconds: the watchdog is IDLE-based (reset on every\n * SDK message), and a healthy streaming turn — native or gateway — emits\n * messages continuously with sub-second gaps, so a 90s silence means the SDK\n * child is genuinely wedged. The prior 5-minute ceiling was needlessly slow to\n * surface a wedged child; 90s stays well clear of any real inter-message gap\n * while turning a wedged turn around quickly. `0` disables. See\n * {@link ClaudeSdkConfig.idleTimeoutMs}.\n */\nexport const DEFAULT_IDLE_TIMEOUT_MS = 90_000\n\n/** Static config for the adapter, parsed from CLI args / env at boot. */\nexport interface ClaudeSdkConfig {\n /** SDK `options.model`. Defaults to {@link DEFAULT_MODEL}. */\n model?: string\n /** Sets `ANTHROPIC_BASE_URL` in the child env — points the harness at real\n * Anthropic, Bedrock/Vertex/Azure, or an Anthropic-compatible gateway. */\n baseUrl?: string\n /** Sets `ANTHROPIC_AUTH_TOKEN` in the child env — the SDK sends it as\n * `Authorization: Bearer`. Pair with {@link baseUrl} to target a gateway\n * (Moonshot / OpenRouter) with a per-spawn key instead of the ambient\n * `ANTHROPIC_API_KEY`. Never logged. */\n authToken?: string\n /**\n * Enable extended thinking (SDK `options.thinking = { type: \"enabled\" }`).\n * Required by some gateway models (e.g. Moonshot's `kimi-k2.7-code`, which\n * rejects a request without it). Off by default — native Claude models pick\n * their own thinking behaviour.\n */\n thinking?: boolean\n /** Working directory for the session (tools are confined here). */\n cwd?: string\n /**\n * Idle watchdog for a turn, in milliseconds. If the SDK's `query()` iterator\n * produces no message for this long, the turn is aborted with a surfaced\n * error instead of hanging forever. This is a defensive guard against a\n * wedged SDK child — one that stops yielding messages and never delivers the\n * SDK's terminal `result`, nor closes — which would otherwise leave the turn\n * stuck `busy` with zero output (the worst failure mode). The observed cause\n * is environmental, NOT the model or its response shape: a conflicting host\n * env leaking into the spawned SDK subprocess (e.g. a stray\n * `ANTHROPIC_BASE_URL`, or a `CLAUDE_CODE_USE_BEDROCK`/`_VERTEX` auth toggle\n * inherited from a Claude Code shell) can send the child down a path that\n * never completes. Moonshot's own Anthropic-compatible responses (empty\n * `thinking.signature`, a non-`msg_` `chatcmpl-…` id, a `message_delta`-\n * terminated stream) are consumed and finalised correctly by the SDK —\n * verified live end-to-end under a clean env — so the guard is a safety net\n * for a wedged child, not a gateway/response defect. Idle-based (reset on\n * every message), so a legitimately long generation or tool run is\n * unaffected. `0` disables the watchdog. Defaults to\n * {@link DEFAULT_IDLE_TIMEOUT_MS}. Overridable at the CLI via\n * `CLAUDE_SDK_IDLE_TIMEOUT_MS`.\n */\n idleTimeoutMs?: number\n /**\n * How the harness handles tool-permission prompts. Defaults to\n * `bypassPermissions` (with the required danger flag) so the arm can act\n * autonomously inside the daemon's sandbox, mirroring how the claude-code\n * arm is spawned. Override via `CLAUDE_SDK_PERMISSION_MODE`.\n */\n permissionMode?: PermissionMode\n}\n\n/**\n * Map ACP `session/new` MCP server declarations to the SDK's\n * `mcpServers` record (keyed by name). Lets the daemon inject a scoped toolset\n * into the harness exactly like any other arm. Env pairs / headers arrive as\n * `{ name, value }` lists on the wire; flatten them to the record shape the\n * SDK expects.\n */\nexport function mapAcpMcpServers(\n servers: McpServer[] | undefined,\n): Record<string, McpServerConfig> {\n const out: Record<string, McpServerConfig> = {}\n for (const server of servers ?? []) {\n if (\"type\" in server && server.type === \"http\") {\n out[server.name] = {\n type: \"http\",\n url: server.url,\n headers: flattenPairs(server.headers),\n }\n } else if (\"type\" in server && server.type === \"sse\") {\n out[server.name] = {\n type: \"sse\",\n url: server.url,\n headers: flattenPairs(server.headers),\n }\n } else {\n // Stdio is the default (untagged) ACP MCP variant.\n out[server.name] = {\n type: \"stdio\",\n command: server.command,\n args: server.args,\n env: flattenPairs(server.env),\n }\n }\n }\n return out\n}\n\n/** Flatten an ACP `{ name, value }[]` list to a `Record<string, string>`. */\nfunction flattenPairs(\n pairs: Array<{ name: string; value: string }> | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const pair of pairs ?? []) out[pair.name] = pair.value\n return out\n}\n\n/**\n * Assemble the SDK `Options` for a single `query()` call.\n *\n * - `sessionId` pins a stable UUID on the FIRST turn so the ACP session id and\n * the SDK session id match (enabling resume).\n * - `resume` continues that same session on later turns.\n * - Native mode (no `base_url`): the ambient env — `ANTHROPIC_API_KEY` or the\n * Claude Code subscription/OAuth login — is passed through unchanged; an\n * explicit `auth_token` still wins as `ANTHROPIC_AUTH_TOKEN`.\n * - Gateway mode (`base_url` set → a non-Anthropic host): the ambient\n * `ANTHROPIC_API_KEY` is SCRUBBED (it must never be sent to a third-party\n * gateway — that both 401s and leaks the real key). The gateway bearer is\n * resolved from, in order, the explicit `auth_token`, an explicit\n * `ANTHROPIC_AUTH_TOKEN`, or the gateway's conventional key env named by the\n * mode via `CLAUDE_SDK_GATEWAY_KEY_ENV` (e.g. `MOONSHOT_API_KEY`). Every\n * internal model tier is also pinned to the resolved model so a single-model\n * gateway never gets a tier it can't serve (e.g. Moonshot rejecting\n * `claude-haiku-*`). The {@link CLOUD_PROVIDER_REDIRECT_TOGGLES} leaked from\n * a Claude-Code parent shell are also scrubbed so the gateway `base_url`\n * isn't overridden.\n */\nexport function buildQueryOptions(args: {\n config: ClaudeSdkConfig\n abortController: AbortController\n /** Set on the first turn to fix the session UUID. */\n sessionId?: string\n /** Set on resuming turns. */\n resume?: string\n mcpServers?: McpServer[]\n env?: Record<string, string | undefined>\n}): Options {\n const { config, abortController, sessionId, resume, mcpServers } = args\n const model = config.model ?? DEFAULT_MODEL\n const baseEnv = args.env ?? process.env\n const env: Record<string, string | undefined> = { ...baseEnv }\n if (config.baseUrl) {\n // Gateway mode (non-Anthropic host). Auth hygiene: an ambient\n // ANTHROPIC_API_KEY must NEVER reach a third-party gateway (it 401s AND\n // leaks the real Anthropic key). Resolve the gateway bearer from, in order,\n // the explicit auth_token, an explicit ANTHROPIC_AUTH_TOKEN, or the\n // gateway's conventional key env named by the mode via\n // CLAUDE_SDK_GATEWAY_KEY_ENV (e.g. MOONSHOT_API_KEY). Then scrub the\n // Anthropic key so exactly the gateway's own credential is presented; if\n // none resolves, present no credential (fail clean, never leak).\n env.ANTHROPIC_BASE_URL = config.baseUrl\n const gatewayKeyEnv = baseEnv.CLAUDE_SDK_GATEWAY_KEY_ENV\n const bearer =\n config.authToken ??\n baseEnv.ANTHROPIC_AUTH_TOKEN ??\n (gatewayKeyEnv ? baseEnv[gatewayKeyEnv] : undefined)\n delete env.ANTHROPIC_API_KEY\n if (bearer) env.ANTHROPIC_AUTH_TOKEN = bearer\n else delete env.ANTHROPIC_AUTH_TOKEN\n // A Claude-Code parent shell may leak CLAUDE_CODE_USE_BEDROCK / _VERTEX\n // (etc.) into this child's env; the SDK honours those ahead of\n // ANTHROPIC_BASE_URL, silently sending the turn to the wrong provider\n // instead of the gateway (the confirmed cause of turns wedging forever).\n // Scrub so exactly the gateway base_url + bearer are presented.\n for (const key of CLOUD_PROVIDER_REDIRECT_TOGGLES) delete env[key]\n // Pin every tier the harness might request (opus/sonnet/haiku defaults + the\n // small/fast background model) to the one model the gateway serves.\n env.ANTHROPIC_MODEL = model\n env.ANTHROPIC_DEFAULT_OPUS_MODEL = model\n env.ANTHROPIC_DEFAULT_SONNET_MODEL = model\n env.ANTHROPIC_DEFAULT_HAIKU_MODEL = model\n env.ANTHROPIC_SMALL_FAST_MODEL = model\n } else if (config.authToken) {\n // Native Anthropic: an explicit bearer (e.g. a subscription/OAuth token)\n // still wins; otherwise the SDK uses the ambient ANTHROPIC_API_KEY or the\n // Claude Code login (subscription), left untouched.\n env.ANTHROPIC_AUTH_TOKEN = config.authToken\n }\n\n const options: Options = {\n model,\n abortController,\n permissionMode: config.permissionMode ?? \"bypassPermissions\",\n // Required companion to bypassPermissions — this arm runs unattended.\n allowDangerouslySkipPermissions: true,\n // Hermetic embed: don't silently pull in filesystem settings / CLAUDE.md;\n // the daemon owns the configuration surface.\n settingSources: [],\n // Stream partial (`stream_event`) messages so a long thinking / generation\n // stretch is observable live instead of surfacing only at message\n // boundaries. Two things depend on it: (1) the daemon's output ring — the\n // mapped text/thinking deltas keep `lastOutputAt` advancing during a long\n // busy turn instead of freezing until the next tool boundary; and (2) the\n // turn watchdog (acp-host `#nextMessage`), which resets on every SDK\n // message — without partials, a >90s thinking block (kimi-k2.7-code with\n // `--thinking`) yields NO message and the idle watchdog wrongly aborts a\n // healthy turn. See message-map's `streamEventUpdates`.\n includePartialMessages: true,\n env,\n ...(config.cwd ? { cwd: config.cwd } : {}),\n ...(sessionId ? { sessionId } : {}),\n ...(resume ? { resume } : {}),\n }\n // Extended thinking, opt-in. Required by thinking-gated gateway models such\n // as kimi-k2.7-code (rejects a request with no `thinking`). The property's\n // type contextualises the literal, so no cast is needed.\n if (config.thinking) options.thinking = { type: \"enabled\" }\n const mapped = mapAcpMcpServers(mcpServers)\n if (Object.keys(mapped).length > 0) options.mcpServers = mapped\n return options\n}\n","/**\n * Pure mapping from the Claude Agent SDK's message stream (`SDKMessage`, the\n * values `query()` yields) to AIP-44 ACP `session/update` payloads. Kept\n * side-effect free and dependency-light (types only) so it is straightforward\n * to unit-test; the ACP host (acp-host.ts) owns the wire/IO and forwards\n * whatever this returns.\n *\n * I/O stays 100% Anthropic-native: we read the SDK's real message shapes and\n * translate them to ACP updates — no format translation of the model I/O.\n *\n * The SDK emits a typed union on `query()`. We surface:\n * - `stream_event` text delta → ACP `agent_message_chunk` (streamed prose)\n * - `stream_event` thinking delta → ACP `agent_thought_chunk` (streamed reasoning)\n * - `assistant` text blocks → ACP `agent_message_chunk` (assistant prose)\n * - `assistant` tool_use → ACP `tool_call` (a tool started)\n * - `user` tool_result → ACP `tool_call_update` (that tool finished/failed)\n * - `result` → ACP `usage_update` (tokens + cost)\n * The `system`/`init` message carries the SDK `session_id`, handled separately\n * by the host (see {@link systemInitSessionId}).\n *\n * With `includePartialMessages` on (see options.ts), assistant prose arrives\n * TWICE: first as streamed `stream_event` text deltas, then again in the\n * terminal complete `assistant` message. The host tracks whether it saw any\n * partial and asks {@link sdkMessageToUpdates} to suppress the complete\n * message's text so the ring isn't double-fed (see `suppressAssistantText`).\n * `thinking` is only ever surfaced via the streamed deltas — the complete\n * `assistant` message's thinking block is intentionally not mapped.\n */\n\nimport type {\n SDKAssistantMessage,\n SDKMessage,\n SDKPartialAssistantMessage,\n SDKResultMessage,\n SDKSystemMessage,\n SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\"\nimport type { SessionUpdate, ToolKind, UsageUpdate } from \"@agentclientprotocol/sdk\"\n\n/**\n * A `usage_update` session update. ACP's `UsageUpdate` models `size`/`used`/\n * `cost`; we widen it with the optional `tokensIn`/`tokensOut` the agentproto\n * runtime also reads (see packages/acp translateSessionUpdate + runtime\n * sessions.ts), so a session whose adapter reports tokens can be priced even\n * without a `cost`. Assignable to `SessionUpdate` structurally (extra fields\n * are allowed), so no cast is needed.\n */\nexport type UsageSessionUpdate = UsageUpdate & {\n sessionUpdate: \"usage_update\"\n tokensIn?: number\n tokensOut?: number\n}\n\n/** Map a Claude Code built-in tool name to the ACP {@link ToolKind} that\n * drives client icon/UI treatment. Unknown/MCP tools fall back to \"other\". */\nexport function toolKindForClaudeTool(name: string): ToolKind {\n switch (name) {\n case \"Read\":\n case \"NotebookRead\":\n return \"read\"\n case \"Write\":\n case \"Edit\":\n case \"MultiEdit\":\n case \"NotebookEdit\":\n return \"edit\"\n case \"Bash\":\n case \"BashOutput\":\n case \"KillBash\":\n return \"execute\"\n case \"Grep\":\n case \"Glob\":\n return \"search\"\n case \"WebFetch\":\n case \"WebSearch\":\n return \"fetch\"\n case \"Task\":\n return \"think\"\n default:\n return \"other\"\n }\n}\n\n/** Read a string-valued property from an unknown value without an unsafe\n * cast — narrows via `in` and a `typeof` guard. */\nfunction stringField(input: unknown, key: string): string | undefined {\n if (input && typeof input === \"object\" && key in input) {\n const value: unknown = Reflect.get(input, key)\n if (typeof value === \"string\") return value\n }\n return undefined\n}\n\n/** A short, human-readable title for a tool call, e.g. `Bash: ls -la` or\n * `Read: src/index.ts`. Falls back to the bare tool name. */\nexport function toolCallTitle(name: string, input: unknown): string {\n const hint =\n stringField(input, \"command\") ??\n stringField(input, \"file_path\") ??\n stringField(input, \"path\") ??\n stringField(input, \"pattern\") ??\n stringField(input, \"url\")\n return hint ? `${name}: ${hint}` : name\n}\n\n/** Translate one complete `assistant` message into ACP updates: one per text\n * block (agent_message_chunk) and one per tool_use block (tool_call).\n *\n * `suppressText` drops the text blocks — set by the host once it has seen\n * `stream_event` deltas this turn, since the prose already streamed and\n * re-emitting the complete copy would double-feed the ring. tool_use blocks\n * are always emitted (they carry the full input the daemon needs and never\n * arrive as a usable partial). */\nexport function assistantMessageUpdates(\n msg: SDKAssistantMessage,\n suppressText = false,\n): SessionUpdate[] {\n const updates: SessionUpdate[] = []\n for (const block of msg.message.content) {\n if (block.type === \"text\") {\n if (suppressText || !block.text) continue\n updates.push({\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text: block.text },\n })\n } else if (block.type === \"tool_use\") {\n updates.push({\n sessionUpdate: \"tool_call\",\n toolCallId: block.id,\n title: toolCallTitle(block.name, block.input),\n kind: toolKindForClaudeTool(block.name),\n status: \"in_progress\",\n rawInput: block.input,\n })\n }\n }\n return updates\n}\n\n/**\n * Translate a `stream_event` (partial-assistant) message into ACP deltas.\n * Only `content_block_delta` text / thinking deltas carry user-visible content:\n * - `text_delta` → `agent_message_chunk` (streamed assistant prose)\n * - `thinking_delta` → `agent_thought_chunk` (streamed extended-thinking)\n * Every other frame (block start/stop, `input_json_delta`, `signature_delta`,\n * message-level `message_start`/`message_delta`/`message_stop`) produces\n * nothing here — but still counts as an SDK message to the host's turn\n * watchdog, which is exactly why partial streaming keeps a long thinking turn\n * from being mistaken for a stall.\n *\n * Read structurally (via typed field guards) rather than importing the beta\n * `RawContentBlockDelta` union — this file stays dependency-light per its\n * header, and the two delta shapes we care about are tiny and stable\n * (`{ type: \"text_delta\", text }` / `{ type: \"thinking_delta\", thinking }`).\n */\nexport function streamEventUpdates(\n msg: SDKPartialAssistantMessage,\n): SessionUpdate[] {\n const event: unknown = msg.event\n if (stringField(event, \"type\") !== \"content_block_delta\") return []\n const delta =\n event && typeof event === \"object\" ? Reflect.get(event, \"delta\") : undefined\n switch (stringField(delta, \"type\")) {\n case \"text_delta\": {\n const text = stringField(delta, \"text\")\n return text\n ? [\n {\n sessionUpdate: \"agent_message_chunk\",\n content: { type: \"text\", text },\n },\n ]\n : []\n }\n case \"thinking_delta\": {\n const thinking = stringField(delta, \"thinking\")\n return thinking\n ? [\n {\n sessionUpdate: \"agent_thought_chunk\",\n content: { type: \"text\", text: thinking },\n },\n ]\n : []\n }\n default:\n return []\n }\n}\n\n/** Translate a `user` message's tool_result blocks into ACP\n * `tool_call_update`s. Non-tool user echoes (a plain string, or the initial\n * prompt) produce nothing. */\nexport function userMessageUpdates(msg: SDKUserMessage): SessionUpdate[] {\n const content = msg.message.content\n if (typeof content === \"string\") return []\n const updates: SessionUpdate[] = []\n for (const block of content) {\n if (block.type !== \"tool_result\") continue\n updates.push({\n sessionUpdate: \"tool_call_update\",\n toolCallId: block.tool_use_id,\n status: block.is_error ? \"failed\" : \"completed\",\n rawOutput: block.content,\n })\n }\n return updates\n}\n\n/** The largest reported context-window size across the turn's models, or 0. */\nfunction contextWindowOf(msg: SDKResultMessage): number {\n let size = 0\n for (const usage of Object.values(msg.modelUsage)) {\n if (usage.contextWindow > size) size = usage.contextWindow\n }\n return size\n}\n\n/** Translate a `result` message into an ACP `usage_update`. Native Anthropic\n * usage → the shape the runtime already consumes: `size` (context window),\n * `used` (tokens in context), `cost` (from `total_cost_usd`), and the\n * `tokensIn`/`tokensOut` extension. */\nexport function resultUsageUpdate(msg: SDKResultMessage): UsageSessionUpdate {\n const u = msg.usage\n const cacheRead = u.cache_read_input_tokens ?? 0\n const cacheCreate = u.cache_creation_input_tokens ?? 0\n const tokensIn = u.input_tokens + cacheRead + cacheCreate\n const tokensOut = u.output_tokens\n return {\n sessionUpdate: \"usage_update\",\n size: contextWindowOf(msg),\n used: tokensIn + tokensOut,\n cost: { amount: msg.total_cost_usd, currency: \"USD\" },\n tokensIn,\n tokensOut,\n }\n}\n\n/**\n * Dispatch one SDK message to the ACP updates it produces (possibly none).\n * `system`/`init` is intentionally not mapped here — its `session_id` is read\n * by the host via {@link systemInitSessionId}, not surfaced as an update.\n *\n * `suppressAssistantText` is forwarded to {@link assistantMessageUpdates}: the\n * host sets it once a `stream_event` has streamed this turn's prose, so the\n * terminal complete `assistant` message doesn't re-emit the same text.\n */\nexport function sdkMessageToUpdates(\n msg: SDKMessage,\n opts: { suppressAssistantText?: boolean } = {},\n): SessionUpdate[] {\n switch (msg.type) {\n case \"stream_event\":\n return streamEventUpdates(msg)\n case \"assistant\":\n return assistantMessageUpdates(msg, opts.suppressAssistantText ?? false)\n case \"user\":\n return userMessageUpdates(msg)\n case \"result\":\n return [resultUsageUpdate(msg)]\n default:\n return []\n }\n}\n\n/** Extract the SDK `session_id` from the `system`/`init` message, else null. */\nexport function systemInitSessionId(msg: SDKMessage): string | null {\n if (msg.type === \"system\" && isInit(msg)) return msg.session_id\n return null\n}\n\n/** Narrow a `system` message to its `init` subtype (which carries the\n * authoritative `session_id` and model). */\nfunction isInit(msg: SDKMessage & { type: \"system\" }): msg is SDKSystemMessage {\n return msg.subtype === \"init\"\n}\n","/**\n * The agent side of AIP-44 ACP, backed by the Claude Agent SDK's headless\n * `query()`.\n *\n * Implements the `@agentclientprotocol/sdk` `Agent` interface: on\n * `session/prompt` it drives `query({ prompt, options })` and relays the SDK's\n * native message stream as ACP `session/update`s (assistant text, tool calls,\n * usage). I/O stays 100% Anthropic-native — no format translation of the model\n * I/O — so the daemon spawns this like any other ACP arm.\n *\n * Session identity: ACP requires a session id at `session/new`, before any\n * `query()` has run. We generate a UUID there and PIN it via the SDK's\n * `options.sessionId` on the first turn, so our ACP session id and the SDK's\n * `session_id` are the same value — which then feeds `options.resume` on later\n * turns (agentproto resume).\n */\n\nimport type {\n AgentSideConnection,\n Agent as AcpAgent,\n AuthenticateRequest,\n CancelNotification,\n InitializeRequest,\n InitializeResponse,\n McpServer,\n NewSessionRequest,\n NewSessionResponse,\n PromptRequest,\n PromptResponse,\n SetSessionConfigOptionRequest,\n SetSessionConfigOptionResponse,\n SetSessionModeRequest,\n} from \"@agentclientprotocol/sdk\"\nimport { PROTOCOL_VERSION } from \"@agentclientprotocol/sdk\"\nimport {\n query as sdkQuery,\n type Options,\n type SDKMessage,\n type SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\"\nimport { sdkMessageToUpdates, systemInitSessionId } from \"./message-map.js\"\nimport {\n buildQueryOptions,\n DEFAULT_IDLE_TIMEOUT_MS,\n type ClaudeSdkConfig,\n} from \"./options.js\"\n\n/** The single SDK entry point we depend on — the headless async generator.\n * Typed structurally and injectable so tests can drive the host with a faked\n * message stream (no live Anthropic key required). */\nexport type QueryFn = (params: {\n prompt: string | AsyncIterable<SDKUserMessage>\n options?: Options\n}) => AsyncIterable<SDKMessage>\n\ninterface SessionState {\n /** The pinned ACP/SDK session id. */\n readonly id: string\n /** MCP servers injected by the daemon at `session/new`. */\n readonly mcpServers: McpServer[]\n /** null until the first turn has pinned the SDK session. */\n started: boolean\n /** The SDK's own session id, adopted from the `init` message. */\n sdkSessionId: string | null\n /** In-flight turn, for cancellation. */\n prompt: AbortController | null\n}\n\n/** A message from an unknown thrown value, without an unsafe cast. */\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\n/**\n * Thrown by the {@link ClaudeSdkAcpAgent}'s turn watchdog when `query()` stops\n * yielding messages: the SDK child wedged and never delivered the terminal\n * `result`, so the async iterator would otherwise never terminate. A defensive\n * safety net for an environmentally wedged child (e.g. a conflicting host env\n * leaked into the SDK subprocess), not a response-shape problem — a healthy\n * turn always reaches `result`. Distinct from a user cancel so the host\n * surfaces it as an error rather than silently reporting the turn as cancelled.\n */\nexport class TurnStalledError extends Error {\n constructor(public readonly idleMs: number) {\n super(\n `claude-sdk: query() produced no message for ${idleMs}ms — the model ` +\n `stream stalled and never delivered a terminal result. Aborting the ` +\n `turn to avoid a silent, zero-output hang. If this was a slow but ` +\n `healthy turn, raise CLAUDE_SDK_IDLE_TIMEOUT_MS.`,\n )\n this.name = \"TurnStalledError\"\n }\n}\n\n/** Pull the user's text out of an ACP prompt (its `text` content blocks). */\nexport function promptText(params: PromptRequest): string {\n return params.prompt\n .filter((b) => b.type === \"text\")\n .map((b) => b.text)\n .join(\"\")\n .trim()\n}\n\nexport class ClaudeSdkAcpAgent implements AcpAgent {\n readonly #conn: AgentSideConnection\n readonly #config: ClaudeSdkConfig\n readonly #query: QueryFn\n readonly #sessions = new Map<string, SessionState>()\n\n constructor(\n conn: AgentSideConnection,\n config: ClaudeSdkConfig = {},\n query: QueryFn = sdkQuery,\n ) {\n this.#conn = conn\n this.#config = config\n this.#query = query\n }\n\n async initialize(_params: InitializeRequest): Promise<InitializeResponse> {\n return {\n protocolVersion: PROTOCOL_VERSION,\n agentCapabilities: {\n // Turns resume via the SDK's session store (options.resume), keyed by\n // the pinned session id — but there is no ACP `session/load` replay\n // surface, so we advertise loadSession: false.\n loadSession: false,\n },\n }\n }\n\n async authenticate(\n _params: AuthenticateRequest,\n ): Promise<Record<string, never>> {\n // Auth (ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, or Bedrock/Vertex/Foundry\n // env) is read from the spawn env by the SDK — no ACP-level handshake.\n return {}\n }\n\n async newSession(params: NewSessionRequest): Promise<NewSessionResponse> {\n const id = crypto.randomUUID()\n this.#sessions.set(id, {\n id,\n mcpServers: params.mcpServers ?? [],\n started: false,\n sdkSessionId: null,\n prompt: null,\n })\n return { sessionId: id }\n }\n\n async prompt(params: PromptRequest): Promise<PromptResponse> {\n const session = this.#sessions.get(params.sessionId)\n if (!session) throw new Error(`unknown session ${params.sessionId}`)\n\n // Cancel any in-flight turn for this session before starting a new one.\n session.prompt?.abort()\n const ac = new AbortController()\n session.prompt = ac\n\n const text = promptText(params)\n try {\n const options = buildQueryOptions({\n config: this.#config,\n abortController: ac,\n // First turn pins the id; later turns resume the SDK session.\n ...(session.started\n ? { resume: session.sdkSessionId ?? session.id }\n : { sessionId: session.id }),\n mcpServers: session.mcpServers,\n })\n session.started = true\n\n await this.#drive(session, text, options, ac)\n } catch (err) {\n // A watchdog stall aborts `ac` to tear down the SDK subprocess, so check\n // the stall FIRST — otherwise it would masquerade as a user cancel and be\n // silently swallowed, which is exactly the zero-output failure we fix.\n if (ac.signal.aborted && !(err instanceof TurnStalledError)) {\n session.prompt = null\n return { stopReason: \"cancelled\" }\n }\n // Surface the failure as a message chunk, then end the turn — better UX\n // than a bare JSON-RPC error the host may swallow.\n await this.#conn.sessionUpdate({\n sessionId: session.id,\n update: {\n sessionUpdate: \"agent_message_chunk\",\n content: {\n type: \"text\",\n text: `\\n[claude-sdk error] ${errorMessage(err)}\\n`,\n },\n },\n })\n session.prompt = null\n return { stopReason: \"refusal\" }\n }\n\n const cancelled = ac.signal.aborted\n session.prompt = null\n return { stopReason: cancelled ? \"cancelled\" : \"end_turn\" }\n }\n\n async cancel(params: CancelNotification): Promise<void> {\n this.#sessions.get(params.sessionId)?.prompt?.abort()\n }\n\n /**\n * The daemon applies operator options (model, base_url) at spawn — via the\n * manifest's `bin_args_template` / `env` — then also calls this ACP config\n * hook (its default \"config apply\" path). Everything is already in effect,\n * so this reports our (empty) runtime-configurable set. Without it the spawn\n * fails with \"Method not found: session/set_config_option\".\n */\n async setSessionConfigOption(\n _params: SetSessionConfigOptionRequest,\n ): Promise<SetSessionConfigOptionResponse> {\n return { configOptions: [] }\n }\n\n /** No agent-specific modes; accept and ignore so a host that sets one\n * doesn't error. */\n async setSessionMode(\n _params: SetSessionModeRequest,\n ): Promise<Record<string, never>> {\n return {}\n }\n\n /** Drive one `query()` turn: adopt the SDK session id from `init`, then map\n * each SDK message to ACP updates and relay them.\n *\n * Iteration is driven manually (rather than `for await`) so an idle watchdog\n * can bound the wait for each next message. If the SDK child wedges mid-turn\n * — stops yielding messages without delivering the terminal `result` and\n * without closing (e.g. a conflicting host env leaked into the subprocess) —\n * the watchdog aborts the turn with a {@link TurnStalledError} instead of\n * awaiting forever with zero output. A defensive safety net; a well-behaved\n * turn (Moonshot included, under a clean env) reaches `result` and this\n * never fires. */\n async #drive(\n session: SessionState,\n text: string,\n options: Options,\n ac: AbortController,\n ): Promise<void> {\n const idleMs = this.#config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS\n const iterator = this.#query({ prompt: text, options })[\n Symbol.asyncIterator\n ]()\n // Once a `stream_event` has streamed this turn's prose, the terminal\n // complete `assistant` message repeats it — suppress its text so the ring\n // isn't fed the same prose twice (see message-map's suppressAssistantText).\n let sawPartial = false\n try {\n while (!ac.signal.aborted) {\n const next = await this.#nextMessage(iterator, idleMs, ac)\n if (next.done) break\n const msg = next.value\n const sdkId = systemInitSessionId(msg)\n if (sdkId) session.sdkSessionId = sdkId\n if (msg.type === \"stream_event\") sawPartial = true\n for (const update of sdkMessageToUpdates(msg, {\n suppressAssistantText: sawPartial,\n })) {\n await this.#conn.sessionUpdate({ sessionId: session.id, update })\n }\n }\n } finally {\n // Best-effort generator close on any exit (stall, cancel, error). Do NOT\n // await it: on a stall the generator is suspended mid-`await` and its\n // `.return()` never settles, so awaiting here would re-introduce the very\n // hang we guard against. The turn's AbortController — already aborted on\n // a stall or a cancel — is what actually tears the SDK subprocess down.\n void Promise.resolve(iterator.return?.(undefined)).catch(() => undefined)\n }\n }\n\n /**\n * Await the next SDK message, but no longer than `idleMs`. On timeout the\n * turn is treated as stalled: abort the shared controller (tearing down the\n * SDK subprocess) and reject with {@link TurnStalledError}. `idleMs <= 0`\n * disables the watchdog and awaits indefinitely (legacy behaviour).\n */\n async #nextMessage(\n iterator: AsyncIterator<SDKMessage>,\n idleMs: number,\n ac: AbortController,\n ): Promise<IteratorResult<SDKMessage>> {\n const next = iterator.next()\n if (idleMs <= 0) return next\n // If the watchdog wins the race, `next` settles later with nobody awaiting\n // it; pre-attach a no-op handler so a late rejection isn't \"unhandled\".\n void next.catch(() => undefined)\n let timer: ReturnType<typeof setTimeout> | undefined\n const watchdog = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n ac.abort()\n reject(new TurnStalledError(idleMs))\n }, idleMs)\n // Don't let the watchdog alone keep the event loop alive.\n timer.unref()\n })\n try {\n return await Promise.race([next, watchdog])\n } finally {\n if (timer) clearTimeout(timer)\n }\n }\n}\n","/**\n * Boots the ACP server over stdio — the standard wiring for a spawned ACP\n * agent (mirrors the @agentclientprotocol/sdk agent example): the agent writes\n * JSON-RPC to stdout and reads from stdin.\n */\n\nimport { Readable, Writable } from \"node:stream\"\nimport { AgentSideConnection, ndJsonStream } from \"@agentclientprotocol/sdk\"\nimport { ClaudeSdkAcpAgent } from \"./acp-host.js\"\nimport type { ClaudeSdkConfig } from \"./options.js\"\n\nexport function runAcpOverStdio(\n config: ClaudeSdkConfig = {},\n): AgentSideConnection {\n // ndJsonStream(writable, readable): outgoing bytes -> stdout, incoming <- stdin.\n const toClient = Writable.toWeb(process.stdout) as WritableStream<Uint8Array>\n const fromClient = Readable.toWeb(\n process.stdin,\n ) as unknown as ReadableStream<Uint8Array>\n const stream = ndJsonStream(toClient, fromClient)\n return new AgentSideConnection(\n (conn) => new ClaudeSdkAcpAgent(conn, config),\n stream,\n )\n}\n"]}