@cabane/companion 0.6.157 → 0.6.158

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.
Files changed (3) hide show
  1. package/dist/cli.js +217 -166
  2. package/dist/runtime.js +202 -165
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2896,6 +2896,208 @@ var init_options = __esm({
2896
2896
  }
2897
2897
  });
2898
2898
 
2899
+ // packages/agent-runtime/src/claude-code/failure-evidence.ts
2900
+ function createFailureEvidence() {
2901
+ const signals = { sawRejectedLimit: false };
2902
+ return {
2903
+ observe(msg) {
2904
+ if (msg.type === "assistant" || msg.type === "auth_status") {
2905
+ const error = msg.error;
2906
+ if (typeof error === "string" && error.length > 0) {
2907
+ if (msg.type === "assistant") signals.lastAssistantError = error;
2908
+ else signals.authError = error;
2909
+ }
2910
+ } else if (msg.type === "rate_limit_event") {
2911
+ const info = msg.rate_limit_info;
2912
+ if (info?.status === "rejected") {
2913
+ signals.sawRejectedLimit = true;
2914
+ signals.rateLimitResetIso = resetsAtToIso(info.resetsAt) ?? signals.rateLimitResetIso;
2915
+ if (typeof info.rateLimitType === "string") signals.rateLimitType = info.rateLimitType;
2916
+ }
2917
+ }
2918
+ },
2919
+ preInitReason(msg) {
2920
+ const failure = msg ? classifyPreInitFrame(msg, signals) : classifyFailure(signals, { text: "" });
2921
+ return failure ? encodeFailureReason(failure) : "session_start_failed";
2922
+ },
2923
+ failedResultReason(msg) {
2924
+ const failure = classifyResultFailure(msg, signals);
2925
+ const resultText = msg.result ?? "";
2926
+ const isError = msg.is_error === true;
2927
+ return failure ? encodeFailureReason(failure) : isError ? `error:${resultText.slice(0, 200) || "unknown"}` : `result_error:${msg.subtype}`;
2928
+ },
2929
+ thrownFailure(message2, initReceived) {
2930
+ return initReceived ? classifyErrorText(message2) : classifyFailure(signals, { text: message2 });
2931
+ }
2932
+ };
2933
+ }
2934
+ function classifyFailure(s, frame) {
2935
+ const rejectedIsCap = s.sawRejectedLimit && (s.rateLimitResetIso !== void 0 || isSubscriptionWindow(s.rateLimitType));
2936
+ if (rejectedIsCap || frame.terminalReason === "blocking_limit")
2937
+ return {
2938
+ kind: "usage_capped",
2939
+ ...s.rateLimitResetIso ? { resetsAt: s.rateLimitResetIso } : {}
2940
+ };
2941
+ return classifyAssistantError(s.lastAssistantError) ?? classifyErrorText([s.authError, frame.text].filter(Boolean).join(" "));
2942
+ }
2943
+ function classifyResultFailure(msg, s) {
2944
+ const resultText = msg.result ?? "";
2945
+ const terminalReason = msg.terminal_reason;
2946
+ const errors = msg.errors;
2947
+ const text = [resultText, ...Array.isArray(errors) ? errors.map(String) : []].join(" ");
2948
+ return classifyFailure(s, { terminalReason, text });
2949
+ }
2950
+ function classifyPreInitFrame(msg, s) {
2951
+ if (msg.type === "result") {
2952
+ const isError = msg.is_error === true;
2953
+ if (msg.subtype === "success" && !isError) return classifyFailure(s, { text: "" });
2954
+ return classifyResultFailure(msg, s);
2955
+ }
2956
+ if (msg.type !== "assistant") return classifyFailure(s, { text: "" });
2957
+ const text = contentBlocks(msg).flatMap((b) => b.type === "text" && typeof b.text === "string" ? [b.text] : []).join(" ");
2958
+ return classifyFailure(s, { text });
2959
+ }
2960
+ function preInitToolActivity(msg) {
2961
+ const kind = msg.type === "assistant" ? "tool_use" : msg.type === "user" ? "tool_result" : null;
2962
+ return kind !== null && contentBlocks(msg).some((b) => b.type === kind);
2963
+ }
2964
+ function contentBlocks(msg) {
2965
+ const content = msg.message?.content;
2966
+ return Array.isArray(content) ? content : [];
2967
+ }
2968
+ function isSubscriptionWindow(value) {
2969
+ return value === "five_hour" || value === "seven_day" || value === "seven_day_opus" || value === "seven_day_sonnet" || value === "overage";
2970
+ }
2971
+ var init_failure_evidence = __esm({
2972
+ "packages/agent-runtime/src/claude-code/failure-evidence.ts"() {
2973
+ "use strict";
2974
+ init_failure();
2975
+ }
2976
+ });
2977
+
2978
+ // packages/agent-runtime/src/claude-code/context-usage.ts
2979
+ function createContextUsage() {
2980
+ let resolvedModel;
2981
+ let lastRequestContextTokens;
2982
+ const compactions = [];
2983
+ return {
2984
+ get resolvedModel() {
2985
+ return resolvedModel;
2986
+ },
2987
+ recordInit(msg) {
2988
+ const model = msg.model;
2989
+ if (typeof model === "string" && model.length > 0) resolvedModel = model;
2990
+ },
2991
+ recordCompaction(msg) {
2992
+ const compaction = readCompaction(msg);
2993
+ if (compaction) compactions.push(compaction);
2994
+ },
2995
+ recordRequest(msg) {
2996
+ const tokens = readRequestContextTokens(msg);
2997
+ if (tokens !== void 0) lastRequestContextTokens = tokens;
2998
+ },
2999
+ async resultUsage(msg, readContextUsage) {
3000
+ const usage = readSdkUsage(msg.usage);
3001
+ if (usage) {
3002
+ if (lastRequestContextTokens !== void 0) usage.contextTokens = lastRequestContextTokens;
3003
+ const window = readContextWindow(msg, resolvedModel);
3004
+ if (window !== void 0) usage.contextWindow = window;
3005
+ if (compactions.length > 0) usage.contextCompactions = compactions;
3006
+ const reading = await readHarnessContext(readContextUsage);
3007
+ if (reading) Object.assign(usage, reading);
3008
+ }
3009
+ return usage;
3010
+ }
3011
+ };
3012
+ }
3013
+ function readSdkUsage(usage) {
3014
+ if (!usage || typeof usage !== "object") return void 0;
3015
+ const fields = usage;
3016
+ const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
3017
+ const cacheReadTokens = num(fields.cache_read_input_tokens);
3018
+ const cacheCreationTokens = num(fields.cache_creation_input_tokens);
3019
+ const inputTokens = num(fields.input_tokens) + cacheCreationTokens + cacheReadTokens;
3020
+ const outputTokens = num(fields.output_tokens);
3021
+ return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
3022
+ }
3023
+ function readRequestContextTokens(msg) {
3024
+ return readSdkUsage(msg.message?.usage)?.inputTokens;
3025
+ }
3026
+ async function readHarnessContext(read) {
3027
+ if (!read) return void 0;
3028
+ let timer;
3029
+ const timeout = new Promise((resolve2) => {
3030
+ timer = setTimeout(() => resolve2(void 0), CONTEXT_READING_TIMEOUT_MS);
3031
+ });
3032
+ try {
3033
+ return parseContextUsage(await Promise.race([read(), timeout]));
3034
+ } catch {
3035
+ return void 0;
3036
+ } finally {
3037
+ clearTimeout(timer);
3038
+ }
3039
+ }
3040
+ function parseContextUsage(response) {
3041
+ const r = response;
3042
+ if (!r || typeof r !== "object") return void 0;
3043
+ const total = readContextCount(r.totalTokens);
3044
+ const window = readContextCount(r.maxTokens);
3045
+ if (total === void 0 || window === void 0 || window === 0) return void 0;
3046
+ const categories = [];
3047
+ for (const c of Array.isArray(r.categories) ? r.categories : []) {
3048
+ const row3 = c;
3049
+ const tokens = readContextCount(row3?.tokens);
3050
+ if (typeof row3?.name === "string" && tokens !== void 0 && typeof row3.kind === "string" && CATEGORY_KINDS.has(row3.kind)) {
3051
+ categories.push({ name: row3.name, tokens, kind: row3.kind });
3052
+ }
3053
+ }
3054
+ const buffer = categories.filter((c) => c.kind === "buffer").reduce((sum, c) => sum + c.tokens, 0);
3055
+ return {
3056
+ contextTokens: total,
3057
+ contextWindow: window,
3058
+ ...buffer > 0 && buffer < window ? { contextCompactAt: window - buffer } : {},
3059
+ ...categories.length > 0 ? { contextCategories: categories } : {}
3060
+ };
3061
+ }
3062
+ function readCompaction(msg) {
3063
+ const meta = msg.compact_metadata;
3064
+ const preTokens = readContextCount(meta?.pre_tokens);
3065
+ if (!meta || preTokens === void 0) return void 0;
3066
+ if (meta.trigger !== "manual" && meta.trigger !== "auto") return void 0;
3067
+ const postTokens = readContextCount(meta.post_tokens);
3068
+ return {
3069
+ trigger: meta.trigger,
3070
+ preTokens,
3071
+ ...postTokens !== void 0 ? { postTokens } : {}
3072
+ };
3073
+ }
3074
+ function readContextWindow(msg, resolvedModel) {
3075
+ const modelUsage = msg.modelUsage;
3076
+ if (!modelUsage || typeof modelUsage !== "object") return void 0;
3077
+ const pos = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
3078
+ if (resolvedModel) {
3079
+ const direct = pos(modelUsage[resolvedModel]?.contextWindow);
3080
+ if (direct !== void 0) return direct;
3081
+ }
3082
+ let max;
3083
+ for (const entry of Object.values(modelUsage)) {
3084
+ const w = pos(entry?.contextWindow);
3085
+ if (w !== void 0 && (max === void 0 || w > max)) max = w;
3086
+ }
3087
+ return max;
3088
+ }
3089
+ function readContextCount(v) {
3090
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
3091
+ }
3092
+ var CONTEXT_READING_TIMEOUT_MS, CATEGORY_KINDS;
3093
+ var init_context_usage = __esm({
3094
+ "packages/agent-runtime/src/claude-code/context-usage.ts"() {
3095
+ "use strict";
3096
+ CONTEXT_READING_TIMEOUT_MS = 2e3;
3097
+ CATEGORY_KINDS = /* @__PURE__ */ new Set(["used", "free", "buffer", "deferred"]);
3098
+ }
3099
+ });
3100
+
2899
3101
  // packages/agent-runtime/src/claude-code/loop.ts
