zelari-code 2.18.0 → 2.18.1

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;