omnius 1.0.468 → 1.0.469

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/index.js CHANGED
@@ -14298,27 +14298,62 @@ function replaceAllOccurrences(haystack, needle, replacement) {
14298
14298
  return haystack.split(needle).join(replacement);
14299
14299
  }
14300
14300
  function buildMissingOldStringLlmContent(input) {
14301
+ const attemptedLineCount = input.attemptedOldString.split("\n").length;
14302
+ const attemptedCharCount = input.attemptedOldString.length;
14301
14303
  const lines = [
14302
14304
  "[FILE_EDIT_OLD_STRING_NOT_FOUND]",
14303
14305
  `path=${input.path}`,
14304
14306
  "The attempted old_string was absent from the current file.",
14307
+ `attempted_old_string_lines=${attemptedLineCount}`,
14308
+ `attempted_old_string_chars=${attemptedCharCount}`,
14309
+ "repair_state=needs_current_range",
14310
+ "patch_ready=false",
14311
+ "read_required=true unless current path+start_line+end_line+expected_hash are already present in active evidence",
14305
14312
  "Do not copy diagnostic gutters into old_string. Ignore line numbers, leading '>' markers, and the '|' separator.",
14313
+ "Transport rule: file_edit is for exact unique current text. If the intended edit is a contiguous line-range delete/replace/insert, use file_patch with start_line/end_line from file_read and expected_hash or expected_old_content.",
14314
+ "Range patch contract: if patch_ready=true or current target line range plus expected_hash are known, call file_patch. If the range/hash is missing after stale exact edit failure, file_read the target once.",
14306
14315
  "",
14307
- "attempted_old_string:",
14308
- fencedText(input.attemptedOldString)
14316
+ ...diagnosticTextBlock("attempted_old_string", input.attemptedOldString)
14309
14317
  ];
14310
14318
  if (input.snippetContent) {
14311
14319
  const range = input.snippetStartLine && input.snippetEndLine && input.totalLines ? `lines ${input.snippetStartLine}-${input.snippetEndLine} of ${input.totalLines}` : "closest current text";
14312
- lines.push("", `copyable_current_text_without_gutters (${range}):`, fencedText(stripDiagnosticGutters(input.snippetContent)), "", "Next action: build a new file_edit old_string only from the copyable_current_text_without_gutters block, or file_read the target if more context is needed.");
14320
+ lines.push("", `current_anchor_range=${range}`, "target_range_status=anchor_only_not_patch_ready", `copyable_current_text_without_gutters (${range}):`, fencedText(stripDiagnosticGutters(input.snippetContent)), "", "Next action: build a new file_edit old_string only from the copyable_current_text_without_gutters block, or use file_patch from fresh file_read line numbers when the target is a block/range.");
14313
14321
  } else {
14314
- lines.push("", "Next action: file_read the target, then build old_string from exact current file content.");
14322
+ lines.push("", "Next action: file_read the target, then either build old_string from exact current file content or use file_patch for a line-range edit.");
14315
14323
  }
14316
14324
  lines.push("", "Do not use shell text-rewrite commands as a workaround for this edit failure; keep the change tracked through file_edit, batch_edit, file_patch, or file_write.");
14317
14325
  if (input.newString.length > 0) {
14318
- lines.push("", "desired_new_string:", fencedText(input.newString));
14326
+ lines.push("", ...diagnosticTextBlock("desired_new_string", input.newString));
14319
14327
  }
14320
14328
  return lines.join("\n");
14321
14329
  }