2900
3102
  async function* decodeSdkStream(iter, ctx2) {
2901
3103
  const pending = /* @__PURE__ */ new Map();
@@ -2911,17 +3113,15 @@ async function* decodeSdkStream(iter, ctx2) {
2911
3113
  let resultReason;
2912
3114
  let sawResult = false;
2913
3115
  let usage;
2914
- const compactions = [];
2915
- let lastRequestContextTokens;
2916
- let resolvedModel;
2917
- const signals = { sawRejectedLimit: false };
3116
+ const contextUsage = createContextUsage();
3117
+ const failureEvidence = createFailureEvidence();
2918
3118
  let preInitNotice = null;
2919
3119
  try {
2920
3120
  for await (const msg of iter) {
2921
3121
  if (ctx2.signal.aborted) return;
3122
+ failureEvidence.observe(msg);
2922
3123
  if (msg.type === "system" && msg.subtype === "init") {
2923
- const initModel = msg.model;
2924
- if (typeof initModel === "string" && initModel.length > 0) resolvedModel = initModel;
3124
+ contextUsage.recordInit(msg);
2925
3125
  mcpInventory = readMcpInventory(msg);
2926
3126
  workspaceProven = provesWorkspaceTools(msg);
2927
3127
  if (!workspaceProven) {
@@ -2938,63 +3138,35 @@ async function* decodeSdkStream(iter, ctx2) {
2938
3138
  };
2939
3139
  }
2940
3140
  } else if (msg.type === "system" && msg.subtype === "compact_boundary") {
2941
- const compaction = readCompaction(msg);
2942
- if (compaction) compactions.push(compaction);
3141
+ contextUsage.recordCompaction(msg);
2943
3142
  } else if (!workspaceProven && (msg.type === "assistant" || msg.type === "user" || msg.type === "result")) {
2944
3143
  if (preInitToolActivity(msg) && ctx2.startEvidence) ctx2.startEvidence.toolActivity = true;
2945
- const failure = classifyPreInitFrame(msg, signals);
2946
- resultReason = failure ? encodeFailureReason(failure) : "session_start_failed";
3144
+ resultReason = failureEvidence.preInitReason(msg);
2947
3145
  if (msg.type === "assistant" && isHarnessAuthored(msg))
2948
3146
  preInitNotice = harnessNoticeText(msg);
2949
3147
  break;
2950
3148
  } else if (msg.type === "assistant") {
2951
- const assistantErr = msg.error;
2952
- if (typeof assistantErr === "string" && assistantErr.length > 0) {
2953
- signals.lastAssistantError = assistantErr;
2954
- }
2955
3149
  if (isHarnessAuthored(msg)) {
2956
3150
  await emitHarnessMessage(msg, emit, pending, buffer);
2957
3151
  yield* drain(out);
2958
3152
  continue;
2959
3153
  }
2960
- const reqContext = readRequestContextTokens(msg);
2961
- if (reqContext !== void 0) lastRequestContextTokens = reqContext;
3154
+ contextUsage.recordRequest(msg);
2962
3155
  await processAssistantMessage(msg, emit, pending, buffer);
2963
3156
  yield* drain(out);
2964
3157
  } else if (msg.type === "user") {
2965
3158
  await emitToolResults(msg, emit, pending);
2966
3159
  yield* drain(out);
2967
- } else if (msg.type === "rate_limit_event") {
2968
- const info = msg.rate_limit_info;
2969
- if (info?.status === "rejected") {
2970
- signals.sawRejectedLimit = true;
2971
- signals.rateLimitResetIso = resetsAtToIso(info.resetsAt) ?? signals.rateLimitResetIso;
2972
- if (typeof info.rateLimitType === "string") signals.rateLimitType = info.rateLimitType;
2973
- }
2974
- } else if (msg.type === "auth_status") {
2975
- const err = msg.error;
2976
- if (typeof err === "string" && err.length > 0) signals.authError = err;
2977
3160
  } else if (msg.type === "result") {
2978
3161
  const origin = msg.origin;
2979
3162
  if (origin?.kind === "task-notification") continue;
2980
3163
  sawResult = true;
2981
- usage = readSdkUsage(msg);
2982
- if (usage) {
2983
- if (lastRequestContextTokens !== void 0)
2984
- usage.contextTokens = lastRequestContextTokens;
2985
- const window = readContextWindow(msg, resolvedModel);
2986
- if (window !== void 0) usage.contextWindow = window;
2987
- if (compactions.length > 0) usage.contextCompactions = compactions;
2988
- const reading = await readHarnessContext(ctx2.readContextUsage);
2989
- if (reading) Object.assign(usage, reading);
2990
- }
3164
+ usage = await contextUsage.resultUsage(msg, ctx2.readContextUsage);
2991
3165
  const isError = msg.is_error === true;
2992
3166
  if (msg.subtype === "success" && !isError) {
2993
3167
  ok = true;
2994
3168
  } else {
2995
- const resultText = msg.result ?? "";
2996
- const failure = classifyResultFailure(msg, signals);
2997
- resultReason = failure ? encodeFailureReason(failure) : isError ? `error:${resultText.slice(0, 200) || "unknown"}` : `result_error:${msg.subtype}`;
3169
+ resultReason = failureEvidence.failedResultReason(msg);
2998
3170
  ok = false;
2999
3171
  }
3000
3172
  break;
@@ -3003,7 +3175,7 @@ async function* decodeSdkStream(iter, ctx2) {
3003
3175
  } catch (err) {
3004
3176
  if (ctx2.signal.aborted) throw err;
3005
3177
  const message2 = err instanceof Error ? err.message : String(err);
3006
- const failure = mcpInventory.initReceived ? classifyErrorText(message2) : classifyFailure(signals, { text: message2 });
3178
+ const failure = failureEvidence.thrownFailure(message2, mcpInventory.initReceived);
3007
3179
  if (!failure && (mcpInventory.initReceived || ctx2.resumedSessionId === null)) throw err;
3008
3180
  ok = false;
3009
3181
  if (failure) {
@@ -3018,8 +3190,7 @@ async function* decodeSdkStream(iter, ctx2) {
3018
3190
  if (!workspaceProven) {
3019
3191
  ok = false;
3020
3192
  if (resultReason === void 0) {
3021
- const failure = classifyFailure(signals, { text: "" });
3022
- resultReason = failure ? encodeFailureReason(failure) : "session_start_failed";
3193
+ resultReason = failureEvidence.preInitReason();
3023
3194
  }
3024
3195
  if (preInitNotice) yield { type: "runtime_notice", body: preInitNotice };
3025
3196
  }
@@ -3037,7 +3208,7 @@ async function* decodeSdkStream(iter, ctx2) {
3037
3208
  ok,
3038
3209
  ...resultReason ? { reason: resultReason } : {},
3039
3210
  ...usage ? { usage } : {},
3040
- ...resolvedModel ? { resolvedModel } : {},
3211
+ ...contextUsage.resolvedModel ? { resolvedModel: contextUsage.resolvedModel } : {},
3041
3212
  mcpInventory
3042
3213
  };
3043
3214
  }
@@ -3056,38 +3227,6 @@ function provesWorkspaceTools(msg) {
3056
3227
  const tools = msg.tools;
3057
3228
  return Array.isArray(tools) && tools.includes("mcp__cabane__query");
3058
3229
  }
3059
- function classifyFailure(s, frame) {
3060
- const rejectedIsCap = s.sawRejectedLimit && (s.rateLimitResetIso !== void 0 || isSubscriptionWindow(s.rateLimitType));
3061
- if (rejectedIsCap || frame.terminalReason === "blocking_limit")
3062
- return {
3063
- kind: "usage_capped",
3064
- ...s.rateLimitResetIso ? { resetsAt: s.rateLimitResetIso } : {}
3065
- };
3066
- return classifyAssistantError(s.lastAssistantError) ?? classifyErrorText([s.authError, frame.text].filter(Boolean).join(" "));
3067
- }
3068
- function classifyResultFailure(msg, s) {
3069
- const resultText = msg.result ?? "";
3070
- const terminalReason = msg.terminal_reason;
3071
- const errors = msg.errors;
3072
- const text = [resultText, ...Array.isArray(errors) ? errors.map(String) : []].join(" ");
3073
- return classifyFailure(s, { terminalReason, text });
3074
- }
3075
- function classifyPreInitFrame(msg, s) {
3076
- if (msg.type === "result") {
3077
- const isError = msg.is_error === true;
3078
- if (msg.subtype === "success" && !isError) return classifyFailure(s, { text: "" });
3079
- return classifyResultFailure(msg, s);
3080
- }
3081
- if (msg.type !== "assistant") return classifyFailure(s, { text: "" });
3082
- const error = msg.error;
3083
- const signals = typeof error === "string" && error.length > 0 ? { ...s, lastAssistantError: error } : s;
3084
- const text = contentBlocks(msg).flatMap((b) => b.type === "text" && typeof b.text === "string" ? [b.text] : []).join(" ");
3085
- return classifyFailure(signals, { text });
3086
- }
3087
- function preInitToolActivity(msg) {
3088
- const kind = msg.type === "assistant" ? "tool_use" : msg.type === "user" ? "tool_result" : null;
3089
- return kind !== null && contentBlocks(msg).some((b) => b.type === kind);
3090
- }
3091
3230
  function isHarnessAuthored(msg) {
3092
3231
  const error = msg.error;
3093
3232
  if (typeof error === "string" && error.length > 0) return true;
@@ -3111,107 +3250,19 @@ async function emitHarnessMessage(msg, emit, pending, buffer) {
3111
3250
  );
3112
3251
  }
3113
3252
  }
3114
- function contentBlocks(msg) {
3115
- const content = msg.message?.content;
3116
- return Array.isArray(content) ? content : [];
3117
- }
3118
- function isSubscriptionWindow(value) {
3119
- return value === "five_hour" || value === "seven_day" || value === "seven_day_opus" || value === "seven_day_sonnet" || value === "overage";
3120
- }
3121
3253
  function* drain(out) {
3122
3254
  while (out.length > 0) yield out.shift();
3123
3255
  }
3124
- function readSdkUsage(msg) {
3125
- const usage = msg.usage;
3126
- if (!usage || typeof usage !== "object") return void 0;
3127
- const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
3128
- const cacheReadTokens = num(usage.cache_read_input_tokens);
3129
- const cacheCreationTokens = num(usage.cache_creation_input_tokens);
3130
- const inputTokens = num(usage.input_tokens) + cacheCreationTokens + cacheReadTokens;
3131
- const outputTokens = num(usage.output_tokens);
3132
- return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
3133
- }
3134
- function readRequestContextTokens(msg) {
3135
- const usage = msg.message?.usage;
3136
- if (!usage || typeof usage !== "object") return void 0;
3137
- const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
3138
- return num(usage.input_tokens) + num(usage.cache_read_input_tokens) + num(usage.cache_creation_input_tokens);
3139
- }
3140
- async function readHarnessContext(read) {
3141
- if (!read) return void 0;
3142
- let timer;
3143
- const timeout = new Promise((resolve2) => {
3144
- timer = setTimeout(() => resolve2(void 0), CONTEXT_READING_TIMEOUT_MS);
3145
- });
3146
- try {
3147
- return parseContextUsage(await Promise.race([read(), timeout]));
3148
- } catch {
3149
- return void 0;
3150
- } finally {
3151
- clearTimeout(timer);
3152
- }
3153
- }
3154
- function parseContextUsage(response) {
3155
- const r = response;
3156
- if (!r || typeof r !== "object") return void 0;
3157
- const count = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
3158
- const total = count(r.totalTokens);
3159
- const window = count(r.maxTokens);
3160
- if (total === void 0 || window === void 0 || window === 0) return void 0;
3161
- const categories = [];
3162
- for (const c of Array.isArray(r.categories) ? r.categories : []) {
3163
- const row3 = c;
3164
- const tokens = count(row3?.tokens);
3165
- if (typeof row3?.name === "string" && tokens !== void 0 && typeof row3.kind === "string" && CATEGORY_KINDS.has(row3.kind)) {
3166
- categories.push({ name: row3.name, tokens, kind: row3.kind });
3167
- }
3168
- }
3169
- const buffer = categories.filter((c) => c.kind === "buffer").reduce((sum, c) => sum + c.tokens, 0);
3170
- return {
3171
- contextTokens: total,
3172
- contextWindow: window,
3173
- ...buffer > 0 && buffer < window ? { contextCompactAt: window - buffer } : {},
3174
- ...categories.length > 0 ? { contextCategories: categories } : {}
3175
- };
3176
- }
3177
- function readCompaction(msg) {
3178
- const meta = msg.compact_metadata;
3179
- const count = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
3180
- const preTokens = count(meta?.pre_tokens);
3181
- if (!meta || preTokens === void 0) return void 0;
3182
- if (meta.trigger !== "manual" && meta.trigger !== "auto") return void 0;
3183
- const postTokens = count(meta.post_tokens);
3184
- return {
3185
- trigger: meta.trigger,
3186
- preTokens,
3187
- ...postTokens !== void 0 ? { postTokens } : {}
3188
- };
3189
- }
3190
- function readContextWindow(msg, resolvedModel) {
3191
- const modelUsage = msg.modelUsage;
3192
- if (!modelUsage || typeof modelUsage !== "object") return void 0;
3193
- const pos = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
3194
- if (resolvedModel) {
3195
- const direct = pos(modelUsage[resolvedModel]?.contextWindow);
3196
- if (direct !== void 0) return direct;
3197
- }
3198
- let max;
3199
- for (const entry of Object.values(modelUsage)) {
3200
- const w = pos(entry?.contextWindow);
3201
- if (w !== void 0 && (max === void 0 || w > max)) max = w;
3202
- }
3203
- return max;
3204
- }
3205
- var HARNESS_PLACEHOLDERS, CONTEXT_READING_TIMEOUT_MS, CATEGORY_KINDS;
3256
+ var HARNESS_PLACEHOLDERS;
3206
3257
  var init_loop = __esm({
3207
3258
  "packages/agent-runtime/src/claude-code/loop.ts"() {
3208
3259
  "use strict";
3209
3260
  init_transcript();
3210
3261
  init_failure();
3211
3262
  init_session();
3263
+ init_failure_evidence();
3264
+ init_context_usage();
3212
3265
  HARNESS_PLACEHOLDERS = /* @__PURE__ */ new Set(["No response requested.", "(no content)"]);
3213
- CONTEXT_READING_TIMEOUT_MS = 2e3;
3214
- CATEGORY_KINDS = /* @__PURE__ */ new Set(["used", "free", "buffer", "deferred"]);
3215
3266
  }
3216
3267
  });
3217
3268
 
package/dist/runtime.js CHANGED
@@ -4288,6 +4288,196 @@ function dedupe(xs) {
4288
4288
  return [...new Set(xs)];
4289
4289
  }
4290
4290
 
4291
+ // packages/agent-runtime/src/claude-code/failure-evidence.ts
4292
+ function createFailureEvidence() {
4293
+ const signals = { sawRejectedLimit: false };
4294
+ return {
4295
+ observe(msg) {
4296
+ if (msg.type === "assistant" || msg.type === "auth_status") {
4297
+ const error = msg.error;
4298
+ if (typeof error === "string" && error.length > 0) {
4299
+ if (msg.type === "assistant") signals.lastAssistantError = error;
4300
+ else signals.authError = error;
4301
+ }
4302
+ } else if (msg.type === "rate_limit_event") {
4303
+ const info = msg.rate_limit_info;
4304
+ if (info?.status === "rejected") {
4305
+ signals.sawRejectedLimit = true;
4306
+ signals.rateLimitResetIso = resetsAtToIso(info.resetsAt) ?? signals.rateLimitResetIso;
4307
+ if (typeof info.rateLimitType === "string") signals.rateLimitType = info.rateLimitType;
4308
+ }
4309
+ }
4310
+ },
4311
+ preInitReason(msg) {
4312
+ const failure = msg ? classifyPreInitFrame(msg, signals) : classifyFailure(signals, { text: "" });
4313
+ return failure ? encodeFailureReason(failure) : "session_start_failed";
4314
+ },
4315
+ failedResultReason(msg) {
4316
+ const failure = classifyResultFailure(msg, signals);
4317
+ const resultText = msg.result ?? "";
4318
+ const isError = msg.is_error === true;
4319
+ return failure ? encodeFailureReason(failure) : isError ? `error:${resultText.slice(0, 200) || "unknown"}` : `result_error:${msg.subtype}`;
4320
+ },
4321
+ thrownFailure(message2, initReceived) {
4322
+ return initReceived ? classifyErrorText(message2) : classifyFailure(signals, { text: message2 });
4323
+ }
4324
+ };
4325
+ }
4326
+ function classifyFailure(s, frame) {
4327
+ const rejectedIsCap = s.sawRejectedLimit && (s.rateLimitResetIso !== void 0 || isSubscriptionWindow(s.rateLimitType));
4328
+ if (rejectedIsCap || frame.terminalReason === "blocking_limit")
4329
+ return {
4330
+ kind: "usage_capped",
4331
+ ...s.rateLimitResetIso ? { resetsAt: s.rateLimitResetIso } : {}
4332
+ };
4333
+ return classifyAssistantError(s.lastAssistantError) ?? classifyErrorText([s.authError, frame.text].filter(Boolean).join(" "));
4334
+ }
4335
+ function classifyResultFailure(msg, s) {
4336
+ const resultText = msg.result ?? "";
4337
+ const terminalReason = msg.terminal_reason;
4338
+ const errors = msg.errors;
4339
+ const text = [resultText, ...Array.isArray(errors) ? errors.map(String) : []].join(" ");
4340
+ return classifyFailure(s, { terminalReason, text });
4341
+ }
4342
+ function classifyPreInitFrame(msg, s) {
4343
+ if (msg.type === "result") {
4344
+ const isError = msg.is_error === true;
4345
+ if (msg.subtype === "success" && !isError) return classifyFailure(s, { text: "" });
4346
+ return classifyResultFailure(msg, s);
4347
+ }
4348
+ if (msg.type !== "assistant") return classifyFailure(s, { text: "" });
4349
+ const text = contentBlocks(msg).flatMap((b) => b.type === "text" && typeof b.text === "string" ? [b.text] : []).join(" ");
4350
+ return classifyFailure(s, { text });
4351
+ }
4352
+ function preInitToolActivity(msg) {
4353
+ const kind = msg.type === "assistant" ? "tool_use" : msg.type === "user" ? "tool_result" : null;
4354
+ return kind !== null && contentBlocks(msg).some((b) => b.type === kind);
4355
+ }
4356
+ function contentBlocks(msg) {
4357
+ const content = msg.message?.content;
4358
+ return Array.isArray(content) ? content : [];
4359
+ }
4360
+ function isSubscriptionWindow(value) {
4361
+ return value === "five_hour" || value === "seven_day" || value === "seven_day_opus" || value === "seven_day_sonnet" || value === "overage";
4362
+ }
4363
+
4364
+ // packages/agent-runtime/src/claude-code/context-usage.ts
4365
+ function createContextUsage() {
4366
+ let resolvedModel;
4367
+ let lastRequestContextTokens;
4368
+ const compactions = [];
4369
+ return {
4370
+ get resolvedModel() {
4371
+ return resolvedModel;
4372
+ },
4373
+ recordInit(msg) {
4374
+ const model = msg.model;
4375
+ if (typeof model === "string" && model.length > 0) resolvedModel = model;
4376
+ },
4377
+ recordCompaction(msg) {
4378
+ const compaction = readCompaction(msg);
4379
+ if (compaction) compactions.push(compaction);
4380
+ },
4381
+ recordRequest(msg) {
4382
+ const tokens = readRequestContextTokens(msg);
4383
+ if (tokens !== void 0) lastRequestContextTokens = tokens;
4384
+ },
4385
+ async resultUsage(msg, readContextUsage) {
4386
+ const usage = readSdkUsage(msg.usage);
4387
+ if (usage) {
4388
+ if (lastRequestContextTokens !== void 0) usage.contextTokens = lastRequestContextTokens;
4389
+ const window = readContextWindow(msg, resolvedModel);
4390
+ if (window !== void 0) usage.contextWindow = window;
4391
+ if (compactions.length > 0) usage.contextCompactions = compactions;
4392
+ const reading = await readHarnessContext(readContextUsage);
4393
+ if (reading) Object.assign(usage, reading);
4394
+ }
4395
+ return usage;
4396
+ }
4397
+ };
4398
+ }
4399
+ function readSdkUsage(usage) {
4400
+ if (!usage || typeof usage !== "object") return void 0;
4401
+ const fields = usage;
4402
+ const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
4403
+ const cacheReadTokens = num(fields.cache_read_input_tokens);
4404
+ const cacheCreationTokens = num(fields.cache_creation_input_tokens);
4405
+ const inputTokens = num(fields.input_tokens) + cacheCreationTokens + cacheReadTokens;
4406
+ const outputTokens = num(fields.output_tokens);
4407
+ return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
4408
+ }
4409
+ function readRequestContextTokens(msg) {
4410
+ return readSdkUsage(msg.message?.usage)?.inputTokens;
4411
+ }
4412
+ var CONTEXT_READING_TIMEOUT_MS = 2e3;
4413
+ async function readHarnessContext(read) {
4414
+ if (!read) return void 0;
4415
+ let timer;
4416
+ const timeout = new Promise((resolve2) => {
4417
+ timer = setTimeout(() => resolve2(void 0), CONTEXT_READING_TIMEOUT_MS);
4418
+ });
4419
+ try {
4420
+ return parseContextUsage(await Promise.race([read(), timeout]));
4421
+ } catch {
4422
+ return void 0;
4423
+ } finally {
4424
+ clearTimeout(timer);
4425
+ }
4426
+ }
4427
+ var CATEGORY_KINDS = /* @__PURE__ */ new Set(["used", "free", "buffer", "deferred"]);
4428
+ function parseContextUsage(response) {
4429
+ const r = response;
4430
+ if (!r || typeof r !== "object") return void 0;
4431
+ const total = readContextCount(r.totalTokens);
4432
+ const window = readContextCount(r.maxTokens);
4433
+ if (total === void 0 || window === void 0 || window === 0) return void 0;
4434
+ const categories = [];
4435
+ for (const c of Array.isArray(r.categories) ? r.categories : []) {
4436
+ const row = c;
4437
+ const tokens = readContextCount(row?.tokens);
4438
+ if (typeof row?.name === "string" && tokens !== void 0 && typeof row.kind === "string" && CATEGORY_KINDS.has(row.kind)) {
4439
+ categories.push({ name: row.name, tokens, kind: row.kind });
4440
+ }
4441
+ }
4442
+ const buffer = categories.filter((c) => c.kind === "buffer").reduce((sum, c) => sum + c.tokens, 0);
4443
+ return {
4444
+ contextTokens: total,
4445
+ contextWindow: window,
4446
+ ...buffer > 0 && buffer < window ? { contextCompactAt: window - buffer } : {},
4447
+ ...categories.length > 0 ? { contextCategories: categories } : {}
4448
+ };
4449
+ }
4450
+ function readCompaction(msg) {
4451
+ const meta = msg.compact_metadata;
4452
+ const preTokens = readContextCount(meta?.pre_tokens);
4453
+ if (!meta || preTokens === void 0) return void 0;
4454
+ if (meta.trigger !== "manual" && meta.trigger !== "auto") return void 0;
4455
+ const postTokens = readContextCount(meta.post_tokens);
4456
+ return {
4457
+ trigger: meta.trigger,
4458
+ preTokens,
4459
+ ...postTokens !== void 0 ? { postTokens } : {}
4460
+ };
4461
+ }
4462
+ function readContextWindow(msg, resolvedModel) {
4463
+ const modelUsage = msg.modelUsage;
4464
+ if (!modelUsage || typeof modelUsage !== "object") return void 0;
4465
+ const pos = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
4466
+ if (resolvedModel) {
4467
+ const direct = pos(modelUsage[resolvedModel]?.contextWindow);
4468
+ if (direct !== void 0) return direct;
4469
+ }
4470
+ let max;
4471
+ for (const entry of Object.values(modelUsage)) {
4472
+ const w = pos(entry?.contextWindow);
4473
+ if (w !== void 0 && (max === void 0 || w > max)) max = w;
4474
+ }
4475
+ return max;
4476
+ }
4477
+ function readContextCount(v) {
4478
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
4479
+ }
4480
+
4291
4481
  // packages/agent-runtime/src/claude-code/loop.ts
4292
4482
  async function* decodeSdkStream(iter, ctx2) {
4293
4483
  const pending = /* @__PURE__ */ new Map();
@@ -4303,17 +4493,15 @@ async function* decodeSdkStream(iter, ctx2) {
4303
4493
  let resultReason;
4304
4494
  let sawResult = false;
4305
4495
  let usage;
4306
- const compactions = [];
4307
- let lastRequestContextTokens;
4308
- let resolvedModel;
4309
- const signals = { sawRejectedLimit: false };
4496
+ const contextUsage = createContextUsage();
4497
+ const failureEvidence = createFailureEvidence();
4310
4498
  let preInitNotice = null;
4311
4499
  try {
4312
4500
  for await (const msg of iter) {
4313
4501
  if (ctx2.signal.aborted) return;
4502
+ failureEvidence.observe(msg);
4314
4503
  if (msg.type === "system" && msg.subtype === "init") {
4315
- const initModel = msg.model;
4316
- if (typeof initModel === "string" && initModel.length > 0) resolvedModel = initModel;
4504
+ contextUsage.recordInit(msg);
4317
4505
  mcpInventory = readMcpInventory(msg);
4318
4506
  workspaceProven = provesWorkspaceTools(msg);
4319
4507
  if (!workspaceProven) {
@@ -4330,63 +4518,35 @@ async function* decodeSdkStream(iter, ctx2) {
4330
4518
  };
4331
4519
  }
4332
4520
  } else if (msg.type === "system" && msg.subtype === "compact_boundary") {
4333
- const compaction = readCompaction(msg);
4334
- if (compaction) compactions.push(compaction);
4521
+ contextUsage.recordCompaction(msg);
4335
4522
  } else if (!workspaceProven && (msg.type === "assistant" || msg.type === "user" || msg.type === "result")) {
4336
4523
  if (preInitToolActivity(msg) && ctx2.startEvidence) ctx2.startEvidence.toolActivity = true;
4337
- const failure = classifyPreInitFrame(msg, signals);
4338
- resultReason = failure ? encodeFailureReason(failure) : "session_start_failed";
4524
+ resultReason = failureEvidence.preInitReason(msg);
4339
4525
  if (msg.type === "assistant" && isHarnessAuthored(msg))
4340
4526
  preInitNotice = harnessNoticeText(msg);
4341
4527
  break;
4342
4528
  } else if (msg.type === "assistant") {
4343
- const assistantErr = msg.error;
4344
- if (typeof assistantErr === "string" && assistantErr.length > 0) {
4345
- signals.lastAssistantError = assistantErr;
4346
- }
4347
4529
  if (isHarnessAuthored(msg)) {
4348
4530
  await emitHarnessMessage(msg, emit, pending, buffer);
4349
4531
  yield* drain(out);
4350
4532
  continue;
4351
4533
  }
4352
- const reqContext = readRequestContextTokens(msg);
4353
- if (reqContext !== void 0) lastRequestContextTokens = reqContext;
4534
+ contextUsage.recordRequest(msg);
4354
4535
  await processAssistantMessage(msg, emit, pending, buffer);
4355
4536
  yield* drain(out);
4356
4537
  } else if (msg.type === "user") {
4357
4538
  await emitToolResults(msg, emit, pending);
4358
4539
  yield* drain(out);
4359
- } else if (msg.type === "rate_limit_event") {
4360
- const info = msg.rate_limit_info;
4361
- if (info?.status === "rejected") {
4362
- signals.sawRejectedLimit = true;
4363
- signals.rateLimitResetIso = resetsAtToIso(info.resetsAt) ?? signals.rateLimitResetIso;
4364
- if (typeof info.rateLimitType === "string") signals.rateLimitType = info.rateLimitType;
4365
- }
4366
- } else if (msg.type === "auth_status") {
4367
- const err = msg.error;
4368
- if (typeof err === "string" && err.length > 0) signals.authError = err;
4369
4540
  } else if (msg.type === "result") {
4370
4541
  const origin = msg.origin;
4371
4542
  if (origin?.kind === "task-notification") continue;
4372
4543
  sawResult = true;
4373
- usage = readSdkUsage(msg);
4374
- if (usage) {
4375
- if (lastRequestContextTokens !== void 0)
4376
- usage.contextTokens = lastRequestContextTokens;
4377
- const window = readContextWindow(msg, resolvedModel);
4378
- if (window !== void 0) usage.contextWindow = window;
4379
- if (compactions.length > 0) usage.contextCompactions = compactions;
4380
- const reading = await readHarnessContext(ctx2.readContextUsage);
4381
- if (reading) Object.assign(usage, reading);
4382
- }
4544
+ usage = await contextUsage.resultUsage(msg, ctx2.readContextUsage);
4383
4545
  const isError = msg.is_error === true;
4384
4546
  if (msg.subtype === "success" && !isError) {
4385
4547
  ok = true;
4386
4548
  } else {
4387
- const resultText = msg.result ?? "";
4388
- const failure = classifyResultFailure(msg, signals);
4389
- resultReason = failure ? encodeFailureReason(failure) : isError ? `error:${resultText.slice(0, 200) || "unknown"}` : `result_error:${msg.subtype}`;
4549
+ resultReason = failureEvidence.failedResultReason(msg);
4390
4550
  ok = false;
4391
4551
  }
4392
4552
  break;
@@ -4395,7 +4555,7 @@ async function* decodeSdkStream(iter, ctx2) {
4395
4555
  } catch (err) {
4396
4556
  if (ctx2.signal.aborted) throw err;
4397
4557
  const message2 = err instanceof Error ? err.message : String(err);
4398
- const failure = mcpInventory.initReceived ? classifyErrorText(message2) : classifyFailure(signals, { text: message2 });
4558
+ const failure = failureEvidence.thrownFailure(message2, mcpInventory.initReceived);
4399
4559
  if (!failure && (mcpInventory.initReceived || ctx2.resumedSessionId === null)) throw err;
4400
4560
  ok = false;
4401
4561
  if (failure) {
@@ -4410,8 +4570,7 @@ async function* decodeSdkStream(iter, ctx2) {
4410
4570
  if (!workspaceProven) {
4411
4571
  ok = false;
4412
4572
  if (resultReason === void 0) {
4413
- const failure = classifyFailure(signals, { text: "" });
4414
- resultReason = failure ? encodeFailureReason(failure) : "session_start_failed";
4573
+ resultReason = failureEvidence.preInitReason();
4415
4574
  }
4416
4575
  if (preInitNotice) yield { type: "runtime_notice", body: preInitNotice };
4417
4576
  }
@@ -4429,7 +4588,7 @@ async function* decodeSdkStream(iter, ctx2) {
4429
4588
  ok,
4430
4589
  ...resultReason ? { reason: resultReason } : {},
4431
4590
  ...usage ? { usage } : {},
4432
- ...resolvedModel ? { resolvedModel } : {},
4591
+ ...contextUsage.resolvedModel ? { resolvedModel: contextUsage.resolvedModel } : {},
4433
4592
  mcpInventory
4434
4593
  };
4435
4594
  }
@@ -4448,38 +4607,6 @@ function provesWorkspaceTools(msg) {
4448
4607
  const tools = msg.tools;
4449
4608
  return Array.isArray(tools) && tools.includes("mcp__cabane__query");
4450
4609
  }
4451
- function classifyFailure(s, frame) {
4452
- const rejectedIsCap = s.sawRejectedLimit && (s.rateLimitResetIso !== void 0 || isSubscriptionWindow(s.rateLimitType));
4453
- if (rejectedIsCap || frame.terminalReason === "blocking_limit")
4454
- return {
4455
- kind: "usage_capped",
4456
- ...s.rateLimitResetIso ? { resetsAt: s.rateLimitResetIso } : {}
4457
- };
4458
- return classifyAssistantError(s.lastAssistantError) ?? classifyErrorText([s.authError, frame.text].filter(Boolean).join(" "));
4459
- }
4460
- function classifyResultFailure(msg, s) {
4461
- const resultText = msg.result ?? "";
4462
- const terminalReason = msg.terminal_reason;
4463
- const errors = msg.errors;
4464
- const text = [resultText, ...Array.isArray(errors) ? errors.map(String) : []].join(" ");
4465
- return classifyFailure(s, { terminalReason, text });
4466
- }
4467
- function classifyPreInitFrame(msg, s) {
4468
- if (msg.type === "result") {
4469
- const isError = msg.is_error === true;
4470
- if (msg.subtype === "success" && !isError) return classifyFailure(s, { text: "" });
4471
- return classifyResultFailure(msg, s);
4472
- }
4473
- if (msg.type !== "assistant") return classifyFailure(s, { text: "" });
4474
- const error = msg.error;
4475
- const signals = typeof error === "string" && error.length > 0 ? { ...s, lastAssistantError: error } : s;
4476
- const text = contentBlocks(msg).flatMap((b) => b.type === "text" && typeof b.text === "string" ? [b.text] : []).join(" ");
4477
- return classifyFailure(signals, { text });
4478
- }
4479
- function preInitToolActivity(msg) {
4480
- const kind = msg.type === "assistant" ? "tool_use" : msg.type === "user" ? "tool_result" : null;
4481
- return kind !== null && contentBlocks(msg).some((b) => b.type === kind);
4482
- }
4483
4610
  function isHarnessAuthored(msg) {
4484
4611
  const error = msg.error;
4485
4612
  if (typeof error === "string" && error.length > 0) return true;
@@ -4504,99 +4631,9 @@ async function emitHarnessMessage(msg, emit, pending, buffer) {
4504
4631
  );
4505
4632
  }
4506
4633
  }
4507
- function contentBlocks(msg) {
4508
- const content = msg.message?.content;
4509
- return Array.isArray(content) ? content : [];
4510
- }
4511
- function isSubscriptionWindow(value) {
4512
- return value === "five_hour" || value === "seven_day" || value === "seven_day_opus" || value === "seven_day_sonnet" || value === "overage";
4513
- }
4514
4634
  function* drain(out) {
4515
4635
  while (out.length > 0) yield out.shift();
4516
4636
  }
4517
- function readSdkUsage(msg) {
4518
- const usage = msg.usage;
4519
- if (!usage || typeof usage !== "object") return void 0;
4520
- const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
4521
- const cacheReadTokens = num(usage.cache_read_input_tokens);
4522
- const cacheCreationTokens = num(usage.cache_creation_input_tokens);
4523
- const inputTokens = num(usage.input_tokens) + cacheCreationTokens + cacheReadTokens;
4524
- const outputTokens = num(usage.output_tokens);
4525
- return { inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens };
4526
- }
4527
- function readRequestContextTokens(msg) {
4528
- const usage = msg.message?.usage;
4529
- if (!usage || typeof usage !== "object") return void 0;
4530
- const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
4531
- return num(usage.input_tokens) + num(usage.cache_read_input_tokens) + num(usage.cache_creation_input_tokens);
4532
- }
4533
- var CONTEXT_READING_TIMEOUT_MS = 2e3;
4534
- async function readHarnessContext(read) {
4535
- if (!read) return void 0;
4536
- let timer;
4537
- const timeout = new Promise((resolve2) => {
4538
- timer = setTimeout(() => resolve2(void 0), CONTEXT_READING_TIMEOUT_MS);
4539
- });
4540
- try {
4541
- return parseContextUsage(await Promise.race([read(), timeout]));
4542
- } catch {
4543
- return void 0;
4544
- } finally {
4545
- clearTimeout(timer);
4546
- }
4547
- }
4548
- var CATEGORY_KINDS = /* @__PURE__ */ new Set(["used", "free", "buffer", "deferred"]);
4549
- function parseContextUsage(response) {
4550
- const r = response;
4551
- if (!r || typeof r !== "object") return void 0;
4552
- const count = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
4553
- const total = count(r.totalTokens);
4554
- const window = count(r.maxTokens);
4555
- if (total === void 0 || window === void 0 || window === 0) return void 0;
4556
- const categories = [];
4557
- for (const c of Array.isArray(r.categories) ? r.categories : []) {
4558
- const row = c;
4559
- const tokens = count(row?.tokens);
4560
- if (typeof row?.name === "string" && tokens !== void 0 && typeof row.kind === "string" && CATEGORY_KINDS.has(row.kind)) {
4561
- categories.push({ name: row.name, tokens, kind: row.kind });
4562
- }
4563
- }
4564
- const buffer = categories.filter((c) => c.kind === "buffer").reduce((sum, c) => sum + c.tokens, 0);
4565
- return {
4566
- contextTokens: total,
4567
- contextWindow: window,
4568
- ...buffer > 0 && buffer < window ? { contextCompactAt: window - buffer } : {},
4569
- ...categories.length > 0 ? { contextCategories: categories } : {}
4570
- };
4571
- }
4572
- function readCompaction(msg) {
4573
- const meta = msg.compact_metadata;
4574
- const count = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.round(v) : void 0;
4575
- const preTokens = count(meta?.pre_tokens);
4576
- if (!meta || preTokens === void 0) return void 0;
4577
- if (meta.trigger !== "manual" && meta.trigger !== "auto") return void 0;
4578
- const postTokens = count(meta.post_tokens);
4579
- return {
4580
- trigger: meta.trigger,
4581
- preTokens,
4582
- ...postTokens !== void 0 ? { postTokens } : {}
4583
- };
4584
- }
4585
- function readContextWindow(msg, resolvedModel) {
4586
- const modelUsage = msg.modelUsage;
4587
- if (!modelUsage || typeof modelUsage !== "object") return void 0;
4588
- const pos = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
4589
- if (resolvedModel) {
4590
- const direct = pos(modelUsage[resolvedModel]?.contextWindow);
4591
- if (direct !== void 0) return direct;
4592
- }
4593
- let max;
4594
- for (const entry of Object.values(modelUsage)) {
4595
- const w = pos(entry?.contextWindow);
4596
- if (w !== void 0 && (max === void 0 || w > max)) max = w;
4597
- }
4598
- return max;
4599
- }
4600
4637
 
4601
4638
  // packages/agent-runtime/src/claude-code/prompt-input.ts
4602
4639
  function buildQueryPrompt(req, openUntil) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cabane/companion",
3
- "version": "0.6.157",
3
+ "version": "0.6.158",
4
4
  "type": "module",
5
5
  "description": "The Cabane Companion (headless): connect an agent on your machine to your Cabane workspace as a responder — drive work against your own codebase, files, and MCP servers without putting any of it in Cabane.",
6
6
  "license": "UNLICENSED",