zelari-code 2.18.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23108,6 +23108,9 @@ var init_ObserverBus = __esm({
23108
23108
  });
23109
23109
 
23110
23110
  // packages/core/dist/core/AgentHarness.js
23111
+ function gateAdvice(hardLimit) {
23112
+ return hardLimit ? "Finalize now with the evidence already collected; no further tool calls will run this turn." : "Prioritize verification/repair actions (test, typecheck, build, read failures) or finalize honestly.";
23113
+ }
23111
23114
  function hashToolCall(toolName, args) {
23112
23115
  const canonical = stableStringify2(args);
23113
23116
  return `${toolName}::${canonical}`;
@@ -23139,10 +23142,18 @@ function normalizeTextToolArgs(name, args) {
23139
23142
  }
23140
23143
  return out;
23141
23144
  }
23142
- function parseTextToolCalls(text) {
23145
+ function parseTextToolCallsDetailed(text) {
23146
+ let truncatedBlock = false;
23147
+ let rawBody = null;
23143
23148
  const m = /---TOOLS---\s*([\s\S]*?)---END---/.exec(text);
23144
23149
  if (m?.[1]) {
23145
- let body = m[1].trim();
23150
+ rawBody = m[1];
23151
+ } else if (text.includes("---TOOLS---")) {
23152
+ rawBody = text.slice(text.indexOf("---TOOLS---") + "---TOOLS---".length);
23153
+ truncatedBlock = true;
23154
+ }
23155
+ if (rawBody !== null) {
23156
+ let body = rawBody.trim();
23146
23157
  body = body.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
23147
23158
  const candidates = [body];
23148
23159
  if (/\]\s*\[/.test(body)) {
@@ -23157,7 +23168,7 @@ function parseTextToolCalls(text) {
23157
23168
  for (const cand of candidates) {
23158
23169
  const items = tryParseToolArray(cand);
23159
23170
  if (items.length > 0)
23160
- return items;
23171
+ return { calls: items, truncatedBlock };
23161
23172
  }
23162
23173
  const arrays = extractJsonArrays(body);
23163
23174
  if (arrays.length > 1) {
@@ -23166,16 +23177,19 @@ function parseTextToolCalls(text) {
23166
23177
  merged.push(...tryParseToolArray(a));
23167
23178
  }
23168
23179
  if (merged.length > 0)
23169
- return merged;
23180
+ return { calls: merged, truncatedBlock };
23170
23181
  }
23171
23182
  const objs = extractToolObjects(body);
23172
23183
  if (objs.length > 0)
23173
- return objs;
23184
+ return { calls: objs, truncatedBlock };
23174
23185
  }
23175
23186
  const mini = parseMinimaxStyleToolCalls(text);
23176
23187
  if (mini.length > 0)
23177
- return mini;
23178
- return [];
23188
+ return { calls: mini, truncatedBlock };
23189
+ return { calls: [], truncatedBlock };
23190
+ }
23191
+ function parseTextToolCalls(text) {
23192
+ return parseTextToolCallsDetailed(text).calls;
23179
23193
  }
23180
23194
  function parseMinimaxStyleToolCalls(text) {
23181
23195
  const out = [];
@@ -23322,25 +23336,63 @@ function extractJsonArrays(text) {
23322
23336
  }
23323
23337
  return out;
23324
23338
  }
23339
+ function findBalancedBrace(text, openIdx) {
23340
+ let depth = 0;
23341
+ let inStr = false;
23342
+ let esc2 = false;
23343
+ for (let j = openIdx; j < text.length; j++) {
23344
+ const c = text[j];
23345
+ if (inStr) {
23346
+ if (esc2)
23347
+ esc2 = false;
23348
+ else if (c === "\\")
23349
+ esc2 = true;
23350
+ else if (c === '"')
23351
+ inStr = false;
23352
+ continue;
23353
+ }
23354
+ if (c === '"') {
23355
+ inStr = true;
23356
+ continue;
23357
+ }
23358
+ if (c === "{")
23359
+ depth++;
23360
+ else if (c === "}") {
23361
+ depth--;
23362
+ if (depth === 0)
23363
+ return j;
23364
+ }
23365
+ }
23366
+ return -1;
23367
+ }
23325
23368
  function extractToolObjects(text) {
23326
23369
  const out = [];
23327
- const re = /\{\s*"name"\s*:\s*"([^"]+)"\s*,\s*"args"\s*:\s*(\{[\s\S]*?\})\s*\}/g;
23370
+ const headRe = /\{\s*"name"\s*:\s*"([^"]+)"\s*,\s*"args"\s*:\s*/g;
23328
23371
  let match;
23329
- while ((match = re.exec(text)) !== null) {
23372
+ while ((match = headRe.exec(text)) !== null) {
23330
23373
  const name = match[1];
23374
+ const argsStart = match.index + match[0].length;
23331
23375
  let args = {};
23332
- try {
23333
- const parsed = JSON.parse(match[2]);
23334
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
23335
- args = parsed;
23376
+ if (text[argsStart] === "{") {
23377
+ const end = findBalancedBrace(text, argsStart);
23378
+ if (end === -1)
23379
+ continue;
23380
+ try {
23381
+ const parsed = JSON.parse(text.slice(argsStart, end + 1));
23382
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
23383
+ args = parsed;
23384
+ } else {
23385
+ continue;
23386
+ }
23387
+ } catch {
23388
+ continue;
23336
23389
  }
23337
- } catch {
23338
23390
  }
23339
23391
  out.push({ name, args });
23340
23392
  }
23341
23393
  return out;
23342
23394
  }
23343
- var TOOL_CALL_TRUNCATED_RECOVERY_MARKER, TOOL_CALL_TRUNCATED_RECOVERY_USER, BUILD_LIVENESS_RECOVERY_PROMPT, AgentHarness, DOOM_LOOP_THRESHOLD;
23395
+ var TOOL_CALL_TRUNCATED_RECOVERY_MARKER, TOOL_CALL_TRUNCATED_RECOVERY_USER, TEXT_TOOLS_FAILED_MARKER, TEXT_TOOLS_FAILED_USER, TEXT_TOOLS_PARTIAL_MARKER, TEXT_TOOLS_PARTIAL_USER, BUILD_LIVENESS_RECOVERY_PROMPT, AgentHarness, DOOM_LOOP_THRESHOLD;
23344
23396
  var init_AgentHarness = __esm({
23345
23397
  "packages/core/dist/core/AgentHarness.js"() {
23346
23398
  "use strict";
@@ -23354,6 +23406,10 @@ var init_AgentHarness = __esm({
23354
23406
  init_textLoopDetect();
23355
23407
  TOOL_CALL_TRUNCATED_RECOVERY_MARKER = "[harness] Previous tool call was truncated";
23356
23408
  TOOL_CALL_TRUNCATED_RECOVERY_USER = `${TOOL_CALL_TRUNCATED_RECOVERY_MARKER} by the provider before completion (finish_reason=tool_calls but no complete tool_call arrived). Retry with a shorter payload or split the work into smaller tool calls.`;
23409
+ TEXT_TOOLS_FAILED_MARKER = "[harness] Your ---TOOLS--- block did not run";
23410
+ TEXT_TOOLS_FAILED_USER = `${TEXT_TOOLS_FAILED_MARKER}: no call parsed (malformed, or truncated by the provider before ---END---). Re-emit the calls with native tool_call, or ONE valid ---TOOLS--- JSON array \u2014 smaller payloads if the block was cut off.`;
23411
+ TEXT_TOOLS_PARTIAL_MARKER = "[harness] Your ---TOOLS--- block was cut off";
23412
+ TEXT_TOOLS_PARTIAL_USER = `${TEXT_TOOLS_PARTIAL_MARKER} by the provider before ---END---: only the complete leading call(s) ran \u2014 the incomplete tail was dropped. Re-emit the remaining work with native tool_call or smaller payloads.`;
23357
23413
  BUILD_LIVENESS_RECOVERY_PROMPT = "[build-liveness] The requested task requires an on-disk implementation, but no successful project mutation has occurred yet. Continue working. Inspect only as needed, then make the required change with an available mutating tool. Do not merely describe a patch or claim completion.";
23358
23414
  AgentHarness = class {
23359
23415
  config;
@@ -23583,7 +23639,7 @@ var init_AgentHarness = __esm({
23583
23639
  const gate = this.checkToolCallGate(p3.toolName, p3.args);
23584
23640
  if (!gate.allowed) {
23585
23641
  return {
23586
- content: `[resource-gate] ${gate.reason ?? "denied by resource policy"} Prioritize verification/repair actions (test, typecheck, build, read failures) or finalize honestly.`,
23642
+ content: `[resource-gate] ${gate.reason ?? "denied by resource policy"} ` + gateAdvice(gate.hardLimit),
23587
23643
  isError: true,
23588
23644
  durationMs: 0
23589
23645
  };
@@ -23848,6 +23904,8 @@ ${shared.content}`,
23848
23904
  return null;
23849
23905
  if (this.buildProgress.recoveries >= maxBuildRecoveries)
23850
23906
  return null;
23907
+ if (!this.checkToolCallGate("edit_file", {}).allowed)
23908
+ return null;
23851
23909
  this.buildProgress.recoveries += 1;
23852
23910
  this.config.messages.push({ role: "user", content: BUILD_LIVENESS_RECOVERY_PROMPT });
23853
23911
  return {
@@ -24244,7 +24302,8 @@ ${cached2}`
24244
24302
  finishRef.value = "stop";
24245
24303
  finishRef.clarificationRequested = true;
24246
24304
  }
24247
- const textTools = clarificationPause ? [] : parseTextToolCalls(turnText);
24305
+ const textParse = clarificationPause ? { calls: [], truncatedBlock: false } : parseTextToolCallsDetailed(turnText);
24306
+ const textTools = textParse.calls;
24248
24307
  const toolsToRun = textTools.filter((tt) => {
24249
24308
  const key = hashToolCall(tt.name, tt.args);
24250
24309
  return !turnToolCalls.some((n) => hashToolCall(n.name, n.args) === key);
@@ -24252,12 +24311,21 @@ ${cached2}`
24252
24311
  if (!clarificationPause && (/---TOOLS---/.test(turnText) || /<\/?minimax:tool_call\b/i.test(turnText) || /invoke\s+name\s*=/i.test(turnText) || /\]\s*<\s*\]\s*minimax\s*\[/i.test(turnText)) && textTools.length === 0) {
24253
24312
  const parseErr = createBrainEvent("error", this.sessionId, {
24254
24313
  severity: "recoverable",
24255
- message: "Found text-format tool block but parse failed; tool calls were not executed. Prefer native tool_call, or ---TOOLS--- with ONE valid JSON array.",
24314
+ message: textParse.truncatedBlock ? "Found text-format tool block but parse failed; the block is TRUNCATED (no ---END--- marker \u2014 the provider cut the response mid-block). Tool calls were not executed. Re-emit with native tool_call or smaller payloads." : "Found text-format tool block but parse failed; tool calls were not executed. Prefer native tool_call, or ---TOOLS--- with ONE valid JSON array.",
24256
24315
  code: "text_tools_parse_failed"
24257
24316
  });
24258
24317
  this.emit(parseErr);
24259
24318
  yield parseErr;
24260
24319
  }
24320
+ if (!clarificationPause && textParse.truncatedBlock && textTools.length > 0) {
24321
+ const partial2 = createBrainEvent("error", this.sessionId, {
24322
+ severity: "recoverable",
24323
+ message: `Text-format tool block was truncated (missing ---END---): recovered ${textTools.length} complete call(s); the incomplete tail was dropped.`,
24324
+ code: "text_tools_truncated"
24325
+ });
24326
+ this.emit(partial2);
24327
+ yield partial2;
24328
+ }
24261
24329
  if (!clarificationPause && toolsToRun.length > 0 && this.config.toolRegistry && !this.cancelled && this.textToolReentries < 4) {
24262
24330
  let executedAny = false;
24263
24331
  for (let ti = 0; ti < toolsToRun.length; ti++) {
@@ -24280,7 +24348,7 @@ ${cached2}`
24280
24348
  yield startEv;
24281
24349
  const gate = this.checkToolCallGate(tt.name, tt.args);
24282
24350
  if (!gate.allowed) {
24283
- const denied = `[resource-gate] ${gate.reason ?? "denied by resource policy"} Prioritize verification/repair actions (test, typecheck, build, read failures) or finalize honestly.`;
24351
+ const denied = `[resource-gate] ${gate.reason ?? "denied by resource policy"} ` + gateAdvice(gate.hardLimit);
24284
24352
  const denyEv = createBrainEvent("tool_execution_end", this.sessionId, {
24285
24353
  toolCallId,
24286
24354
  result: denied,
@@ -24407,6 +24475,15 @@ ${cached2}`
24407
24475
  });
24408
24476
  }
24409
24477
  }
24478
+ if (!clarificationPause) {
24479
+ const feedbackText = textParse.truncatedBlock && textTools.length > 0 ? TEXT_TOOLS_PARTIAL_USER : /---TOOLS---/.test(turnText) && textTools.length === 0 ? TEXT_TOOLS_FAILED_USER : null;
24480
+ if (feedbackText) {
24481
+ const last = this.config.messages[this.config.messages.length - 1];
24482
+ if (!(last?.role === "user" && typeof last.content === "string" && (last.content.includes(TEXT_TOOLS_PARTIAL_MARKER) || last.content.includes(TEXT_TOOLS_FAILED_MARKER)))) {
24483
+ this.config.messages.push({ role: "user", content: feedbackText });
24484
+ }
24485
+ }
24486
+ }
24410
24487
  break;
24411
24488
  } else if (delta.kind === "error") {
24412
24489
  finishRef.providerError = true;
@@ -25341,6 +25418,10 @@ __export(harness_exports, {
25341
25418
  SessionJsonlWriter: () => SessionJsonlWriter,
25342
25419
  TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
25343
25420
  TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
25421
+ TEXT_TOOLS_FAILED_MARKER: () => TEXT_TOOLS_FAILED_MARKER,
25422
+ TEXT_TOOLS_FAILED_USER: () => TEXT_TOOLS_FAILED_USER,
25423
+ TEXT_TOOLS_PARTIAL_MARKER: () => TEXT_TOOLS_PARTIAL_MARKER,
25424
+ TEXT_TOOLS_PARTIAL_USER: () => TEXT_TOOLS_PARTIAL_USER,
25344
25425
  TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
25345
25426
  TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
25346
25427
  canonicalTools: () => canonicalTools,
@@ -25360,6 +25441,7 @@ __export(harness_exports, {
25360
25441
  normalizeToolName: () => normalizeToolName,
25361
25442
  parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
25362
25443
  parseTextToolCalls: () => parseTextToolCalls,
25444
+ parseTextToolCallsDetailed: () => parseTextToolCallsDetailed,
25363
25445
  readSession: () => readSession,
25364
25446
  recordRequest: () => recordRequest,
25365
25447
  recordToolResult: () => recordToolResult,
@@ -35811,6 +35893,10 @@ __export(dist_exports, {
35811
35893
  TERMINAL_STATUSES: () => TERMINAL_STATUSES,
35812
35894
  TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
35813
35895
  TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
35896
+ TEXT_TOOLS_FAILED_MARKER: () => TEXT_TOOLS_FAILED_MARKER,
35897
+ TEXT_TOOLS_FAILED_USER: () => TEXT_TOOLS_FAILED_USER,
35898
+ TEXT_TOOLS_PARTIAL_MARKER: () => TEXT_TOOLS_PARTIAL_MARKER,
35899
+ TEXT_TOOLS_PARTIAL_USER: () => TEXT_TOOLS_PARTIAL_USER,
35814
35900
  TIER_RANK: () => TIER_RANK,
35815
35901
  TOOL_CALL_TRUNCATED_RECOVERY_MARKER: () => TOOL_CALL_TRUNCATED_RECOVERY_MARKER,
35816
35902
  TOOL_CALL_TRUNCATED_RECOVERY_USER: () => TOOL_CALL_TRUNCATED_RECOVERY_USER,
@@ -36040,6 +36126,7 @@ __export(dist_exports, {
36040
36126
  parsePersonaVerdict: () => parsePersonaVerdict,
36041
36127
  parseProjectRootFromWorkspaceContext: () => parseProjectRootFromWorkspaceContext,
36042
36128
  parseTextToolCalls: () => parseTextToolCalls,
36129
+ parseTextToolCallsDetailed: () => parseTextToolCallsDetailed,
36043
36130
  parseThinking: () => parseThinking,
36044
36131
  parseVerificationRunPayload: () => parseVerificationRunPayload,
36045
36132
  parseVerificationTable: () => parseVerificationTable,
@@ -37123,6 +37210,20 @@ function mapBrainEventToSpine(ev) {
37123
37210
  data: { text: TOOL_CALL_TRUNCATED_RECOVERY_USER }
37124
37211
  };
37125
37212
  }
37213
+ if (ev.code === "text_tools_parse_failed") {
37214
+ return {
37215
+ kind: "user.message",
37216
+ actor: ACTOR_USER,
37217
+ data: { text: TEXT_TOOLS_FAILED_USER }
37218
+ };
37219
+ }
37220
+ if (ev.code === "text_tools_truncated") {
37221
+ return {
37222
+ kind: "user.message",
37223
+ actor: ACTOR_USER,
37224
+ data: { text: TEXT_TOOLS_PARTIAL_USER }
37225
+ };
37226
+ }
37126
37227
  return null;
37127
37228
  default:
37128
37229
  return null;
@@ -50035,15 +50136,39 @@ function spineMemoryEventNote(handle, event) {
50035
50136
  } catch {
50036
50137
  }
50037
50138
  }
50139
+ function bufferOf(holder) {
50140
+ let buf = buffers.get(holder);
50141
+ if (!buf) {
50142
+ buf = [];
50143
+ buffers.set(holder, buf);
50144
+ }
50145
+ return buf;
50146
+ }
50038
50147
  function memorySinkFor(holder) {
50039
50148
  return (event) => {
50040
50149
  const handle = holder.current;
50041
- if (handle) spineMemoryEventNote(handle, event);
50150
+ if (handle) {
50151
+ spineMemoryEventNote(handle, event);
50152
+ return;
50153
+ }
50154
+ const buf = bufferOf(holder);
50155
+ if (buf.length < PRE_BIND_BUFFER_CAP) buf.push(event);
50156
+ else holder.droppedEvents = (holder.droppedEvents ?? 0) + 1;
50042
50157
  };
50043
50158
  }
50159
+ function flushMemorySpineNotes(holder) {
50160
+ const handle = holder.current;
50161
+ const buf = buffers.get(holder);
50162
+ if (!handle || !buf?.length) return;
50163
+ const pending = buf.splice(0, buf.length);
50164
+ for (const event of pending) spineMemoryEventNote(handle, event);
50165
+ }
50166
+ var PRE_BIND_BUFFER_CAP, buffers;
50044
50167
  var init_spineTelemetry = __esm({
50045
50168
  "src/cli/memory/spineTelemetry.ts"() {
50046
50169
  "use strict";
50170
+ PRE_BIND_BUFFER_CAP = 32;
50171
+ buffers = /* @__PURE__ */ new WeakMap();
50047
50172
  }
50048
50173
  });
50049
50174
 
@@ -52013,6 +52138,51 @@ var init_persistCompact = __esm({
52013
52138
  }
52014
52139
  });
52015
52140
 
52141
+ // src/cli/budget/contextProjection.ts
52142
+ function policyFromOccupancy(occupancy, thresholds = DEFAULT_THRESHOLDS) {
52143
+ if (occupancy >= thresholds.hardAt) return "hard";
52144
+ if (occupancy >= thresholds.compactAt) return "compact";
52145
+ if (occupancy >= thresholds.warnAt) return "warn";
52146
+ return "ok";
52147
+ }
52148
+ function recordFromBudget(budget, thresholds = DEFAULT_THRESHOLDS) {
52149
+ return {
52150
+ occupancy: budget.occupancy,
52151
+ estimatedHistoryTokens: budget.estimatedHistoryTokens,
52152
+ contextLimit: budget.contextLimit,
52153
+ ...budget.contextPressureTokens !== void 0 ? { contextPressureTokens: budget.contextPressureTokens } : {},
52154
+ policy: policyFromOccupancy(budget.occupancy, thresholds)
52155
+ };
52156
+ }
52157
+ function thresholdsFor(model, provider) {
52158
+ return capabilitiesFor(model, provider).compaction;
52159
+ }
52160
+ function noteBudgetProjection(handle, record2) {
52161
+ try {
52162
+ handle.note("context.projection", {
52163
+ subject: "context.projection",
52164
+ occupancy: record2.occupancy,
52165
+ estimatedHistoryTokens: record2.estimatedHistoryTokens,
52166
+ contextLimit: record2.contextLimit,
52167
+ ...record2.contextPressureTokens !== void 0 ? { contextPressureTokens: record2.contextPressureTokens } : {},
52168
+ policy: record2.policy
52169
+ });
52170
+ } catch {
52171
+ }
52172
+ }
52173
+ var DEFAULT_THRESHOLDS;
52174
+ var init_contextProjection = __esm({
52175
+ "src/cli/budget/contextProjection.ts"() {
52176
+ "use strict";
52177
+ init_capabilities();
52178
+ DEFAULT_THRESHOLDS = {
52179
+ warnAt: 0.7,
52180
+ compactAt: 0.85,
52181
+ hardAt: 0.95
52182
+ };
52183
+ }
52184
+ });
52185
+
52016
52186
  // src/cli/budget/modelContextBuilder.ts
52017
52187
  function messageWasRecompacted(message, history2) {
52018
52188
  if (message.compactedFromSeq === void 0) return false;
@@ -52119,6 +52289,15 @@ async function buildModelContext(input) {
52119
52289
  occupancy: Math.min(1, estimated / budget.contextLimit)
52120
52290
  };
52121
52291
  }
52292
+ if (input.budgetNoteHandle) {
52293
+ try {
52294
+ noteBudgetProjection(
52295
+ input.budgetNoteHandle,
52296
+ recordFromBudget(budget, thresholdsFor(input.model, input.provider))
52297
+ );
52298
+ } catch {
52299
+ }
52300
+ }
52122
52301
  return {
52123
52302
  history: history2,
52124
52303
  requestTail,
@@ -52136,6 +52315,7 @@ var init_modelContextBuilder = __esm({
52136
52315
  init_tokenBudget();
52137
52316
  init_requestMeter();
52138
52317
  init_persistCompact();
52318
+ init_contextProjection();
52139
52319
  init_headlessSpine();
52140
52320
  init_session();
52141
52321
  }
@@ -63034,6 +63214,20 @@ function asNumber2(v) {
63034
63214
  function asCallId(v, seq) {
63035
63215
  return typeof v === "string" && v.length > 0 ? v : `seq:${seq}`;
63036
63216
  }
63217
+ function parseProjection(data) {
63218
+ const policy = asString3(data.policy);
63219
+ return {
63220
+ contextChars: asNumber2(data.contextChars) ?? 0,
63221
+ returnedCount: asNumber2(data.returnedCount) ?? 0,
63222
+ occupancy: asNumber2(data.occupancy),
63223
+ estimatedHistoryTokens: asNumber2(data.estimatedHistoryTokens),
63224
+ contextLimit: asNumber2(data.contextLimit),
63225
+ contextPressureTokens: asNumber2(data.contextPressureTokens),
63226
+ durationMs: asNumber2(data.durationMs),
63227
+ backend: asString3(data.backend) || void 0,
63228
+ policy: policy === "ok" || policy === "warn" || policy === "compact" || policy === "hard" ? policy : void 0
63229
+ };
63230
+ }
63037
63231
  function newTurn(index, userText) {
63038
63232
  return {
63039
63233
  index,
@@ -63115,17 +63309,14 @@ function deriveHarnessState(events) {
63115
63309
  }
63116
63310
  case "session.compacted": {
63117
63311
  support.compactions += 1;
63118
- const saved = asNumber2(e.data.tokensSaved);
63312
+ const saved = asNumber2(e.data.savedTokens) ?? asNumber2(e.data.tokensSaved);
63119
63313
  if (saved !== void 0) tokensSaved = (tokensSaved ?? 0) + saved;
63120
63314
  break;
63121
63315
  }
63122
63316
  case "note": {
63123
63317
  const subject = asString3(e.data.subject);
63124
63318
  if (subject === "context.projection") {
63125
- support.contextProjections.push({
63126
- contextChars: asNumber2(e.data.contextChars) ?? 0,
63127
- returnedCount: asNumber2(e.data.returnedCount) ?? 0
63128
- });
63319
+ support.contextProjections.push(parseProjection(e.data));
63129
63320
  } else if (subject === "memory_event") {
63130
63321
  support.memoryEvents += 1;
63131
63322
  }
@@ -64076,6 +64267,7 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
64076
64267
  toolSpecs: typeof toolRegistry.fingerprints === "function" ? toolRegistry.fingerprints() : void 0
64077
64268
  });
64078
64269
  spineHolder.current = spine;
64270
+ flushMemorySpineNotes(spineHolder);
64079
64271
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
64080
64272
  emitEvent(sessionStartedEvent(spine));
64081
64273
  if (opts.orchestrationDecision) {
@@ -64213,6 +64405,8 @@ async function runOneTurn(opts, provider, model, providerStream, extras) {
64213
64405
  tools,
64214
64406
  sessionId: spine.sessionId,
64215
64407
  providerStream,
64408
+ // T4-S2: budget occupancy/policy onto the spine (context.projection note).
64409
+ budgetNoteHandle: spine,
64216
64410
  onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
64217
64411
  persistCompaction: async (payload) => {
64218
64412
  await spine.appendEvent({
@@ -65957,6 +66151,7 @@ async function runHeadlessCouncil(opts, provider, model, providerStream, extras)
65957
66151
  workspace: cwd
65958
66152
  });
65959
66153
  spineHolder.current = spine;
66154
+ flushMemorySpineNotes(spineHolder);
65960
66155
  const seededHistory = await seedHeadlessModelHistory(spine, opts.history);
65961
66156
  emitEvent(sessionStartedEvent(spine));
65962
66157
  if (opts.orchestrationDecision) {
@@ -65996,6 +66191,8 @@ async function runHeadlessCouncil(opts, provider, model, providerStream, extras)
65996
66191
  tools: contextTools,
65997
66192
  sessionId: spine.sessionId,
65998
66193
  providerStream,
66194
+ // T4-S2: budget occupancy/policy onto the spine (context.projection note).
66195
+ budgetNoteHandle: spine,
65999
66196
  onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
66000
66197
  persistCompaction: async (payload) => {
66001
66198
  await spine.appendEvent({
@@ -66211,6 +66408,8 @@ async function runHeadlessZelari(opts, provider, model, providerStream, extras)
66211
66408
  tools: contextTools,
66212
66409
  sessionId: spine.sessionId,
66213
66410
  providerStream,
66411
+ // T4-S2: budget occupancy/policy onto the spine (context.projection note).
66412
+ budgetNoteHandle: spine,
66214
66413
  onCompactionMetric: (metrics) => recordCompactionMetrics(spine.sessionId, provider, model, metrics),
66215
66414
  persistCompaction: async (payload) => {
66216
66415
  await spine.appendEvent({
@@ -69942,6 +70141,9 @@ __export(inspectSession_exports, {
69942
70141
  });
69943
70142
  import path89 from "node:path";
69944
70143
  import { existsSync as existsSync56 } from "node:fs";
70144
+ function formatLimit(limit) {
70145
+ return `${Math.round(limit / 1e3)}k`;
70146
+ }
69945
70147
  function renderInspectReport(state3) {
69946
70148
  const lines = [
69947
70149
  `session ${state3.session.sessionId} status=${state3.session.status} turns=${state3.execution.turnsTotal}`
@@ -69960,9 +70162,8 @@ function renderInspectReport(state3) {
69960
70162
  lines.push("support lens:");
69961
70163
  const projections = state3.support.contextProjections;
69962
70164
  const last = projections[projections.length - 1];
69963
- lines.push(
69964
- ` context projections: ${projections.length}` + (last ? ` (last: ${last.contextChars} chars \u2192 ${last.returnedCount} items)` : "")
69965
- );
70165
+ const tail2 = !last ? "" : last.occupancy !== void 0 && last.contextLimit !== void 0 ? ` (last: ${Math.round(last.occupancy * 100)}% ${last.policy ?? "?"} (limit ${formatLimit(last.contextLimit)}))` : ` (last: ${last.contextChars} chars \u2192 ${last.returnedCount} items)`;
70166
+ lines.push(` context projections: ${projections.length}${tail2}`);
69966
70167
  lines.push(` memory events: ${state3.support.memoryEvents}`);
69967
70168
  const saved = state3.support.tokensSavedByCompaction;
69968
70169
  lines.push(
@@ -76671,6 +76872,7 @@ async function handleKrakenGraph(ctx, prompt) {
76671
76872
  onWarning: (warning) => appendSystem(ctx.setMessages, warning),
76672
76873
  onEvent: memorySinkFor(tuiSpineHolder)
76673
76874
  }) : void 0;
76875
+ flushMemorySpineNotes(tuiSpineHolder);
76674
76876
  const audit = new AuditLogger();
76675
76877
  const taskToolDeps = {
76676
76878
  createSubAgentContext: createKrakenSubAgentContextFactory({