@agentproto/adapter-claude-sdk 0.5.7 → 0.5.9

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.
@@ -50,10 +50,27 @@ function flattenPairs(pairs) {
50
50
  for (const pair of pairs ?? []) out[pair.name] = pair.value;
51
51
  return out;
52
52
  }
53
+ var UnroutedGatewayModelError = class extends Error {
54
+ constructor(model) {
55
+ super(
56
+ `claude-sdk: model "${model}" is a vendor/product catalog ref, but no base_url is configured to route it \u2014 this adapter would otherwise send it straight to the real Anthropic API, which either 400s ("not a valid model ID") or silently falls back to a real Claude model, still billed. Set a base_url that fronts the provider that actually serves "${model}" (e.g. route.gateway: "openrouter" for an OpenRouter-hosted model), or request a native claude-* model instead.`
57
+ );
58
+ this.name = "UnroutedGatewayModelError";
59
+ }
60
+ };
61
+ function isVendorProductModelRef(model) {
62
+ return model.includes("/");
63
+ }
64
+ function hasCloudProviderRedirect(env) {
65
+ return CLOUD_PROVIDER_REDIRECT_TOGGLES.some((key) => Boolean(env[key]));
66
+ }
53
67
  function buildQueryOptions(args) {
54
68
  const { config, abortController, sessionId, resume, mcpServers } = args;
55
69
  const model = config.model ?? DEFAULT_MODEL;
56
70
  const baseEnv = args.env ?? process.env;
71
+ if (!config.baseUrl && isVendorProductModelRef(model) && !hasCloudProviderRedirect(baseEnv)) {
72
+ throw new UnroutedGatewayModelError(model);
73
+ }
57
74
  const env = { ...baseEnv };
58
75
  if (config.baseUrl) {
59
76
  env.ANTHROPIC_BASE_URL = config.baseUrl;
@@ -438,6 +455,6 @@ function runAcpOverStdio(config = {}) {
438
455
  );
439
456
  }
440
457
 
441
- export { ClaudeSdkAcpAgent, DEFAULT_MODEL, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates };
442
- //# sourceMappingURL=chunk-2LNYIR6L.mjs.map
443
- //# sourceMappingURL=chunk-2LNYIR6L.mjs.map
458
+ export { ClaudeSdkAcpAgent, DEFAULT_MODEL, UnroutedGatewayModelError, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates };
459
+ //# sourceMappingURL=chunk-TT4O3BGM.mjs.map
460
+ //# sourceMappingURL=chunk-TT4O3BGM.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":";;;;;;;;;;AAcO,IAAM,aAAA,GAAgB;AAc7B,IAAM,+BAAA,GAAkC;AAAA,EACtC,yBAAA;AAAA,EACA,wBAAA;AAAA,EACA,yBAAA;AAAA,EACA,+BAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF,CAAA;AAaO,IAAM,uBAAA,GAA0B,GAAA;AAWhC,IAAM,4BAAA,GAA+B,GAAA;AAwErC,SAAS,iBACd,OAAA,EACiC;AACjC,EAAA,MAAM,MAAuC,EAAC;AAC9C,EAAA,KAAA,MAAW,MAAA,IAAU,OAAA,IAAW,EAAC,EAAG;AAClC,IAAA,IAAI,MAAA,IAAU,MAAA,IAAU,MAAA,CAAO,IAAA,KAAS,MAAA,EAAQ;AAC9C,MAAA,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI;AAAA,QACjB,IAAA,EAAM,MAAA;AAAA,QACN,KAAK,MAAA,CAAO,GAAA;AAAA,QACZ,OAAA,EAAS,YAAA,CAAa,MAAA,CAAO,OAAO;AAAA,OACtC;AAAA,IACF,CAAA,MAAA,IAAW,MAAA,IAAU,MAAA,IAAU,MAAA,CAAO,SAAS,KAAA,EAAO;AACpD,MAAA,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI;AAAA,QACjB,IAAA,EAAM,KAAA;AAAA,QACN,KAAK,MAAA,CAAO,GAAA;AAAA,QACZ,OAAA,EAAS,YAAA,CAAa,MAAA,CAAO,OAAO;AAAA,OACtC;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI;AAAA,QACjB,IAAA,EAAM,OAAA;AAAA,QACN,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,MAAM,MAAA,CAAO,IAAA;AAAA,QACb,GAAA,EAAK,YAAA,CAAa,MAAA,CAAO,GAAG;AAAA,OAC9B;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAGA,SAAS,aACP,KAAA,EACwB;AACxB,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAS,EAAC,MAAO,IAAA,CAAK,IAAI,IAAI,IAAA,CAAK,KAAA;AACtD,EAAA,OAAO,GAAA;AACT;AASO,IAAM,yBAAA,GAAN,cAAwC,KAAA,CAAM;AAAA,EACnD,YAAY,KAAA,EAAe;AACzB,IAAA,KAAA;AAAA,MACE,CAAA,mBAAA,EAAsB,KAAK,CAAA,mUAAA,EAKd,KAAK,CAAA,gHAAA;AAAA,KAEpB;AACA,IAAA,IAAA,CAAK,IAAA,GAAO,2BAAA;AAAA,EACd;AACF;AAeA,SAAS,wBAAwB,KAAA,EAAwB;AACvD,EAAA,OAAO,KAAA,CAAM,SAAS,GAAG,CAAA;AAC3B;AASA,SAAS,yBACP,GAAA,EACS;AACT,EAAA,OAAO,+BAAA,CAAgC,KAAK,CAAC,GAAA,KAAQ,QAAQ,GAAA,CAAI,GAAG,CAAC,CAAC,CAAA;AACxE;AAuCO,SAAS,kBAAkB,IAAA,EAStB;AACV,EAAA,MAAM,EAAE,MAAA,EAAQ,eAAA,EAAiB,SAAA,EAAW,MAAA,EAAQ,YAAW,GAAI,IAAA;AACnE,EAAA,MAAM,KAAA,GAAQ,OAAO,KAAA,IAAS,aAAA;AAC9B,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA;AACpC,EAAA,IACE,CAAC,OAAO,OAAA,IACR,uBAAA,CAAwB,KAAK,CAAA,IAC7B,CAAC,wBAAA,CAAyB,OAAO,CAAA,EACjC;AACA,IAAA,MAAM,IAAI,0BAA0B,KAAK,CAAA;AAAA,EAC3C;AACA,EAAA,MAAM,GAAA,GAA0C,EAAE,GAAG,OAAA,EAAQ;AAC7D,EAAA,IAAI,OAAO,OAAA,EAAS;AAOlB,IAAA,GAAA,CAAI,qBAAqB,MAAA,CAAO,OAAA;AAChC,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,IAAa,OAAA,CAAQ,oBAAA;AAC3C,IAAA,OAAO,GAAA,CAAI,iBAAA;AACX,IAAA,IAAI,MAAA,MAAY,oBAAA,GAAuB,MAAA;AAAA,gBAC3B,GAAA,CAAI,oBAAA;AAMhB,IAAA,KAAA,MAAW,GAAA,IAAO,+BAAA,EAAiC,OAAO,GAAA,CAAI,GAAG,CAAA;AAGjE,IAAA,GAAA,CAAI,eAAA,GAAkB,KAAA;AACtB,IAAA,GAAA,CAAI,4BAAA,GAA+B,KAAA;AACnC,IAAA,GAAA,CAAI,8BAAA,GAAiC,KAAA;AACrC,IAAA,GAAA,CAAI,6BAAA,GAAgC,KAAA;AACpC,IAAA,GAAA,CAAI,0BAAA,GAA6B,KAAA;AAAA,EACnC,CAAA,MAAA,IAAW,OAAO,SAAA,EAAW;AAI3B,IAAA,GAAA,CAAI,uBAAuB,MAAA,CAAO,SAAA;AAAA,EACpC;AAEA,EAAA,MAAM,OAAA,GAAmB;AAAA,IACvB,KAAA;AAAA,IACA,eAAA;AAAA,IACA,cAAA,EAAgB,OAAO,cAAA,IAAkB,mBAAA;AAAA;AAAA,IAEzC,+BAAA,EAAiC,IAAA;AAAA;AAAA;AAAA,IAGjC,gBAAgB,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUjB,sBAAA,EAAwB,IAAA;AAAA,IACxB,GAAA;AAAA,IACA,GAAI,OAAO,GAAA,GAAM,EAAE,KAAK,MAAA,CAAO,GAAA,KAAQ,EAAC;AAAA,IACxC,GAAI,SAAA,GAAY,EAAE,SAAA,KAAc,EAAC;AAAA,IACjC,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW;AAAC,GAC7B;AAIA,EAAA,IAAI,OAAO,QAAA,EAAU,OAAA,CAAQ,QAAA,GAAW,EAAE,MAAM,SAAA,EAAU;AAC1D,EAAA,MAAM,MAAA,GAAS,iBAAiB,UAAU,CAAA;AAC1C,EAAA,IAAI,OAAO,IAAA,CAAK,MAAM,EAAE,MAAA,GAAS,CAAA,UAAW,UAAA,GAAa,MAAA;AACzD,EAAA,OAAO,OAAA;AACT;;;AChSO,SAAS,sBAAsB,IAAA,EAAwB;AAC5D,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,OAAA;AAAA,IACL,KAAK,MAAA;AAAA,IACL,KAAK,WAAA;AAAA,IACL,KAAK,cAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,MAAA;AAAA,IACL,KAAK,YAAA;AAAA,IACL,KAAK,UAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,MAAA;AAAA,IACL,KAAK,MAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,UAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT;AACE,MAAA,OAAO,OAAA;AAAA;AAEb;AAIA,SAAS,WAAA,CAAY,OAAgB,GAAA,EAAiC;AACpE,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,KAAA,EAAO;AACtD,IAAA,MAAM,KAAA,GAAiB,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,GAAG,CAAA;AAC7C,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AAAA,EACxC;AACA,EAAA,OAAO,MAAA;AACT;AAIO,SAAS,aAAA,CAAc,MAAc,KAAA,EAAwB;AAClE,EAAA,MAAM,OACJ,WAAA,CAAY,KAAA,EAAO,SAAS,CAAA,IAC5B,WAAA,CAAY,OAAO,WAAW,CAAA,IAC9B,YAAY,KAAA,EAAO,MAAM,KACzB,WAAA,CAAY,KAAA,EAAO,SAAS,CAAA,IAC5B,WAAA,CAAY,OAAO,KAAK,CAAA;AAC1B,EAAA,OAAO,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,GAAK,IAAA;AACrC;AAUO,SAAS,uBAAA,CACd,GAAA,EACA,YAAA,GAAe,KAAA,EACE;AACjB,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,KAAA,MAAW,KAAA,IAAS,GAAA,CAAI,OAAA,CAAQ,OAAA,EAAS;AACvC,IAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAQ;AACzB,MAAA,IAAI,YAAA,IAAgB,CAAC,KAAA,CAAM,IAAA,EAAM;AACjC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,aAAA,EAAe,qBAAA;AAAA,QACf,SAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,MAAM,IAAA;AAAK,OAC3C,CAAA;AAAA,IACH,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,UAAA,EAAY;AACpC,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,aAAA,EAAe,WAAA;AAAA,QACf,YAAY,KAAA,CAAM,EAAA;AAAA,QAClB,KAAA,EAAO,aAAA,CAAc,KAAA,CAAM,IAAA,EAAM,MAAM,KAAK,CAAA;AAAA,QAC5C,IAAA,EAAM,qBAAA,CAAsB,KAAA,CAAM,IAAI,CAAA;AAAA,QACtC,MAAA,EAAQ,aAAA;AAAA,QACR,UAAU,KAAA,CAAM;AAAA,OACjB,CAAA;AAAA,IACH;AAAA,EACF;AACA,EAAA,OAAO,OAAA;AACT;AAkBO,SAAS,mBACd,GAAA,EACiB;AACjB,EAAA,MAAM,QAAiB,GAAA,CAAI,KAAA;AAC3B,EAAA,IAAI,YAAY,KAAA,EAAO,MAAM,CAAA,KAAM,qBAAA,SAA8B,EAAC;AAClE,EAAA,MAAM,KAAA,GACJ,SAAS,OAAO,KAAA,KAAU,WAAW,OAAA,CAAQ,GAAA,CAAI,KAAA,EAAO,OAAO,CAAA,GAAI,MAAA;AACrE,EAAA,QAAQ,WAAA,CAAY,KAAA,EAAO,MAAM,CAAA;AAAG,IAClC,KAAK,YAAA,EAAc;AACjB,MAAA,MAAM,IAAA,GAAO,WAAA,CAAY,KAAA,EAAO,MAAM,CAAA;AACtC,MAAA,OAAO,IAAA,GACH;AAAA,QACE;AAAA,UACE,aAAA,EAAe,qBAAA;AAAA,UACf,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA;AAAK;AAChC,UAEF,EAAC;AAAA,IACP;AAAA,IACA,KAAK,gBAAA,EAAkB;AACrB,MAAA,MAAM,QAAA,GAAW,WAAA,CAAY,KAAA,EAAO,UAAU,CAAA;AAC9C,MAAA,OAAO,QAAA,GACH;AAAA,QACE;AAAA,UACE,aAAA,EAAe,qBAAA;AAAA,UACf,OAAA,EAAS,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,QAAA;AAAS;AAC1C,UAEF,EAAC;AAAA,IACP;AAAA,IACA;AACE,MAAA,OAAO,EAAC;AAAA;AAEd;AAKO,SAAS,mBAAmB,GAAA,EAAsC;AACvE,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,OAAA;AAC5B,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,EAAC;AACzC,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,KAAA,CAAM,SAAS,aAAA,EAAe;AAClC,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,aAAA,EAAe,kBAAA;AAAA,MACf,YAAY,KAAA,CAAM,WAAA;AAAA,MAClB,MAAA,EAAQ,KAAA,CAAM,QAAA,GAAW,QAAA,GAAW,WAAA;AAAA,MACpC,WAAW,KAAA,CAAM;AAAA,KAClB,CAAA;AAAA,EACH;AACA,EAAA,OAAO,OAAA;AACT;AAGA,SAAS,gBAAgB,GAAA,EAA+B;AACtD,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,UAAU,CAAA,EAAG;AACjD,IAAA,IAAI,KAAA,CAAM,aAAA,GAAgB,IAAA,EAAM,IAAA,GAAO,KAAA,CAAM,aAAA;AAAA,EAC/C;AACA,EAAA,OAAO,IAAA;AACT;AAMO,SAAS,kBAAkB,GAAA,EAA2C;AAC3E,EAAA,MAAM,IAAI,GAAA,CAAI,KAAA;AACd,EAAA,MAAM,SAAA,GAAY,EAAE,uBAAA,IAA2B,CAAA;AAC/C,EAAA,MAAM,WAAA,GAAc,EAAE,2BAAA,IAA+B,CAAA;AACrD,EAAA,MAAM,QAAA,GAAW,CAAA,CAAE,YAAA,GAAe,SAAA,GAAY,WAAA;AAC9C,EAAA,MAAM,YAAY,CAAA,CAAE,aAAA;AACpB,EAAA,OAAO;AAAA,IACL,aAAA,EAAe,cAAA;AAAA,IACf,IAAA,EAAM,gBAAgB,GAAG,CAAA;AAAA,IACzB,MAAM,QAAA,GAAW,SAAA;AAAA,IACjB,MAAM,EAAE,MAAA,EAAQ,GAAA,CAAI,cAAA,EAAgB,UAAU,KAAA,EAAM;AAAA,IACpD,QAAA;AAAA,IACA;AAAA,GACF;AACF;AAWO,SAAS,mBAAA,CACd,GAAA,EACA,IAAA,GAA4C,EAAC,EAC5B;AACjB,EAAA,QAAQ,IAAI,IAAA;AAAM,IAChB,KAAK,cAAA;AACH,MAAA,OAAO,mBAAmB,GAAG,CAAA;AAAA,IAC/B,KAAK,WAAA;AACH,MAAA,OAAO,uBAAA,CAAwB,GAAA,EAAK,IAAA,CAAK,qBAAA,IAAyB,KAAK,CAAA;AAAA,IACzE,KAAK,MAAA;AACH,MAAA,OAAO,mBAAmB,GAAG,CAAA;AAAA,IAC/B,KAAK,QAAA;AACH,MAAA,OAAO,CAAC,iBAAA,CAAkB,GAAG,CAAC,CAAA;AAAA,IAChC;AACE,MAAA,OAAO,EAAC;AAAA;AAEd;AAGO,SAAS,oBAAoB,GAAA,EAAgC;AAClE,EAAA,IAAI,IAAI,IAAA,KAAS,QAAA,IAAY,OAAO,GAAG,CAAA,SAAU,GAAA,CAAI,UAAA;AACrD,EAAA,OAAO,IAAA;AACT;AAIA,SAAS,OAAO,GAAA,EAA+D;AAC7E,EAAA,OAAO,IAAI,OAAA,KAAY,MAAA;AACzB;AC5MA,SAAS,aAAa,GAAA,EAAsB;AAC1C,EAAA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AACxD;AAWO,IAAM,gBAAA,GAAN,cAA+B,KAAA,CAAM;AAAA,EAC1C,YAA4B,MAAA,EAAgB;AAC1C,IAAA,KAAA;AAAA,MACE,+CAA+C,MAAM,CAAA,uMAAA;AAAA,KAIvD;AAN0B,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAO1B,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AAAA,EAR4B,MAAA;AAS9B,CAAA;AAGO,SAAS,WAAW,MAAA,EAA+B;AACxD,EAAA,OAAO,OAAO,MAAA,CACX,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,MAAM,CAAA,CAC/B,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAI,EACjB,IAAA,CAAK,EAAE,EACP,IAAA,EAAK;AACV;AAEO,IAAM,oBAAN,MAA4C;AAAA,EACxC,KAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,uBAAgB,GAAA,EAA0B;AAAA,EAEnD,YACE,IAAA,EACA,MAAA,GAA0B,EAAC,EAC3BA,UAAiBC,KAAA,EACjB;AACA,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,MAAA,GAASD,OAAA;AAAA,EAChB;AAAA,EAEA,MAAM,WAAW,OAAA,EAAyD;AACxE,IAAA,OAAO;AAAA,MACL,eAAA,EAAiB,gBAAA;AAAA,MACjB,iBAAA,EAAmB;AAAA;AAAA;AAAA;AAAA,QAIjB,WAAA,EAAa;AAAA;AACf,KACF;AAAA,EACF;AAAA,EAEA,MAAM,aACJ,OAAA,EACgC;AAGhC,IAAA,OAAO,EAAC;AAAA,EACV;AAAA,EAEA,MAAM,WAAW,MAAA,EAAwD;AACvE,IAAA,MAAM,EAAA,GAAK,OAAO,UAAA,EAAW;AAC7B,IAAA,IAAA,CAAK,SAAA,CAAU,IAAI,EAAA,EAAI;AAAA,MACrB,EAAA;AAAA,MACA,UAAA,EAAY,MAAA,CAAO,UAAA,IAAc,EAAC;AAAA,MAClC,OAAA,EAAS,KAAA;AAAA,MACT,YAAA,EAAc,IAAA;AAAA,MACd,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,OAAO,EAAE,WAAW,EAAA,EAAG;AAAA,EACzB;AAAA,EAEA,MAAM,OAAO,MAAA,EAAgD;AAC3D,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,OAAO,SAAS,CAAA;AACnD,IAAA,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,CAAA,gBAAA,EAAmB,MAAA,CAAO,SAAS,CAAA,CAAE,CAAA;AAGnE,IAAA,OAAA,CAAQ,QAAQ,KAAA,EAAM;AACtB,IAAA,MAAM,EAAA,GAAK,IAAI,eAAA,EAAgB;AAC/B,IAAA,OAAA,CAAQ,MAAA,GAAS,EAAA;AAEjB,IAAA,MAAM,IAAA,GAAO,WAAW,MAAM,CAAA;AAC9B,IAAA,IAAI;AACF,MAAA,MAAM,UAAU,iBAAA,CAAkB;AAAA,QAChC,QAAQ,IAAA,CAAK,OAAA;AAAA,QACb,eAAA,EAAiB,EAAA;AAAA;AAAA,QAEjB,GAAI,OAAA,CAAQ,OAAA,GACR,EAAE,MAAA,EAAQ,OAAA,CAAQ,YAAA,IAAgB,OAAA,CAAQ,EAAA,EAAG,GAC7C,EAAE,SAAA,EAAW,QAAQ,EAAA,EAAG;AAAA,QAC5B,YAAY,OAAA,CAAQ;AAAA,OACrB,CAAA;AACD,MAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAElB,MAAA,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,EAAS,IAAA,EAAM,SAAS,EAAE,CAAA;AAAA,IAC9C,SAAS,GAAA,EAAK;AAIZ,MAAA,IAAI,EAAA,CAAG,MAAA,CAAO,OAAA,IAAW,EAAE,eAAe,gBAAA,CAAA,EAAmB;AAC3D,QAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AACjB,QAAA,OAAO,EAAE,YAAY,WAAA,EAAY;AAAA,MACnC;AAGA,MAAA,MAAM,IAAA,CAAK,MAAM,aAAA,CAAc;AAAA,QAC7B,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,MAAA,EAAQ;AAAA,UACN,aAAA,EAAe,qBAAA;AAAA,UACf,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,mBAAA,EAAwB,YAAA,CAAa,GAAG,CAAC;AAAA;AAAA;AACjD;AACF,OACD,CAAA;AACD,MAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AACjB,MAAA,OAAO,EAAE,YAAY,SAAA,EAAU;AAAA,IACjC;AAEA,IAAA,MAAM,SAAA,GAAY,GAAG,MAAA,CAAO,OAAA;AAC5B,IAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AACjB,IAAA,OAAO,EAAE,UAAA,EAAY,SAAA,GAAY,WAAA,GAAc,UAAA,EAAW;AAAA,EAC5D;AAAA,EAEA,MAAM,OAAO,MAAA,EAA2C;AACtD,IAAA,IAAA,CAAK,UAAU,GAAA,CAAI,MAAA,CAAO,SAAS,CAAA,EAAG,QAAQ,KAAA,EAAM;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,uBACJ,OAAA,EACyC;AACzC,IAAA,OAAO,EAAE,aAAA,EAAe,EAAC,EAAE;AAAA,EAC7B;AAAA;AAAA;AAAA,EAIA,MAAM,eACJ,OAAA,EACgC;AAChC,IAAA,OAAO,EAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,MAAA,CACJ,OAAA,EACA,IAAA,EACA,SACA,EAAA,EACe;AACf,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,aAAA,IAAiB,uBAAA;AAC7C,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,iBAAA,IAAqB,4BAAA;AACrD,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,CAAA,CACpD,MAAA,CAAO,aACT,CAAA,EAAE;AAIF,IAAA,IAAI,UAAA,GAAa,KAAA;AAKjB,IAAA,IAAI,WAAA,GAAc,KAAA;AAClB,IAAA,IAAI;AACF,MAAA,OAAO,CAAC,EAAA,CAAG,MAAA,CAAO,OAAA,EAAS;AACzB,QAAA,MAAM,UAAA,GAAa,cAAc,UAAA,GAAa,MAAA;AAC9C,QAAA,MAAM,OAAO,MAAM,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,YAAY,EAAE,CAAA;AAC7D,QAAA,IAAI,KAAK,IAAA,EAAM;AACf,QAAA,MAAM,MAAM,IAAA,CAAK,KAAA;AACjB,QAAA,MAAM,KAAA,GAAQ,oBAAoB,GAAG,CAAA;AACrC,QAAA,IAAI,KAAA,UAAe,YAAA,GAAe,KAAA;AAClC,QAAA,IAAI,GAAA,CAAI,IAAA,KAAS,cAAA,EAAgB,UAAA,GAAa,IAAA;AAE9C,QAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,UAAA,KAAA,MAAW,KAAA,IAAS,GAAA,CAAI,OAAA,CAAQ,OAAA,EAAS;AACvC,YAAA,IAAI,KAAA,CAAM,IAAA,KAAS,UAAA,EAAY,WAAA,GAAc,IAAA;AAAA,UAC/C;AAAA,QACF,CAAA,MAAA,IAAW,GAAA,CAAI,IAAA,KAAS,MAAA,EAAQ;AAC9B,UAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,OAAA;AAC5B,UAAA,IACE,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IACrB,OAAA,CAAQ,IAAA,CAAK,CAAC,KAAA,KAAU,KAAA,CAAM,IAAA,KAAS,aAAa,CAAA,EACpD;AACA,YAAA,WAAA,GAAc,KAAA;AAAA,UAChB;AAAA,QACF;AAEA,QAAA,KAAA,MAAW,MAAA,IAAU,oBAAoB,GAAA,EAAK;AAAA,UAC5C,qBAAA,EAAuB;AAAA,SACxB,CAAA,EAAG;AACF,UAAA,MAAM,IAAA,CAAK,MAAM,aAAA,CAAc,EAAE,WAAW,OAAA,CAAQ,EAAA,EAAI,QAAQ,CAAA;AAAA,QAClE;AAAA,MACF;AAAA,IACF,CAAA,SAAE;AAMA,MAAA,KAAK,OAAA,CAAQ,QAAQ,QAAA,CAAS,MAAA,GAAS,MAAS,CAAC,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IAC1E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YAAA,CACJ,QAAA,EACA,MAAA,EACA,EAAA,EACqC;AACrC,IAAA,MAAM,IAAA,GAAO,SAAS,IAAA,EAAK;AAC3B,IAAA,IAAI,MAAA,IAAU,GAAG,OAAO,IAAA;AAGxB,IAAA,KAAK,IAAA,CAAK,KAAA,CAAM,MAAM,MAAS,CAAA;AAC/B,IAAA,IAAI,KAAA;AACJ,IAAA,MAAM,QAAA,GAAW,IAAI,OAAA,CAAe,CAAC,UAAU,MAAA,KAAW;AACxD,MAAA,KAAA,GAAQ,WAAW,MAAM;AACvB,QAAA,EAAA,CAAG,KAAA,EAAM;AACT,QAAA,MAAA,CAAO,IAAI,gBAAA,CAAiB,MAAM,CAAC,CAAA;AAAA,MACrC,GAAG,MAAM,CAAA;AAET,MAAA,KAAA,CAAM,KAAA,EAAM;AAAA,IACd,CAAC,CAAA;AACD,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,IAAA,EAAM,QAAQ,CAAC,CAAA;AAAA,IAC5C,CAAA,SAAE;AACA,MAAA,IAAI,KAAA,eAAoB,KAAK,CAAA;AAAA,IAC/B;AAAA,EACF;AACF;AChUO,SAAS,eAAA,CACd,MAAA,GAA0B,EAAC,EACN;AAErB,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AAC9C,EAAA,MAAM,aAAa,QAAA,CAAS,KAAA;AAAA,IAC1B,OAAA,CAAQ;AAAA,GACV;AACA,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,QAAA,EAAU,UAAU,CAAA;AAChD,EAAA,OAAO,IAAI,mBAAA;AAAA,IACT,CAAC,IAAA,KAAS,IAAI,iBAAA,CAAkB,MAAM,MAAM,CAAA;AAAA,IAC5C;AAAA,GACF;AACF","file":"chunk-TT4O3BGM.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 * Thrown by {@link buildQueryOptions} when a spawn requests a `vendor/product`\n * catalog-style model with no `base_url` to route it through — see that\n * function's \"unrouted-model guard\" doc section for the full rationale.\n * Distinct class (not a bare `Error`) so a host can pattern-match it if it\n * ever wants to.\n */\nexport class UnroutedGatewayModelError extends Error {\n constructor(model: string) {\n super(\n `claude-sdk: model \"${model}\" is a vendor/product catalog ref, but no ` +\n `base_url is configured to route it — this adapter would otherwise ` +\n `send it straight to the real Anthropic API, which either 400s (\"not ` +\n `a valid model ID\") or silently falls back to a real Claude model, ` +\n `still billed. Set a base_url that fronts the provider that actually ` +\n `serves \"${model}\" (e.g. route.gateway: \"openrouter\" for an ` +\n `OpenRouter-hosted model), or request a native claude-* model instead.`,\n )\n this.name = \"UnroutedGatewayModelError\"\n }\n}\n\n/**\n * True for a `vendor/product` catalog-style model ref (e.g.\n * `deepseek/deepseek-v4-flash-0731`, `z-ai/glm-5.2`) — the canonical form this\n * whole codebase uses for a gateway-routed model (see\n * `@agentproto/model-catalog/route-identity`'s module doc). Such an id is\n * NEVER valid on the real Anthropic wire (Anthropic's own ids — `claude-…`,\n * and every entry this adapter's `models.allowed` declares under `provider:\n * \"anthropic\"` — never contain a `/`), so one reaching here with no\n * `base_url` to route it through is unambiguously a dropped/skipped routing\n * step upstream, not a legitimate native spawn. A BARE gateway-native id (no\n * `/`, e.g. Moonshot's `kimi-k2.7-code`) is deliberately NOT flagged here —\n * that shape is ambiguous with a yet-unlisted native id, so guarding it would\n * risk a false positive; the `/` form has no such ambiguity. */\nfunction isVendorProductModelRef(model: string): boolean {\n return model.includes(\"/\")\n}\n\n/** True when the ambient env has already redirected the SDK to a cloud\n * provider (Bedrock/Vertex/Foundry/…) via one of {@link\n * CLOUD_PROVIDER_REDIRECT_TOGGLES} — those providers use their OWN model-id\n * conventions, some of which DO contain vendor-prefixed segments (e.g.\n * Bedrock's `anthropic.claude-…-v1:0` uses `.`, but a Bedrock inference\n * profile ARN-style id can contain `/`), so the unrouted-model guard must not\n * fire once a cloud redirect is already active. */\nfunction hasCloudProviderRedirect(\n env: Record<string, string | undefined>,\n): boolean {\n return CLOUD_PROVIDER_REDIRECT_TOGGLES.some((key) => Boolean(env[key]))\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 *\n * Unrouted-model guard: when `base_url` is UNSET (native mode, or an already-\n * active cloud-provider redirect) and the model is a `vendor/product`\n * catalog-style ref (e.g. `deepseek/deepseek-v4-flash-0731` — see {@link\n * isVendorProductModelRef}), the model reaches the real Anthropic API\n * verbatim — a routing bug upstream (a gateway model whose `base_url`\n * injection was dropped, skipped, or never wired), never a legitimate native\n * spawn (Anthropic's own ids never contain `/`). Sending it anyway is exactly\n * the failure this guard exists to prevent: real dogfooding turned up THREE\n * distinct symptoms of it (an empty turn still billed, a 400 \"not a valid\n * model ID\" once the mis-prefixed id reached Anthropic, and — worst —\n * Anthropic silently answering with a real Claude model at full Anthropic\n * rates while the caller believed it was talking to the requested gateway\n * model). {@link buildQueryOptions} now fails FAST with {@link\n * UnroutedGatewayModelError} before any request is made — zero-cost, and the\n * error message names the exact model/gateway mismatch — rather than risking\n * any of those three silent-failure shapes.\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 if (\n !config.baseUrl &&\n isVendorProductModelRef(model) &&\n !hasCloudProviderRedirect(baseEnv)\n ) {\n throw new UnroutedGatewayModelError(model)\n }\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-2LNYIR6L.mjs';
2
+ import { runAcpOverStdio } from './chunk-TT4O3BGM.mjs';
3
3
 
4
4
  /**
5
5
  * @agentproto/adapter-claude-sdk v0.1.0-alpha
package/dist/index.d.ts CHANGED
@@ -81,6 +81,16 @@ interface ClaudeSdkConfig {
81
81
  * SDK expects.
82
82
  */
83
83
  declare function mapAcpMcpServers(servers: McpServer[] | undefined): Record<string, McpServerConfig>;
84
+ /**
85
+ * Thrown by {@link buildQueryOptions} when a spawn requests a `vendor/product`
86
+ * catalog-style model with no `base_url` to route it through — see that
87
+ * function's "unrouted-model guard" doc section for the full rationale.
88
+ * Distinct class (not a bare `Error`) so a host can pattern-match it if it
89
+ * ever wants to.
90
+ */
91
+ declare class UnroutedGatewayModelError extends Error {
92
+ constructor(model: string);
93
+ }
84
94
  /**
85
95
  * Assemble the SDK `Options` for a single `query()` call.
86
96
  *
@@ -100,6 +110,23 @@ declare function mapAcpMcpServers(servers: McpServer[] | undefined): Record<stri
100
110
  * (e.g. Moonshot rejecting `claude-haiku-*`). The
101
111
  * {@link CLOUD_PROVIDER_REDIRECT_TOGGLES} leaked from a Claude-Code parent
102
112
  * shell are also scrubbed so the gateway `base_url` isn't overridden.
113
+ *
114
+ * Unrouted-model guard: when `base_url` is UNSET (native mode, or an already-
115
+ * active cloud-provider redirect) and the model is a `vendor/product`
116
+ * catalog-style ref (e.g. `deepseek/deepseek-v4-flash-0731` — see {@link
117
+ * isVendorProductModelRef}), the model reaches the real Anthropic API
118
+ * verbatim — a routing bug upstream (a gateway model whose `base_url`
119
+ * injection was dropped, skipped, or never wired), never a legitimate native
120
+ * spawn (Anthropic's own ids never contain `/`). Sending it anyway is exactly
121
+ * the failure this guard exists to prevent: real dogfooding turned up THREE
122
+ * distinct symptoms of it (an empty turn still billed, a 400 "not a valid
123
+ * model ID" once the mis-prefixed id reached Anthropic, and — worst —
124
+ * Anthropic silently answering with a real Claude model at full Anthropic
125
+ * rates while the caller believed it was talking to the requested gateway
126
+ * model). {@link buildQueryOptions} now fails FAST with {@link
127
+ * UnroutedGatewayModelError} before any request is made — zero-cost, and the
128
+ * error message names the exact model/gateway mismatch — rather than risking
129
+ * any of those three silent-failure shapes.
103
130
  */
104
131
  declare function buildQueryOptions(args: {
105
132
  config: ClaudeSdkConfig;
@@ -270,4 +297,4 @@ declare function runAcpOverStdio(config?: ClaudeSdkConfig): AgentSideConnection;
270
297
  declare const claudeSdk: AgentCliHandle;
271
298
  declare function claudeSdkRuntime(): AgentCliRuntime;
272
299
 
273
- export { ClaudeSdkAcpAgent, type ClaudeSdkConfig, DEFAULT_MODEL, type QueryFn, type UsageSessionUpdate, assistantMessageUpdates, buildQueryOptions, claudeSdk, claudeSdkRuntime, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates };
300
+ export { ClaudeSdkAcpAgent, type ClaudeSdkConfig, DEFAULT_MODEL, type QueryFn, UnroutedGatewayModelError, type UsageSessionUpdate, assistantMessageUpdates, buildQueryOptions, claudeSdk, claudeSdkRuntime, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates };
package/dist/index.mjs CHANGED
@@ -1,12 +1,15 @@
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';
1
+ import { DEFAULT_MODEL } from './chunk-TT4O3BGM.mjs';
2
+ export { ClaudeSdkAcpAgent, DEFAULT_MODEL, UnroutedGatewayModelError, assistantMessageUpdates, buildQueryOptions, mapAcpMcpServers, promptText, resultUsageUpdate, runAcpOverStdio, sdkMessageToUpdates, systemInitSessionId, toolCallTitle, toolKindForClaudeTool, userMessageUpdates } from './chunk-TT4O3BGM.mjs';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { defineAgentCli, createAgentCliRuntime } from '@agentproto/driver-agent-cli';
5
+ import { listNativeModelIds } from '@agentproto/model-catalog/llm';
5
6
 
6
7
  /**
7
8
  * @agentproto/adapter-claude-sdk v0.1.0-alpha
8
9
  * First-party agentproto adapter: Claude Agent SDK headless query() -> ACP server.
9
10
  */
11
+ var NATIVE_ANTHROPIC_DENYLIST = /* @__PURE__ */ new Set([]);
12
+ var NATIVE_ANTHROPIC_MODELS = listNativeModelIds("anthropic").filter((id) => !NATIVE_ANTHROPIC_DENYLIST.has(id)).map((id) => ({ id, provider: "anthropic" }));
10
13
  var cliEntry = fileURLToPath(new URL("./cli.mjs", import.meta.url));
11
14
  var claudeSdk = defineAgentCli({
12
15
  name: "claude-sdk",
@@ -87,11 +90,10 @@ var claudeSdk = defineAgentCli({
87
90
  // ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN. The `model` option remains
88
91
  // free-form, so any gateway id works even if it is not listed here.
89
92
  allowed: [
90
- // Native Anthropic
91
- { id: "claude-haiku-4-5-20251001", provider: "anthropic" },
92
- { id: "claude-sonnet-5", provider: "anthropic" },
93
- { id: "claude-opus-4-8", provider: "anthropic" },
94
- { id: "claude-fable-5", provider: "anthropic" },
93
+ // Native Anthropic — every id the catalog's own `/v1/models` sync
94
+ // currently carries for this provider (see NATIVE_ANTHROPIC_MODELS
95
+ // above), not a hand-typed subset.
96
+ ...NATIVE_ANTHROPIC_MODELS,
95
97
  // Gateway providers — routing is resolved by the runtime. OpenRouter ids
96
98
  // carry the `@openrouter` route-identity suffix so the catalog join pins
97
99
  // the gateway route (a bare 2-segment id resolves to the dead direct
@@ -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 { 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-k3\", provider: \"moonshot\" },\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 // Requesty — route resolved from the catalog `@route`. Verified\n // runnable: a spawn on sference/thinkingcap-qwen3.6-27b@requesty is\n // accepted and produces the same route/profile/key-fingerprint\n // descriptor as the claude-code spawn on the same model.\n { id: \"sference/thinkingcap-qwen3.6-27b@requesty\", provider: \"requesty\" },\n { id: \"sference/glm-5.2@requesty\", provider: \"requesty\" },\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-k3@llm-endpoint\", provider: \"llm-endpoint\" },\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"]}
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 { listNativeModelIds } from \"@agentproto/model-catalog/llm\"\nimport { DEFAULT_MODEL } from \"./options.js\"\n\n// Native-Anthropic model menu, derived from the catalog's own synced\n// `/v1/models` listing (see `listNativeModelIds`) rather than a hand-typed\n// id array — a hand-typed list silently drops a newly-published id (e.g.\n// Anthropic shipping `claude-opus-4-9`) until someone notices and opens a\n// PR. Nothing is known to need hiding today, so the denylist starts empty\n// — it exists purely as the one sanctioned manual override (a specific id\n// we've vetted and want OFF this adapter), never as a stand-in for a\n// hand-typed allowlist.\nconst NATIVE_ANTHROPIC_DENYLIST = new Set<string>([])\nconst NATIVE_ANTHROPIC_MODELS = listNativeModelIds(\"anthropic\")\n .filter(id => !NATIVE_ANTHROPIC_DENYLIST.has(id))\n .map(id => ({ id, provider: \"anthropic\" as const }))\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 — every id the catalog's own `/v1/models` sync\n // currently carries for this provider (see NATIVE_ANTHROPIC_MODELS\n // above), not a hand-typed subset.\n ...NATIVE_ANTHROPIC_MODELS,\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-k3\", provider: \"moonshot\" },\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 // Requesty — route resolved from the catalog `@route`. Verified\n // runnable: a spawn on sference/thinkingcap-qwen3.6-27b@requesty is\n // accepted and produces the same route/profile/key-fingerprint\n // descriptor as the claude-code spawn on the same model.\n { id: \"sference/thinkingcap-qwen3.6-27b@requesty\", provider: \"requesty\" },\n { id: \"sference/glm-5.2@requesty\", provider: \"requesty\" },\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-k3@llm-endpoint\", provider: \"llm-endpoint\" },\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 UnroutedGatewayModelError,\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.5.7",
3
+ "version": "0.5.9",
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,8 +48,9 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@agentclientprotocol/sdk": "^0.21.0",
51
- "@anthropic-ai/claude-agent-sdk": "^0.3.232",
52
- "@agentproto/driver-agent-cli": "2.3.0",
51
+ "@anthropic-ai/claude-agent-sdk": "^0.3.251",
52
+ "@agentproto/driver-agent-cli": "2.4.0",
53
+ "@agentproto/model-catalog": "0.9.0",
53
54
  "@agentproto/provider-presets": "0.6.1"
54
55
  },
55
56
  "devDependencies": {
@@ -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-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"]}