14330
+ function diagnosticTextBlock(label, text2) {
14331
+ const maxChars = 700;
14332
+ const maxLines = 12;
14333
+ const lineCount = text2.split("\n").length;
14334
+ if (text2.length <= maxChars && lineCount <= maxLines) {
14335
+ return [`${label}:`, fencedText(text2)];
14336
+ }
14337
+ return [
14338
+ `${label}_preview:`,
14339
+ fencedText(previewText(text2, maxChars)),
14340
+ `${label}_omitted=true`,
14341
+ `${label}_omitted_reason=stale failed edit payload is not authoritative current file evidence`
14342
+ ];
14343
+ }
14344
+ function previewText(text2, maxChars) {
14345
+ if (text2.length <= maxChars)
14346
+ return text2;
14347
+ const headSize = Math.floor(maxChars * 0.65);
14348
+ const tailSize = Math.max(80, maxChars - headSize - 64);
14349
+ const head = text2.slice(0, headSize).trimEnd();
14350
+ const tail = text2.slice(-tailSize).trimStart();
14351
+ return `${head}
14352
+ ...
14353
+ [omitted ${text2.length - head.length - tail.length} chars]
14354
+ ...
14355
+ ${tail}`;
14356
+ }
14322
14357
  function buildAmbiguousOldStringLlmContent(input) {
14323
14358
  const replaceAllArgs = {
14324
14359
  path: input.path,
@@ -14367,7 +14402,7 @@ var init_file_edit = __esm({
14367
14402
  init_text_encoding();
14368
14403
  FileEditTool = class {
14369
14404
  name = "file_edit";
14370
- description = "Make a precise edit to a file by replacing an exact string match. The old_string must be unique in the file unless replace_all is true. Use replace_all to rename variables or change repeated patterns throughout the file.";
14405
+ description = "Make a precise edit to a file by replacing an exact string match. The old_string must be unique in the file unless replace_all is true. Use replace_all to rename variables or change repeated patterns throughout the file. Use file_patch instead when file_read line numbers identify a contiguous block to delete, replace, or insert around.";
14371
14406
  parameters = {
14372
14407
  type: "object",
14373
14408
  properties: {
@@ -14490,6 +14525,8 @@ var init_file_edit = __esm({
14490
14525
  }
14491
14526
  }
14492
14527
  if (occurrences === 0) {
14528
+ const attemptedOldStringLines = oldString.split("\n").length;
14529
+ const attemptedOldStringChars = oldString.length;
14493
14530
  const alreadyAppliedLines = newString.length > 0 ? findMatchLines(content, newString) : [];
14494
14531
  if (alreadyAppliedLines.length > 0) {
14495
14532
  const lineInfo = alreadyAppliedLines.length === 1 ? `line ${alreadyAppliedLines[0]}` : `${alreadyAppliedLines.length} locations (lines ${alreadyAppliedLines.join(", ")})`;
@@ -14512,10 +14549,12 @@ var init_file_edit = __esm({
14512
14549
  const pct = Math.round(snippet.similarity * 100);
14513
14550
  errorMsg += `
14514
14551
 
14515
- Current file content (closest match, ${pct}% similarity, lines ${snippet.startLine}–${snippet.endLine} of ${snippet.totalLines}):
14552
+ Attempted old_string spans ${attemptedOldStringLines} line(s), ${attemptedOldStringChars} chars. The diagnostic below is the closest anchor-line match, not proof that the whole old_string exists.
14553
+
14554
+ Current file content (closest anchor-line match, ${pct}% line similarity, lines ${snippet.startLine}–${snippet.endLine} of ${snippet.totalLines}):
14516
14555
  ${snippet.content}
14517
14556
 
14518
- Use the EXACT current content above to construct a working old_string. Do not retry with a different guess — the file on disk has changed since you last read it.`;
14557
+ Use the EXACT current content above to construct a working old_string. If the intended change is a contiguous line range, use file_patch with start_line/end_line from a fresh file_read. Do not retry with a different guess — the file on disk has changed since you last read it.`;
14519
14558
  } else {
14520
14559
  errorMsg += ` The file is empty or binary. Use file_read to inspect.`;
14521
14560
  }
@@ -28917,7 +28956,7 @@ var init_file_patch = __esm({
28917
28956
  init_text_encoding();
28918
28957
  FilePatchTool = class {
28919
28958
  name = "file_patch";
28920
- description = "Edit specific line ranges in a file. More precise than string matching for large files. Modes: 'replace' replaces lines start_line..end_line with new_content, 'insert_before' inserts before start_line, 'insert_after' inserts after start_line, 'delete' removes lines start_line..end_line. Use dry_run to preview changes.";
28959
+ description = "Edit specific line ranges in a file. More precise than string matching for large files. Modes: 'replace' replaces lines start_line..end_line with new_content, 'insert_before' inserts before start_line, 'insert_after' inserts after start_line, 'delete' removes lines start_line..end_line. Use this instead of file_edit when file_read line numbers identify the contiguous block to change. Use dry_run to preview changes.";
28921
28960
  parameters = {
28922
28961
  type: "object",
28923
28962
  properties: {
@@ -578077,6 +578116,43 @@ import { z as z17 } from "zod";
578077
578116
  function cleanToolActionReasonField(value2) {
578078
578117
  return String(value2 ?? "").replace(/\s+/g, " ").trim();
578079
578118
  }
578119
+ function stripShellQuotedSegments(command) {
578120
+ let out = "";
578121
+ let quote2 = null;
578122
+ let escaped = false;
578123
+ for (let i2 = 0; i2 < command.length; i2++) {
578124
+ const ch = command[i2];
578125
+ if (quote2 === "'") {
578126
+ if (ch === "'")
578127
+ quote2 = null;
578128
+ out += " ";
578129
+ continue;
578130
+ }
578131
+ if (quote2 === '"') {
578132
+ if (escaped) {
578133
+ escaped = false;
578134
+ out += " ";
578135
+ continue;
578136
+ }
578137
+ if (ch === "\\") {
578138
+ escaped = true;
578139
+ out += " ";
578140
+ continue;
578141
+ }
578142
+ if (ch === '"')
578143
+ quote2 = null;
578144
+ out += " ";
578145
+ continue;
578146
+ }
578147
+ if (ch === "'" || ch === '"') {
578148
+ quote2 = ch;
578149
+ out += " ";
578150
+ continue;
578151
+ }
578152
+ out += ch;
578153
+ }
578154
+ return out;
578155
+ }
578080
578156
  function parsePersistentMemoryMode(value2) {
578081
578157
  if (value2 === "full" || value2 === "deferred" || value2 === "off")
578082
578158
  return value2;
@@ -579826,6 +579902,8 @@ ${parts.join("\n")}
579826
579902
  lines.push(`recent_failed_approaches=${ts.failedApproaches.slice(-3).join(" | ").replace(/\s+/g, " ").slice(0, 420)}`);
579827
579903
  }
579828
579904
  lines.push("tool_call_contract=Mutating/side-effectful tool calls require action_reason {task_anchor,intent,evidence,expected_result,scope}; read-only evidence tools may include it but must never be blocked only for missing metadata. Compact public facts only, no hidden chain-of-thought.");
579905
+ lines.push("edit_transport_contract=file_edit is for exact unique current text copied from file_read; file_patch is for line-range delete/replace/insert using file_read line numbers and expected_hash/current target evidence. A failed file_edit invalidates the edit premise; rebuild from current evidence instead of broadening into file_write unless the task is truly whole-file replacement.");
579906
+ lines.push("range_patch_contract=If patch_ready=true or current path+start_line+end_line+expected_hash are known, call file_patch. If read_required=true or a stale exact edit lacks current range/hash, call file_read once. Do not call file_read when patch_ready=true.");
579829
579907
  lines.push(`scope_contract=${Array.from(TOOL_ACTION_REASON_SCOPES).join("|")}; use targeted_patch for constrained code edits and full_file_rewrite only for deliberate whole-file replacement.`);
579830
579908
  const focus = this._focusSupervisor?.snapshot().directive ?? null;
579831
579909
  if (focus) {
@@ -580035,7 +580113,7 @@ ${parts.join("\n")}
580035
580113
  temperature: options2?.temperature ?? 0,
580036
580114
  requestTimeoutMs: options2?.requestTimeoutMs ?? 3e5,
580037
580115
  taskTimeoutMs: options2?.taskTimeoutMs ?? 0,
580038
- // 0 = no hard timeout (turn budget is the loop breaker)
580116
+ // legacy health-check interval only; never a hard timeout
580039
580117
  compactionThreshold: options2?.compactionThreshold ?? 4e4,
580040
580118
  deepContext: options2?.deepContext ?? false,
580041
580119
  dynamicContext: options2?.dynamicContext ?? "",
@@ -583757,17 +583835,18 @@ ${contentPreview}
583757
583835
  const cmd = rawCmd.trim();
583758
583836
  if (!cmd)
583759
583837
  return false;
583760
- if (/(^|[^&\d])(>|>>)\s*\S/.test(cmd))
583838
+ const unquoted = stripShellQuotedSegments(cmd);
583839
+ if (/(^|[^&\d])(>|>>)\s*\S/.test(unquoted))
583761
583840
  return true;
583762
- if (/\|\s*(?:tee|dd)\b/i.test(cmd))
583841
+ if (/\|\s*(?:tee|dd)\b/i.test(unquoted))
583763
583842
  return true;
583764
- if (/\b(?:sed|gsed)\s+(?:[^\n;&|]*\s)?(?:-i|--in-place)\b/i.test(cmd))
583843
+ if (/\b(?:sed|gsed)\s+(?:[^\n;&|]*\s)?(?:-i|--in-place)\b/i.test(unquoted))
583765
583844
  return true;
583766
- if (/\bperl\s+-[A-Za-z]*i[A-Za-z]*\b/.test(cmd))
583845
+ if (/\bperl\s+-[A-Za-z]*i[A-Za-z]*\b/.test(unquoted))
583767
583846
  return true;
583768
- if (/\b(?:cp|mv|rm|mkdir|rmdir|touch|truncate|ln|install|chmod|chown|chgrp|setfacl)\b/i.test(cmd))
583847
+ if (/\b(?:cp|mv|rm|mkdir|rmdir|touch|truncate|ln|install|chmod|chown|chgrp|setfacl)\b/i.test(unquoted))
583769
583848
  return true;
583770
- if (/\b(?:udevadm|mount|umount|modprobe|insmod)\b/i.test(cmd))
583849
+ if (/\b(?:udevadm|mount|umount|modprobe|insmod)\b/i.test(unquoted))
583771
583850
  return true;
583772
583851
  if (/\b(?:python3?|node|ruby|deno|bun)\b[\s\S]{0,240}\b(?:writeFile|writeFileSync|openSync|mkdirSync|renameSync|unlinkSync|rmSync)\b/i.test(cmd))
583773
583852
  return true;
@@ -586026,44 +586105,13 @@ Respond with your assessment, then take action.`;
586026
586105
  }
586027
586106
  const cleanedTask = cleanForStorage(task) || task.slice(0, 500);
586028
586107
  const start2 = Date.now();
586029
- const taskTimeoutMs = this.options.taskTimeoutMs;
586030
- const hardDeadlineMs = Number.isFinite(taskTimeoutMs) && taskTimeoutMs > 0 ? start2 + taskTimeoutMs : Number.POSITIVE_INFINITY;
586031
- let timedOut = false;
586032
- let timeoutSummary = "";
586033
- const remainingTaskMs = () => Number.isFinite(hardDeadlineMs) ? Math.max(0, hardDeadlineMs - Date.now()) : Number.POSITIVE_INFINITY;
586108
+ const taskTimeoutMs = Number.isFinite(this.options.taskTimeoutMs) && this.options.taskTimeoutMs > 0 ? this.options.taskTimeoutMs : Number.POSITIVE_INFINITY;
586034
586109
  const boundedRequestTimeoutMs = () => {
586035
586110
  const configured = Number.isFinite(this.options.requestTimeoutMs) && this.options.requestTimeoutMs > 0 ? this.options.requestTimeoutMs : 3e5;
586036
- const remaining = remainingTaskMs();
586037
- return Number.isFinite(remaining) ? Math.max(1, Math.min(configured, remaining)) : configured;
586038
- };
586039
- const markTaskTimedOut = (phase, turn) => {
586040
- if (timedOut)
586041
- return;
586042
- timedOut = true;
586043
- timeoutSummary = `Incomplete: task timed out after ${taskTimeoutMs}ms during ${phase}.`;
586044
- this.emit({
586045
- type: "error",
586046
- content: timeoutSummary,
586047
- ...typeof turn === "number" ? { turn } : {},
586048
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
586049
- });
586050
- this._onTypedEvent?.({
586051
- type: "run_failed",
586052
- runId: this._sessionId ?? "unknown",
586053
- error: timeoutSummary,
586054
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
586055
- });
586056
- };
586057
- const checkTaskTimeout = (phase, turn) => {
586058
- if (!Number.isFinite(hardDeadlineMs))
586059
- return false;
586060
- if (Date.now() < hardDeadlineMs)
586061
- return false;
586062
- markTaskTimedOut(phase, turn);
586063
- return true;
586111
+ return configured;
586064
586112
  };
586065
586113
  const selfEvalInterval = taskTimeoutMs;
586066
- let nextSelfEval = start2 + selfEvalInterval;
586114
+ let nextSelfEval = Number.isFinite(selfEvalInterval) ? start2 + selfEvalInterval : Number.POSITIVE_INFINITY;
586067
586115
  let selfEvalCount = 0;
586068
586116
  const toolCallLog = [];
586069
586117
  this.aborted = false;
@@ -586930,8 +586978,6 @@ TASK: ${scrubbedTask}` : scrubbedTask;
586930
586978
  };
586931
586979
  const turnCap = this.options.maxTurns && this.options.maxTurns > 0 ? this.options.maxTurns : Number.MAX_SAFE_INTEGER;
586932
586980
  for (let turn = 0; turn < turnCap; turn++) {
586933
- if (checkTaskTimeout("primary turn", turn))
586934
- break;
586935
586981
  clearTurnState(this._appState);
586936
586982
  this._maybeApplyThinkGuard();
586937
586983
  if (this._paused) {
@@ -588604,10 +588650,8 @@ ${memoryLines.join("\n")}`
588604
588650
  break;
588605
588651
  }
588606
588652
  } else {
588607
- const recovered = await this.retryOnTransient(reqErr, chatRequest, turn, hardDeadlineMs);
588653
+ const recovered = await this.retryOnTransient(reqErr, chatRequest, turn);
588608
588654
  if (!recovered) {
588609
- if (checkTaskTimeout("backend request", turn))
588610
- break;
588611
588655
  const errMsg = reqErr instanceof Error ? reqErr.message : String(reqErr);
588612
588656
  const cause = reqErr instanceof Error && reqErr.cause ? ` (${reqErr.cause.message ?? ""} ${reqErr.cause?.code ?? ""})` : "";
588613
588657
  this.emit({
@@ -592287,9 +592331,7 @@ Your most recent tool calls SUCCEEDED. If the task is complete, call task_comple
592287
592331
  }
592288
592332
  }
592289
592333
  let prevCycleToolCalls = toolCallCount;
592290
- while (!completed && !this.aborted && !this._completionIncompleteVerification && !timedOut && this.options.bruteForce && bruteForceCycle < this.options.bruteForceMaxCycles) {
592291
- if (checkTaskTimeout("brute-force re-engagement"))
592292
- break;
592334
+ while (!completed && !this.aborted && !this._completionIncompleteVerification && this.options.bruteForce && bruteForceCycle < this.options.bruteForceMaxCycles) {
592293
592335
  bruteForceCycle++;
592294
592336
  const totalTurns = messages2.filter((m2) => m2.role === "assistant").length;
592295
592337
  if (bruteForceCycle > 1 && toolCallCount === prevCycleToolCalls) {
@@ -592353,8 +592395,6 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
592353
592395
  }
592354
592396
  const restartTurnCap = this.options.maxTurns && this.options.maxTurns > 0 ? this.options.maxTurns : Number.MAX_SAFE_INTEGER;
592355
592397
  for (let turn = 0; turn < restartTurnCap; turn++) {
592356
- if (checkTaskTimeout("brute-force turn", turn))
592357
- break;
592358
592398
  if (this._completionIncompleteVerification)
592359
592399
  break;
592360
592400
  this._maybeApplyThinkGuard();
@@ -592483,10 +592523,8 @@ ${this.options.maxTurns && this.options.maxTurns > 0 ? `You have ${this.options.
592483
592523
  break;
592484
592524
  }
592485
592525
  } else {
592486
- const recovered = await this.retryOnTransient(reqErr, chatRequest, turn, hardDeadlineMs);
592526
+ const recovered = await this.retryOnTransient(reqErr, chatRequest, turn);
592487
592527
  if (!recovered) {
592488
- if (checkTaskTimeout("brute-force backend request", turn))
592489
- break;
592490
592528
  const errMsg2 = reqErr instanceof Error ? reqErr.message : String(reqErr);
592491
592529
  const cause2 = reqErr instanceof Error && reqErr.cause ? ` (${reqErr.cause.message ?? ""} ${reqErr.cause?.code ?? ""})` : "";
592492
592530
  this.emit({
@@ -592963,9 +593001,6 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
592963
593001
  }
592964
593002
  const durationMs = Date.now() - start2;
592965
593003
  const incompleteVerification = this._completionIncompleteVerification;
592966
- if (timedOut && !summary) {
592967
- summary = timeoutSummary || `Incomplete: task timed out after ${taskTimeoutMs}ms.`;
592968
- }
592969
593004
  if (incompleteVerification && !summary) {
592970
593005
  summary = incompleteVerification.summary;
592971
593006
  }
@@ -594512,10 +594547,11 @@ ${marker}` : marker);
594512
594547
  return null;
594513
594548
  if (process.env["OMNIUS_ALLOW_STALE_REPAIR_OVERWRITE"] === "1")
594514
594549
  return null;
594515
- if (this.options.modelTier !== "small" && this.options.modelTier !== "medium")
594516
- return null;
594517
594550
  if (args?.["dry_run"] === true || args?.["dryRun"] === true)
594518
594551
  return null;
594552
+ const tier = this.options.modelTier ?? "large";
594553
+ if (tier !== "small" && tier !== "medium")
594554
+ return null;
594519
594555
  const path12 = this.extractPrimaryToolPath(args);
594520
594556
  if (!path12)
594521
594557
  return null;
@@ -594529,7 +594565,7 @@ ${marker}` : marker);
594529
594565
  return null;
594530
594566
  return [
594531
594567
  `[EDIT REPAIR LOCK] A recent narrow edit to ${active.path} failed because the model-visible target diverged from disk (${active.errorKind}; latest_file_hash=${active.latestFileHash || "unknown"}).`,
594532
- `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration on ${this.options.modelTier ?? "unknown"} tier models.`,
594568
+ `This full-file overwrite was NOT executed. A stale narrow edit must not be repaired by broad file regeneration; preserve a constrained edit path until fresh target evidence is used.`,
594533
594569
  ``,
594534
594570
  `Allowed next actions:`,
594535
594571
  `1. file_read ${active.path} once and construct file_edit from exact current text.`,
@@ -597851,6 +597887,8 @@ ${result}`
597851
597887
  return true;
597852
597888
  if (/stream timeout|no response or chunk within|no response within \d+\s*s|stream stalled/i.test(msg))
597853
597889
  return true;
597890
+ if (/AbortError|operation was aborted|aborted due to timeout|signal timed out|timeout.*aborted/i.test(msg))
597891
+ return true;
597854
597892
  if (/received HTML error page/i.test(msg))
597855
597893
  return true;
597856
597894
  if (/model is loading|server busy|overloaded/i.test(msg))
@@ -598131,11 +598169,13 @@ ${description}`
598131
598169
  * until recovery; other transient backend errors use bounded backoff.
598132
598170
  * Returns the response on success, or null if recovery did not apply.
598133
598171
  */
598134
- async retryOnTransient(initialErr, chatRequest, turn, hardDeadlineMs) {
598172
+ async retryOnTransient(initialErr, chatRequest, turn) {
598173
+ if (this.aborted)
598174
+ return null;
598135
598175
  if (!this.isTransientError(initialErr))
598136
598176
  return null;
598137
598177
  const errMsg = flattenErrorText(initialErr);
598138
- const isNetworkError2 = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|UND_ERR|other side closed|stream timeout|no response or chunk within|no response within \d+\s*s|stream stalled/i.test(errMsg);
598178
+ const isNetworkError2 = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|socket hang up|UND_ERR|other side closed|stream timeout|no response or chunk within|no response within \d+\s*s|stream stalled|AbortError|operation was aborted|aborted due to timeout|signal timed out|timeout.*aborted/i.test(errMsg);
598139
598179
  const isAuthError = this.isRecoverableAuthError(initialErr);
598140
598180
  const isGpuSlotUnavailable = this.isGpuSlotUnavailableError(initialErr);
598141
598181
  const maxRetries = isNetworkError2 || isGpuSlotUnavailable || isAuthError ? Infinity : 3;
@@ -598146,15 +598186,6 @@ ${description}`
598146
598186
  while (attempt <= (maxRetries === Infinity ? Number.MAX_SAFE_INTEGER : maxRetries)) {
598147
598187
  if (this.aborted)
598148
598188
  return null;
598149
- if (Number.isFinite(hardDeadlineMs) && Date.now() >= hardDeadlineMs) {
598150
- this.emit({
598151
- type: "error",
598152
- content: "Task timeout reached during backend retry",
598153
- turn,
598154
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
598155
- });
598156
- return null;
598157
- }
598158
598189
  if (this.isPaymentRequiredError(initialErr) && typeof backend.rotateKey === "function") {
598159
598190
  const rotated = backend.rotateKey();
598160
598191
  if (rotated) {
@@ -598204,7 +598235,7 @@ ${description}`
598204
598235
  }
598205
598236
  }
598206
598237
  const delay4 = isGpuSlotUnavailable ? baseDelayMs : Math.min(baseDelayMs * Math.pow(2, attempt - 1), maxDelayMs);
598207
- const effectiveDelay = Number.isFinite(hardDeadlineMs) ? Math.max(0, Math.min(delay4, hardDeadlineMs - Date.now())) : delay4;
598238
+ const effectiveDelay = delay4;
598208
598239
  const attemptLabel = maxRetries === Infinity ? `${attempt}` : `${attempt}/${maxRetries}`;
598209
598240
  if (isGpuSlotUnavailable) {
598210
598241
  this.emit({
@@ -598222,15 +598253,6 @@ ${description}`
598222
598253
  await new Promise((r2) => setTimeout(r2, effectiveDelay));
598223
598254
  if (this.aborted)
598224
598255
  return null;
598225
- if (Number.isFinite(hardDeadlineMs) && Date.now() >= hardDeadlineMs) {
598226
- this.emit({
598227
- type: "error",
598228
- content: "Task timeout reached before backend retry could resume",
598229
- turn,
598230
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
598231
- });
598232
- return null;
598233
- }
598234
598256
  try {
598235
598257
  this._recordContextWindowDump("agent_turn_transient_retry", chatRequest, turn, attempt);
598236
598258
  const response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
@@ -728316,8 +728338,9 @@ function adoptHandoffRuns() {
728316
728338
  } catch {
728317
728339
  }
728318
728340
  }
728319
- if (r2.deadlineAtMs && r2.deadlineAtMs > 0 && process.env["OMNIUS_DISABLE_DAEMON_TIMEOUT_KILL"] !== "1") {
728320
- const remainingMs = r2.deadlineAtMs - Date.now();
728341
+ const adoptedDeadlineAtMs = typeof r2.deadlineAtMs === "number" && r2.deadlineAtMs > 0 ? r2.deadlineAtMs : 0;
728342
+ if (false) {
728343
+ const remainingMs = adoptedDeadlineAtMs - Date.now();
728321
728344
  const adoptedPid = r2.pid;
728322
728345
  const adoptedJobId = r2.jobId;
728323
728346
  const fireTimeout = () => {
@@ -728803,13 +728826,13 @@ function handleHelp(req3, res) {
728803
728826
  enable: "POST /v1/chat/completions with body {agent_loop: true} runs an N-turn server-side loop. Daemon executes any tool_calls matching daemon-resident tools and re-prompts; client-side tool_calls cause the loop to yield back so caller can execute them.",
728804
728827
  merge_daemon_tools: "Body field include_daemon_tools: ['read'] (or ['read','run']) merges the daemon's matching tools into the offered tools[] array automatically — no need to hand-list web_search/web_fetch/file_read/etc.",
728805
728828
  max_turns: "Body field max_turns (default 8, max 64).",
728806
- timeout: "Body field timeout_s caps the whole loop (default 30 min, max 1 hour). Per-backend-call timeout is separate (see OMNIUS_BACKEND_TIMEOUT_S).",
728829
+ timeout: "Body field timeout_s is treated as a backend/request liveness hint only; it must not kill an active agent loop.",
728807
728830
  prompt_template: "Body field prompt_template: 'factual-first' prepends a system message instructing the model to call web_search FIRST for any factual question.",
728808
728831
  response_envelope: "Standard OpenAI chat.completion shape PLUS a _agent_loop: {turns, log:[], done, reason} field. Reason is one of: model_returned_content, client_tools_pending, max_turns_exhausted."
728809
728832
  },
728810
728833
  backend_timeout: {
728811
728834
  env: "OMNIUS_BACKEND_TIMEOUT_S — default 120 seconds, max 3600 (1 hour).",
728812
- per_request: "Body field timeout_s on /v1/chat/completions, /v1/run, agent_loop. Caps to 1h.",
728835
+ per_request: "Body field timeout_s on /v1/chat/completions, /v1/run, agent_loop is request/backend liveness only, not a task deadline.",
728813
728836
  rationale: "Q1 (Cody/SA) — was hardcoded 120s, broke cold-start tool-calling thinks on large models."
728814
728837
  },
728815
728838
  run_lifecycle: {
@@ -730111,32 +730134,6 @@ ${task}` : task;
730111
730134
  }
730112
730135
  };
730113
730136
  onChildClose(child, finish);
730114
- const deadline = setTimeout(
730115
- () => {
730116
- if (done) return;
730117
- try {
730118
- if (child.pid) process.kill(-child.pid, "SIGTERM");
730119
- } catch {
730120
- }
730121
- try {
730122
- if (child.pid) process.kill(child.pid, "SIGTERM");
730123
- } catch {
730124
- }
730125
- setTimeout(() => {
730126
- try {
730127
- if (child.pid) process.kill(-child.pid, "SIGKILL");
730128
- } catch {
730129
- }
730130
- try {
730131
- if (child.pid) process.kill(child.pid, "SIGKILL");
730132
- } catch {
730133
- }
730134
- finish();
730135
- }, 3e3).unref();
730136
- },
730137
- (generateTimeoutS + 30) * 1e3
730138
- );
730139
- deadline.unref();
730140
730137
  });
730141
730138
  if (buf.trim()) finalLines.push(buf);
730142
730139
  const rawFinal = finalLines.join("\n").trim();
@@ -730203,33 +730200,6 @@ ${task}` : task;
730203
730200
  }
730204
730201
  };
730205
730202
  onChildClose(child, finish);
730206
- const deadline = setTimeout(
730207
- () => {
730208
- if (done) return;
730209
- killedByDeadline = true;
730210
- try {
730211
- if (child.pid) process.kill(-child.pid, "SIGTERM");
730212
- } catch {
730213
- }
730214
- try {
730215
- if (child.pid) process.kill(child.pid, "SIGTERM");
730216
- } catch {
730217
- }
730218
- setTimeout(() => {
730219
- try {
730220
- if (child.pid) process.kill(-child.pid, "SIGKILL");
730221
- } catch {
730222
- }
730223
- try {
730224
- if (child.pid) process.kill(child.pid, "SIGKILL");
730225
- } catch {
730226
- }
730227
- finish();
730228
- }, 3e3).unref();
730229
- },
730230
- (generateTimeoutS + 30) * 1e3
730231
- );
730232
- deadline.unref();
730233
730203
  });
730234
730204
  if (nonStreamBuf.trim()) nonStreamLines.push(nonStreamBuf);
730235
730205
  const rawNonStream = nonStreamLines.join("\n").trim();
@@ -730253,7 +730223,7 @@ ${task}` : task;
730253
730223
  } catch {
730254
730224
  }
730255
730225
  if (!content) {
730256
- const errMsg = killedByDeadline ? `Agent exceeded ${generateTimeoutS}s timeout and was killed.` : backendError ? `Backend error: ${backendError}` : "Agent produced no response.";
730226
+ const errMsg = backendError ? `Backend error: ${backendError}` : "Agent produced no response.";
730257
730227
  jsonResponse(res, 200, {
730258
730228
  model: model.replace(/^[a-z]+\//, ""),
730259
730229
  created_at: createdAt,
@@ -730842,9 +730812,7 @@ async function handleV1Run(req3, res) {
730842
730812
  } catch {
730843
730813
  }
730844
730814
  let _rca1DeadlineFired = false;
730845
- const _rca1KillSwitch = process.env["OMNIUS_DISABLE_DAEMON_TIMEOUT_KILL"] === "1";
730846
- const _rca1EffectiveTimeoutS = timeout2 && timeout2 > 0 ? timeout2 : activeProfile?.limits?.timeout_s && activeProfile.limits.timeout_s > 0 ? activeProfile.limits.timeout_s : 1800;
730847
- const _rca1DeadlineAtMs = Date.now() + (_rca1EffectiveTimeoutS + 60) * 1e3;
730815
+ const _rca1Deadline = null;
730848
730816
  if (job.pid > 0) {
730849
730817
  const runCtx = getOmniusRunContext();
730850
730818
  registerProcessLease({
@@ -730859,50 +730827,9 @@ async function handleV1Run(req3, res) {
730859
730827
  reason: `API run: ${task.slice(0, 240)}`,
730860
730828
  command: sandbox === "container" ? `container:${`omnius-${id2}`}` : [process.execPath, omniusBin, ...args].join(" "),
730861
730829
  cwd: cwd4,
730862
- hardDeadlineAt: _rca1DeadlineAtMs
730830
+ hardDeadlineAt: void 0
730863
730831
  });
730864
730832
  }
730865
- if (!_rca1KillSwitch) {
730866
- job.deadlineAtMs = _rca1DeadlineAtMs;
730867
- atomicJobWrite(dir, id2, job);
730868
- }
730869
- const _rca1Deadline = _rca1KillSwitch ? null : setTimeout(
730870
- () => {
730871
- if (job.status !== "running") return;
730872
- _rca1DeadlineFired = true;
730873
- job.status = "timeout";
730874
- job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
730875
- atomicJobWrite(dir, id2, job);
730876
- try {
730877
- if (child.pid) process.kill(-child.pid, "SIGTERM");
730878
- } catch {
730879
- }
730880
- try {
730881
- if (child.pid) process.kill(child.pid, "SIGTERM");
730882
- } catch {
730883
- }
730884
- setTimeout(() => {
730885
- try {
730886
- if (child.pid) process.kill(-child.pid, "SIGKILL");
730887
- } catch {
730888
- }
730889
- try {
730890
- if (child.pid) process.kill(child.pid, "SIGKILL");
730891
- } catch {
730892
- }
730893
- }, 3e4).unref();
730894
- try {
730895
- publishEvent(
730896
- "run.timeout",
730897
- { run_id: id2, deadline_s: _rca1EffectiveTimeoutS },
730898
- { subject: authUser, aimsControl: "A.6.2.6" }
730899
- );
730900
- } catch {
730901
- }
730902
- },
730903
- (_rca1EffectiveTimeoutS + 60) * 1e3
730904
- );
730905
- if (_rca1Deadline) _rca1Deadline.unref();
730906
730833
  if (streamMode) {
730907
730834
  res.writeHead(200, {
730908
730835
  "Content-Type": "text/event-stream",
@@ -733988,7 +733915,7 @@ ${historyLines}
733988
733915
  reason: `chat run ${session.id}`,
733989
733916
  command: [process.execPath, omniusBin, ...args].join(" "),
733990
733917
  cwd: cwdPath,
733991
- hardDeadlineAt: Date.now() + chatTimeoutS * 1e3 + 3e4
733918
+ hardDeadlineAt: void 0
733992
733919
  });
733993
733920
  }
733994
733921
  const releaseChatLease = (status2, reason) => {
@@ -734212,7 +734139,6 @@ ${historyLines}
734212
734139
  });
734213
734140
  child.stderr?.on("data", () => {
734214
734141
  });
734215
- const killDeadlineMs = chatTimeoutS * 1e3 + 3e4;
734216
734142
  let killedByDeadline = false;
734217
734143
  await new Promise((resolve77) => {
734218
734144
  let done = false;
@@ -734223,30 +734149,6 @@ ${historyLines}
734223
734149
  }
734224
734150
  };
734225
734151
  onChildClose(child, finish);
734226
- const deadline = setTimeout(() => {
734227
- if (done) return;
734228
- killedByDeadline = true;
734229
- try {
734230
- if (child.pid) process.kill(-child.pid, "SIGTERM");
734231
- } catch {
734232
- }
734233
- try {
734234
- if (child.pid) process.kill(child.pid, "SIGTERM");
734235
- } catch {
734236
- }
734237
- setTimeout(() => {
734238
- try {
734239
- if (child.pid) process.kill(-child.pid, "SIGKILL");
734240
- } catch {
734241
- }
734242
- try {
734243
- if (child.pid) process.kill(child.pid, "SIGKILL");
734244
- } catch {
734245
- }
734246
- finish();
734247
- }, 3e3).unref();
734248
- }, killDeadlineMs);
734249
- deadline.unref();
734250
734152
  });
734251
734153
  if (nonStreamBuf.trim()) nonStreamLines.push(nonStreamBuf);
734252
734154
  const rawNonStream = nonStreamLines.join("\n").trim();
@@ -734288,7 +734190,7 @@ ${historyLines}
734288
734190
  "X-Session-ID, X-Request-ID, X-API-Version, ETag"
734289
734191
  );
734290
734192
  if (!content) {
734291
- const errMsg = killedByDeadline ? `Agent exceeded ${chatTimeoutS}s timeout and was killed. Try a simpler prompt or increase timeout_s in the request body.` : backendError ? `Backend error: ${backendError}` : "Agent produced no response. The model may have failed to load (try a smaller model or check 'ollama ps' for VRAM contention).";
734193
+ const errMsg = backendError ? `Backend error: ${backendError}` : "Agent produced no response. The model may have failed to load (try a smaller model or check 'ollama ps' for VRAM contention).";
734292
734194
  try {
734293
734195
  finishInFlightChat(
734294
734196
  session.id,
@@ -739711,8 +739613,6 @@ Only tools allowed by this profile are visible and executable.`
739711
739613
  maxTokens: realtimeEnabled ? 512 : 16384,
739712
739614
  temperature: realtimeEnabled ? 0.6 : 0,
739713
739615
  requestTimeoutMs: config.timeoutMs,
739714
- taskTimeoutMs: 36e5,
739715
- // 60 minutes — never give up prematurely
739716
739616
  compactionThreshold,
739717
739617
  deepContext: deepContext ?? false,
739718
739618
  dynamicContext,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.468",
3
+ "version": "1.0.469",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.468",
9
+ "version": "1.0.469",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.468",
3
+ "version": "1.0.469",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",