@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.
- package/dist/cli.js +217 -166
- package/dist/runtime.js +202 -165
- 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
|
|
2915
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
4307
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
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",
|