@eddyskywalker/dsh-chatgpt-subscription 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -3169,7 +3169,7 @@ function identityKey(credentials) {
3169
3169
  //#endregion
3170
3170
  //#region src/host/routes.ts
3171
3171
  const MAX_BODY_BYTES$2 = 64 * 1024;
3172
- function registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwitcher) {
3172
+ function registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwitcher, routeAudit) {
3173
3173
  const handler = async (request, response) => {
3174
3174
  const url = new URL(request.url ?? "/", "http://dsh.local");
3175
3175
  if (request.method === "GET" && url.pathname === `/api/dsh-chatgpt-subscription/status`) {
@@ -3187,6 +3187,32 @@ function registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwit
3187
3187
  });
3188
3188
  return;
3189
3189
  }
3190
+ if (request.method === "GET" && url.pathname === `/api/dsh-chatgpt-subscription/subagent-route-audit`) {
3191
+ const sessionId = url.searchParams.get("sessionId");
3192
+ if (sessionId === null || sessionId.length === 0) {
3193
+ jsonError(response, 400, {
3194
+ code: "bad-request",
3195
+ message: "A sessionId query parameter is required."
3196
+ });
3197
+ return;
3198
+ }
3199
+ if (routeAudit === void 0) {
3200
+ jsonError(response, 404, {
3201
+ code: "route-audit-failed",
3202
+ message: "Subagent route audit is not installed."
3203
+ });
3204
+ return;
3205
+ }
3206
+ try {
3207
+ json(response, {
3208
+ ok: true,
3209
+ value: await routeAudit(sessionId)
3210
+ });
3211
+ } catch (error) {
3212
+ jsonError(response, 500, publicError(error instanceof Error ? error : /* @__PURE__ */ new Error("The route audit failed."), "route-audit-failed"));
3213
+ }
3214
+ return;
3215
+ }
3190
3216
  if (request.method === "GET" && url.pathname === `/api/dsh-chatgpt-subscription/mermaid.min.js`) {
3191
3217
  try {
3192
3218
  const mermaidPath = createRequire(import.meta.url).resolve("mermaid/dist/mermaid.min.js");
@@ -5255,7 +5281,7 @@ function sanitizeText$2(text) {
5255
5281
  function isRecord$4(value) {
5256
5282
  return typeof value === "object" && value !== null && !Array.isArray(value);
5257
5283
  }
5258
- function asString$5(value) {
5284
+ function asString$6(value) {
5259
5285
  return typeof value === "string" ? value : void 0;
5260
5286
  }
5261
5287
  function safeJsonParse$2(text) {
@@ -5285,7 +5311,7 @@ function attachmentOf$2(block) {
5285
5311
  }
5286
5312
  function attachmentLabel$2(block) {
5287
5313
  const attachment = isRecord$4(block.attachment) ? block.attachment : void 0;
5288
- return asString$5(attachment?.name) || asString$5(attachment?.attachmentId);
5314
+ return asString$6(attachment?.name) || asString$6(attachment?.attachmentId);
5289
5315
  }
5290
5316
  function collectImageRefs$2(content, refs) {
5291
5317
  if (!Array.isArray(content)) return;
@@ -5324,7 +5350,7 @@ function base64Length$2(bytes) {
5324
5350
  function requestImageBytes$2(block) {
5325
5351
  const attachment = attachmentOf$2(block);
5326
5352
  if (attachment) return base64Length$2(attachment.bytes);
5327
- const inline = asString$5(block.data) || asString$5(block.base64);
5353
+ const inline = asString$6(block.data) || asString$6(block.base64);
5328
5354
  return inline ? inline.length : void 0;
5329
5355
  }
5330
5356
  function collectRequestImageBytes$2(content, lengths) {
@@ -5428,10 +5454,10 @@ function unavailableImageText$2(block) {
5428
5454
  return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
5429
5455
  }
5430
5456
  function imageBlockToPart(block, images) {
5431
- let data = asString$5(block.data) || asString$5(block.base64);
5457
+ let data = asString$6(block.data) || asString$6(block.base64);
5432
5458
  const source = isRecord$4(block.source) ? block.source : void 0;
5433
- if (!data && source) data = asString$5(source.data) || asString$5(source.base64);
5434
- let mimeType = asString$5(block.mimeType) || asString$5(block.mediaType) || (source ? asString$5(source.mimeType) || asString$5(source.mediaType) : void 0) || "image/png";
5459
+ if (!data && source) data = asString$6(source.data) || asString$6(source.base64);
5460
+ let mimeType = asString$6(block.mimeType) || asString$6(block.mediaType) || (source ? asString$6(source.mimeType) || asString$6(source.mediaType) : void 0) || "image/png";
5435
5461
  if (data?.startsWith("data:")) {
5436
5462
  const match = data.match(/^data:([^;,]+);base64,(.*)$/s);
5437
5463
  if (match) {
@@ -5487,7 +5513,7 @@ function replayBlockFor(message, index) {
5487
5513
  }
5488
5514
  }
5489
5515
  function thoughtSignature(part) {
5490
- return asString$5(part?.thoughtSignature) || asString$5(part?.thought_signature) || asString$5(part?.thinkingSignature) || asString$5(part?.textSignature);
5516
+ return asString$6(part?.thoughtSignature) || asString$6(part?.thought_signature) || asString$6(part?.thinkingSignature) || asString$6(part?.textSignature);
5491
5517
  }
5492
5518
  function replayPart(part) {
5493
5519
  const copy = { ...part };
@@ -5506,7 +5532,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
5506
5532
  if (!isRecord$4(block)) continue;
5507
5533
  const replay = replayBlockFor(message, index);
5508
5534
  const originalParts = Array.isArray(replay?.parts) ? replay.parts.filter(isRecord$4) : [];
5509
- if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$5(part.text) || "").join("") === sanitizeText$2(String(block.text || ""))) {
5535
+ if ((block.type === "text" || block.type === "reasoning") && originalParts.length > 0 && originalParts.every((part) => !part.functionCall) && originalParts.map((part) => asString$6(part.text) || "").join("") === sanitizeText$2(String(block.text || ""))) {
5510
5536
  parts.push(...originalParts.map(replayPart));
5511
5537
  continue;
5512
5538
  }
@@ -5527,7 +5553,7 @@ function assistantParts(message, model, runtimeModel, toolCalls) {
5527
5553
  const toolId = String(block.id || "");
5528
5554
  const toolName = String(block.name || "");
5529
5555
  const originalCall = originalParts.find((part) => isRecord$4(part.functionCall));
5530
- const wireId = asString$5((isRecord$4(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
5556
+ const wireId = asString$6((isRecord$4(originalCall?.functionCall) ? originalCall.functionCall : void 0)?.id) || (toolCallIdNeeded(model.id, runtimeModel) ? sanitizeToolCallId(toolId, toolName) : originalCall ? void 0 : toolId || void 0);
5531
5557
  toolCalls.set(toolId, {
5532
5558
  name: toolName,
5533
5559
  id: wireId
@@ -5804,8 +5830,8 @@ function processStreamLine(line, state) {
5804
5830
  if (isRecord$4(part.functionCall)) {
5805
5831
  out.push(...closeCurrentBlock(state));
5806
5832
  const fc = part.functionCall;
5807
- const toolName = asString$5(fc.name) || "";
5808
- const toolId = asString$5(fc.id) || sanitizeToolCallId("", toolName);
5833
+ const toolName = asString$6(fc.name) || "";
5834
+ const toolId = asString$6(fc.id) || sanitizeToolCallId("", toolName);
5809
5835
  const argsText = JSON.stringify(isRecord$4(fc.args) ? fc.args : {});
5810
5836
  const index = state.blocks.length;
5811
5837
  const block = {
@@ -5843,7 +5869,7 @@ function processStreamLine(line, state) {
5843
5869
  }
5844
5870
  collectUsage(chunk.usageMetadata, state);
5845
5871
  if (responseData !== chunk) collectUsage(responseData.usageMetadata, state);
5846
- const finishReason = asString$5(candidate?.finishReason) || asString$5(responseData.finishReason);
5872
+ const finishReason = asString$6(candidate?.finishReason) || asString$6(responseData.finishReason);
5847
5873
  if (finishReason) {
5848
5874
  state.finishReason = finishReason;
5849
5875
  out.push(...closeCurrentBlock(state));
@@ -7528,10 +7554,10 @@ function timeoutSignal$1(signal, ms) {
7528
7554
  function isRecord$3(value) {
7529
7555
  return typeof value === "object" && value !== null && !Array.isArray(value);
7530
7556
  }
7531
- function asRecord$3(value) {
7557
+ function asRecord$4(value) {
7532
7558
  return isRecord$3(value) ? value : void 0;
7533
7559
  }
7534
- function asString$4(value) {
7560
+ function asString$5(value) {
7535
7561
  if (typeof value === "string" && value.trim() !== "") return value;
7536
7562
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
7537
7563
  }
@@ -7544,7 +7570,7 @@ function asNumber$1(value) {
7544
7570
  }
7545
7571
  function firstString$1(record, keys) {
7546
7572
  for (const key of keys) {
7547
- const value = asString$4(record[key]);
7573
+ const value = asString$5(record[key]);
7548
7574
  if (value !== void 0) return value;
7549
7575
  }
7550
7576
  }
@@ -7598,16 +7624,16 @@ const ORG_KEYS = [
7598
7624
  ];
7599
7625
  /** Map `/alpha/whoami` (or a stored key's own facts) onto the public account DTO. */
7600
7626
  function parseWhoami(payload, fallback = {}) {
7601
- const root = asRecord$3(payload) ?? {};
7602
- const data = asRecord$3(root.data) ?? root;
7603
- const user = asRecord$3(deepValue(data, USER_KEYS)) ?? {};
7604
- const org = asRecord$3(deepValue(data, ORG_KEYS)) ?? {};
7605
- const key = asRecord$3(deepValue(data, [
7627
+ const root = asRecord$4(payload) ?? {};
7628
+ const data = asRecord$4(root.data) ?? root;
7629
+ const user = asRecord$4(deepValue(data, USER_KEYS)) ?? {};
7630
+ const org = asRecord$4(deepValue(data, ORG_KEYS)) ?? {};
7631
+ const key = asRecord$4(deepValue(data, [
7606
7632
  "apiKey",
7607
7633
  "key",
7608
7634
  "credential"
7609
7635
  ])) ?? {};
7610
- const subscription = asRecord$3(deepValue(data, [
7636
+ const subscription = asRecord$4(deepValue(data, [
7611
7637
  "subscription",
7612
7638
  "plan",
7613
7639
  "tier"
@@ -7711,14 +7737,14 @@ function humanizeWindowKey$1(key) {
7711
7737
  * — so they are read here first, by name.
7712
7738
  */
7713
7739
  function parseWindowLimits(payload, consumed = []) {
7714
- const root = asRecord$3(payload) ?? {};
7715
- const limits = asRecord$3(deepValue(asRecord$3(root.data) ?? root, ["windowLimits", "window_limits"]));
7740
+ const root = asRecord$4(payload) ?? {};
7741
+ const limits = asRecord$4(deepValue(asRecord$4(root.data) ?? root, ["windowLimits", "window_limits"]));
7716
7742
  if (limits === void 0) return [];
7717
7743
  const keys = [...WINDOW_ORDER$1.filter((key) => limits[key] !== void 0), ...Object.keys(limits).filter((key) => !WINDOW_ORDER$1.includes(key))];
7718
7744
  const meters = [];
7719
7745
  for (const key of keys) {
7720
7746
  if (key === "limited" || key === "exceeded") continue;
7721
- const record = asRecord$3(limits[key]);
7747
+ const record = asRecord$4(limits[key]);
7722
7748
  if (record === void 0) continue;
7723
7749
  const cap = firstNumber$1(record, [
7724
7750
  "cap",
@@ -7752,8 +7778,8 @@ function parseWindowLimits(payload, consumed = []) {
7752
7778
  * source for a remaining balance.
7753
7779
  */
7754
7780
  function parseCreditBalances(payload, consumed = []) {
7755
- const root = asRecord$3(payload) ?? {};
7756
- const credits = asRecord$3(deepValue(asRecord$3(root.data) ?? root, ["credits"]));
7781
+ const root = asRecord$4(payload) ?? {};
7782
+ const credits = asRecord$4(deepValue(asRecord$4(root.data) ?? root, ["credits"]));
7757
7783
  if (credits === void 0) return [];
7758
7784
  const monthly = firstNumber$1(credits, ["monthlyCredits", "monthly_credits"]);
7759
7785
  const purchased = firstNumber$1(credits, ["purchasedCredits", "purchased_credits"]);
@@ -7782,7 +7808,7 @@ function parseCreditBalances(payload, consumed = []) {
7782
7808
  /** Resolve the plan id the subscription or credits payload reports, when either does. */
7783
7809
  function parsePlanId(payloads) {
7784
7810
  for (const payload of payloads) {
7785
- const id = asString$4(deepValue(payload, [
7811
+ const id = asString$5(deepValue(payload, [
7786
7812
  "planId",
7787
7813
  "plan_id",
7788
7814
  "priceId",
@@ -7800,13 +7826,13 @@ function parsePlanId(payloads) {
7800
7826
  * subscription's remaining credits as usable would be worse than showing none.
7801
7827
  */
7802
7828
  function parseSubscriptionStatus(payload) {
7803
- const root = asRecord$3(payload) ?? {};
7804
- return asString$4(deepValue(asRecord$3(root.data) ?? root, ["status"])) ?? null;
7829
+ const root = asRecord$4(payload) ?? {};
7830
+ return asString$5(deepValue(asRecord$4(root.data) ?? root, ["status"])) ?? null;
7805
7831
  }
7806
7832
  /** End of the current billing period, in Unix milliseconds. */
7807
7833
  function parseSubscriptionPeriodEnd(payload) {
7808
- const root = asRecord$3(payload) ?? {};
7809
- return parseTimestamp$1(deepValue(asRecord$3(root.data) ?? root, ["currentPeriodEnd", "current_period_end"]));
7834
+ const root = asRecord$4(payload) ?? {};
7835
+ return parseTimestamp$1(deepValue(asRecord$4(root.data) ?? root, ["currentPeriodEnd", "current_period_end"]));
7810
7836
  }
7811
7837
  /**
7812
7838
  * Turn one billing/usage payload into meters.
@@ -8023,9 +8049,9 @@ function parseUsageWindows$1(payload) {
8023
8049
  return windows;
8024
8050
  }
8025
8051
  function extractCreditsBalance(payload) {
8026
- const root = asRecord$3(payload) ?? {};
8027
- const data = asRecord$3(root.data) ?? root;
8028
- const credits = asRecord$3(data.credits);
8052
+ const root = asRecord$4(payload) ?? {};
8053
+ const data = asRecord$4(root.data) ?? root;
8054
+ const credits = asRecord$4(data.credits);
8029
8055
  if (credits !== void 0) {
8030
8056
  const pools = [
8031
8057
  "monthlyCredits",
@@ -8057,11 +8083,11 @@ let cachedCatalog;
8057
8083
  let catalogInFlight = null;
8058
8084
  /** Parse the public `/provider/v1/models` payload. */
8059
8085
  function parseProviderModels(payload) {
8060
- const root = asRecord$3(payload) ?? {};
8086
+ const root = asRecord$4(payload) ?? {};
8061
8087
  const list = Array.isArray(root.data) ? root.data : Array.isArray(payload) ? payload : [];
8062
8088
  const models = [];
8063
8089
  for (const entry of list) {
8064
- const record = asRecord$3(entry);
8090
+ const record = asRecord$4(entry);
8065
8091
  if (!record) continue;
8066
8092
  const id = firstString$1(record, [
8067
8093
  "id",
@@ -8262,7 +8288,7 @@ function buildModelOptions$1(catalog, enabledModelIds, overrides) {
8262
8288
  function isRecord$2(value) {
8263
8289
  return typeof value === "object" && value !== null && !Array.isArray(value);
8264
8290
  }
8265
- function asString$3(value) {
8291
+ function asString$4(value) {
8266
8292
  return typeof value === "string" ? value : void 0;
8267
8293
  }
8268
8294
  function safeJsonParse$1(text) {
@@ -8304,7 +8330,7 @@ function attachmentOf$1(block) {
8304
8330
  }
8305
8331
  function attachmentLabel$1(block) {
8306
8332
  const attachment = isRecord$2(block.attachment) ? block.attachment : void 0;
8307
- return asString$3(attachment?.name) || asString$3(attachment?.attachmentId);
8333
+ return asString$4(attachment?.name) || asString$4(attachment?.attachmentId);
8308
8334
  }
8309
8335
  function collectImageRefs$1(content, refs) {
8310
8336
  if (!Array.isArray(content)) return;
@@ -8320,7 +8346,7 @@ function base64Length$1(bytes) {
8320
8346
  function requestImageBytes$1(block) {
8321
8347
  const attachment = attachmentOf$1(block);
8322
8348
  if (attachment) return base64Length$1(attachment.bytes);
8323
- const inline = asString$3(block.data) || asString$3(block.base64);
8349
+ const inline = asString$4(block.data) || asString$4(block.base64);
8324
8350
  return inline ? inline.length : void 0;
8325
8351
  }
8326
8352
  function collectRequestImageBytes$1(content, lengths) {
@@ -8406,10 +8432,10 @@ function unavailableImageText$1(block) {
8406
8432
  return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
8407
8433
  }
8408
8434
  function imageBlockToInline$1(block, images) {
8409
- let data = asString$3(block.data) || asString$3(block.base64);
8435
+ let data = asString$4(block.data) || asString$4(block.base64);
8410
8436
  const source = isRecord$2(block.source) ? block.source : void 0;
8411
- if (!data && source) data = asString$3(source.data) || asString$3(source.base64);
8412
- let mediaType = asString$3(block.mimeType) || asString$3(block.mediaType) || (source ? asString$3(source.mimeType) || asString$3(source.mediaType) : void 0) || "image/png";
8437
+ if (!data && source) data = asString$4(source.data) || asString$4(source.base64);
8438
+ let mediaType = asString$4(block.mimeType) || asString$4(block.mediaType) || (source ? asString$4(source.mimeType) || asString$4(source.mediaType) : void 0) || "image/png";
8413
8439
  if (data?.startsWith("data:")) {
8414
8440
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
8415
8441
  if (matched) {
@@ -8831,7 +8857,7 @@ function processOpenAIStreamLine$1(line, state) {
8831
8857
  const choice = isRecord$2(choices[0]) ? choices[0] : void 0;
8832
8858
  const delta = isRecord$2(choice?.delta) ? choice.delta : void 0;
8833
8859
  if (delta) {
8834
- const reasoning = asString$3(delta.reasoning_content) ?? asString$3(delta.reasoning);
8860
+ const reasoning = asString$4(delta.reasoning_content) ?? asString$4(delta.reasoning);
8835
8861
  if (reasoning !== void 0 && reasoning !== "") {
8836
8862
  out.push(...closeToolCalls$1(state));
8837
8863
  if (state.current === null || state.current.type !== "reasoning") out.push(...openTextBlock$1(state, "reasoning"));
@@ -8843,7 +8869,7 @@ function processOpenAIStreamLine$1(line, state) {
8843
8869
  text: sanitizeText$1(reasoning)
8844
8870
  });
8845
8871
  }
8846
- const content = asString$3(delta.content);
8872
+ const content = asString$4(delta.content);
8847
8873
  if (content !== void 0 && content !== "") {
8848
8874
  out.push(...closeToolCalls$1(state));
8849
8875
  if (state.current === null || state.current.type !== "text") out.push(...openTextBlock$1(state, "text"));
@@ -8861,7 +8887,7 @@ function processOpenAIStreamLine$1(line, state) {
8861
8887
  out.push(...applyOpenAIToolDelta$1(entry, state));
8862
8888
  }
8863
8889
  }
8864
- const finish = asString$3(choice?.finish_reason);
8890
+ const finish = asString$4(choice?.finish_reason);
8865
8891
  if (finish !== void 0 && finish !== "") {
8866
8892
  state.finishReason = finish;
8867
8893
  out.push(...closeCurrent$1(state));
@@ -8878,8 +8904,8 @@ function applyOpenAIToolDelta$1(entry, state) {
8878
8904
  out.push(...closeCurrent$1(state));
8879
8905
  call = {
8880
8906
  blockIndex: state.blocks.length,
8881
- id: asString$3(entry.id) ?? `call_${wireIndex}`,
8882
- name: asString$3(fn.name) ?? "",
8907
+ id: asString$4(entry.id) ?? `call_${wireIndex}`,
8908
+ name: asString$4(fn.name) ?? "",
8883
8909
  arguments: "",
8884
8910
  started: false
8885
8911
  };
@@ -8892,13 +8918,13 @@ function applyOpenAIToolDelta$1(entry, state) {
8892
8918
  state.toolCalls.set(wireIndex, call);
8893
8919
  } else {
8894
8920
  if (call.id === `call_${wireIndex}`) {
8895
- const id = asString$3(entry.id);
8921
+ const id = asString$4(entry.id);
8896
8922
  if (id !== void 0) call.id = id;
8897
8923
  }
8898
- const name = asString$3(fn.name);
8924
+ const name = asString$4(fn.name);
8899
8925
  if (name !== void 0 && name !== "") call.name = name;
8900
8926
  }
8901
- const argsDelta = asString$3(fn.arguments) ?? "";
8927
+ const argsDelta = asString$4(fn.arguments) ?? "";
8902
8928
  if (argsDelta !== "") call.arguments += argsDelta;
8903
8929
  if (!call.started) {
8904
8930
  call.started = true;
@@ -8930,7 +8956,7 @@ function processAnthropicStreamLine$1(line, state) {
8930
8956
  if (payload === "" || payload === "[DONE]") return [];
8931
8957
  const event = safeJsonParse$1(payload);
8932
8958
  if (!isRecord$2(event)) return [];
8933
- const type = asString$3(event.type);
8959
+ const type = asString$4(event.type);
8934
8960
  const out = [];
8935
8961
  if (type === "message_start") {
8936
8962
  const message = isRecord$2(event.message) ? event.message : void 0;
@@ -8942,21 +8968,21 @@ function processAnthropicStreamLine$1(line, state) {
8942
8968
  state.cacheWriteTokens = numberOr$1(usage.cache_creation_input_tokens, 0);
8943
8969
  state.outputTokens = numberOr$1(usage.output_tokens, 0);
8944
8970
  }
8945
- const stop = message ? asString$3(message.stop_reason) : void 0;
8971
+ const stop = message ? asString$4(message.stop_reason) : void 0;
8946
8972
  if (stop !== void 0 && stop !== null) state.finishReason = stop;
8947
8973
  return out;
8948
8974
  }
8949
8975
  if (type === "content_block_start") {
8950
8976
  const contentIndex = numberOr$1(event.index, 0);
8951
8977
  const block = isRecord$2(event.content_block) ? event.content_block : {};
8952
- const blockType = asString$3(block.type);
8978
+ const blockType = asString$4(block.type);
8953
8979
  out.push(...closeCurrent$1(state));
8954
8980
  if (blockType === "tool_use") {
8955
8981
  const index = state.blocks.length;
8956
8982
  const pending = {
8957
8983
  blockIndex: index,
8958
- id: asString$3(block.id) ?? `toolu_${contentIndex}`,
8959
- name: asString$3(block.name) ?? "",
8984
+ id: asString$4(block.id) ?? `toolu_${contentIndex}`,
8985
+ name: asString$4(block.name) ?? "",
8960
8986
  arguments: "",
8961
8987
  started: true
8962
8988
  };
@@ -8999,10 +9025,10 @@ function processAnthropicStreamLine$1(line, state) {
8999
9025
  if (type === "content_block_delta") {
9000
9026
  const contentIndex = numberOr$1(event.index, 0);
9001
9027
  const delta = isRecord$2(event.delta) ? event.delta : {};
9002
- const deltaType = asString$3(delta.type);
9028
+ const deltaType = asString$4(delta.type);
9003
9029
  if (deltaType === "input_json_delta") {
9004
9030
  const pending = state.toolCalls.get(contentIndex);
9005
- const partial = asString$3(delta.partial_json) ?? "";
9031
+ const partial = asString$4(delta.partial_json) ?? "";
9006
9032
  if (pending !== void 0) {
9007
9033
  pending.arguments += partial;
9008
9034
  out.push({
@@ -9015,7 +9041,7 @@ function processAnthropicStreamLine$1(line, state) {
9015
9041
  }
9016
9042
  return out;
9017
9043
  }
9018
- const text = deltaType === "thinking_delta" ? asString$3(delta.thinking) : asString$3(delta.text);
9044
+ const text = deltaType === "thinking_delta" ? asString$4(delta.thinking) : asString$4(delta.text);
9019
9045
  if (text !== void 0 && text !== "") {
9020
9046
  const index = state.contentIndexes.get(contentIndex) ?? state.current?.index;
9021
9047
  const kind = deltaType === "thinking_delta" ? "reasoning" : "text";
@@ -9072,7 +9098,7 @@ function processAnthropicStreamLine$1(line, state) {
9072
9098
  }
9073
9099
  if (type === "message_delta") {
9074
9100
  const delta = isRecord$2(event.delta) ? event.delta : void 0;
9075
- const stop = delta ? asString$3(delta.stop_reason) : void 0;
9101
+ const stop = delta ? asString$4(delta.stop_reason) : void 0;
9076
9102
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
9077
9103
  const usage = isRecord$2(event.usage) ? event.usage : void 0;
9078
9104
  if (usage) {
@@ -9085,7 +9111,7 @@ function processAnthropicStreamLine$1(line, state) {
9085
9111
  state.done = true;
9086
9112
  return closeStream$1(state);
9087
9113
  }
9088
- if (type === "error") throw new LlmError(`Command Code stream error: ${asString$3((isRecord$2(event.error) ? event.error : {}).message) ?? "unknown error"}`, "PROVIDER_ERROR");
9114
+ if (type === "error") throw new LlmError(`Command Code stream error: ${asString$4((isRecord$2(event.error) ? event.error : {}).message) ?? "unknown error"}`, "PROVIDER_ERROR");
9089
9115
  return out;
9090
9116
  }
9091
9117
  function tokenUsage$1(state) {
@@ -10771,7 +10797,7 @@ function withTimeout(signal, ms) {
10771
10797
  function oauthEndpoint(host, endpoint) {
10772
10798
  return `${host.replace(/\/+$/, "")}${endpoint}`;
10773
10799
  }
10774
- function asRecord$2(value) {
10800
+ function asRecord$3(value) {
10775
10801
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
10776
10802
  }
10777
10803
  /**
@@ -10782,8 +10808,8 @@ function asRecord$2(value) {
10782
10808
  * caller decides whether the flow continues.
10783
10809
  */
10784
10810
  function oauthErrorFields(payload) {
10785
- const root = asRecord$2(payload) ?? {};
10786
- const nested = asRecord$2(root.error);
10811
+ const root = asRecord$3(payload) ?? {};
10812
+ const nested = asRecord$3(root.error);
10787
10813
  if (nested !== void 0) return {
10788
10814
  code: typeof nested.code === "string" ? nested.code : "",
10789
10815
  description: String(nested.message ?? nested.error_description ?? nested.detail ?? nested.type ?? "")
@@ -10815,7 +10841,7 @@ async function requestDeviceAuthorization(options = {}) {
10815
10841
  const { description } = oauthErrorFields(payload);
10816
10842
  throw new Error(`Device authorization failed (${response.status})${description ? `: ${description}` : ""}`);
10817
10843
  }
10818
- const record = asRecord$2(payload) ?? {};
10844
+ const record = asRecord$3(payload) ?? {};
10819
10845
  const userCode = typeof record.user_code === "string" ? record.user_code : "";
10820
10846
  const deviceCode = typeof record.device_code === "string" ? record.device_code : "";
10821
10847
  const complete = typeof record.verification_uri_complete === "string" ? record.verification_uri_complete : "";
@@ -10857,7 +10883,7 @@ async function pollDeviceToken(host, deviceCode, options) {
10857
10883
  signal: withTimeout(options.signal, OAUTH_TIMEOUT_MS)
10858
10884
  });
10859
10885
  const payload = await response.json().catch(() => void 0);
10860
- const record = asRecord$2(payload) ?? {};
10886
+ const record = asRecord$3(payload) ?? {};
10861
10887
  if (response.status === 200 && typeof record.access_token === "string" && record.access_token !== "") return {
10862
10888
  kind: "success",
10863
10889
  token: parseTokenResponse(record)
@@ -10983,7 +11009,7 @@ async function refreshAccessToken(refreshToken, options = {}) {
10983
11009
  const payload = await response.json().catch(() => void 0);
10984
11010
  const { code, description } = oauthErrorFields(payload);
10985
11011
  if (response.status === 401 || response.status === 403 || code === "invalid_grant") throw new KimiCodeUnauthorizedError(description || "Token refresh was rejected; sign in again.");
10986
- if (response.ok) return parseTokenResponse(asRecord$2(payload) ?? {});
11012
+ if (response.ok) return parseTokenResponse(asRecord$3(payload) ?? {});
10987
11013
  if (!RETRYABLE_REFRESH_STATUSES.has(response.status)) throw new Error(description || `Token refresh failed (HTTP ${response.status}).`);
10988
11014
  lastError = new KimiCodeRetryableError(description || `Token refresh failed (HTTP ${response.status}).`);
10989
11015
  } catch (error) {
@@ -11208,10 +11234,10 @@ const FIXED_POINT_CENTS = 1e6;
11208
11234
  function isRecord$1(value) {
11209
11235
  return typeof value === "object" && value !== null && !Array.isArray(value);
11210
11236
  }
11211
- function asRecord$1(value) {
11237
+ function asRecord$2(value) {
11212
11238
  return isRecord$1(value) ? value : void 0;
11213
11239
  }
11214
- function asString$2(value) {
11240
+ function asString$3(value) {
11215
11241
  if (typeof value === "string" && value.trim() !== "") return value;
11216
11242
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
11217
11243
  }
@@ -11225,7 +11251,7 @@ function asNumber(value) {
11225
11251
  }
11226
11252
  function firstString(record, keys) {
11227
11253
  for (const key of keys) {
11228
- const value = asString$2(record[key]);
11254
+ const value = asString$3(record[key]);
11229
11255
  if (value !== void 0) return value;
11230
11256
  }
11231
11257
  }
@@ -11311,24 +11337,24 @@ function clearCachedCatalog() {
11311
11337
  * length is dropped rather than shown as a zero-capacity model.
11312
11338
  */
11313
11339
  function parseCatalogModel(value) {
11314
- const record = asRecord$1(value);
11340
+ const record = asRecord$2(value);
11315
11341
  if (record === void 0) return void 0;
11316
- const id = asString$2(record.id);
11342
+ const id = asString$3(record.id);
11317
11343
  if (id === void 0) return void 0;
11318
11344
  const contextWindow = firstNumber(record, ["context_length", "contextLength"]);
11319
11345
  if (contextWindow === void 0 || contextWindow <= 0) return void 0;
11320
- const efforts = asRecord$1(record.think_efforts) ?? asRecord$1(record.thinkEfforts);
11346
+ const efforts = asRecord$2(record.think_efforts) ?? asRecord$2(record.thinkEfforts);
11321
11347
  const validEfforts = Array.isArray(efforts?.valid_efforts) ? efforts.valid_efforts.filter((entry) => typeof entry === "string") : Array.isArray(efforts?.validEfforts) ? efforts.validEfforts.filter((entry) => typeof entry === "string") : void 0;
11322
11348
  const modalities = ["text"];
11323
11349
  if (record.supports_image_in === true || record.supportsImageIn === true) modalities.push("image");
11324
11350
  if (record.supports_video_in === true || record.supportsVideoIn === true) modalities.push("video");
11325
- const protocol = asString$2(record.protocol);
11351
+ const protocol = asString$3(record.protocol);
11326
11352
  return {
11327
11353
  id,
11328
- name: asString$2(record.display_name) ?? asString$2(record.displayName) ?? void 0,
11354
+ name: asString$3(record.display_name) ?? asString$3(record.displayName) ?? void 0,
11329
11355
  contextWindow,
11330
11356
  ...validEfforts === void 0 || validEfforts.length === 0 ? {} : { reasoningEfforts: validEfforts },
11331
- ...asString$2(efforts?.default_effort ?? efforts?.defaultEffort) === void 0 ? {} : { defaultReasoningEffort: asString$2(efforts?.default_effort ?? efforts?.defaultEffort) },
11357
+ ...asString$3(efforts?.default_effort ?? efforts?.defaultEffort) === void 0 ? {} : { defaultReasoningEffort: asString$3(efforts?.default_effort ?? efforts?.defaultEffort) },
11332
11358
  inputModalities: modalities,
11333
11359
  protocol: protocol === "anthropic" ? "anthropic" : "openai",
11334
11360
  ...record.supports_video_in === true || record.supportsVideoIn === true ? { supportsVideo: true } : {},
@@ -11364,7 +11390,7 @@ async function loadProviderModels$1(options = {}) {
11364
11390
  });
11365
11391
  if (!response.ok) throw new Error(`Kimi Code model listing failed (${response.status}).`);
11366
11392
  const payload = await response.json().catch(() => void 0);
11367
- const data = Array.isArray(payload) ? payload : asRecord$1(payload)?.data;
11393
+ const data = Array.isArray(payload) ? payload : asRecord$2(payload)?.data;
11368
11394
  if (!Array.isArray(data)) throw new Error("Kimi Code model listing was not in the documented shape.");
11369
11395
  const models = data.map(parseCatalogModel).filter((model) => model !== void 0);
11370
11396
  catalogCache = {
@@ -11526,7 +11552,7 @@ function usageWindow(id, record, descriptor) {
11526
11552
  * than a fabricated 0%.
11527
11553
  */
11528
11554
  function parseUsageWindows(payload) {
11529
- const root = asRecord$1(payload) ?? {};
11555
+ const root = asRecord$2(payload) ?? {};
11530
11556
  const windows = [];
11531
11557
  const seen = /* @__PURE__ */ new Set();
11532
11558
  const push = (id, record, descriptor) => {
@@ -11536,25 +11562,25 @@ function parseUsageWindows(payload) {
11536
11562
  seen.add(id);
11537
11563
  windows.push(parsed);
11538
11564
  };
11539
- const usages = asRecord$1(root.usages) ?? asRecord$1(root.usageWindows);
11565
+ const usages = asRecord$2(root.usages) ?? asRecord$2(root.usageWindows);
11540
11566
  if (usages !== void 0) {
11541
11567
  const keys = [...WINDOW_ORDER.filter((key) => usages[key] !== void 0), ...Object.keys(usages).filter((key) => !WINDOW_ORDER.includes(key))];
11542
11568
  for (const key of keys) {
11543
- const record = asRecord$1(usages[key]);
11569
+ const record = asRecord$2(usages[key]);
11544
11570
  if (record === void 0) continue;
11545
11571
  push(key, record, WINDOW_DESCRIPTORS[key]);
11546
11572
  }
11547
11573
  }
11548
- const topLevel = asRecord$1(root.usage);
11574
+ const topLevel = asRecord$2(root.usage);
11549
11575
  if (topLevel !== void 0 && seen.size === 0) push("limit_7d", topLevel, WINDOW_DESCRIPTORS.limit_7d);
11550
11576
  const limits = Array.isArray(root.limits) ? root.limits : [];
11551
11577
  for (const entry of limits) {
11552
- const record = asRecord$1(entry);
11578
+ const record = asRecord$2(entry);
11553
11579
  if (record === void 0) continue;
11554
- const detail = asRecord$1(record.detail) ?? record;
11555
- const window = asRecord$1(record.window);
11580
+ const detail = asRecord$2(record.detail) ?? record;
11581
+ const window = asRecord$2(record.window);
11556
11582
  const duration = firstNumber(window ?? {}, ["duration"]);
11557
- const unit = asString$2(window?.timeUnit ?? window?.time_unit);
11583
+ const unit = asString$3(window?.timeUnit ?? window?.time_unit);
11558
11584
  const minutes = duration === void 0 ? null : unit === "TIME_UNIT_HOUR" ? duration * 60 : duration;
11559
11585
  push(minutes === 300 ? "limit_5h" : minutes === 10080 ? "limit_7d" : firstString(record, ["id", "name"]) ?? `limit-${windows.length + 1}`, detail, minutes === null ? void 0 : {
11560
11586
  label: minutes === 300 ? "5-hour" : `${minutes}-minute`,
@@ -11585,14 +11611,14 @@ function fixedPointToCents(value) {
11585
11611
  * under-report a charge limit by six orders of magnitude.
11586
11612
  */
11587
11613
  function moneyCents(value) {
11588
- const record = asRecord$1(value);
11614
+ const record = asRecord$2(value);
11589
11615
  if (record === void 0) return null;
11590
11616
  const cents = asNumber(record.priceInCents ?? record.price_in_cents);
11591
11617
  return cents === void 0 || !Number.isFinite(cents) ? null : Math.round(cents);
11592
11618
  }
11593
11619
  function moneyCurrency(value) {
11594
- const record = asRecord$1(value);
11595
- return record === void 0 ? void 0 : asString$2(record.currency);
11620
+ const record = asRecord$2(value);
11621
+ return record === void 0 ? void 0 : asString$3(record.currency);
11596
11622
  }
11597
11623
  /**
11598
11624
  * Read the booster wallet (the pay-as-you-go top-up pool).
@@ -11602,11 +11628,11 @@ function moneyCurrency(value) {
11602
11628
  * cannot spend.
11603
11629
  */
11604
11630
  function parseExtraUsage(payload) {
11605
- const root = asRecord$1(payload) ?? {};
11606
- const wallet = asRecord$1(root.boosterWallet) ?? asRecord$1(root.booster_wallet) ?? asRecord$1(root.extraUsage);
11631
+ const root = asRecord$2(payload) ?? {};
11632
+ const wallet = asRecord$2(root.boosterWallet) ?? asRecord$2(root.booster_wallet) ?? asRecord$2(root.extraUsage);
11607
11633
  if (wallet === void 0) return null;
11608
- const balance = asRecord$1(wallet.balance);
11609
- const balanceType = asString$2(balance?.type);
11634
+ const balance = asRecord$2(wallet.balance);
11635
+ const balanceType = asString$3(balance?.type);
11610
11636
  const amount = asNumber(balance?.amount);
11611
11637
  if (balance === void 0 || balanceType !== "BOOSTER" || amount === void 0 || amount <= 0) return null;
11612
11638
  const limit = wallet.monthlyChargeLimit ?? wallet.monthly_charge_limit;
@@ -11617,7 +11643,7 @@ function parseExtraUsage(payload) {
11617
11643
  monthlyChargeLimitEnabled: wallet.monthlyChargeLimitEnabled === true || wallet.monthly_charge_limit_enabled === true,
11618
11644
  monthlyChargeLimitCents: moneyCents(limit),
11619
11645
  monthlyUsedCents: moneyCents(used),
11620
- currency: moneyCurrency(limit) ?? moneyCurrency(used) ?? asString$2(wallet.currency) ?? "USD"
11646
+ currency: moneyCurrency(limit) ?? moneyCurrency(used) ?? asString$3(wallet.currency) ?? "USD"
11621
11647
  };
11622
11648
  }
11623
11649
  /**
@@ -11654,7 +11680,7 @@ function membershipLevelName(level) {
11654
11680
  * `user_level_name` still yields a readable tier instead of a raw enum.
11655
11681
  */
11656
11682
  function parsePlanName(payload) {
11657
- const root = asRecord$1(payload) ?? {};
11683
+ const root = asRecord$2(payload) ?? {};
11658
11684
  const direct = firstString(root, [
11659
11685
  "user_level_name",
11660
11686
  "userLevelName",
@@ -11662,18 +11688,18 @@ function parsePlanName(payload) {
11662
11688
  "plan_name"
11663
11689
  ]);
11664
11690
  if (direct !== void 0) return direct;
11665
- const membership = asRecord$1(asRecord$1(root.user)?.membership);
11666
- const named = asString$2(membership?.level_name ?? membership?.levelName);
11691
+ const membership = asRecord$2(asRecord$2(root.user)?.membership);
11692
+ const named = asString$3(membership?.level_name ?? membership?.levelName);
11667
11693
  if (named !== void 0) return named;
11668
- return membershipLevelName(asString$2(membership?.level) ?? null);
11694
+ return membershipLevelName(asString$3(membership?.level) ?? null);
11669
11695
  }
11670
11696
  /** Machine tier level when the service reports one. */
11671
11697
  function parsePlanLevel(payload) {
11672
- const root = asRecord$1(payload) ?? {};
11698
+ const root = asRecord$2(payload) ?? {};
11673
11699
  const direct = firstNumber(root, ["user_level", "userLevel"]);
11674
11700
  if (direct !== void 0) return String(direct);
11675
- const membership = asRecord$1(asRecord$1(root.user)?.membership);
11676
- return asString$2(membership?.level ?? membership?.levelId ?? membership?.level_id) ?? null;
11701
+ const membership = asRecord$2(asRecord$2(root.user)?.membership);
11702
+ return asString$3(membership?.level ?? membership?.levelId ?? membership?.level_id) ?? null;
11677
11703
  }
11678
11704
  /**
11679
11705
  * Fetch and cache the account's quota snapshot.
@@ -11740,7 +11766,7 @@ function accountFromCredentials(credentials, payload, profile) {
11740
11766
  const planLevel = (profile === void 0 ? null : parsePlanLevel(profile)) ?? (payload === void 0 ? null : parsePlanLevel(payload));
11741
11767
  return {
11742
11768
  userId: credentials.userId ?? identity.userId ?? null,
11743
- nickname: (profile === void 0 ? null : firstString(asRecord$1(profile) ?? {}, [
11769
+ nickname: (profile === void 0 ? null : firstString(asRecord$2(profile) ?? {}, [
11744
11770
  "nickname",
11745
11771
  "username",
11746
11772
  "name"
@@ -11941,7 +11967,7 @@ function videoBlockLabel(block) {
11941
11967
  function isRecord(value) {
11942
11968
  return typeof value === "object" && value !== null && !Array.isArray(value);
11943
11969
  }
11944
- function asString$1(value) {
11970
+ function asString$2(value) {
11945
11971
  return typeof value === "string" ? value : void 0;
11946
11972
  }
11947
11973
  function safeJsonParse(text) {
@@ -12100,7 +12126,7 @@ function attachmentOf(block) {
12100
12126
  }
12101
12127
  function attachmentLabel(block) {
12102
12128
  const attachment = isRecord(block.attachment) ? block.attachment : void 0;
12103
- return asString$1(attachment?.name) || asString$1(attachment?.attachmentId);
12129
+ return asString$2(attachment?.name) || asString$2(attachment?.attachmentId);
12104
12130
  }
12105
12131
  function collectImageRefs(content, refs) {
12106
12132
  if (!Array.isArray(content)) return;
@@ -12116,7 +12142,7 @@ function base64Length(bytes) {
12116
12142
  function requestImageBytes(block) {
12117
12143
  const attachment = attachmentOf(block);
12118
12144
  if (attachment) return base64Length(attachment.bytes);
12119
- const inline = asString$1(block.data) || asString$1(block.base64);
12145
+ const inline = asString$2(block.data) || asString$2(block.base64);
12120
12146
  return inline ? inline.length : void 0;
12121
12147
  }
12122
12148
  function collectRequestImageBytes(content, lengths) {
@@ -12214,7 +12240,7 @@ function collectVideoRefs(content, refs) {
12214
12240
  }
12215
12241
  /** Base64 length of one video occurrence, or undefined when it states none. */
12216
12242
  function requestVideoBytes(block) {
12217
- const inline = asString$1(block.data) || asString$1(block.base64);
12243
+ const inline = asString$2(block.data) || asString$2(block.base64);
12218
12244
  if (inline) return inline.length;
12219
12245
  const attachment = videoAttachmentOf(block);
12220
12246
  return attachment === void 0 ? void 0 : base64LengthOf(attachment.bytes);
@@ -12313,8 +12339,8 @@ function requestHasVideo(options) {
12313
12339
  function videoBlockToInline(block, videos, videoAccepted) {
12314
12340
  const label = videoBlockLabel(block);
12315
12341
  if (!videoAccepted) return { omission: videoOmissionText("unsupported-model", label) };
12316
- let data = asString$1(block.data) || asString$1(block.base64);
12317
- let mediaType = asString$1(block.mediaType) || asString$1(block.mimeType);
12342
+ let data = asString$2(block.data) || asString$2(block.base64);
12343
+ let mediaType = asString$2(block.mediaType) || asString$2(block.mimeType);
12318
12344
  if (data?.startsWith("data:")) {
12319
12345
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
12320
12346
  if (matched) {
@@ -12341,10 +12367,10 @@ function unavailableImageText(block) {
12341
12367
  return `[image unavailable: ${label ? `${label} could not be read` : "the image could not be read"}; ask the user to attach it again if the image is needed]`;
12342
12368
  }
12343
12369
  function imageBlockToInline(block, images) {
12344
- let data = asString$1(block.data) || asString$1(block.base64);
12370
+ let data = asString$2(block.data) || asString$2(block.base64);
12345
12371
  const source = isRecord(block.source) ? block.source : void 0;
12346
- if (!data && source) data = asString$1(source.data) || asString$1(source.base64);
12347
- let mediaType = asString$1(block.mimeType) || asString$1(block.mediaType) || (source ? asString$1(source.mimeType) || asString$1(source.mediaType) : void 0) || "image/png";
12372
+ if (!data && source) data = asString$2(source.data) || asString$2(source.base64);
12373
+ let mediaType = asString$2(block.mimeType) || asString$2(block.mediaType) || (source ? asString$2(source.mimeType) || asString$2(source.mediaType) : void 0) || "image/png";
12348
12374
  if (data?.startsWith("data:")) {
12349
12375
  const matched = data.match(/^data:([^;,]+);base64,(.*)$/s);
12350
12376
  if (matched) {
@@ -12968,7 +12994,7 @@ function processOpenAIStreamLine(line, state) {
12968
12994
  if (!isRecord(chunk)) return [];
12969
12995
  const out = [];
12970
12996
  const errorPayload = isRecord(chunk.error) ? chunk.error : void 0;
12971
- if (errorPayload !== void 0) throw new LlmError(`Kimi Code stream error: ${asString$1(errorPayload.message) ?? "unknown error"}`, "PROVIDER_ERROR");
12997
+ if (errorPayload !== void 0) throw new LlmError(`Kimi Code stream error: ${asString$2(errorPayload.message) ?? "unknown error"}`, "PROVIDER_ERROR");
12972
12998
  const usage = isRecord(chunk.usage) ? chunk.usage : void 0;
12973
12999
  if (usage) {
12974
13000
  state.sawUsage = true;
@@ -12984,7 +13010,7 @@ function processOpenAIStreamLine(line, state) {
12984
13010
  const choice = isRecord(choices[0]) ? choices[0] : void 0;
12985
13011
  const delta = isRecord(choice?.delta) ? choice.delta : void 0;
12986
13012
  if (delta) {
12987
- const reasoning = asString$1(delta.reasoning_content) ?? asString$1(delta.reasoning);
13013
+ const reasoning = asString$2(delta.reasoning_content) ?? asString$2(delta.reasoning);
12988
13014
  if (reasoning !== void 0 && reasoning !== "") {
12989
13015
  out.push(...closeToolCalls(state));
12990
13016
  if (state.current === null || state.current.type !== "reasoning") out.push(...openTextBlock(state, "reasoning"));
@@ -12996,7 +13022,7 @@ function processOpenAIStreamLine(line, state) {
12996
13022
  text: sanitizeText(reasoning)
12997
13023
  });
12998
13024
  }
12999
- const content = asString$1(delta.content);
13025
+ const content = asString$2(delta.content);
13000
13026
  if (content !== void 0 && content !== "") {
13001
13027
  out.push(...closeToolCalls(state));
13002
13028
  if (state.current === null || state.current.type !== "text") out.push(...openTextBlock(state, "text"));
@@ -13014,7 +13040,7 @@ function processOpenAIStreamLine(line, state) {
13014
13040
  out.push(...applyOpenAIToolDelta(entry, state));
13015
13041
  }
13016
13042
  }
13017
- const finish = asString$1(choice?.finish_reason);
13043
+ const finish = asString$2(choice?.finish_reason);
13018
13044
  if (finish !== void 0 && finish !== "") {
13019
13045
  state.finishReason = finish;
13020
13046
  out.push(...closeCurrent(state));
@@ -13031,8 +13057,8 @@ function applyOpenAIToolDelta(entry, state) {
13031
13057
  out.push(...closeCurrent(state));
13032
13058
  call = {
13033
13059
  blockIndex: state.blocks.length,
13034
- id: asString$1(entry.id) ?? `call_${wireIndex}`,
13035
- name: asString$1(fn.name) ?? "",
13060
+ id: asString$2(entry.id) ?? `call_${wireIndex}`,
13061
+ name: asString$2(fn.name) ?? "",
13036
13062
  arguments: "",
13037
13063
  started: false
13038
13064
  };
@@ -13045,13 +13071,13 @@ function applyOpenAIToolDelta(entry, state) {
13045
13071
  state.toolCalls.set(wireIndex, call);
13046
13072
  } else {
13047
13073
  if (call.id === `call_${wireIndex}`) {
13048
- const id = asString$1(entry.id);
13074
+ const id = asString$2(entry.id);
13049
13075
  if (id !== void 0) call.id = id;
13050
13076
  }
13051
- const name = asString$1(fn.name);
13077
+ const name = asString$2(fn.name);
13052
13078
  if (name !== void 0 && name !== "") call.name = name;
13053
13079
  }
13054
- const argsDelta = asString$1(fn.arguments) ?? "";
13080
+ const argsDelta = asString$2(fn.arguments) ?? "";
13055
13081
  if (argsDelta !== "") call.arguments += argsDelta;
13056
13082
  if (!call.started) {
13057
13083
  call.started = true;
@@ -13080,7 +13106,7 @@ function processAnthropicStreamLine(line, state) {
13080
13106
  if (payload === "" || payload === "[DONE]") return [];
13081
13107
  const event = safeJsonParse(payload);
13082
13108
  if (!isRecord(event)) return [];
13083
- const type = asString$1(event.type);
13109
+ const type = asString$2(event.type);
13084
13110
  const out = [];
13085
13111
  if (type === "message_start") {
13086
13112
  const message = isRecord(event.message) ? event.message : void 0;
@@ -13092,21 +13118,21 @@ function processAnthropicStreamLine(line, state) {
13092
13118
  state.cacheWriteTokens = numberOr(usage.cache_creation_input_tokens, 0);
13093
13119
  state.outputTokens = numberOr(usage.output_tokens, 0);
13094
13120
  }
13095
- const stop = message ? asString$1(message.stop_reason) : void 0;
13121
+ const stop = message ? asString$2(message.stop_reason) : void 0;
13096
13122
  if (stop !== void 0) state.finishReason = stop;
13097
13123
  return out;
13098
13124
  }
13099
13125
  if (type === "content_block_start") {
13100
13126
  const contentIndex = numberOr(event.index, 0);
13101
13127
  const block = isRecord(event.content_block) ? event.content_block : {};
13102
- const blockType = asString$1(block.type);
13128
+ const blockType = asString$2(block.type);
13103
13129
  out.push(...closeCurrent(state));
13104
13130
  if (blockType === "tool_use") {
13105
13131
  const index = state.blocks.length;
13106
13132
  const pending = {
13107
13133
  blockIndex: index,
13108
- id: asString$1(block.id) ?? `toolu_${contentIndex}`,
13109
- name: asString$1(block.name) ?? "",
13134
+ id: asString$2(block.id) ?? `toolu_${contentIndex}`,
13135
+ name: asString$2(block.name) ?? "",
13110
13136
  arguments: "",
13111
13137
  started: true
13112
13138
  };
@@ -13149,10 +13175,10 @@ function processAnthropicStreamLine(line, state) {
13149
13175
  if (type === "content_block_delta") {
13150
13176
  const contentIndex = numberOr(event.index, 0);
13151
13177
  const delta = isRecord(event.delta) ? event.delta : {};
13152
- const deltaType = asString$1(delta.type);
13178
+ const deltaType = asString$2(delta.type);
13153
13179
  if (deltaType === "input_json_delta") {
13154
13180
  const pending = state.toolCalls.get(contentIndex);
13155
- const partial = asString$1(delta.partial_json) ?? "";
13181
+ const partial = asString$2(delta.partial_json) ?? "";
13156
13182
  if (pending !== void 0) {
13157
13183
  pending.arguments += partial;
13158
13184
  out.push({
@@ -13165,7 +13191,7 @@ function processAnthropicStreamLine(line, state) {
13165
13191
  }
13166
13192
  return out;
13167
13193
  }
13168
- const text = deltaType === "thinking_delta" ? asString$1(delta.thinking) : asString$1(delta.text);
13194
+ const text = deltaType === "thinking_delta" ? asString$2(delta.thinking) : asString$2(delta.text);
13169
13195
  if (text !== void 0 && text !== "") {
13170
13196
  const index = state.contentIndexes.get(contentIndex) ?? state.current?.index;
13171
13197
  const kind = deltaType === "thinking_delta" ? "reasoning" : "text";
@@ -13222,7 +13248,7 @@ function processAnthropicStreamLine(line, state) {
13222
13248
  }
13223
13249
  if (type === "message_delta") {
13224
13250
  const delta = isRecord(event.delta) ? event.delta : void 0;
13225
- const stop = delta ? asString$1(delta.stop_reason) : void 0;
13251
+ const stop = delta ? asString$2(delta.stop_reason) : void 0;
13226
13252
  if (stop !== void 0 && stop !== "") state.finishReason = stop;
13227
13253
  const usage = isRecord(event.usage) ? event.usage : void 0;
13228
13254
  if (usage) {
@@ -13235,7 +13261,7 @@ function processAnthropicStreamLine(line, state) {
13235
13261
  state.done = true;
13236
13262
  return closeStream(state);
13237
13263
  }
13238
- if (type === "error") throw new LlmError(`Kimi Code stream error: ${asString$1((isRecord(event.error) ? event.error : {}).message) ?? "unknown error"}`, "PROVIDER_ERROR");
13264
+ if (type === "error") throw new LlmError(`Kimi Code stream error: ${asString$2((isRecord(event.error) ? event.error : {}).message) ?? "unknown error"}`, "PROVIDER_ERROR");
13239
13265
  return out;
13240
13266
  }
13241
13267
  let cacheStats = {
@@ -14378,11 +14404,21 @@ const SUBAGENT_POLICY_EVENT = "subagent/model-selection-policy";
14378
14404
  /** Delegation tools whose child routes this guard authorizes. */
14379
14405
  const DEFAULT_DELEGATION_TOOLS = ["subagent"];
14380
14406
  /**
14407
+ * Delegation tools that start their child on the caller's own route by design.
14408
+ * `subagent_fork` is the shipped one: it omits `modelSelectionSettings`, so it
14409
+ * exposes no route parameters and seeds the child from the parent's own
14410
+ * conversation — a child on any other route would discard the inherited prefix
14411
+ * and its cache. Inherit mode is what keeps that design honest: the fork still
14412
+ * cannot choose, but an allowlist-carrying Session now refuses to let it run on
14413
+ * a route the user did not authorize.
14414
+ */
14415
+ const DEFAULT_SUBAGENT_INHERIT_TOOLS = ["subagent_fork"];
14416
+ /**
14381
14417
  * Read one deployment event field as a string.
14382
14418
  * @param value - Candidate field value from a durable event.
14383
14419
  * @returns the string value, or undefined for any other type.
14384
14420
  */
14385
- function asString(value) {
14421
+ function asString$1(value) {
14386
14422
  return typeof value === "string" ? value : void 0;
14387
14423
  }
14388
14424
  /**
@@ -14390,7 +14426,7 @@ function asString(value) {
14390
14426
  * @param value - Candidate field value from a durable event.
14391
14427
  * @returns the record value, or undefined for arrays, null, and primitives.
14392
14428
  */
14393
- function asRecord(value) {
14429
+ function asRecord$1(value) {
14394
14430
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
14395
14431
  }
14396
14432
  /**
@@ -14407,13 +14443,13 @@ function asBoolean(value) {
14407
14443
  * @returns every well-formed route, or undefined when the payload carries none.
14408
14444
  */
14409
14445
  function parseAllowedRoutes(data) {
14410
- const allowed = asRecord(data)?.["allowedModels"];
14446
+ const allowed = asRecord$1(data)?.["allowedModels"];
14411
14447
  if (!Array.isArray(allowed)) return void 0;
14412
14448
  const routes = [];
14413
14449
  for (const entry of allowed) {
14414
- const record = asRecord(entry);
14415
- const provider = asString(record?.["provider"]);
14416
- const model = asString(record?.["model"]);
14450
+ const record = asRecord$1(entry);
14451
+ const provider = asString$1(record?.["provider"]);
14452
+ const model = asString$1(record?.["model"]);
14417
14453
  if (provider === void 0 || model === void 0) continue;
14418
14454
  if (provider.length === 0 || model.length === 0) continue;
14419
14455
  routes.push({
@@ -14458,7 +14494,7 @@ function authorizedRoutesFor(agent, sessions) {
14458
14494
  if (recorded !== void 0) return recorded;
14459
14495
  const header = session.header;
14460
14496
  if (header?.origin !== "subagent") return void 0;
14461
- const parentId = asString(header.parentSession);
14497
+ const parentId = asString$1(header.parentSession);
14462
14498
  if (parentId === void 0) return void 0;
14463
14499
  session = sessions.get(parentId);
14464
14500
  }
@@ -14474,7 +14510,7 @@ function subagentModelSelectionPreference(settings) {
14474
14510
  const register = settings["register"];
14475
14511
  if (typeof register !== "function") return void 0;
14476
14512
  try {
14477
- const value = asRecord(register.call(settings, SUBAGENT_MODEL_SELECTION_NAMESPACE, z.object({
14513
+ const value = asRecord$1(register.call(settings, SUBAGENT_MODEL_SELECTION_NAMESPACE, z.object({
14478
14514
  enabled: z.boolean().default(false),
14479
14515
  allowedModels: z.array(z.object({
14480
14516
  provider: z.string().min(1).required(),
@@ -14490,6 +14526,40 @@ function subagentModelSelectionPreference(settings) {
14490
14526
  return;
14491
14527
  }
14492
14528
  }
14529
+ /**
14530
+ * Read the route an inherit-mode child would run on: the calling agent's own
14531
+ * effective request route. This mirrors the delegation seam's
14532
+ * `parentAgentOptionsForDelegation`, where the latest request header owns
14533
+ * provider/model after request-time model selection and the creation options
14534
+ * remain the fallback before the first request. `AuthorizationAgent.options` is
14535
+ * deliberately NOT a fallback while a header exists — after a mid-session model
14536
+ * switch the creation options are stale, and trusting them would authorize the
14537
+ * route the session no longer uses.
14538
+ * @param agent - Calling agent.
14539
+ * @returns the inherited route fields, each absent when its source did not supply it.
14540
+ */
14541
+ function inheritedRouteOf(agent) {
14542
+ const session = agent?.session;
14543
+ let header;
14544
+ try {
14545
+ header = session?.requestHeader?.();
14546
+ } catch {
14547
+ header = void 0;
14548
+ }
14549
+ if (header?.config !== void 0) {
14550
+ const provider = asString$1(header.config.provider);
14551
+ const model = asString$1(header.config.model);
14552
+ if (provider !== void 0 || model !== void 0) return {
14553
+ provider,
14554
+ model,
14555
+ reasoningEffort: asString$1(header.config.reasoningEffort)
14556
+ };
14557
+ }
14558
+ return {
14559
+ provider: asString$1(agent?.options?.provider),
14560
+ model: asString$1(agent?.options?.model)
14561
+ };
14562
+ }
14493
14563
  /** Whether an exact route is authorized by a allowlist. */
14494
14564
  function routesInclude(allowed, provider, model) {
14495
14565
  return allowed.some((route) => route.provider === provider && route.model === model);
@@ -14534,24 +14604,76 @@ function unauthorizedRouteReason(provider, model, allowed, explicit) {
14534
14604
  return `subagent model selection: ${explicit ? "the model this call selected is not on the Session allowlist" : "the route this call would inherit from the parent is not on the Session allowlist"} (${route}). Provide an authorized provider and model — ${authorizedRoutesText(allowed)} — using list_subagent_models to inspect their reasoning efforts.`;
14535
14605
  }
14536
14606
  /**
14607
+ * Build the denial reason for an inherit-mode delegation that named a route.
14608
+ * The fork backend accepts no route parameters, so a named pair is not a
14609
+ * partial override the backend would ignore — it is a request to change the
14610
+ * route, which is exactly what an inherit-mode tool exists to prevent.
14611
+ * @param toolName - the tool the model called.
14612
+ * @param provider - the provider the call named.
14613
+ * @param model - the model the call named.
14614
+ * @returns the corrective reason handed back to the model.
14615
+ */
14616
+ function inheritOverrideReason(toolName, provider, model) {
14617
+ return `subagent model selection: "${toolName}" always runs on the calling agent's own route and accepts no provider/model. This call named "${provider}/${model}". Remove those fields, or delegate through a tool that supports explicit child model selection.`;
14618
+ }
14619
+ /**
14620
+ * Build the denial reason for an inherit-mode delegation whose inherited route
14621
+ * is outside the allowlist. Unlike the explicit case this is not something the
14622
+ * call can fix by naming a route, so the reason points at the tool that can.
14623
+ * @param toolName - the tool the model called.
14624
+ * @param provider - the parent route the child would inherit, when known.
14625
+ * @param model - the parent model the child would inherit, when known.
14626
+ * @param allowed - Routes the calling Session authorizes.
14627
+ * @param reasoningEffort - the inherited effort, when the header recorded one.
14628
+ * @returns the corrective reason handed back to the model.
14629
+ */
14630
+ function inheritRouteDenialReason(toolName, provider, model, allowed, reasoningEffort) {
14631
+ return `subagent model selection: "${toolName}" keeps its child on ${provider === void 0 || model === void 0 ? "the calling agent's route" : `"${provider}/${model}"${reasoningEffort === void 0 ? "" : ` (${reasoningEffort})`}`}, which this Session's allowlist does not authorize, so it is unavailable for now. Its child cannot be re-routed, so either delegate through a tool that exposes provider and model — passing one of ${authorizedRoutesText(allowed)} — or continue on an authorized model for this session, after which ${toolName} works again.`;
14632
+ }
14633
+ /**
14634
+ * Resolve one tool's enforcement mode from the configured policies. An
14635
+ * unconfigured name is `undefined`: the guard does not police it, which is how
14636
+ * the plain-name configuration keeps its existing meaning.
14637
+ * @param policies - Configured tool policies in precedence order.
14638
+ * @param toolName - Tool being dispatched.
14639
+ * @returns the first matching mode, or undefined when the guard ignores the tool.
14640
+ */
14641
+ function delegationModeOf(policies, toolName) {
14642
+ for (const policy of policies) if (policy.name === toolName) return policy.mode;
14643
+ }
14644
+ /**
14537
14645
  * Decide whether one delegation call may start its child.
14538
14646
  * @param agent - Calling agent.
14539
14647
  * @param toolName - Tool being dispatched.
14540
14648
  * @param args - Parsed tool arguments.
14541
14649
  * @param preference - Current Host preference, when the settings service exists.
14542
14650
  * @param sessions - Session registry used for ancestor lookup.
14543
- * @param toolNames - Delegation tool names this guard authorizes.
14651
+ * @param toolNames - Delegation tool names this guard authorizes (explicit mode).
14544
14652
  * @param scope - Whether an unrecorded Session falls back to the preference.
14653
+ * @param inheritToolNames - Delegation tools that start a child on the caller's own route.
14545
14654
  * @returns a denial reason, or undefined to leave the call untouched.
14546
14655
  */
14547
- function delegationDenialReason(agent, toolName, args, preference, sessions, toolNames = DEFAULT_DELEGATION_TOOLS, scope = "session") {
14548
- if (!toolNames.includes(toolName)) return void 0;
14656
+ function delegationDenialReason(agent, toolName, args, preference, sessions, toolNames = DEFAULT_DELEGATION_TOOLS, scope = "session", inheritToolNames = []) {
14657
+ const mode = delegationModeOf([...toolNames.map((name) => ({
14658
+ name,
14659
+ mode: "explicit"
14660
+ })), ...inheritToolNames.map((name) => ({
14661
+ name,
14662
+ mode: "inherit"
14663
+ }))], toolName);
14664
+ if (mode === void 0) return void 0;
14549
14665
  if (preference !== void 0 && !preference.enabled) return void 0;
14550
14666
  const allowed = authorizedRoutesFor(agent, sessions) ?? (scope === "preference" ? preference?.allowedModels ?? [] : []);
14551
14667
  if (allowed.length === 0) return void 0;
14552
- const request = asRecord(args) ?? {};
14553
- const requestedProvider = asString(request["provider"]);
14554
- const requestedModel = asString(request["model"]);
14668
+ const request = asRecord$1(args) ?? {};
14669
+ const requestedProvider = asString$1(request["provider"]);
14670
+ const requestedModel = asString$1(request["model"]);
14671
+ if (mode === "inherit") {
14672
+ if (requestedProvider !== void 0 && requestedModel !== void 0) return inheritOverrideReason(toolName, requestedProvider, requestedModel);
14673
+ const inherited = inheritedRouteOf(agent);
14674
+ if (inherited.provider !== void 0 && inherited.model !== void 0 && routesInclude(allowed, inherited.provider, inherited.model)) return void 0;
14675
+ return inheritRouteDenialReason(toolName, inherited.provider, inherited.model, allowed, inherited.reasoningEffort);
14676
+ }
14555
14677
  if (requestedProvider === void 0) return requestedModel === void 0 ? missingRouteReason(allowed) : partialRouteReason("provider", requestedModel, allowed);
14556
14678
  if (requestedModel === void 0) return partialRouteReason("model", requestedProvider, allowed);
14557
14679
  if (routesInclude(allowed, requestedProvider, requestedModel)) return void 0;
@@ -14565,7 +14687,7 @@ function delegationDenialReason(agent, toolName, args, preference, sessions, too
14565
14687
  * @returns a guard that denies delegations outside the Session allowlist.
14566
14688
  */
14567
14689
  function createSubagentAuthorization(options) {
14568
- return (agent, toolName, args) => delegationDenialReason(agent, toolName, args, subagentModelSelectionPreference(options.settings), options.sessions, options.toolNames, options.scope ?? "session");
14690
+ return (agent, toolName, args) => delegationDenialReason(agent, toolName, args, subagentModelSelectionPreference(options.settings), options.sessions, options.toolNames, options.scope ?? "session", options.inheritToolNames ?? []);
14569
14691
  }
14570
14692
  /** Delegation names this guard recognizes when configuration omits them. */
14571
14693
  function normalizeDelegationToolNames(value) {
@@ -14573,6 +14695,29 @@ function normalizeDelegationToolNames(value) {
14573
14695
  return [...new Set(names.length === 0 ? [...DEFAULT_DELEGATION_TOOLS] : names.map((name) => name.trim()))];
14574
14696
  }
14575
14697
  /**
14698
+ * Normalize the configured inherit-mode names. Unlike
14699
+ * {@link normalizeDelegationToolNames}, an empty array is a deliberate opt-out
14700
+ * (`[]`) rather than a request for the default, and `undefined` selects the
14701
+ * shipped default.
14702
+ * @param value - Candidate configuration value.
14703
+ * @returns the exact inherit-mode names this guard enforces.
14704
+ */
14705
+ function normalizeInheritToolNames(value) {
14706
+ if (value === void 0) return [...DEFAULT_SUBAGENT_INHERIT_TOOLS];
14707
+ const names = Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [];
14708
+ return [...new Set(names.map((name) => name.trim()))];
14709
+ }
14710
+ /**
14711
+ * Validate the configured inherit-mode names. Emptiness is legal here — it
14712
+ * disables inherit enforcement — but a malformed entry is not.
14713
+ * @param toolNames - Candidate inherit-mode delegation tool names.
14714
+ * @returns the exact names this guard enforces in inherit mode.
14715
+ */
14716
+ function validateInheritToolNames(toolNames) {
14717
+ for (const name of toolNames) if (name.length === 0 || name !== name.trim()) throw new Error(`dsh-chatgpt-subscription: subagentModelInheritTools entry "${name}" must be a non-empty trimmed string`);
14718
+ return [...toolNames];
14719
+ }
14720
+ /**
14576
14721
  * Validate the plugin configuration that owns this guard.
14577
14722
  * @param toolNames - Candidate delegation tool names.
14578
14723
  * @returns the exact names this guard authorizes.
@@ -14591,12 +14736,15 @@ function validateDelegationToolNames(toolNames) {
14591
14736
  */
14592
14737
  function installSubagentModelAuthorization(ctx, sessions, config = {}) {
14593
14738
  const toolNames = validateDelegationToolNames(config.toolNames ?? [...DEFAULT_DELEGATION_TOOLS]);
14739
+ const inheritToolNames = validateInheritToolNames(config.inheritToolNames ?? []);
14740
+ if (inheritToolNames.some((name) => toolNames.includes(name))) throw new Error(`dsh-chatgpt-subscription: a delegation tool cannot be both an explicit and an inherit tool (${inheritToolNames.filter((name) => toolNames.includes(name)).join(", ")})`);
14594
14741
  const scope = validateAuthorizationScope(config.scope ?? "session");
14595
14742
  const settings = ctx.get?.("settings");
14596
14743
  const authorize = createSubagentAuthorization({
14597
14744
  settings,
14598
14745
  sessions,
14599
14746
  toolNames,
14747
+ inheritToolNames,
14600
14748
  scope
14601
14749
  });
14602
14750
  return ctx.tools.guard((exec) => authorize(exec.agent, exec.name, exec.arguments));
@@ -14816,6 +14964,213 @@ function syncPresetTrees(sourceRoot, targetRoot, retire = []) {
14816
14964
  return result;
14817
14965
  }
14818
14966
  //#endregion
14967
+ //#region src/host/subagent-route-audit.ts
14968
+ /**
14969
+ * Read one field as a string.
14970
+ * @param value - Candidate value from a durable event or header.
14971
+ * @returns the string, or undefined for any other type.
14972
+ */
14973
+ function asString(value) {
14974
+ return typeof value === "string" && value.length > 0 ? value : void 0;
14975
+ }
14976
+ /**
14977
+ * Read one field as a plain object.
14978
+ * @param value - Candidate value.
14979
+ * @returns the record, or undefined for arrays, null, and primitives.
14980
+ */
14981
+ function asRecord(value) {
14982
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
14983
+ }
14984
+ /**
14985
+ * Extract the child route a descriptor recorded.
14986
+ * @param data - `subagent/descriptor` payload.
14987
+ * @returns the declared route fields plus provider and label, each when present.
14988
+ */
14989
+ function readChildDescriptor(data) {
14990
+ const record = asRecord(data);
14991
+ if (record === void 0) return void 0;
14992
+ const provider = asString(record["provider"]);
14993
+ const childProvider = asString(record["agentProvider"]);
14994
+ const childModel = asString(record["agentModel"]);
14995
+ const label = asString(record["label"]);
14996
+ if (provider === void 0 && childProvider === void 0 && childModel === void 0) return void 0;
14997
+ return {
14998
+ ...provider === void 0 ? {} : { provider },
14999
+ ...childProvider === void 0 ? {} : { childProvider },
15000
+ ...childModel === void 0 ? {} : { childModel },
15001
+ ...label === void 0 ? {} : { label }
15002
+ };
15003
+ }
15004
+ /**
15005
+ * Read the child-route allowlist a session recorded, from its own log.
15006
+ *
15007
+ * The live guard reads the same event through `policyRoutesOf`, which walks a
15008
+ * session's `eventAt` accessor. The audit holds a resolved session instead, so
15009
+ * it scans the snapshot it already has rather than reopening the log per child.
15010
+ * @param session - the session whose policy is read.
15011
+ * @returns the authorized routes, or undefined when the session recorded none.
15012
+ */
15013
+ function auditedRoutesOf(session) {
15014
+ for (const event of session.events ?? []) {
15015
+ if (event.type !== "subagent/model-selection-policy") continue;
15016
+ const allowed = asRecord(event.data)?.["allowedModels"];
15017
+ if (!Array.isArray(allowed)) continue;
15018
+ const routes = [];
15019
+ for (const entry of allowed) {
15020
+ const provider = asString(asRecord(entry)?.["provider"]);
15021
+ const model = asString(asRecord(entry)?.["model"]);
15022
+ if (provider !== void 0 && model !== void 0) routes.push({
15023
+ provider,
15024
+ model
15025
+ });
15026
+ }
15027
+ if (routes.length > 0) return routes;
15028
+ }
15029
+ }
15030
+ /**
15031
+ * Collect the child routes one parent session recorded.
15032
+ *
15033
+ * Discovery uses both durable signals because they cover different backends: a
15034
+ * `subagent/catalog` event names every continuable child the parent created,
15035
+ * while a descriptor-less or one-shot child is only reachable by scanning the
15036
+ * registry for a session whose header names this parent.
15037
+ * @param parent - the parent session to inspect.
15038
+ * @param sessions - registry used to resolve each child's own log and header.
15039
+ * @returns one finding per child whose route could be read.
15040
+ */
15041
+ function childRoutesOf(parent, sessions) {
15042
+ const parentId = asString(parent.id);
15043
+ const seen = /* @__PURE__ */ new Set();
15044
+ const findings = [];
15045
+ const inspect = (child, childId) => {
15046
+ if (child === void 0 || seen.has(childId)) return;
15047
+ seen.add(childId);
15048
+ const descriptor = child.events?.map((event) => event.type === "subagent/descriptor" ? readChildDescriptor(event.data) : void 0).find((entry) => entry !== void 0);
15049
+ if (descriptor === void 0) return;
15050
+ const headerParent = asString(child.header?.parentSession);
15051
+ findings.push({
15052
+ childId,
15053
+ ...headerParent === void 0 ? {} : { parentId: headerParent },
15054
+ ...descriptor
15055
+ });
15056
+ };
15057
+ for (const event of parent.events ?? []) {
15058
+ if (event.type !== "subagent/catalog") continue;
15059
+ const childId = asString(asRecord(event.data)?.["childId"]);
15060
+ if (childId === void 0) continue;
15061
+ inspect(sessions.get(childId), childId);
15062
+ }
15063
+ if (parentId !== void 0) for (const child of listSessions(sessions)) {
15064
+ const childId = asString(child.id);
15065
+ if (childId === void 0 || childId === parentId) continue;
15066
+ if (asString(child.header?.parentSession) !== parentId) continue;
15067
+ inspect(child, childId);
15068
+ }
15069
+ return findings;
15070
+ }
15071
+ /**
15072
+ * Enumerate the registry, tolerating a resolver that exposes no listing.
15073
+ * @param sessions - the resolver to enumerate.
15074
+ * @returns every session it can serve, or an empty array.
15075
+ */
15076
+ function listSessions(sessions) {
15077
+ const list = sessions.list;
15078
+ if (typeof list !== "function") return [];
15079
+ try {
15080
+ const entries = list.call(sessions);
15081
+ return Array.isArray(entries) ? entries : [];
15082
+ } catch {
15083
+ return [];
15084
+ }
15085
+ }
15086
+ /**
15087
+ * Read the route a session's next request would use: its latest request header,
15088
+ * else its declared creation options. A child that recorded no route of its own
15089
+ * runs here, and this is also the baseline a recorded child route is compared
15090
+ * against.
15091
+ * @param session - the session to read.
15092
+ * @returns the route fields, each absent when its source did not supply it.
15093
+ */
15094
+ function sessionRouteOf(session) {
15095
+ const config = asRecord(asRecord(session?.requestHeader?.())?.["config"]);
15096
+ const provider = asString(config?.["provider"]);
15097
+ const model = asString(config?.["model"]);
15098
+ if (provider !== void 0 || model !== void 0) return {
15099
+ ...provider === void 0 ? {} : { provider },
15100
+ ...model === void 0 ? {} : { model }
15101
+ };
15102
+ const options = asRecord(session?.options);
15103
+ return {
15104
+ ...asString(options?.["provider"]) === void 0 ? {} : { provider: asString(options?.["provider"]) },
15105
+ ...asString(options?.["model"]) === void 0 ? {} : { model: asString(options?.["model"]) }
15106
+ };
15107
+ }
15108
+ /**
15109
+ * Resolve the route a finding actually ran on, following the parent when the
15110
+ * child recorded none, and report whether it matches the parent's.
15111
+ * @param finding - the child under audit.
15112
+ * @param sessions - registry used to resolve the parent.
15113
+ * @returns the effective route and whether it equals the parent's route.
15114
+ */
15115
+ function effectiveRouteOf(finding, sessions) {
15116
+ const parentRoute = finding.parentId === void 0 ? {} : sessionRouteOf(sessions.get(finding.parentId));
15117
+ const route = finding.childProvider !== void 0 || finding.childModel !== void 0 ? {
15118
+ provider: finding.childProvider,
15119
+ model: finding.childModel
15120
+ } : parentRoute;
15121
+ return {
15122
+ ...route,
15123
+ sameAsParent: route.provider !== void 0 && route.model !== void 0 && parentRoute.provider === route.provider && parentRoute.model === route.model
15124
+ };
15125
+ }
15126
+ /**
15127
+ * Decide whether one effective route is covered by an allowlist.
15128
+ * @param allowed - routes the governing Session authorized.
15129
+ * @param route - the route the child actually ran on.
15130
+ * @returns whether the route is authorized.
15131
+ */
15132
+ function routeAllowed(allowed, route) {
15133
+ if (route.provider === void 0 || route.model === void 0) return true;
15134
+ return allowed.some((entry) => entry.provider === route.provider && entry.model === route.model);
15135
+ }
15136
+ /**
15137
+ * Fold one parent session's children into the violations worth reporting.
15138
+ * A finding with an unresolvable route is reported as neither: guessing would
15139
+ * turn this advisory list into a source of false accusations.
15140
+ * @param parent - the parent session to audit.
15141
+ * @param sessions - registry used to resolve children and parents.
15142
+ * @param allowed - routes the parent Session authorized, when it recorded any.
15143
+ * @returns violations, ordered as the children were discovered.
15144
+ */
15145
+ function auditChildRoutes(parent, sessions, allowed) {
15146
+ if (allowed === void 0 || allowed.length === 0) return [];
15147
+ const violations = [];
15148
+ for (const finding of childRoutesOf(parent, sessions)) {
15149
+ const effective = effectiveRouteOf(finding, sessions);
15150
+ if (routeAllowed(allowed, effective)) continue;
15151
+ violations.push({
15152
+ finding,
15153
+ route: {
15154
+ provider: effective.provider,
15155
+ model: effective.model
15156
+ },
15157
+ sameAsParent: effective.sameAsParent
15158
+ });
15159
+ }
15160
+ return violations;
15161
+ }
15162
+ /**
15163
+ * Render one violation as a single model-facing line.
15164
+ * @param violation - the violation to describe.
15165
+ * @returns a one-line summary naming the child, its route, and its origin.
15166
+ */
15167
+ function violationText(violation) {
15168
+ const { finding, route, sameAsParent } = violation;
15169
+ const label = finding.label === void 0 ? "" : ` "${finding.label}"`;
15170
+ const where = route.provider === void 0 || route.model === void 0 ? "an unresolved route" : `${route.provider}/${route.model}`;
15171
+ return `subagent ${finding.childId}${label} ran on ${where}${sameAsParent ? " — the same route as its parent" : " — a route of its own"}${finding.provider === void 0 ? "" : ` (provider "${finding.provider}")`}`;
15172
+ }
15173
+ //#endregion
14819
15174
  //#region src/host/relay-probe.ts
14820
15175
  /**
14821
15176
  * Read-only diagnostic probe for the child→parent subagent relay.
@@ -15198,6 +15553,7 @@ const Config = z.object({
15198
15553
  syncAgentPresets: z.boolean().default(true),
15199
15554
  subagentModelAuthorization: z.boolean().default(true),
15200
15555
  subagentModelTools: z.array(z.string()).default([]),
15556
+ subagentModelInheritTools: z.array(z.string()).default(DEFAULT_SUBAGENT_INHERIT_TOOLS),
15201
15557
  subagentModelScope: z.union([z.const("session"), z.const("preference")]).default("session")
15202
15558
  });
15203
15559
  const inject = [
@@ -15232,6 +15588,7 @@ function apply(ctx, pluginConfig = {}) {
15232
15588
  const kimiCodeModelSettings = new FileModelSettingsStore$2();
15233
15589
  const kimiCodePreferences = registerKimiCodePreferenceStore(ctx.settings, kimiCodeModelSettings);
15234
15590
  const delegationToolNames = normalizeDelegationToolNames(pluginConfig.subagentModelTools);
15591
+ const delegationInheritNames = normalizeInheritToolNames(pluginConfig.subagentModelInheritTools);
15235
15592
  if (pluginConfig.subagentModelAuthorization !== false) ctx.inject(["sessions"], (scoped) => {
15236
15593
  const sessions = scoped.get("sessions");
15237
15594
  if (sessions === void 0) return;
@@ -15239,6 +15596,7 @@ function apply(ctx, pluginConfig = {}) {
15239
15596
  if (typeof scoped.tools?.guard !== "function") return () => void 0;
15240
15597
  return installSubagentModelAuthorization(scoped, sessions, {
15241
15598
  toolNames: delegationToolNames,
15599
+ inheritToolNames: delegationInheritNames,
15242
15600
  scope: pluginConfig.subagentModelScope ?? "session"
15243
15601
  });
15244
15602
  }, "dsh-chatgpt-subscription: subagent model authorization");
@@ -15342,7 +15700,29 @@ function apply(ctx, pluginConfig = {}) {
15342
15700
  ctx.logger.warn(`[dsh-chatgpt-subscription] Web provider selection could not be applied: ${error instanceof Error ? error.message : String(error)}`);
15343
15701
  });
15344
15702
  };
15345
- const disposeRoutes = registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwitcher);
15703
+ const readRouteAudit = (sessionId) => {
15704
+ const sessions = ctx.get("sessions");
15705
+ const target = sessions.get(sessionId);
15706
+ if (target === void 0) throw new Error(`Unknown session "${sessionId}".`);
15707
+ const allowed = auditedRoutesOf(target);
15708
+ return Promise.resolve({
15709
+ sessionId,
15710
+ allowedModels: (allowed ?? []).map((route) => ({
15711
+ provider: route.provider,
15712
+ model: route.model
15713
+ })),
15714
+ violations: auditChildRoutes(target, sessions, allowed).map((violation) => ({
15715
+ childId: violation.finding.childId,
15716
+ parentId: violation.finding.parentId ?? null,
15717
+ provider: violation.finding.provider ?? null,
15718
+ label: violation.finding.label ?? null,
15719
+ routeProvider: violation.route.provider ?? null,
15720
+ routeModel: violation.route.model ?? null,
15721
+ sameAsParent: violation.sameAsParent
15722
+ }))
15723
+ });
15724
+ };
15725
+ const disposeRoutes = registerRoutes(ctx, oauth, usage, preferences, proxyManager, searchSwitcher, readRouteAudit);
15346
15726
  const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID$3], adapter);
15347
15727
  const disposeImageTool = ctx.tools.register(createCodexImageTool(oauth, ctx.attachments, { fetchFn: proxyFetch }));
15348
15728
  const disposeVideoTool = ctx.tools.register(createKimiVideoTool(ctx, { fetchFn: proxyFetch }));
@@ -15392,4 +15772,4 @@ function localWebServerBaseUrl(host, port) {
15392
15772
  return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
15393
15773
  }
15394
15774
  //#endregion
15395
- export { AntigravityAdapter, CodexChatGptAdapter, CommandCodeAdapter, FileCredentialStore as CommandCodeCredentialStore, FileModelSettingsStore as CommandCodeModelSettingsStore, Config, FileCredentialStore$1 as FileCredentialStore, FileModelSettingsStore$1 as FileModelSettingsStore, KIMI_CODE_MODELS, KIMI_CODE_RETRY_POLICY_CONFIG, KimiCodeAdapter, FileCredentialStore$2 as KimiCodeCredentialStore, FileModelSettingsStore$2 as KimiCodeModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, RELAY_PROBE_ENV, RELAY_PROBE_FILE_ENV, RELAY_PROBE_FILE_NAME, RELAY_PROBE_MAX_BYTES, RELAY_SOURCE_KINDS, RelayProbe, ResponsesClient, SUBAGENT_MODEL_SELECTION_NAMESPACE, SUBAGENT_POLICY_EVENT, SearchProviderSwitcher, UsageService, WindowsDpapiTokenStore, apply, authorizedRoutesFor, beginWebLogin as beginKimiCodeLogin, beginWebLogin$1 as beginWebLogin, classifyKimiFailure, clearCachedQuota, clearCachedQuota$1 as clearCommandCodeQuota, clearCachedQuota$2 as clearKimiCodeQuota, credentialPath as commandCodeCredentialPath, modelSettingsPath as commandCodeModelSettingsPath, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createFileRelayProbeSink, createPlatformTokenStore, createSubagentAuthorization, credentialPath$1 as credentialPath, delegationDenialReason, detectSystemProxy, ensureAccessToken as ensureKimiCodeAccessToken, fetchAccountQuota, fetchAccountQuota$1 as fetchCommandCodeQuota, fetchAccountQuota$2 as fetchKimiCodeQuota, fetchUserInfo as fetchKimiCodeUserInfo, getCachedQuota, getWebLoginStatus as getCommandCodeLoginStatus, getCachedQuota$1 as getCommandCodeQuota, getCommandCodeWebStatus, getWebLoginStatus$1 as getKimiCodeLoginStatus, getCachedQuota$2 as getKimiCodeQuota, getKimiCodeWebStatus, inject, installRelayProbe, installSubagentModelAuthorization, credentialPath$2 as kimiCodeCredentialPath, kimiCodeModelDef, modelSettingsPath$1 as kimiCodeModelSettingsPath, loadProviderModels as loadCommandCodeModels, loadProviderModels$1 as loadKimiCodeModels, loginAndSave, mapCodexUsage, modelSettingsPath$2 as modelSettingsPath, normalizeDelegationToolNames, parseAllowedRoutes, parseCodexUsage, parseResponsesStream, policyRoutesOf, refreshAntigravityToken, refreshAccessToken as refreshKimiCodeToken, registerCommandCodePreferenceStore, registerCommandCodeRoutes, registerKimiCodePreferenceStore, registerKimiCodeRoutes, relayProbeEnabled, relayProbeEnvFile, relayProbeEnvValue, relayProbeLogPath, requestDeviceAuthorization as requestKimiCodeDeviceAuthorization, resolveRegion as resolveKimiCodeRegion, saveApiKey as saveCommandCodeApiKey, beginWebLogin$2 as startCommandCodeLogin, subagentModelSelectionPreference, unauthorizedRouteReason, validateAuthorizationScope, validateDelegationToolNames };
15775
+ export { AntigravityAdapter, CodexChatGptAdapter, CommandCodeAdapter, FileCredentialStore as CommandCodeCredentialStore, FileModelSettingsStore as CommandCodeModelSettingsStore, Config, DEFAULT_SUBAGENT_INHERIT_TOOLS, FileCredentialStore$1 as FileCredentialStore, FileModelSettingsStore$1 as FileModelSettingsStore, KIMI_CODE_MODELS, KIMI_CODE_RETRY_POLICY_CONFIG, KimiCodeAdapter, FileCredentialStore$2 as KimiCodeCredentialStore, FileModelSettingsStore$2 as KimiCodeModelSettingsStore, LinuxFileTokenStore, MacKeychainTokenStore, OAuthService, ProxyManager, RELAY_PROBE_ENV, RELAY_PROBE_FILE_ENV, RELAY_PROBE_FILE_NAME, RELAY_PROBE_MAX_BYTES, RELAY_SOURCE_KINDS, RelayProbe, ResponsesClient, SUBAGENT_MODEL_SELECTION_NAMESPACE, SUBAGENT_POLICY_EVENT, SearchProviderSwitcher, UsageService, WindowsDpapiTokenStore, apply, auditChildRoutes, auditedRoutesOf, authorizedRoutesFor, beginWebLogin as beginKimiCodeLogin, beginWebLogin$1 as beginWebLogin, childRoutesOf, classifyKimiFailure, clearCachedQuota, clearCachedQuota$1 as clearCommandCodeQuota, clearCachedQuota$2 as clearKimiCodeQuota, credentialPath as commandCodeCredentialPath, modelSettingsPath as commandCodeModelSettingsPath, createCodexFetchProvider, createCodexImageTool, createCodexSearchProvider, createFileRelayProbeSink, createPlatformTokenStore, createSubagentAuthorization, credentialPath$1 as credentialPath, delegationDenialReason, delegationModeOf, detectSystemProxy, effectiveRouteOf, ensureAccessToken as ensureKimiCodeAccessToken, fetchAccountQuota, fetchAccountQuota$1 as fetchCommandCodeQuota, fetchAccountQuota$2 as fetchKimiCodeQuota, fetchUserInfo as fetchKimiCodeUserInfo, getCachedQuota, getWebLoginStatus as getCommandCodeLoginStatus, getCachedQuota$1 as getCommandCodeQuota, getCommandCodeWebStatus, getWebLoginStatus$1 as getKimiCodeLoginStatus, getCachedQuota$2 as getKimiCodeQuota, getKimiCodeWebStatus, inheritOverrideReason, inheritRouteDenialReason, inheritedRouteOf, inject, installRelayProbe, installSubagentModelAuthorization, credentialPath$2 as kimiCodeCredentialPath, kimiCodeModelDef, modelSettingsPath$1 as kimiCodeModelSettingsPath, loadProviderModels as loadCommandCodeModels, loadProviderModels$1 as loadKimiCodeModels, loginAndSave, mapCodexUsage, modelSettingsPath$2 as modelSettingsPath, normalizeDelegationToolNames, normalizeInheritToolNames, parseAllowedRoutes, parseCodexUsage, parseResponsesStream, policyRoutesOf, readChildDescriptor, refreshAntigravityToken, refreshAccessToken as refreshKimiCodeToken, registerCommandCodePreferenceStore, registerCommandCodeRoutes, registerKimiCodePreferenceStore, registerKimiCodeRoutes, relayProbeEnabled, relayProbeEnvFile, relayProbeEnvValue, relayProbeLogPath, requestDeviceAuthorization as requestKimiCodeDeviceAuthorization, resolveRegion as resolveKimiCodeRegion, saveApiKey as saveCommandCodeApiKey, beginWebLogin$2 as startCommandCodeLogin, subagentModelSelectionPreference, unauthorizedRouteReason, validateAuthorizationScope, validateDelegationToolNames, validateInheritToolNames, violationText };