omnius 1.0.232 → 1.0.234

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
@@ -7416,12 +7416,12 @@ Meta: ${metaKeys.map((k) => `${k}="${meta[k]?.slice(0, 80)}"`).join(", ")}`);
7416
7416
  if (!text)
7417
7417
  continue;
7418
7418
  const record = {};
7419
- for (const [field] of Object.entries(schema)) {
7420
- const normalized = field.replace(/_/g, "[_ ]?");
7419
+ for (const [field2] of Object.entries(schema)) {
7420
+ const normalized = field2.replace(/_/g, "[_ ]?");
7421
7421
  const pattern = new RegExp(`${normalized}[:\\s]+([^\\n]+)`, "i");
7422
7422
  const match = text.match(pattern);
7423
7423
  if (match)
7424
- record[field] = match[1]?.trim();
7424
+ record[field2] = match[1]?.trim();
7425
7425
  }
7426
7426
  if (Object.keys(record).length > 0)
7427
7427
  extracted.push(record);
@@ -10194,13 +10194,13 @@ function buildImageMarker(buffer2) {
10194
10194
  return { mimeType, base64: out.toString("base64") };
10195
10195
  }
10196
10196
  function classifyBrowserGate(input) {
10197
- const haystack = `${input.url}
10197
+ const haystack2 = `${input.url}
10198
10198
  ${input.html.slice(0, 8e4)}
10199
10199
  ${input.text.slice(0, 2e4)}`.toLowerCase();
10200
10200
  const contentHaystack = `${input.html.slice(0, 8e4)}
10201
10201
  ${input.text.slice(0, 2e4)}`.toLowerCase();
10202
10202
  const evidence = [];
10203
- const addIf = (kind, confidence2, pattern, label, hay = haystack) => {
10203
+ const addIf = (kind, confidence2, pattern, label, hay = haystack2) => {
10204
10204
  if (!pattern.test(hay))
10205
10205
  return null;
10206
10206
  evidence.push(label);
@@ -10223,7 +10223,7 @@ ${input.text.slice(0, 2e4)}`.toLowerCase();
10223
10223
  evidence: [`HTTP ${statusFailures[0].status} seen for ${statusFailures[0].url}`]
10224
10224
  };
10225
10225
  }
10226
- if (/\b(enable javascript|javascript is disabled|please enable cookies)\b/i.test(haystack)) {
10226
+ if (/\b(enable javascript|javascript is disabled|please enable cookies)\b/i.test(haystack2)) {
10227
10227
  return { kind: "js_render_failed", confidence: 0.72, evidence: ["JavaScript/cookie render warning found"] };
10228
10228
  }
10229
10229
  if (input.errors.length > 0) {
@@ -12042,36 +12042,36 @@ function extractEditPath(args) {
12042
12042
  }
12043
12043
  return null;
12044
12044
  }
12045
- function countOccurrences(haystack, needle) {
12045
+ function countOccurrences(haystack2, needle) {
12046
12046
  let count = 0;
12047
12047
  let pos = 0;
12048
- while ((pos = haystack.indexOf(needle, pos)) !== -1) {
12048
+ while ((pos = haystack2.indexOf(needle, pos)) !== -1) {
12049
12049
  count++;
12050
12050
  pos += needle.length;
12051
12051
  }
12052
12052
  return count;
12053
12053
  }
12054
- function findMatchLines(haystack, needle) {
12054
+ function findMatchLines(haystack2, needle) {
12055
12055
  const lines = [];
12056
12056
  let pos = 0;
12057
- while ((pos = haystack.indexOf(needle, pos)) !== -1) {
12058
- const lineNumber = haystack.slice(0, pos).split("\n").length;
12057
+ while ((pos = haystack2.indexOf(needle, pos)) !== -1) {
12058
+ const lineNumber = haystack2.slice(0, pos).split("\n").length;
12059
12059
  lines.push(lineNumber);
12060
12060
  pos += needle.length;
12061
12061
  }
12062
12062
  return lines;
12063
12063
  }
12064
- function findMatchOffsets(haystack, needle) {
12064
+ function findMatchOffsets(haystack2, needle) {
12065
12065
  const offsets = [];
12066
12066
  let pos = 0;
12067
- while ((pos = haystack.indexOf(needle, pos)) !== -1) {
12067
+ while ((pos = haystack2.indexOf(needle, pos)) !== -1) {
12068
12068
  offsets.push(pos);
12069
12069
  pos += needle.length;
12070
12070
  }
12071
12071
  return offsets;
12072
12072
  }
12073
- function replaceAllOccurrences(haystack, needle, replacement) {
12074
- return haystack.split(needle).join(replacement);
12073
+ function replaceAllOccurrences(haystack2, needle, replacement) {
12074
+ return haystack2.split(needle).join(replacement);
12075
12075
  }
12076
12076
  var FileEditTool;
12077
12077
  var init_file_edit = __esm({
@@ -13280,12 +13280,12 @@ function extractSearchTerms(query) {
13280
13280
  return terms2;
13281
13281
  }
13282
13282
  function lexicalHitScore(text, terms2) {
13283
- const haystack = text.toLowerCase();
13283
+ const haystack2 = text.toLowerCase();
13284
13284
  if (terms2.length === 0)
13285
13285
  return 0;
13286
13286
  let hits = 0;
13287
13287
  for (const term of terms2) {
13288
- if (haystack.includes(term))
13288
+ if (haystack2.includes(term))
13289
13289
  hits++;
13290
13290
  }
13291
13291
  return clamp012(hits / terms2.length);
@@ -22250,8 +22250,8 @@ function isConsolidated(item) {
22250
22250
  const metadataConsolidated = item.metadata?.["consolidated"] ?? item.metadata?.["isConsolidated"];
22251
22251
  if (typeof metadataConsolidated === "boolean")
22252
22252
  return metadataConsolidated;
22253
- const haystack = `${item.kind} ${item.source} ${String(item.metadata?.["stage"] ?? "")}`.toLowerCase();
22254
- return /\b(gist|summary|semantic|memory|reflection|self_model|social_state|compressed|context_frame|anchor)\b/.test(haystack);
22253
+ const haystack2 = `${item.kind} ${item.source} ${String(item.metadata?.["stage"] ?? "")}`.toLowerCase();
22254
+ return /\b(gist|summary|semantic|memory|reflection|self_model|social_state|compressed|context_frame|anchor)\b/.test(haystack2);
22255
22255
  }
22256
22256
  function addBucket(buckets, key, tokens, consolidated) {
22257
22257
  const k = key || "unknown";
@@ -23971,13 +23971,13 @@ function searchFile(repoRoot, fullPath, query, snippetChars) {
23971
23971
  } catch {
23972
23972
  return null;
23973
23973
  }
23974
- const haystack = flattenSessionContent(raw);
23975
- const lowerHaystack = haystack.toLowerCase();
23974
+ const haystack2 = flattenSessionContent(raw);
23975
+ const lowerHaystack = haystack2.toLowerCase();
23976
23976
  const lowerQuery = query.toLowerCase();
23977
23977
  const positions = allIndexesOf(lowerHaystack, lowerQuery);
23978
23978
  if (positions.length === 0)
23979
23979
  return null;
23980
- const snippets = positions.slice(0, 3).map((pos) => buildSnippet(haystack, pos, query.length, snippetChars));
23980
+ const snippets = positions.slice(0, 3).map((pos) => buildSnippet(haystack2, pos, query.length, snippetChars));
23981
23981
  const stat8 = statSync8(fullPath);
23982
23982
  return {
23983
23983
  file: relative2(repoRoot, fullPath),
@@ -25086,19 +25086,19 @@ var init_aiwg_workflow = __esm({
25086
25086
  // packages/execution/dist/tools/batch-edit.js
25087
25087
  import { readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
25088
25088
  import { resolve as resolve16 } from "node:path";
25089
- function findMatchOffsetsBatch(haystack, needle) {
25089
+ function findMatchOffsetsBatch(haystack2, needle) {
25090
25090
  const offsets = [];
25091
25091
  let pos = 0;
25092
- while ((pos = haystack.indexOf(needle, pos)) !== -1) {
25092
+ while ((pos = haystack2.indexOf(needle, pos)) !== -1) {
25093
25093
  offsets.push(pos);
25094
25094
  pos += needle.length;
25095
25095
  }
25096
25096
  return offsets;
25097
25097
  }
25098
- function countOccurrences2(haystack, needle) {
25098
+ function countOccurrences2(haystack2, needle) {
25099
25099
  let count = 0;
25100
25100
  let pos = 0;
25101
- while ((pos = haystack.indexOf(needle, pos)) !== -1) {
25101
+ while ((pos = haystack2.indexOf(needle, pos)) !== -1) {
25102
25102
  count++;
25103
25103
  pos += needle.length;
25104
25104
  }
@@ -47679,7 +47679,7 @@ function FpSqrt(P2) {
47679
47679
  return sqrt9mod16(P2);
47680
47680
  return tonelliShanks(P2);
47681
47681
  }
47682
- function validateField(field) {
47682
+ function validateField(field2) {
47683
47683
  const initial = {
47684
47684
  ORDER: "bigint",
47685
47685
  BYTES: "number",
@@ -47689,8 +47689,8 @@ function validateField(field) {
47689
47689
  map2[val] = "function";
47690
47690
  return map2;
47691
47691
  }, initial);
47692
- validateObject(field, opts);
47693
- return field;
47692
+ validateObject(field2, opts);
47693
+ return field2;
47694
47694
  }
47695
47695
  function FpPow(Fp, num2, power) {
47696
47696
  if (power < _0n2)
@@ -47998,12 +47998,12 @@ function mulEndoUnsafe(Point, point, k1, k2) {
47998
47998
  }
47999
47999
  return { p1, p2 };
48000
48000
  }
48001
- function createField(order, field, isLE2) {
48002
- if (field) {
48003
- if (field.ORDER !== order)
48001
+ function createField(order, field2, isLE2) {
48002
+ if (field2) {
48003
+ if (field2.ORDER !== order)
48004
48004
  throw new Error("Field.ORDER must match order: Fp == p, Fn == n");
48005
- validateField(field);
48006
- return field;
48005
+ validateField(field2);
48006
+ return field2;
48007
48007
  } else {
48008
48008
  return Field(order, { isLE: isLE2 });
48009
48009
  }
@@ -95916,12 +95916,12 @@ var require_x509_cjs = __commonJS({
95916
95916
  const res = super.toTextObjectEmpty();
95917
95917
  for (const name10 of this.items) {
95918
95918
  const nameObj = name10.toTextObject();
95919
- let field = res[nameObj[TextObject.NAME]];
95920
- if (!Array.isArray(field)) {
95921
- field = [];
95922
- res[nameObj[TextObject.NAME]] = field;
95919
+ let field2 = res[nameObj[TextObject.NAME]];
95920
+ if (!Array.isArray(field2)) {
95921
+ field2 = [];
95922
+ res[nameObj[TextObject.NAME]] = field2;
95923
95923
  }
95924
- field.push(nameObj);
95924
+ field2.push(nameObj);
95925
95925
  }
95926
95926
  return res;
95927
95927
  }
@@ -96578,12 +96578,12 @@ var require_x509_cjs = __commonJS({
96578
96578
  urls.forEach((name10, index) => {
96579
96579
  const nameObj = name10.toTextObject();
96580
96580
  const indexedKey = `${nameObj[TextObject.NAME]} ${index + 1}`;
96581
- let field = names2[indexedKey];
96582
- if (!Array.isArray(field)) {
96583
- field = [];
96584
- names2[indexedKey] = field;
96581
+ let field2 = names2[indexedKey];
96582
+ if (!Array.isArray(field2)) {
96583
+ field2 = [];
96584
+ names2[indexedKey] = field2;
96585
96585
  }
96586
- field.push(nameObj);
96586
+ field2.push(nameObj);
96587
96587
  });
96588
96588
  obj[key] = names2;
96589
96589
  }
@@ -98300,8 +98300,8 @@ var require_crypto = __commonJS({
98300
98300
  notAfter: cert.notAfter
98301
98301
  };
98302
98302
  };
98303
- function getCsrAsn1CharStringType(field) {
98304
- switch (field) {
98303
+ function getCsrAsn1CharStringType(field2) {
98304
+ switch (field2) {
98305
98305
  case "C":
98306
98306
  return "printableString";
98307
98307
  case "E":
@@ -109178,7 +109178,7 @@ var require_form_data = __commonJS({
109178
109178
  util2.inherits(FormData2, CombinedStream);
109179
109179
  FormData2.LINE_BREAK = "\r\n";
109180
109180
  FormData2.DEFAULT_CONTENT_TYPE = "application/octet-stream";
109181
- FormData2.prototype.append = function(field, value2, options2) {
109181
+ FormData2.prototype.append = function(field2, value2, options2) {
109182
109182
  options2 = options2 || {};
109183
109183
  if (typeof options2 === "string") {
109184
109184
  options2 = { filename: options2 };
@@ -109191,7 +109191,7 @@ var require_form_data = __commonJS({
109191
109191
  this._error(new Error("Arrays are not supported."));
109192
109192
  return;
109193
109193
  }
109194
- var header = this._multiPartHeader(field, value2, options2);
109194
+ var header = this._multiPartHeader(field2, value2, options2);
109195
109195
  var footer = this._multiPartFooter();
109196
109196
  append(header);
109197
109197
  append(value2);
@@ -109242,7 +109242,7 @@ var require_form_data = __commonJS({
109242
109242
  callback("Unknown stream");
109243
109243
  }
109244
109244
  };
109245
- FormData2.prototype._multiPartHeader = function(field, value2, options2) {
109245
+ FormData2.prototype._multiPartHeader = function(field2, value2, options2) {
109246
109246
  if (typeof options2.header === "string") {
109247
109247
  return options2.header;
109248
109248
  }
@@ -109251,7 +109251,7 @@ var require_form_data = __commonJS({
109251
109251
  var contents = "";
109252
109252
  var headers = {
109253
109253
  // add custom disposition as third element or keep it two elements if not
109254
- "Content-Disposition": ["form-data", 'name="' + field + '"'].concat(contentDisposition || []),
109254
+ "Content-Disposition": ["form-data", 'name="' + field2 + '"'].concat(contentDisposition || []),
109255
109255
  // if no content type. allow it to be empty array
109256
109256
  "Content-Type": [].concat(contentType || [])
109257
109257
  };
@@ -114124,10 +114124,10 @@ var require_http = __commonJS({
114124
114124
  * @param {string} field Meta field name
114125
114125
  * @returns {Promise<string|null>} Meta field value
114126
114126
  */
114127
- async getMetaField(field) {
114127
+ async getMetaField(field2) {
114128
114128
  const dir = await this.getDirectory();
114129
- if ("meta" in dir && field in dir.meta) {
114130
- return dir.meta[field];
114129
+ if ("meta" in dir && field2 in dir.meta) {
114130
+ return dir.meta[field2];
114131
114131
  }
114132
114132
  return null;
114133
114133
  }
@@ -161578,41 +161578,41 @@ var require_eventsource_stream = __commonJS({
161578
161578
  if (colonPosition === 0) {
161579
161579
  return;
161580
161580
  }
161581
- let field = "";
161581
+ let field2 = "";
161582
161582
  let value2 = "";
161583
161583
  if (colonPosition !== -1) {
161584
- field = line.subarray(0, colonPosition).toString("utf8");
161584
+ field2 = line.subarray(0, colonPosition).toString("utf8");
161585
161585
  let valueStart = colonPosition + 1;
161586
161586
  if (line[valueStart] === SPACE) {
161587
161587
  ++valueStart;
161588
161588
  }
161589
161589
  value2 = line.subarray(valueStart).toString("utf8");
161590
161590
  } else {
161591
- field = line.toString("utf8");
161591
+ field2 = line.toString("utf8");
161592
161592
  value2 = "";
161593
161593
  }
161594
- switch (field) {
161594
+ switch (field2) {
161595
161595
  case "data":
161596
- if (event[field] === void 0) {
161597
- event[field] = value2;
161596
+ if (event[field2] === void 0) {
161597
+ event[field2] = value2;
161598
161598
  } else {
161599
- event[field] += `
161599
+ event[field2] += `
161600
161600
  ${value2}`;
161601
161601
  }
161602
161602
  break;
161603
161603
  case "retry":
161604
161604
  if (isASCIINumber(value2)) {
161605
- event[field] = value2;
161605
+ event[field2] = value2;
161606
161606
  }
161607
161607
  break;
161608
161608
  case "id":
161609
161609
  if (isValidLastEventId(value2)) {
161610
- event[field] = value2;
161610
+ event[field2] = value2;
161611
161611
  }
161612
161612
  break;
161613
161613
  case "event":
161614
161614
  if (value2.length > 0) {
161615
- event[field] = value2;
161615
+ event[field2] = value2;
161616
161616
  }
161617
161617
  break;
161618
161618
  }
@@ -252716,13 +252716,13 @@ var init_RTCIceCandidate = __esm({
252716
252716
  __privateSet4(this, _relatedAddress, null);
252717
252717
  __privateSet4(this, _relatedPort, null);
252718
252718
  for (let i2 = 8; i2 < fields.length; i2++) {
252719
- const field = fields[i2];
252720
- if (field === "raddr") {
252719
+ const field2 = fields[i2];
252720
+ if (field2 === "raddr") {
252721
252721
  __privateSet4(this, _relatedAddress, fields[i2 + 1]);
252722
- } else if (field === "rport") {
252722
+ } else if (field2 === "rport") {
252723
252723
  __privateSet4(this, _relatedPort, parseInt(fields[i2 + 1], 10));
252724
252724
  }
252725
- if (__privateGet4(this, _protocol2) === "tcp" && field === "tcptype") {
252725
+ if (__privateGet4(this, _protocol2) === "tcp" && field2 === "tcptype") {
252726
252726
  __privateSet4(this, _tcpType, fields[i2 + 1]);
252727
252727
  }
252728
252728
  }
@@ -271686,21 +271686,21 @@ Homeostasis: uncertainty=${h.uncertainty.toFixed(2)} coherence=${h.coherence.toF
271686
271686
  // ── Propose Update ───────────────────────────────────────────────────────
271687
271687
  async proposeUpdate(args, start2) {
271688
271688
  const changeType = String(args.change_type ?? "new_fact");
271689
- const field = String(args.field ?? "");
271689
+ const field2 = String(args.field ?? "");
271690
271690
  const value2 = String(args.value ?? "");
271691
271691
  const justification = String(args.justification ?? "");
271692
- if (!field || !value2) {
271692
+ if (!field2 || !value2) {
271693
271693
  return { success: false, output: "field and value required", durationMs: performance.now() - start2 };
271694
271694
  }
271695
271695
  if (this.reflectionGate) {
271696
271696
  try {
271697
- const proposal = `${changeType}: ${field} = ${value2}. Justification: ${justification}`;
271698
- const verdict = await this.reflectionGate(proposal, `Identity update to ${field}`);
271697
+ const proposal = `${changeType}: ${field2} = ${value2}. Justification: ${justification}`;
271698
+ const verdict = await this.reflectionGate(proposal, `Identity update to ${field2}`);
271699
271699
  if (verdict.status === "block") {
271700
271700
  return {
271701
271701
  success: false,
271702
271702
  output: `Identity update BLOCKED by reflection gate:
271703
- Proposal: ${changeType} on ${field}
271703
+ Proposal: ${changeType} on ${field2}
271704
271704
  Findings: ${verdict.findings.join("; ")}
271705
271705
  The reflection layer vetoed this self-update per COHERE invariant.`,
271706
271706
  durationMs: performance.now() - start2
@@ -271713,7 +271713,7 @@ Homeostasis: uncertainty=${h.uncertainty.toFixed(2)} coherence=${h.coherence.toF
271713
271713
  await this.hydrate(start2);
271714
271714
  const oldVersion = this.selfState.version;
271715
271715
  this.selfState.version++;
271716
- switch (field) {
271716
+ switch (field2) {
271717
271717
  case "narrative_summary":
271718
271718
  this.selfState.narrative_summary = value2;
271719
271719
  break;
@@ -271749,11 +271749,11 @@ Homeostasis: uncertainty=${h.uncertainty.toFixed(2)} coherence=${h.coherence.toF
271749
271749
  }
271750
271750
  break;
271751
271751
  default:
271752
- return { success: false, output: `Unknown field: ${field}`, durationMs: performance.now() - start2 };
271752
+ return { success: false, output: `Unknown field: ${field2}`, durationMs: performance.now() - start2 };
271753
271753
  }
271754
271754
  this.selfState.version_history.push({
271755
271755
  version: this.selfState.version,
271756
- change: `${changeType}: ${field} = ${value2.slice(0, 100)} — ${justification.slice(0, 100)}`,
271756
+ change: `${changeType}: ${field2} = ${value2.slice(0, 100)} — ${justification.slice(0, 100)}`,
271757
271757
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
271758
271758
  });
271759
271759
  if (this.selfState.version_history.length > 50) {
@@ -271766,7 +271766,7 @@ Homeostasis: uncertainty=${h.uncertainty.toFixed(2)} coherence=${h.coherence.toF
271766
271766
  return {
271767
271767
  success: true,
271768
271768
  output: `Identity updated: v${oldVersion} → v${this.selfState.version}
271769
- Change: ${changeType} on ${field}
271769
+ Change: ${changeType} on ${field2}
271770
271770
  Justification: ${justification || "(none provided)"}`,
271771
271771
  durationMs: performance.now() - start2
271772
271772
  };
@@ -298725,8 +298725,8 @@ ${lanes.join("\n")}
298725
298725
  if (other === void 0) return 1;
298726
298726
  return compareValues(this.major, other.major) || compareValues(this.minor, other.minor) || compareValues(this.patch, other.patch) || comparePrereleaseIdentifiers(this.prerelease, other.prerelease);
298727
298727
  }
298728
- increment(field) {
298729
- switch (field) {
298728
+ increment(field2) {
298729
+ switch (field2) {
298730
298730
  case "major":
298731
298731
  return new _Version2(this.major + 1, 0, 0);
298732
298732
  case "minor":
@@ -298734,7 +298734,7 @@ ${lanes.join("\n")}
298734
298734
  case "patch":
298735
298735
  return new _Version2(this.major, this.minor, this.patch + 1);
298736
298736
  default:
298737
- return Debug.assertNever(field);
298737
+ return Debug.assertNever(field2);
298738
298738
  }
298739
298739
  }
298740
298740
  with(fields) {
@@ -347877,8 +347877,8 @@ ${lanes.join("\n")}
347877
347877
  var runtimeDependencyFields = ["dependencies", "peerDependencies", "optionalDependencies"];
347878
347878
  function getAllRuntimeDependencies(packageJson) {
347879
347879
  let result;
347880
- for (const field of runtimeDependencyFields) {
347881
- const deps = packageJson[field];
347880
+ for (const field2 of runtimeDependencyFields) {
347881
+ const deps = packageJson[field2];
347882
347882
  if (deps && typeof deps === "object") {
347883
347883
  result = concatenate(result, getOwnKeys(deps));
347884
347884
  }
@@ -446102,13 +446102,13 @@ ${lanes.join("\n")}
446102
446102
  }
446103
446103
  return !isStringANonContextualKeyword(res) ? res || "_" : `_${res}`;
446104
446104
  }
446105
- function stringContainsAt(haystack, needle, startIndex) {
446105
+ function stringContainsAt(haystack2, needle, startIndex) {
446106
446106
  const needleLength = needle.length;
446107
- if (needleLength + startIndex > haystack.length) {
446107
+ if (needleLength + startIndex > haystack2.length) {
446108
446108
  return false;
446109
446109
  }
446110
446110
  for (let i2 = 0; i2 < needleLength; i2++) {
446111
- if (needle.charCodeAt(i2) !== haystack.charCodeAt(i2 + startIndex)) return false;
446111
+ if (needle.charCodeAt(i2) !== haystack2.charCodeAt(i2 + startIndex)) return false;
446112
446112
  }
446113
446113
  return true;
446114
446114
  }
@@ -536919,37 +536919,35 @@ function findOrphans() {
536919
536919
  const isHot = parseFloat(cpu) > 10 ? " ⚠ HIGH CPU" : "";
536920
536920
  lines.push(` ${String(pid).padStart(7)} ${String(ppid).padStart(7)} ${String(cpu).padStart(6)} ${String(mem).padStart(5)} ${String(elapsed).padStart(9)} ${shortCmd}${isHot}`);
536921
536921
  }
536922
- lines.push(`
536923
- To kill a process: process_health(action='kill', pid=PID)`);
536924
- lines.push(`Or from the prompt: /destroy processes --global`);
536922
+ lines.push("\nThese are untracked diagnostics only. They are not killed automatically.");
536923
+ lines.push("To stop a process safely, it must have an active verified Omnius process lease.");
536924
+ lines.push("Use /destroy processes --global to sweep registered stale leases and report untracked matches.");
536925
536925
  return lines.join("\n");
536926
536926
  } catch {
536927
536927
  return "Could not scan for orphan processes.";
536928
536928
  }
536929
536929
  }
536930
- function killProcess2(pid) {
536931
- try {
536932
- try {
536933
- process.kill(-pid, "SIGTERM");
536934
- } catch {
536935
- }
536936
- process.kill(pid, "SIGTERM");
536937
- try {
536938
- execSync28(`sleep 1 && kill -0 ${pid} 2>/dev/null && kill -9 ${pid} 2>/dev/null`, {
536939
- timeout: 3e3,
536940
- stdio: "pipe"
536941
- });
536942
- } catch {
536943
- }
536944
- return `Killed PID ${pid} (SIGTERM → SIGKILL)`;
536945
- } catch (err) {
536946
- return `Failed to kill PID ${pid}: ${err instanceof Error ? err.message : String(err)}`;
536930
+ async function stopRegisteredLeaseByPid(pid) {
536931
+ const lease = listProcessLeases({ includeInactive: false }).find((candidate) => candidate.pid === pid && candidate.status === "active");
536932
+ if (!lease) {
536933
+ return `Refusing to kill PID ${pid}: no active Omnius process lease verifies ownership. Treat it as untracked_omnius_like diagnostics only and stop it manually if needed.`;
536934
+ }
536935
+ const action = await stopProcessLease(lease.leaseId, {
536936
+ reason: "process_health explicit stop"
536937
+ });
536938
+ if (action.action === "killed") {
536939
+ return `Stopped registered Omnius lease ${lease.leaseId} for PID ${pid}: ${action.reason}`;
536940
+ }
536941
+ if (action.action === "suspect_unverified") {
536942
+ return `Refusing to kill PID ${pid}: lease ${lease.leaseId} could not verify current PID identity.`;
536947
536943
  }
536944
+ return `PID ${pid} was not killed; lease ${lease.leaseId} action=${action.action}: ${action.reason}`;
536948
536945
  }
536949
536946
  var OMNIUS_PATTERNS, ProcessHealthTool;
536950
536947
  var init_process_health = __esm({
536951
536948
  "packages/execution/dist/tools/process-health.js"() {
536952
536949
  "use strict";
536950
+ init_process_lifecycle();
536953
536951
  OMNIUS_PATTERNS = [
536954
536952
  "omnius",
536955
536953
  "nexus-daemon",
@@ -536966,7 +536964,7 @@ var init_process_health = __esm({
536966
536964
  ].join("|");
536967
536965
  ProcessHealthTool = class {
536968
536966
  name = "process_health";
536969
- description = "Check system CPU/memory load and find orphaned processes. Actions: 'status' (CPU + memory + top processes), 'orphans' (find stale Omnius-related processes), 'kill' (kill a specific PID). Use this when the system feels slow or when a shell command seems stuck.";
536967
+ description = "Check system CPU/memory load and find orphaned processes. Actions: 'status' (CPU + memory + top processes), 'orphans' (find stale Omnius-related processes), 'kill' (stop a registered Omnius process lease by PID). Use this when the system feels slow or when a shell command seems stuck.";
536970
536968
  parameters = {
536971
536969
  type: "object",
536972
536970
  properties: {
@@ -536977,7 +536975,7 @@ var init_process_health = __esm({
536977
536975
  },
536978
536976
  pid: {
536979
536977
  type: "number",
536980
- description: "Process ID to kill (for 'kill' action)"
536978
+ description: "Process ID to stop, only when it has a verified active Omnius process lease"
536981
536979
  }
536982
536980
  },
536983
536981
  required: []
@@ -536998,7 +536996,7 @@ var init_process_health = __esm({
536998
536996
  if (pid === process.pid || pid === process.ppid) {
536999
536997
  return { success: false, output: "", error: "Cannot kill self or parent process", durationMs: performance.now() - start2 };
537000
536998
  }
537001
- return { success: true, output: killProcess2(pid), durationMs: performance.now() - start2 };
536999
+ return { success: true, output: await stopRegisteredLeaseByPid(pid), durationMs: performance.now() - start2 };
537002
537000
  }
537003
537001
  default:
537004
537002
  return { success: false, output: "", error: `Unknown action: ${action}`, durationMs: performance.now() - start2 };
@@ -555110,7 +555108,7 @@ function renderCriticPrompt(inputs) {
555110
555108
  lines.push(`You are a CRITIC sub-agent. The IMPLEMENTER agent claims to have`);
555111
555109
  lines.push(`completed the work below and called task_complete. Your job is to`);
555112
555110
  lines.push(`audit the implementation and decide whether to APPROVE, REQUEST`);
555113
- lines.push(`CHANGES, or REJECT the claim.`);
555111
+ lines.push(`CHANGES, or BLOCK the claim.`);
555114
555112
  lines.push(``);
555115
555113
  lines.push(`## Cycle: ${cycle + 1} of ${maxCycles}`);
555116
555114
  lines.push(``);
@@ -555120,6 +555118,11 @@ function renderCriticPrompt(inputs) {
555120
555118
  lines.push(`## Working directory`);
555121
555119
  lines.push(inputs.workingDir);
555122
555120
  lines.push(``);
555121
+ if (inputs.finalSummary && inputs.finalSummary.trim().length > 0) {
555122
+ lines.push(`## Proposed final summary / claims`);
555123
+ lines.push(inputs.finalSummary.slice(0, 2e3));
555124
+ lines.push(``);
555125
+ }
555123
555126
  if (inputs.systemPromptDigest && inputs.systemPromptDigest.trim().length > 0) {
555124
555127
  lines.push(`## Constraints from the implementer's system prompt`);
555125
555128
  lines.push(inputs.systemPromptDigest.slice(0, 1500));
@@ -555135,6 +555138,34 @@ function renderCriticPrompt(inputs) {
555135
555138
  }
555136
555139
  }
555137
555140
  lines.push(``);
555141
+ lines.push(`## Observed tool evidence`);
555142
+ if (!inputs.toolEvidence || inputs.toolEvidence.length === 0) {
555143
+ lines.push(`(no tool evidence recorded)`);
555144
+ } else {
555145
+ for (const entry of inputs.toolEvidence.slice(-30)) {
555146
+ const status = entry.success ? "ok" : "failed";
555147
+ const turn = typeof entry.turn === "number" ? ` turn=${entry.turn}` : "";
555148
+ const mutated = entry.mutated ? " mutated=true" : "";
555149
+ const args = entry.argsKey ? ` args=${entry.argsKey.slice(0, 180)}` : "";
555150
+ const preview = entry.outputPreview ? ` -> ${entry.outputPreview.slice(0, 240)}` : "";
555151
+ lines.push(`- [${status}] ${entry.name}${turn}${mutated}${args}${preview}`);
555152
+ }
555153
+ }
555154
+ lines.push(``);
555155
+ if (inputs.completionContractIssues && inputs.completionContractIssues.length > 0) {
555156
+ lines.push(`## Completion-contract gaps`);
555157
+ for (const gap of inputs.completionContractIssues.slice(0, 12)) {
555158
+ lines.push(`- ${gap.slice(0, 300)}`);
555159
+ }
555160
+ lines.push(``);
555161
+ }
555162
+ if (inputs.openLoops && inputs.openLoops.length > 0) {
555163
+ lines.push(`## Open loops / unresolved work`);
555164
+ for (const loop of inputs.openLoops.slice(0, 12)) {
555165
+ lines.push(`- ${loop.slice(0, 300)}`);
555166
+ }
555167
+ lines.push(``);
555168
+ }
555138
555169
  lines.push(`## Files modified (${inputs.diff.length} total)`);
555139
555170
  if (inputs.diff.length === 0) {
555140
555171
  lines.push(`(no file changes detected — this run produced no on-disk artifacts)`);
@@ -555195,6 +555226,10 @@ function renderCriticPrompt(inputs) {
555195
555226
  lines.push(` that say "(none specified)" / "(no items)" / "(empty)" alongside framing`);
555196
555227
  lines.push(` text that asserts the section IS load-bearing. These contradictions`);
555197
555228
  lines.push(` indicate the generator wasn't tested with the empty / minimal-input case.`);
555229
+ lines.push(`13. **Claim/evidence mismatch**: Every high-risk claim in the proposed final`);
555230
+ lines.push(` summary must be backed by observed tool evidence above. Server/tunnel/API/`);
555231
+ lines.push(` model/frontend/delivery claims require direct probes or receipts, not`);
555232
+ lines.push(` inference from a command merely starting without error.`);
555198
555233
  lines.push(``);
555199
555234
  lines.push(`Do NOT flag:`);
555200
555235
  lines.push(`- Stylistic choices (formatting, naming) unless they hide a real bug.`);
@@ -555208,7 +555243,7 @@ function renderCriticPrompt(inputs) {
555208
555243
  lines.push(``);
555209
555244
  lines.push("```json");
555210
555245
  lines.push(`{`);
555211
- lines.push(` "verdict": "approve" | "request_changes" | "reject",`);
555246
+ lines.push(` "verdict": "approve" | "request_changes" | "blocked",`);
555212
555247
  lines.push(` "rationale": "<1-3 sentence summary>",`);
555213
555248
  lines.push(` "pass": ["<file paths cleared with no issues>"],`);
555214
555249
  lines.push(` "issues": [`);
@@ -555228,8 +555263,9 @@ function renderCriticPrompt(inputs) {
555228
555263
  lines.push(`- **approve**: no critical/high issues; only nits if any.`);
555229
555264
  lines.push(`- **request_changes**: at least one critical/high issue OR ≥ 3 medium issues.`);
555230
555265
  lines.push(` The implementer will be given your issues list and asked to fix.`);
555231
- lines.push(`- **reject**: implementation is fundamentally wrong (wrong directory, no real`);
555232
- lines.push(` output, all gaps unresolved). Use sparingly escalates to the user.`);
555266
+ lines.push(`- **blocked**: completion cannot be verified or the implementation is`);
555267
+ lines.push(` fundamentally wrong (wrong directory, no real output, all gaps unresolved,`);
555268
+ lines.push(` required external dependency unavailable). Ends as incomplete verification.`);
555233
555269
  lines.push(``);
555234
555270
  lines.push(`Be honest. Approving broken work wastes the user's time more than asking for`);
555235
555271
  lines.push(`changes. Be specific. Vague feedback is useless to the implementer.`);
@@ -555280,8 +555316,8 @@ function parseCriticVerdict(rawResponse) {
555280
555316
  let verdict;
555281
555317
  if (rawVerdict === "approve" || rawVerdict === "approved")
555282
555318
  verdict = "approve";
555283
- else if (rawVerdict === "reject" || rawVerdict === "rejected")
555284
- verdict = "reject";
555319
+ else if (rawVerdict === "blocked" || rawVerdict === "block" || rawVerdict === "reject" || rawVerdict === "rejected")
555320
+ verdict = "blocked";
555285
555321
  else if (rawVerdict === "request_changes" || rawVerdict === "changes" || rawVerdict === "request-changes")
555286
555322
  verdict = "request_changes";
555287
555323
  else {
@@ -555336,8 +555372,12 @@ function renderVerdictForFeedback(verdict) {
555336
555372
  lines.push(` - ${t2}`);
555337
555373
  lines.push(``);
555338
555374
  }
555339
- lines.push(`Address these issues, then re-call task_complete. Do NOT call task_complete`);
555340
- lines.push(`again until you've made concrete edits to fix the items above.`);
555375
+ if (verdict.verdict === "blocked") {
555376
+ lines.push(`Completion is blocked. Report the blocker and missing evidence as incomplete_verification; do not claim success.`);
555377
+ } else {
555378
+ lines.push(`Address these issues, then re-call task_complete. Do NOT call task_complete`);
555379
+ lines.push(`again until you've made concrete edits to fix the items above.`);
555380
+ }
555341
555381
  return lines.join("\n");
555342
555382
  }
555343
555383
  var init_backward_pass_critic = __esm({
@@ -555444,6 +555484,10 @@ async function runBackwardPass(opts) {
555444
555484
  diff,
555445
555485
  planStatus: opts.planStatus,
555446
555486
  recentFailures: opts.recentFailures,
555487
+ finalSummary: opts.finalSummary,
555488
+ toolEvidence: opts.toolEvidence,
555489
+ completionContractIssues: opts.completionContractIssues,
555490
+ openLoops: opts.openLoops,
555447
555491
  systemPromptDigest: opts.systemPromptDigest,
555448
555492
  cycle: opts.cycle,
555449
555493
  maxCycles: opts.maxCycles
@@ -558292,6 +558336,291 @@ var init_specDecomposer = __esm({
558292
558336
  }
558293
558337
  });
558294
558338
 
558339
+ // packages/orchestrator/dist/completionContract.js
558340
+ function normalizeText(value2, max = 240) {
558341
+ const text = String(value2 ?? "").trim().replace(/\s+/g, " ");
558342
+ return text ? text.slice(0, max) : "";
558343
+ }
558344
+ function normalizeCompletionKey(value2, fallback = "item") {
558345
+ const key = String(value2 ?? fallback).trim().toLowerCase().replace(/[^a-z0-9_.:-]+/g, "_").replace(/_{2,}/g, "_").replace(/^[_:.-]+|[_:.-]+$/g, "").slice(0, 96);
558346
+ return key || fallback;
558347
+ }
558348
+ function field(key, label, description, acceptanceCriteria, sourceMode = "derived", elevation = "required") {
558349
+ return {
558350
+ key: normalizeCompletionKey(key),
558351
+ label,
558352
+ fieldType: "text",
558353
+ elevation,
558354
+ sourceMode,
558355
+ description,
558356
+ acceptanceCriteria
558357
+ };
558358
+ }
558359
+ function dedupFields(fields) {
558360
+ const seen = /* @__PURE__ */ new Set();
558361
+ const out = [];
558362
+ for (const item of fields) {
558363
+ if (seen.has(item.key))
558364
+ continue;
558365
+ seen.add(item.key);
558366
+ out.push(item);
558367
+ }
558368
+ return out;
558369
+ }
558370
+ function requirementFromRule(rule) {
558371
+ const id = normalizeCompletionKey(`req.${rule.surface}`);
558372
+ return {
558373
+ id,
558374
+ surface: rule.surface,
558375
+ label: rule.label,
558376
+ evidenceKind: rule.evidenceKind,
558377
+ acceptanceCriteria: rule.acceptanceCriteria,
558378
+ variableKeys: rule.fields.map((item) => item.key)
558379
+ };
558380
+ }
558381
+ function inferCompletionContract(taskText) {
558382
+ const text = String(taskText || "");
558383
+ const matched = RULES2.filter((rule) => rule.detect.test(text));
558384
+ const effective = matched;
558385
+ const requirements = effective.map(requirementFromRule);
558386
+ const fields = dedupFields(effective.flatMap((rule) => rule.fields));
558387
+ const verifyRequirementIds = requirements.map((requirement) => requirement.id);
558388
+ const phases = [
558389
+ {
558390
+ key: "execute",
558391
+ label: "Execute",
558392
+ instructions: "Complete the requested work while preserving artifacts, outputs, and observations needed for validation.",
558393
+ requirementIds: [],
558394
+ fields: [],
558395
+ gate: {
558396
+ key: "execution_trace",
558397
+ instructions: "Record concrete outputs and blockers as work proceeds."
558398
+ }
558399
+ },
558400
+ {
558401
+ key: "verify",
558402
+ label: "Verify",
558403
+ instructions: "Validate the result against the operator request and required evidence surfaces before delivery.",
558404
+ requirementIds: verifyRequirementIds,
558405
+ fields,
558406
+ gate: {
558407
+ key: "acceptance_gate",
558408
+ instructions: "Every required evidence surface must have an observed tool result, or the final summary must report BLOCKED/unverified for that surface."
558409
+ }
558410
+ },
558411
+ {
558412
+ key: "deliver",
558413
+ label: "Deliver",
558414
+ instructions: "Return the outcome with evidence, unresolved blockers, and next actions.",
558415
+ requirementIds: verifyRequirementIds,
558416
+ fields: [],
558417
+ gate: {
558418
+ key: "result_readback",
558419
+ instructions: "Do not claim completion beyond the evidence collected during verification."
558420
+ }
558421
+ }
558422
+ ];
558423
+ return {
558424
+ goalSummary: normalizeText(text, 500),
558425
+ surfaces: requirements.map((requirement) => requirement.surface),
558426
+ fields,
558427
+ requirements,
558428
+ phases,
558429
+ acceptanceCriteria: requirements.map((requirement) => requirement.acceptanceCriteria)
558430
+ };
558431
+ }
558432
+ function inferCompletionContractFromTexts(texts, fallbackSummary = "") {
558433
+ const combined = texts.map((text) => String(text ?? "").trim()).filter(Boolean).join("\n\n");
558434
+ if (combined)
558435
+ return inferCompletionContract(combined);
558436
+ return inferCompletionContract(fallbackSummary);
558437
+ }
558438
+ function haystack(entry) {
558439
+ return `${entry.name} ${entry.argsKey ?? ""} ${entry.outputPreview ?? ""}`.toLowerCase();
558440
+ }
558441
+ function hasSuccessful(log22, predicate) {
558442
+ return log22.some((entry) => entry.success === true && predicate(entry, haystack(entry)));
558443
+ }
558444
+ function completionEvidenceSatisfied(requirement, log22) {
558445
+ switch (requirement.evidenceKind) {
558446
+ case "build_or_test":
558447
+ return hasSuccessful(log22, (entry, text) => entry.mutated === true || /\b(test|typecheck|tsc|lint|build|compile|vitest|jest|pytest|cargo test|go test|npm run|pnpm .*build)\b/.test(text));
558448
+ case "browser_observation":
558449
+ return hasSuccessful(log22, (entry, text) => /^(browser_action|playwright_browser|carbonyl_browser)$/.test(entry.name) && /\b(observe|screenshot|dom|page_errors|console|network|visible|title|url)\b/.test(text));
558450
+ case "desktop_observation":
558451
+ return hasSuccessful(log22, (entry, text) => /^(desktop_describe|desktop_click|vision_action_loop|screenshot)$/.test(entry.name) && /\b(observe|screenshot|visible|verification|desktop|screen)\b/.test(text));
558452
+ case "source_citation":
558453
+ return hasSuccessful(log22, (entry, text) => /^(file_read|grep_search|find_files|list_directory|web_search|web_fetch|web_crawl|log_explore|diagnostic|shell)$/.test(entry.name) || /\b(source|evidence|root cause|log|file|line|http|arxiv|paper)\b/.test(text));
558454
+ case "service_start": {
558455
+ const hasStartup = hasSuccessful(log22, (_entry, text) => /\b(listen|listening|started|ready|localhost|127\.0\.0\.1|0\.0\.0\.0|port\s*\d{2,5}|http:\/\/)\b/.test(text));
558456
+ const hasDirectProbe = hasSuccessful(log22, (_entry, text) => /\b(curl|fetch|web_fetch|health|status|http\/[12](?:\.[0-9])?|200|201|204|30[1278])\b/.test(text) && /\b(localhost|127\.0\.0\.1|0\.0\.0\.0|http:\/\/|https:\/\/|port\s*\d{2,5})\b/.test(text) && !/\b(502|500|connection refused|not found|failed|error)\b/.test(text));
558457
+ return hasStartup && hasDirectProbe;
558458
+ }
558459
+ case "network_probe":
558460
+ return hasSuccessful(log22, (_entry, text) => /\b(curl|fetch|web_fetch|browser|http\/[12](?:\.[0-9])?|status|200|30[1278])\b/.test(text) && /\b(http|https|trycloudflare|tunnel|ngrok|expose|public url)\b/.test(text) && !/\b(1033|502|connection refused|not found|failed|error)\b/.test(text));
558461
+ case "api_probe":
558462
+ return hasSuccessful(log22, (_entry, text) => /\b(curl|fetch|http|api|endpoint|route|json|sse|stream|status|response|200|201|204)\b/.test(text) && !/\b(json\.parse|unexpected character|502|500|failed|error)\b/.test(text));
558463
+ case "model_probe": {
558464
+ const hasAvailability = hasSuccessful(log22, (_entry, text) => /\b(ollama|\/api\/tags|\/v1\/models|model(?:s)?\s+(?:available|listed|present)|available\s+model|qwen|llama)\b/.test(text) && !/\b(no response|timeout|not available|missing|failed|error|502)\b/.test(text));
558465
+ const hasInference = hasSuccessful(log22, (_entry, text) => /\b(\/api\/chat|\/api\/generate|inference|generate|chat|completion|smoke|response|done)\b/.test(text) && !/\b(no response|timeout|not available|missing|failed|error|502)\b/.test(text));
558466
+ return hasAvailability && hasInference;
558467
+ }
558468
+ case "delivery_receipt":
558469
+ return hasSuccessful(log22, (entry, text) => /^(send_message|telegram|telegram_send|notify|web_fetch|shell)$/.test(entry.name) && /\b(sent|delivered|ok|success|message id|recipient|telegram)\b/.test(text));
558470
+ case "frontend_runtime_probe":
558471
+ return hasSuccessful(log22, (entry, text) => /^(browser_action|playwright_browser|carbonyl_browser|shell)$/.test(entry.name) && /\b(browser|page|console|page_errors|network|screenshot|dom|render|localhost|http|ui)\b/.test(text) && !/\b(json\.parse|page error|console error|network failure|failed|error|502|1033)\b/.test(text));
558472
+ }
558473
+ }
558474
+ function completionContractIssues(args) {
558475
+ if (args.blockedSummary)
558476
+ return [];
558477
+ const issues = [];
558478
+ for (const requirement of args.contract.requirements) {
558479
+ if (completionEvidenceSatisfied(requirement, args.log))
558480
+ continue;
558481
+ issues.push(`${requirement.label} is not proven. Required evidence: ${requirement.acceptanceCriteria}`);
558482
+ }
558483
+ return issues;
558484
+ }
558485
+ function formatCompletionContract(contract) {
558486
+ const lines = [];
558487
+ lines.push(`[DYNAMIC COMPLETION CONTRACT]`);
558488
+ lines.push(`Goal: ${contract.goalSummary || "(no goal text)"}`);
558489
+ lines.push(`Required evidence surfaces: ${contract.surfaces.join(", ") || "none"}`);
558490
+ lines.push(``);
558491
+ lines.push(`Nested variables to track:`);
558492
+ if (contract.fields.length === 0) {
558493
+ lines.push(`- none inferred`);
558494
+ } else {
558495
+ for (const fieldItem of contract.fields.slice(0, 20)) {
558496
+ lines.push(`- ${fieldItem.key} (${fieldItem.elevation}, ${fieldItem.sourceMode}): ${fieldItem.acceptanceCriteria}`);
558497
+ }
558498
+ if (contract.fields.length > 20)
558499
+ lines.push(`- ... +${contract.fields.length - 20} more`);
558500
+ }
558501
+ lines.push(``);
558502
+ lines.push(`Verification requirements:`);
558503
+ for (const requirement of contract.requirements) {
558504
+ lines.push(`- ${requirement.id}: ${requirement.acceptanceCriteria}`);
558505
+ }
558506
+ lines.push(``);
558507
+ lines.push(`Flow: execute -> verify gate -> deliver readback. Missing facts become variables or blockers; they are not assumptions.`);
558508
+ return lines.join("\n");
558509
+ }
558510
+ var RULES2;
558511
+ var init_completionContract = __esm({
558512
+ "packages/orchestrator/dist/completionContract.js"() {
558513
+ "use strict";
558514
+ RULES2 = [
558515
+ {
558516
+ surface: "code",
558517
+ label: "Code/file changes",
558518
+ evidenceKind: "build_or_test",
558519
+ detect: /\b(implement|fix|patch|refactor|rewrite|build|compile|typecheck|test suite|unit test|integration test|source file|codebase|package|typescript|javascript|python|rust|golang)\b/i,
558520
+ acceptanceCriteria: "A relevant build, test, typecheck, lint, or runtime command succeeds after the final file mutation.",
558521
+ fields: [
558522
+ field("code.verify.command", "Verification command", "Command that proves the changed code still works.", "The command is run after the final edit and its real output is observed.")
558523
+ ]
558524
+ },
558525
+ {
558526
+ surface: "browser",
558527
+ label: "Browser/UI state",
558528
+ evidenceKind: "browser_observation",
558529
+ detect: /\b(browser|web\s*page|website|page|playwright|selenium|chromedriver|chrome|headless|gui|login|captcha|form|account|submit|click|type|fill)\b/i,
558530
+ acceptanceCriteria: "A fresh browser observation after the final action shows the expected state and no blocking page/console/network errors.",
558531
+ fields: [
558532
+ field("browser.final_state", "Expected browser state", "The visible browser state that proves the user flow worked.", "A browser observation after the final action shows this state.")
558533
+ ]
558534
+ },
558535
+ {
558536
+ surface: "desktop",
558537
+ label: "Desktop state",
558538
+ evidenceKind: "desktop_observation",
558539
+ detect: /\b(desktop|screen|application|app\b|window|file manager|open a file|laptop|screenshot|vision_action_loop|desktop_describe|desktop_click)\b/i,
558540
+ acceptanceCriteria: "A fresh desktop/vision observation after the final action proves the visible state.",
558541
+ fields: [
558542
+ field("desktop.final_state", "Expected desktop state", "The visible desktop state that proves completion.", "A desktop observation after the final action shows this state.")
558543
+ ]
558544
+ },
558545
+ {
558546
+ surface: "research",
558547
+ label: "Research/root-cause claims",
558548
+ evidenceKind: "source_citation",
558549
+ detect: /\b(discover|root cause|triage|deep dive|review|audit|investigate|prove|validate|forensics|diagnostic|failure mode|literature|source)\b/i,
558550
+ acceptanceCriteria: "Claims cite inspected files, command outputs, logs, documents, or web/source artifacts observed during the run.",
558551
+ fields: [
558552
+ field("research.evidence.items", "Evidence items", "Concrete inspected artifacts supporting the claim.", "Each important claim maps to at least one observed artifact or source.", "data_library", "preferred")
558553
+ ]
558554
+ },
558555
+ {
558556
+ surface: "service",
558557
+ label: "Local service/server",
558558
+ evidenceKind: "service_start",
558559
+ detect: /\b(server|service|daemon|dev server|localhost|listen(?:ing)?|port\s+\d{2,5}|host(?:s|ed|ing)?|online|start(?:ed)?\s+(?:the\s+)?(?:app|server|service))\b/i,
558560
+ acceptanceCriteria: "The service is started, the expected port/base URL is known, and a direct probe reaches it.",
558561
+ fields: [
558562
+ field("runtime.service.port", "Service port", "Port or base URL the local service should listen on.", "A probe reaches the same port/base URL."),
558563
+ field("runtime.service.health_url", "Health URL", "URL or route used to verify the service.", "The route returns a non-error response or expected content.")
558564
+ ]
558565
+ },
558566
+ {
558567
+ surface: "tunnel",
558568
+ label: "Public tunnel",
558569
+ evidenceKind: "network_probe",
558570
+ detect: /\b(cloudflared|cloudflare|tunnel|public url|trycloudflare|ngrok|tailscale funnel|expose)\b/i,
558571
+ acceptanceCriteria: "The public tunnel URL is observed and a network probe confirms it reaches the intended local service.",
558572
+ fields: [
558573
+ field("network.tunnel.public_url", "Public tunnel URL", "Externally reachable URL exposed to the user.", "A probe to this URL returns expected content/status."),
558574
+ field("network.tunnel.target", "Tunnel target", "Local URL/port the tunnel forwards to.", "The target matches the running service port.")
558575
+ ]
558576
+ },
558577
+ {
558578
+ surface: "api",
558579
+ label: "API behavior",
558580
+ evidenceKind: "api_probe",
558581
+ detect: /\b(api|endpoint|route|http|json|sse|streaming|request|response|curl|fetch|webhook)\b/i,
558582
+ acceptanceCriteria: "A realistic request reaches the endpoint and the response body/status/stream shape is inspected.",
558583
+ fields: [
558584
+ field("api.probe.request", "API probe request", "Representative request used to verify the endpoint.", "The request is actually sent and the response is inspected."),
558585
+ field("api.probe.expected_shape", "Expected response shape", "Status/body/stream shape that proves the API works.", "Observed response matches this shape.")
558586
+ ]
558587
+ },
558588
+ {
558589
+ surface: "llm_service",
558590
+ label: "LLM/model service",
558591
+ evidenceKind: "model_probe",
558592
+ detect: /\b(ollama|model|llama|qwen|inference|chat completions?|\/api\/tags|\/v1\/models|think(?:ing)?\s*:\s*false|disable thinking)\b/i,
558593
+ acceptanceCriteria: "Available models are listed or queried, the selected model is present, and one minimal inference/request path is smoke-tested.",
558594
+ fields: [
558595
+ field("runtime.ollama.base_url", "Model service base URL", "Base URL for the model service.", "The base URL responds to a model-list or inference request."),
558596
+ field("runtime.ollama.model", "Selected model", "Model name intended for inference.", "The model appears in a real availability check or successful inference response.")
558597
+ ]
558598
+ },
558599
+ {
558600
+ surface: "delivery",
558601
+ label: "External delivery",
558602
+ evidenceKind: "delivery_receipt",
558603
+ detect: /\b(send|sent|message|dm|email|telegram|slack|discord|share(?:d)?|notify|link to|recipient)\b/i,
558604
+ acceptanceCriteria: "The delivery tool/API returns a success receipt for the intended recipient or the summary reports delivery as unverified/blocked.",
558605
+ fields: [
558606
+ field("delivery.recipients", "Recipients", "People, channels, or addresses that should receive the result.", "Each claimed recipient has a send receipt or is reported unverified."),
558607
+ field("delivery.payload", "Delivery payload", "Link/message/artifact sent to recipients.", "The payload matches the verified result.")
558608
+ ]
558609
+ },
558610
+ {
558611
+ surface: "frontend_runtime",
558612
+ label: "Frontend runtime",
558613
+ evidenceKind: "frontend_runtime_probe",
558614
+ detect: /\b(frontend|ui|nextjs|next\.js|react|page\.tsx|browser|checkbox|clickable|chat interface|progress bar|client)\b/i,
558615
+ acceptanceCriteria: "The UI is opened or smoke-tested after API changes; console, page, and critical network errors are inspected.",
558616
+ fields: [
558617
+ field("frontend.user_flow", "Frontend user flow", "Concrete user flow that proves the UI works.", "The flow is exercised in a browser/runtime probe.")
558618
+ ]
558619
+ }
558620
+ ];
558621
+ }
558622
+ });
558623
+
558295
558624
  // packages/orchestrator/dist/modelProfile.js
558296
558625
  function resolveModelProfile(model) {
558297
558626
  const m2 = model.toLowerCase();
@@ -560516,6 +560845,7 @@ var init_agenticRunner = __esm({
560516
560845
  init_app_state();
560517
560846
  init_streaming_executor();
560518
560847
  init_specDecomposer();
560848
+ init_completionContract();
560519
560849
  init_modelProfile();
560520
560850
  init_failureHandoff();
560521
560851
  init_context_fabric();
@@ -560818,7 +561148,7 @@ var init_agenticRunner = __esm({
560818
561148
  _fileWritesSinceLastWorldState = 0;
560819
561149
  // REG-47: backward-pass critic. After task_complete is requested, a
560820
561150
  // dedicated CRITIC sub-agent reviews the diff + plan reconciliation +
560821
- // recent failures and votes approve / request_changes / reject. On
561151
+ // recent failures and votes approve / request_changes / blocked. On
560822
561152
  // request_changes the issues are injected as feedback and the loop
560823
561153
  // continues. Cycle-bounded so a stubborn/wrong critic can't block
560824
561154
  // forever. Skipped for trivial runs (no file mutations).
@@ -560828,15 +561158,22 @@ var init_agenticRunner = __esm({
560828
561158
  _fileWritesThisRun = 0;
560829
561159
  _backwardPassCyclesUsed = 0;
560830
561160
  _lastBackwardPassVerdict = null;
561161
+ // Run-local completion contract inferred from the user's ask/context before
561162
+ // the first model turn. The model can add evidence, but cannot weaken this
561163
+ // supervisor-owned contract via todo fields or final-summary wording.
561164
+ _completionContract = null;
561165
+ _completionContractSeedText = "";
560831
561166
  // REG-54: completion-gate anti-collapse circuit breaker. The no-progress and
560832
561167
  // completion-provenance gates can hold task_complete indefinitely. When a
560833
561168
  // collapsed/weak model resubmits the same (or a similar) completion summary,
560834
561169
  // the gate rejects it every turn and the model re-emits the identical
560835
561170
  // task_complete forever — a mode-collapse loop. Unlike the backward-pass
560836
561171
  // critic (REG-47), these gates had no cycle bound. We track consecutive holds
560837
- // of the same summary and fail open after a small threshold so the run
560838
- // terminates instead of spinning. Reset whenever a completion is allowed.
561172
+ // of the same summary and terminate as incomplete_verification after a
561173
+ // small threshold so the run stops without falsely marking completion.
561174
+ // Reset whenever a completion is allowed.
560839
561175
  _completionHoldState = { count: 0, lastKey: "" };
561176
+ _completionIncompleteVerification = null;
560840
561177
  // ── WO-AM-01/04/10: Associative memory stores ──
560841
561178
  // Episode store: every tool call → persistent episode with importance + decay
560842
561179
  // Temporal KG: entities + relations with temporal validity (valid_from/valid_until)
@@ -561086,6 +561423,31 @@ var init_agenticRunner = __esm({
561086
561423
  const configured = (this.options.stateDir || "").trim();
561087
561424
  return configured ? _pathResolve(configured) : _pathJoin(process.cwd(), ".omnius");
561088
561425
  }
561426
+ _persistCompletionContract(contract) {
561427
+ try {
561428
+ const dir = _pathJoin(this.omniusStateDir(), "completion-contracts");
561429
+ _fsMkdirSync(dir, { recursive: true });
561430
+ _fsWriteFileSync(_pathJoin(dir, `${this._sessionId}.json`), JSON.stringify({
561431
+ sessionId: this._sessionId,
561432
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
561433
+ contract
561434
+ }, null, 2), "utf8");
561435
+ } catch {
561436
+ }
561437
+ }
561438
+ _initializeCompletionContract(task, context2) {
561439
+ this._completionContractSeedText = [task, context2 ?? ""].map((text) => String(text || "").trim()).filter(Boolean).join("\n\n");
561440
+ this._completionContract = inferCompletionContractFromTexts([this._completionContractSeedText], task);
561441
+ this._persistCompletionContract(this._completionContract);
561442
+ return this._completionContract;
561443
+ }
561444
+ _completionContractForClaims(...claimTexts) {
561445
+ const base3 = this._completionContract;
561446
+ const extras = claimTexts.map((text) => String(text ?? "").trim()).filter(Boolean);
561447
+ if (extras.length === 0 && base3)
561448
+ return base3;
561449
+ return inferCompletionContractFromTexts([this._completionContractSeedText, ...extras], base3?.goalSummary || this._taskState.originalGoal || this._taskState.goal || "");
561450
+ }
561089
561451
  /** Get current task state (for external inspection) */
561090
561452
  get taskState() {
561091
561453
  return this._taskState;
@@ -561931,8 +562293,10 @@ Do NOT call task_complete until all items are marked completed via todo_write.`;
561931
562293
  buildMissionCompletionContract(task, context2) {
561932
562294
  if (process.env["OMNIUS_DISABLE_MISSION_COMPLETION_CONTRACT"] === "1")
561933
562295
  return "";
561934
- const profile = this._inferCompletionProfile(`${task}
561935
- ${context2 ?? ""}`);
562296
+ const profileText = `${task}
562297
+ ${context2 ?? ""}`;
562298
+ const profile = this._inferCompletionProfile(profileText);
562299
+ const completionContract = this._completionContract || this._completionContractForClaims(profileText);
561936
562300
  const requirements = [];
561937
562301
  if (profile.browser)
561938
562302
  requirements.push("browser/UI state must be proven by a post-action screenshot/DOM/observe_bundle pass");
@@ -561942,6 +562306,18 @@ ${context2 ?? ""}`);
561942
562306
  requirements.push("code/file changes must be proven by a relevant build/test/typecheck/runtime command after the last edit");
561943
562307
  if (profile.research)
561944
562308
  requirements.push("research/root-cause claims must cite concrete inspected files, commands, logs, or source artifacts");
562309
+ if (profile.service)
562310
+ requirements.push("local services must be proven by startup evidence plus a direct probe to the claimed port or base URL");
562311
+ if (profile.tunnel)
562312
+ requirements.push("public tunnel claims must be proven by the observed public URL and a network probe showing it reaches the intended local service");
562313
+ if (profile.api)
562314
+ requirements.push("API/streaming claims must be proven by a realistic request whose status and response shape were inspected");
562315
+ if (profile.llmService)
562316
+ requirements.push("LLM/model-service claims must be proven by model availability and a minimal inference or model-list probe");
562317
+ if (profile.delivery)
562318
+ requirements.push("message/share/delivery claims must be proven by a send receipt for each claimed recipient or reported as unverified");
562319
+ if (profile.frontendRuntime)
562320
+ requirements.push("frontend runtime claims must be proven by a browser/runtime smoke check of the user-facing flow");
561945
562321
  if (requirements.length === 0)
561946
562322
  requirements.push("final claims must name the concrete evidence used or state that the task required no external action");
561947
562323
  return [
@@ -561956,17 +562332,39 @@ ${context2 ?? ""}`);
561956
562332
  `A command succeeding proves only that it ran — NOT that the intended effect was achieved. When an action is meant to start, produce, change, or send something, verify that end-state directly with a separate observation before claiming it works; do not infer success from the absence of an error.`,
561957
562333
  `Treat a negative, empty, or error result as evidence of absence or failure and report it as such. Do NOT reinterpret it as success or explain it away with an untested theory; if you have a candidate explanation, prove it with another observation first. Never assert a causal or ownership relationship between processes, files, components, sessions, or memories unless the observed output explicitly shows it — invented provenance is a completion-blocking failure.`,
561958
562334
  `For browser/form/account/send flows: after the last click/type/navigate/submit action, capture a fresh browser observation and verify the visible final state before completion.`,
561959
- `If completion is impossible, use a summary beginning BLOCKED: and name the exact blocker plus the evidence already collected.`
562335
+ `If completion is impossible, use a summary beginning BLOCKED: and name the exact blocker plus the evidence already collected.`,
562336
+ ``,
562337
+ formatCompletionContract(completionContract)
561960
562338
  ].join("\n");
561961
562339
  }
561962
562340
  _inferCompletionProfile(text) {
561963
562341
  const t2 = text.toLowerCase();
561964
- const browser3 = /\b(browser|web\s*page|website|page|playwright|selenium|chromedriver|chrome|headless|gui|proton|login|captcha|form|account|compose|mail|submit|click|type|fill)\b/.test(t2);
561965
- const desktop = /\b(desktop|screen|application|app\b|window|file manager|open a file|laptop|screenshot|vision_action_loop|desktop_describe|desktop_click)\b/.test(t2);
561966
- const code8 = /\b(implement|fix|patch|refactor|rewrite|build|compile|typecheck|test suite|unit test|integration test|source file|codebase|package|typescript|javascript|python|rust|golang)\b/.test(t2);
561967
- const research = /\b(discover|root cause|triage|deep dive|review|audit|investigate|prove|validate|forensics|diagnostic|failure mode)\b/.test(t2);
562342
+ const contract = this._completionContractForClaims(text);
562343
+ const hasSurface = (surface) => contract.surfaces.includes(surface);
562344
+ const browser3 = hasSurface("browser") || /\b(browser|web\s*page|website|page|playwright|selenium|chromedriver|chrome|headless|gui|proton|login|captcha|form|account|compose|mail|submit|click|type|fill)\b/.test(t2);
562345
+ const desktop = hasSurface("desktop") || /\b(desktop|screen|application|app\b|window|file manager|open a file|laptop|screenshot|vision_action_loop|desktop_describe|desktop_click)\b/.test(t2);
562346
+ const code8 = hasSurface("code") || /\b(implement|fix|patch|refactor|rewrite|build|compile|typecheck|test suite|unit test|integration test|source file|codebase|package|typescript|javascript|python|rust|golang)\b/.test(t2);
562347
+ const research = hasSurface("research") || /\b(discover|root cause|triage|deep dive|review|audit|investigate|prove|validate|forensics|diagnostic|failure mode)\b/.test(t2);
562348
+ const service = hasSurface("service");
562349
+ const tunnel = hasSurface("tunnel");
562350
+ const api = hasSurface("api");
562351
+ const llmService = hasSurface("llm_service");
562352
+ const delivery = hasSurface("delivery");
562353
+ const frontendRuntime = hasSurface("frontend_runtime");
561968
562354
  const formLike = /\b(form|fill|submit|signup|sign up|login|log in|account|compose|send|sent|mail|captcha|checkout|payment|upload)\b/.test(t2);
561969
- return { browser: browser3, desktop, code: code8, research, formLike };
562355
+ return {
562356
+ browser: browser3,
562357
+ desktop,
562358
+ code: code8,
562359
+ research,
562360
+ service,
562361
+ tunnel,
562362
+ api,
562363
+ llmService,
562364
+ delivery,
562365
+ frontendRuntime,
562366
+ formLike
562367
+ };
561970
562368
  }
561971
562369
  _completionSummaryHasProvenance(summary) {
561972
562370
  return /\b(provenance|evidence|verified|validated|confirmed|observed|screenshot|dom|console|network|log|test|typecheck|build|passed|opened|sent|created|submitted|blocked)\b/i.test(summary);
@@ -562367,6 +562765,7 @@ ${context2 ?? ""}`);
562367
562765
  const summary = input.summary || "";
562368
562766
  const blockedSummary = this._isBlockedCompletionSummary(summary);
562369
562767
  const profile = this._inferCompletionProfile(input.taskGoal);
562768
+ const completionContract = this._completionContractForClaims(input.summary, input.answerText);
562370
562769
  const log22 = input.toolCallLog.filter((entry) => entry.name !== "task_complete");
562371
562770
  const claimText = `${summary}
562372
562771
  ${input.answerText ?? ""}`;
@@ -562394,7 +562793,7 @@ ${input.answerText ?? ""}`;
562394
562793
  const desktopUsed = log22.some((entry) => /^(desktop_describe|desktop_click|vision_action_loop|screenshot)$/.test(entry.name));
562395
562794
  const mutated = log22.some((entry) => entry.mutated === true);
562396
562795
  const issues = [];
562397
- const actionHeavy = profile.browser || profile.desktop || profile.code || profile.research || browserUsed || desktopUsed || mutated || this._fileWritesThisRun > 0;
562796
+ const actionHeavy = profile.browser || profile.desktop || profile.code || profile.research || profile.service || profile.tunnel || profile.api || profile.llmService || profile.delivery || profile.frontendRuntime || completionContract.requirements.length > 0 || browserUsed || desktopUsed || mutated || this._fileWritesThisRun > 0;
562398
562797
  if (!actionHeavy)
562399
562798
  return { proceed: true };
562400
562799
  if (blockedSummary)
@@ -562471,6 +562870,11 @@ ${input.answerText ?? ""}`;
562471
562870
  if (!this._completionSummaryHasProvenance(summary)) {
562472
562871
  issues.push("The completion summary does not include an explicit Evidence/Provenance note.");
562473
562872
  }
562873
+ issues.push(...completionContractIssues({
562874
+ contract: completionContract,
562875
+ log: log22,
562876
+ blockedSummary
562877
+ }));
562474
562878
  if (issues.length === 0)
562475
562879
  return { proceed: true };
562476
562880
  const recentEvidence = successfulNonCompletion.slice(-6).map((entry) => {
@@ -562529,11 +562933,11 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562529
562933
  * up auto-blocking and surfaces a status event so the caller can take
562530
562934
  * a different path (eg. surface to user). max cycles enforced here.
562531
562935
  */
562532
- async _runBackwardPassReview(turn) {
562936
+ async _runBackwardPassReview(turn, toolCallLog, proposedSummary = "") {
562533
562937
  const optOverride = this.options.backwardPassReview;
562534
- const raw = (process.env["OMNIUS_BACKWARD_PASS"] || "off").toLowerCase();
562535
- const envEnabled = raw === "on" || raw === "1" || raw === "true";
562536
- const enabled2 = optOverride === true || optOverride !== false && envEnabled;
562938
+ const raw = (process.env["OMNIUS_BACKWARD_PASS"] || "on").toLowerCase();
562939
+ const envDisabled = raw === "off" || raw === "0" || raw === "false";
562940
+ const enabled2 = optOverride === true || optOverride !== false && !envDisabled;
562537
562941
  if (!enabled2)
562538
562942
  return { proceed: true };
562539
562943
  const minWrites = parseInt(process.env["OMNIUS_BACKWARD_PASS_MIN_WRITES"] || "1", 10) || 1;
@@ -562541,12 +562945,30 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562541
562945
  return { proceed: true };
562542
562946
  const maxCycles = parseInt(process.env["OMNIUS_BACKWARD_PASS_MAX_CYCLES"] || "2", 10) || 2;
562543
562947
  if (this._backwardPassCyclesUsed >= maxCycles) {
562948
+ const reason = `backward-pass review exhausted ${this._backwardPassCyclesUsed}/${maxCycles} cycle(s) without approval`;
562949
+ this._completionIncompleteVerification = {
562950
+ reason,
562951
+ summary: [
562952
+ "INCOMPLETE_VERIFICATION: backward-pass review did not approve completion before the review cycle limit.",
562953
+ "",
562954
+ `Attempted summary: ${proposedSummary || "(no summary)"}`,
562955
+ "",
562956
+ "Not verified / blocked:",
562957
+ reason,
562958
+ "",
562959
+ "Evidence:",
562960
+ `Last backward-pass verdict: ${this._lastBackwardPassVerdict || "unknown"}`
562961
+ ].join("\n")
562962
+ };
562544
562963
  this.emit({
562545
562964
  type: "status",
562546
- content: `REG-47 backward-pass skipped — already used ${this._backwardPassCyclesUsed}/${maxCycles} cycles. Allowing task_complete.`,
562965
+ content: `REG-47 backward-pass exhausted ${this._backwardPassCyclesUsed}/${maxCycles} cycles; ending as incomplete_verification instead of completing.`,
562547
562966
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
562548
562967
  });
562549
- return { proceed: true };
562968
+ return {
562969
+ proceed: false,
562970
+ feedback: "Backward-pass review cycle limit was reached before approval. End as incomplete_verification and report the missing verification evidence instead of claiming completion."
562971
+ };
562550
562972
  }
562551
562973
  const _backend = this.backend;
562552
562974
  const _criticTimeoutMs = parseInt(process.env["OMNIUS_BACKWARD_PASS_TIMEOUT_MS"] || "120000", 10) || 12e4;
@@ -562606,6 +563028,24 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562606
563028
  attempts: entry.attempts,
562607
563029
  preview: (entry.wentWrong || "").slice(0, 200)
562608
563030
  })).sort((a2, b) => b.attempts - a2.attempts).slice(0, 5);
563031
+ const criticToolEvidence = toolCallLog.filter((entry) => entry.name !== "task_complete").slice(-40).map((entry) => ({
563032
+ name: entry.name,
563033
+ argsKey: entry.argsKey.slice(0, 300),
563034
+ success: entry.success === true,
563035
+ outputPreview: (entry.outputPreview ?? "").slice(0, 500),
563036
+ turn: entry.turn,
563037
+ mutated: entry.mutated === true
563038
+ }));
563039
+ const completionContract = this._completionContractForClaims(proposedSummary);
563040
+ const criticContractIssues = completionContractIssues({
563041
+ contract: completionContract,
563042
+ log: toolCallLog.filter((entry) => entry.name !== "task_complete"),
563043
+ blockedSummary: /^\s*BLOCKED\b/i.test(proposedSummary || "")
563044
+ });
563045
+ const openLoops = [
563046
+ ...todos.filter((todo) => todo.status !== "completed" && todo.status !== "blocked").slice(0, 12).map((todo) => `todo still ${todo.status}: ${todo.content}`),
563047
+ ...recentFailures.filter((failure) => failure.attempts >= 3).map((failure) => `unresolved repeated failure: ${failure.stem} (${failure.attempts} attempts)`)
563048
+ ];
562609
563049
  let result;
562610
563050
  try {
562611
563051
  result = await runBackwardPass({
@@ -562618,6 +563058,10 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562618
563058
  rationale: t2.rationale
562619
563059
  })),
562620
563060
  recentFailures,
563061
+ finalSummary: proposedSummary,
563062
+ toolEvidence: criticToolEvidence,
563063
+ completionContractIssues: criticContractIssues,
563064
+ openLoops,
562621
563065
  callable,
562622
563066
  maxFiles: parseInt(process.env["OMNIUS_BACKWARD_PASS_MAX_FILES"] || "60", 10) || 60,
562623
563067
  maxFilePreviewBytes: parseInt(process.env["OMNIUS_BACKWARD_PASS_MAX_FILE_PREVIEW"] || "8000", 10) || 8e3,
@@ -562625,12 +563069,30 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562625
563069
  maxCycles
562626
563070
  });
562627
563071
  } catch (e2) {
563072
+ const reason = `backward-pass runner failed: ${e2 instanceof Error ? e2.message : String(e2)}`;
563073
+ this._completionIncompleteVerification = {
563074
+ reason,
563075
+ summary: [
563076
+ "INCOMPLETE_VERIFICATION: backward-pass review could not verify completion.",
563077
+ "",
563078
+ `Attempted summary: ${proposedSummary || "(no summary)"}`,
563079
+ "",
563080
+ "Not verified / blocked:",
563081
+ reason,
563082
+ "",
563083
+ "Evidence:",
563084
+ criticContractIssues.length > 0 ? criticContractIssues.map((issue) => `- ${issue}`).join("\n") : "No completion-contract gaps were available before the critic failure."
563085
+ ].join("\n")
563086
+ };
562628
563087
  this.emit({
562629
563088
  type: "status",
562630
- content: `REG-47 backward-pass runner threw: ${e2 instanceof Error ? e2.message : String(e2)}. Allowing task_complete (fail-soft).`,
563089
+ content: `REG-47 backward-pass runner threw: ${e2 instanceof Error ? e2.message : String(e2)}. Ending as incomplete_verification instead of completing.`,
562631
563090
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
562632
563091
  });
562633
- return { proceed: true };
563092
+ return {
563093
+ proceed: false,
563094
+ feedback: "Backward-pass review failed before completion could be verified. Report incomplete_verification rather than claiming success."
563095
+ };
562634
563096
  }
562635
563097
  this._backwardPassCyclesUsed++;
562636
563098
  this._lastBackwardPassVerdict = result.verdict.verdict;
@@ -562643,10 +563105,25 @@ ${recentVisualEvidence}` : `Recent structured visual evidence: none recorded.`,
562643
563105
  if (result.verdict.verdict === "approve")
562644
563106
  return { proceed: true };
562645
563107
  const feedback = result.feedbackMessage;
562646
- if (result.verdict.verdict === "reject") {
563108
+ if (result.verdict.verdict === "blocked") {
563109
+ const reason = `backward-pass critic blocked completion: ${result.verdict.rationale.slice(0, 240)}`;
563110
+ this._completionIncompleteVerification = {
563111
+ reason,
563112
+ summary: [
563113
+ "INCOMPLETE_VERIFICATION: backward-pass critic blocked completion.",
563114
+ "",
563115
+ `Attempted summary: ${proposedSummary || "(no summary)"}`,
563116
+ "",
563117
+ "Not verified / blocked:",
563118
+ reason,
563119
+ "",
563120
+ "Evidence:",
563121
+ feedback
563122
+ ].join("\n")
563123
+ };
562647
563124
  this.emit({
562648
563125
  type: "status",
562649
- content: `REG-47 critic REJECTED implementation. Rationale: ${result.verdict.rationale.slice(0, 200)}`,
563126
+ content: `REG-47 critic BLOCKED completion. Rationale: ${result.verdict.rationale.slice(0, 200)}`,
562650
563127
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
562651
563128
  });
562652
563129
  }
@@ -565167,6 +565644,9 @@ Respond with your assessment, then take action.`;
565167
565644
  this._fileWritesThisRun = 0;
565168
565645
  this._backwardPassCyclesUsed = 0;
565169
565646
  this._lastBackwardPassVerdict = null;
565647
+ this._completionContract = null;
565648
+ this._completionContractSeedText = "";
565649
+ this._completionIncompleteVerification = null;
565170
565650
  this._lastWorldStateTurn = -1;
565171
565651
  this._fileWritesSinceLastWorldState = 0;
565172
565652
  this._resetVisualEvidenceState();
@@ -565305,6 +565785,7 @@ Respond with your assessment, then take action.`;
565305
565785
  verbose: false
565306
565786
  });
565307
565787
  this._hookManager.runSessionHook("session_start", this._sessionId);
565788
+ this._initializeCompletionContract(task, context2);
565308
565789
  this._sessionStartMs = Date.now();
565309
565790
  if (process.env["OMNIUS_DISABLE_PREFLIGHT"] !== "1") {
565310
565791
  try {
@@ -565728,6 +566209,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565728
566209
  });
565729
566210
  if (!gate.shouldInject || !gate.content)
565730
566211
  return false;
566212
+ lastCompletionGateReason = "discovery happened but no deliverable or explicit blocker is recorded";
566213
+ lastCompletionGateFeedback = gate.content;
565731
566214
  messages2.push({ role: "system", content: gate.content });
565732
566215
  this.emit({
565733
566216
  type: "status",
@@ -565737,6 +566220,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565737
566220
  });
565738
566221
  return true;
565739
566222
  };
566223
+ let lastCompletionGateReason = "";
566224
+ let lastCompletionGateFeedback = "";
565740
566225
  const holdProvenanceTaskComplete = (args, turn) => {
565741
566226
  const proposedSummary = extractTaskCompleteSummary(args);
565742
566227
  const lastAssistantText = (() => {
@@ -565756,6 +566241,8 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565756
566241
  });
565757
566242
  if (gate.proceed)
565758
566243
  return false;
566244
+ lastCompletionGateReason = gate.reason;
566245
+ lastCompletionGateFeedback = gate.feedback;
565759
566246
  messages2.push({
565760
566247
  role: "system",
565761
566248
  content: gate.feedback
@@ -565798,13 +566285,31 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565798
566285
  this._completionHoldState.count = 1;
565799
566286
  }
565800
566287
  if (this._completionHoldState.count >= completionHoldEscapeMax) {
566288
+ const proposedSummary = extractTaskCompleteSummary(args) || "(no summary)";
566289
+ const reason = lastCompletionGateReason || "required completion evidence is still missing";
566290
+ const evidenceFeedback = lastCompletionGateFeedback ? lastCompletionGateFeedback.trim().slice(0, 4e3) : "No additional gate details were recorded.";
566291
+ const incompleteSummary = [
566292
+ "INCOMPLETE_VERIFICATION: completion was requested repeatedly, but required evidence is still missing.",
566293
+ "",
566294
+ `Attempted summary: ${proposedSummary}`,
566295
+ "",
566296
+ "Not verified / blocked:",
566297
+ reason,
566298
+ "",
566299
+ "Evidence:",
566300
+ evidenceFeedback
566301
+ ].join("\n");
566302
+ this._completionIncompleteVerification = {
566303
+ reason,
566304
+ summary: incompleteSummary
566305
+ };
565801
566306
  messages2.push({
565802
566307
  role: "system",
565803
- content: `[COMPLETION GATE ESCAPE] task_complete was held ${this._completionHoldState.count} times for the same summary without new progress. The gate feedback above is not being acted on, so completion is now ALLOWED to avoid a stall/mode-collapse loop. If the summary lacks evidence, that limitation stands in the final result.`
566308
+ content: `[INCOMPLETE VERIFICATION TERMINAL STATE] task_complete was held ${this._completionHoldState.count} times for the same summary without new evidence. The run is ending as incomplete_verification, not completed. Report the missing evidence plainly.`
565804
566309
  });
565805
566310
  this.emit({
565806
566311
  type: "status",
565807
- content: `completion gates yielding after ${this._completionHoldState.count} repeated holds to prevent a mode-collapse loop`,
566312
+ content: `completion gates ended run as incomplete_verification after ${this._completionHoldState.count} repeated holds: ${reason}`,
565808
566313
  turn,
565809
566314
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
565810
566315
  });
@@ -565812,9 +566317,9 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565812
566317
  type: "adversary_reaction",
565813
566318
  adversary: {
565814
566319
  class: "guidance",
565815
- shortText: "Completion gate escape (anti-loop)",
566320
+ shortText: "Completion gate terminal incomplete",
565816
566321
  confidence: 0.9,
565817
- details: `Same task_complete summary held ${this._completionHoldState.count}× failing open to terminate the run.`
566322
+ details: `Same task_complete summary held ${this._completionHoldState.count}x; ending incomplete_verification instead of completing.`
565818
566323
  },
565819
566324
  turn,
565820
566325
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -565830,11 +566335,11 @@ TASK: ${scrubbedTask}` : scrubbedTask;
565830
566335
  role: "system",
565831
566336
  content: `${feedback}
565832
566337
 
565833
- [ADVISORY ONLY] Backward-pass critique is non-blocking; do not treat this as a tool failure or completion refusal.`
566338
+ [COMPLETION BLOCKED] Backward-pass critique requested changes. Continue the work, gather evidence, then call task_complete again only after addressing it.`
565834
566339
  });
565835
566340
  this.emit({
565836
566341
  type: "status",
565837
- content: "backward-pass critique emitted without blocking completion",
566342
+ content: "backward-pass critique blocked completion",
565838
566343
  turn,
565839
566344
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
565840
566345
  });
@@ -568005,7 +568510,7 @@ Corrective action: try a different approach first: read relevant files, adjust a
568005
568510
  } else if (tool.parameters && typeof tool.parameters === "object") {
568006
568511
  const required = tool.parameters.required;
568007
568512
  if (Array.isArray(required)) {
568008
- const missing = required.filter((field) => tc.arguments[field] === void 0 || tc.arguments[field] === null);
568513
+ const missing = required.filter((field2) => tc.arguments[field2] === void 0 || tc.arguments[field2] === null);
568009
568514
  if (missing.length > 0) {
568010
568515
  validationError = `Missing required parameter(s): ${missing.join(", ")}`;
568011
568516
  }
@@ -569387,11 +569892,17 @@ ${sr.result.output}`;
569387
569892
  });
569388
569893
  } else {
569389
569894
  if (holdTaskCompleteGates(matchTc.arguments, turn)) {
569895
+ if (this._completionIncompleteVerification)
569896
+ break;
569390
569897
  continue;
569391
569898
  }
569392
- const _bp1 = await this._runBackwardPassReview(turn);
569393
- if (_bp1 && !_bp1.proceed && _bp1.feedback) {
569394
- emitBackwardPassAdvisory(_bp1.feedback, turn);
569899
+ const _bp1 = await this._runBackwardPassReview(turn, toolCallLog, extractTaskCompleteSummary(matchTc.arguments));
569900
+ if (_bp1 && !_bp1.proceed) {
569901
+ if (_bp1.feedback)
569902
+ emitBackwardPassAdvisory(_bp1.feedback, turn);
569903
+ if (this._completionIncompleteVerification)
569904
+ break;
569905
+ continue;
569395
569906
  }
569396
569907
  completed = true;
569397
569908
  summary = extractTaskCompleteSummary(matchTc.arguments);
@@ -569410,7 +569921,7 @@ ${sr.result.output}`;
569410
569921
  }
569411
569922
  }
569412
569923
  }
569413
- if (!completed) {
569924
+ if (!completed && !this._completionIncompleteVerification) {
569414
569925
  const unhandled = rawToolCalls.filter((tc) => !handledIds.has(tc.id));
569415
569926
  for (const tc of unhandled) {
569416
569927
  if (this.aborted)
@@ -569442,11 +569953,17 @@ ${sr.result.output}`;
569442
569953
  });
569443
569954
  } else {
569444
569955
  if (holdTaskCompleteGates(r2.tc.arguments, turn)) {
569956
+ if (this._completionIncompleteVerification)
569957
+ break;
569445
569958
  continue;
569446
569959
  }
569447
- const _bp2 = await this._runBackwardPassReview(turn);
569448
- if (_bp2 && !_bp2.proceed && _bp2.feedback) {
569449
- emitBackwardPassAdvisory(_bp2.feedback, turn);
569960
+ const _bp2 = await this._runBackwardPassReview(turn, toolCallLog, extractTaskCompleteSummary(r2.tc.arguments));
569961
+ if (_bp2 && !_bp2.proceed) {
569962
+ if (_bp2.feedback)
569963
+ emitBackwardPassAdvisory(_bp2.feedback, turn);
569964
+ if (this._completionIncompleteVerification)
569965
+ break;
569966
+ continue;
569450
569967
  }
569451
569968
  completed = true;
569452
569969
  summary = extractTaskCompleteSummary(r2.tc.arguments);
@@ -569534,11 +570051,17 @@ ${sr.result.output}`;
569534
570051
  });
569535
570052
  } else {
569536
570053
  if (holdTaskCompleteGates(r2.tc.arguments, turn)) {
570054
+ if (this._completionIncompleteVerification)
570055
+ break;
569537
570056
  continue;
569538
570057
  }
569539
- const _bp3 = await this._runBackwardPassReview(turn);
569540
- if (_bp3 && !_bp3.proceed && _bp3.feedback) {
569541
- emitBackwardPassAdvisory(_bp3.feedback, turn);
570058
+ const _bp3 = await this._runBackwardPassReview(turn, toolCallLog, extractTaskCompleteSummary(r2.tc.arguments));
570059
+ if (_bp3 && !_bp3.proceed) {
570060
+ if (_bp3.feedback)
570061
+ emitBackwardPassAdvisory(_bp3.feedback, turn);
570062
+ if (this._completionIncompleteVerification)
570063
+ break;
570064
+ continue;
569542
570065
  }
569543
570066
  completed = true;
569544
570067
  summary = extractTaskCompleteSummary(r2.tc.arguments);
@@ -569557,11 +570080,11 @@ ${sr.result.output}`;
569557
570080
  }
569558
570081
  }
569559
570082
  }
569560
- if (completed)
570083
+ if (completed || this._completionIncompleteVerification)
569561
570084
  break;
569562
570085
  }
569563
570086
  }
569564
- if (completed)
570087
+ if (completed || this._completionIncompleteVerification)
569565
570088
  break;
569566
570089
  this.adversaryObserve(messages2, turn);
569567
570090
  const currentRepScore = this.detectRepetition(toolCallLog);
@@ -569755,6 +570278,8 @@ Call task_complete(summary="...") NOW with whatever you have.`
569755
570278
  if (/task.?complete|all tests pass/i.test(content)) {
569756
570279
  const completionArgs = { summary: content };
569757
570280
  if (holdTaskCompleteGates(completionArgs, turn)) {
570281
+ if (this._completionIncompleteVerification)
570282
+ break;
569758
570283
  continue;
569759
570284
  }
569760
570285
  completed = true;
@@ -570326,11 +570851,17 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
570326
570851
  });
570327
570852
  } else {
570328
570853
  if (holdTaskCompleteGates(tc.arguments, turn)) {
570854
+ if (this._completionIncompleteVerification)
570855
+ break;
570329
570856
  continue;
570330
570857
  }
570331
- const _bp4 = await this._runBackwardPassReview(turn);
570332
- if (_bp4 && !_bp4.proceed && _bp4.feedback) {
570333
- emitBackwardPassAdvisory(_bp4.feedback, turn);
570858
+ const _bp4 = await this._runBackwardPassReview(turn, toolCallLog, extractTaskCompleteSummary(tc.arguments));
570859
+ if (_bp4 && !_bp4.proceed) {
570860
+ if (_bp4.feedback)
570861
+ emitBackwardPassAdvisory(_bp4.feedback, turn);
570862
+ if (this._completionIncompleteVerification)
570863
+ break;
570864
+ continue;
570334
570865
  }
570335
570866
  completed = true;
570336
570867
  summary = extractTaskCompleteSummary(tc.arguments);
@@ -570348,7 +570879,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
570348
570879
  }
570349
570880
  }
570350
570881
  }
570351
- if (completed)
570882
+ if (completed || this._completionIncompleteVerification)
570352
570883
  break;
570353
570884
  } else {
570354
570885
  const content = msg.content || "";
@@ -570379,6 +570910,8 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
570379
570910
  } else {
570380
570911
  const completionArgs = { summary: content };
570381
570912
  if (holdTaskCompleteGates(completionArgs, turn)) {
570913
+ if (this._completionIncompleteVerification)
570914
+ break;
570382
570915
  continue;
570383
570916
  }
570384
570917
  completed = true;
@@ -570428,6 +570961,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
570428
570961
  }
570429
570962
  }
570430
570963
  const durationMs = Date.now() - start2;
570964
+ if (this._completionIncompleteVerification && !summary) {
570965
+ summary = this._completionIncompleteVerification.summary;
570966
+ }
570967
+ const runStatus = completed ? "completed" : this._completionIncompleteVerification ? "incomplete_verification" : "incomplete";
570431
570968
  this._emitMASTSummary("run-end");
570432
570969
  this.emit({
570433
570970
  type: "complete",
@@ -570479,7 +571016,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
570479
571016
  const consolidation = {
570480
571017
  sessionId: this._sessionId,
570481
571018
  task: cleanedTask.slice(0, 500),
570482
- outcome: completed ? "success" : this.aborted ? "aborted" : "timeout",
571019
+ outcome: completed ? "success" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "timeout",
570483
571020
  turns: messages2.filter((m2) => m2.role === "assistant").length,
570484
571021
  toolsUsed: [...new Set(toolCallLog.map((tc) => tc.name))],
570485
571022
  filesModified: extractPaths(toolCallLog, [
@@ -571055,7 +571592,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
571055
571592
  // training. Storing the scaffolded version would teach future models
571056
571593
  // to reproduce signpost text as part of their task understanding.
571057
571594
  task: cleanedTask.slice(0, 1e3),
571058
- outcome: completed ? "pass" : this.aborted ? "aborted" : "timeout",
571595
+ outcome: completed ? "pass" : this.aborted ? "aborted" : runStatus === "incomplete_verification" ? "incomplete_verification" : "timeout",
571059
571596
  model: this.backend.model ?? "unknown",
571060
571597
  modelTier: this.options.modelTier ?? "large",
571061
571598
  turns: messages2.filter((m2) => m2.role === "assistant").length,
@@ -571129,6 +571666,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
571129
571666
  } catch {
571130
571667
  }
571131
571668
  return {
571669
+ status: runStatus,
571132
571670
  completed,
571133
571671
  turns: messages2.filter((m2) => m2.role === "assistant").length,
571134
571672
  toolCalls: toolCallCount,
@@ -579395,11 +579933,11 @@ function isHandoffVague(handoff) {
579395
579933
  /resolved the problem/i
579396
579934
  ];
579397
579935
  const vagueFields = [handoff.salientSummary, handoff.whatWasImplemented, handoff.whatWasLeftUndone];
579398
- for (const field of vagueFields) {
579399
- if (!field)
579936
+ for (const field2 of vagueFields) {
579937
+ if (!field2)
579400
579938
  continue;
579401
579939
  for (const pattern of vaguePatterns) {
579402
- if (pattern.test(field) && field.length < 100) {
579940
+ if (pattern.test(field2) && field2.length < 100) {
579403
579941
  return true;
579404
579942
  }
579405
579943
  }
@@ -580523,6 +581061,8 @@ __export(dist_exports3, {
580523
581061
  clearTurnState: () => clearTurnState,
580524
581062
  combineValidatorResults: () => combineValidatorResults,
580525
581063
  compilePersonalityPrompt: () => compilePersonalityPrompt,
581064
+ completionContractIssues: () => completionContractIssues,
581065
+ completionEvidenceSatisfied: () => completionEvidenceSatisfied,
580526
581066
  computeStabilityHash: () => computeStabilityHash,
580527
581067
  computeTodoReminder: () => computeTodoReminder,
580528
581068
  createAppState: () => createAppState,
@@ -580542,6 +581082,7 @@ __export(dist_exports3, {
580542
581082
  extractLessons: () => extractLessons,
580543
581083
  extractMidTaskSteeringInput: () => extractMidTaskSteeringInput,
580544
581084
  extractTaskCompleteSummary: () => extractTaskCompleteSummary,
581085
+ formatCompletionContract: () => formatCompletionContract,
580545
581086
  formatHermesToolResponse: () => formatHermesToolResponse,
580546
581087
  generateAssertionId: () => generateAssertionId,
580547
581088
  generateFeatureId: () => generateFeatureId,
@@ -580568,6 +581109,8 @@ __export(dist_exports3, {
580568
581109
  getSidecarPath: () => getSidecarPath,
580569
581110
  getStartupOrder: () => getStartupOrder,
580570
581111
  getStateSummary: () => getStateSummary,
581112
+ inferCompletionContract: () => inferCompletionContract,
581113
+ inferCompletionContractFromTexts: () => inferCompletionContractFromTexts,
580571
581114
  initializeValidationState: () => initializeValidationState,
580572
581115
  interpretSteeringIngress: () => interpretSteeringIngress,
580573
581116
  isConcurrencySafe: () => isConcurrencySafe,
@@ -580578,6 +581121,7 @@ __export(dist_exports3, {
580578
581121
  loadMemoryWeightingConfig: () => loadMemoryWeightingConfig,
580579
581122
  loadStabilityIndex: () => loadStabilityIndex,
580580
581123
  materializeMemoryItems: () => materializeMemoryItems,
581124
+ normalizeCompletionKey: () => normalizeCompletionKey,
580581
581125
  parseCritique: () => parseCritique,
580582
581126
  parseMetaCritique: () => parseMetaCritique,
580583
581127
  parsePlan: () => parsePlan,
@@ -580677,6 +581221,7 @@ var init_dist8 = __esm({
580677
581221
  init_skill_fork();
580678
581222
  init_missionSystem();
580679
581223
  init_specDecomposer();
581224
+ init_completionContract();
580680
581225
  init_streaming_executor();
580681
581226
  init_app_state();
580682
581227
  init_textSanitize();
@@ -601181,10 +601726,10 @@ ${CONTENT_BG_SEQ}`);
601181
601726
  let removed = false;
601182
601727
  const start2 = Math.max(0, this._contentLines.length - maxRecentLines);
601183
601728
  for (let i2 = this._contentLines.length - 1; i2 >= start2; i2--) {
601184
- const haystack = normalize2(this._contentLines[i2] ?? "");
601185
- if (haystack.length < 12) continue;
601186
- const shortHaystack = haystack.slice(0, Math.min(40, haystack.length));
601187
- if (haystack.includes(shortNeedle) || needle.includes(shortHaystack)) {
601729
+ const haystack2 = normalize2(this._contentLines[i2] ?? "");
601730
+ if (haystack2.length < 12) continue;
601731
+ const shortHaystack = haystack2.slice(0, Math.min(40, haystack2.length));
601732
+ if (haystack2.includes(shortNeedle) || needle.includes(shortHaystack)) {
601188
601733
  this._contentLines.splice(i2, 1);
601189
601734
  removed = true;
601190
601735
  }
@@ -621021,8 +621566,8 @@ sleep 1
621021
621566
  });
621022
621567
  items.push({
621023
621568
  key: "__kill__",
621024
- label: "Kill Omnius schedulers + active runs",
621025
- detail: "Stop scheduler/nexus processes and terminate active Omnius runs"
621569
+ label: "Stop registered schedulers + active runs",
621570
+ detail: "Disable scheduler sources and stop registry-owned Omnius runs"
621026
621571
  });
621027
621572
  const result = await tuiSelect({
621028
621573
  items,
@@ -621386,7 +621931,7 @@ sleep 1
621386
621931
  body: JSON.stringify({}),
621387
621932
  headers: { "Content-Type": "application/json" }
621388
621933
  });
621389
- renderInfo("Kill signal sent to Omnius scheduler processes.");
621934
+ renderInfo("Scheduler sources disabled and registered scheduler leases stopped where verified.");
621390
621935
  } catch (e2) {
621391
621936
  renderError(e2?.message || String(e2));
621392
621937
  }
@@ -640874,7 +641419,7 @@ var init_component_benefit = __esm({
640874
641419
  }
640875
641420
  /** Record one batch — for each sampled component, did the decision text reference its needle? */
640876
641421
  recordOutcome(chatKey, samples, decisionText) {
640877
- const haystack = decisionText.toLowerCase();
641422
+ const haystack2 = decisionText.toLowerCase();
640878
641423
  let map2 = this._byChat.get(chatKey);
640879
641424
  if (!map2) {
640880
641425
  map2 = /* @__PURE__ */ new Map();
@@ -640883,7 +641428,7 @@ var init_component_benefit = __esm({
640883
641428
  const now = Date.now();
640884
641429
  for (const sample of samples) {
640885
641430
  const needle = sample.needle.toLowerCase();
640886
- const hit = needle.length >= 3 && haystack.includes(needle);
641431
+ const hit = needle.length >= 3 && haystack2.includes(needle);
640887
641432
  let st = map2.get(sample.key);
640888
641433
  if (!st) {
640889
641434
  st = { score: 0.5, samples: 0, hits: 0, lastSeenAt: now };
@@ -645279,6 +645824,31 @@ function adaptTool5(tool, todoSessionId, progress) {
645279
645824
  }
645280
645825
  });
645281
645826
  }
645827
+ function normalizeTelegramImageAnalyzeDetail(value2) {
645828
+ const raw = String(value2 ?? "auto").trim().toLowerCase();
645829
+ return raw === "text" || raw === "visual" || raw === "full" ? raw : "auto";
645830
+ }
645831
+ function stripTelegramImagePayloadMarkers(value2) {
645832
+ return value2.replace(/\n?\[IMAGE_BASE64:[^\]]+\]/g, "\n[IMAGE_BASE64 omitted from display]");
645833
+ }
645834
+ function truncateTelegramStageOutput(value2, maxChars = 3500) {
645835
+ const clean5 = stripTelegramImagePayloadMarkers(value2).replace(/\n{3,}/g, "\n\n").trim();
645836
+ if (clean5.length <= maxChars) return clean5;
645837
+ return `${clean5.slice(0, maxChars).trimEnd()}
645838
+ ... (${clean5.length - maxChars} more chars omitted)`;
645839
+ }
645840
+ function telegramTextExtractionSignal(text) {
645841
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
645842
+ const chars = text.replace(/\s+/g, "").length;
645843
+ const longestLine = lines.reduce((max, line) => Math.max(max, line.length), 0);
645844
+ return {
645845
+ chars,
645846
+ lines: lines.length,
645847
+ longestLine,
645848
+ dense: chars >= 700 || lines.length >= 8 || longestLine >= 140,
645849
+ present: chars >= 8
645850
+ };
645851
+ }
645282
645852
  function telegramBotAccessSettingsFromApi(settings) {
645283
645853
  return {
645284
645854
  isAccessRestricted: Boolean(settings.is_access_restricted),
@@ -645414,7 +645984,7 @@ function renderTelegramSubAgentError(username, error) {
645414
645984
  const preview = error.length > 80 ? error.slice(0, 77) + "..." : error;
645415
645985
  renderTelegramCoalescedRow(`${c3.red("✘")} ${c3.bold(`@${username}`)}: ${c3.dim(preview)}`);
645416
645986
  }
645417
- var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTATING_GROUPS, DEFAULT_TELEGRAM_TOOL_GROUP_POLICY, TELEGRAM_TOOL_BUTTON_LABELS, TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, TELEGRAM_PUBLIC_VISION_STACK_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_EXTERNAL_ACQUISITION_CONTRACT, TELEGRAM_LINK_INTEGRITY_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA, TELEGRAM_INTERACTION_DECISION_REPAIR_SCHEMA, TELEGRAM_CHAT_REPLY_RESPONSE_FORMAT, TELEGRAM_SPACED_URL_RE, TELEGRAM_HTTP_URL_RE, TELEGRAM_STUCK_SELF_TALK_PREFIXES, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_ASSOCIATIVE_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_USER_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_ACTION_LIMIT, TELEGRAM_ASSOCIATIVE_RELATION_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_MEMORY_GENERIC_QUERY_TOKENS, TELEGRAM_SUB_AGENT_BOUNDED_OPTIONS, TELEGRAM_PUBLIC_FAST_OPTIONS, TELEGRAM_ADMIN_EVIDENCE_OPTIONS, TELEGRAM_SUB_AGENT_DEFAULT_LIMIT, TELEGRAM_SUB_AGENT_MAX_LIMIT, TELEGRAM_SUB_AGENT_BURST_CONTEXT_LIMIT, TELEGRAM_ADMIN_LIVE_PANEL_PAGES, TELEGRAM_ADMIN_LIVE_MUTATION_TOOLS, TELEGRAM_PUBLIC_HELP_COMMANDS2, TELEGRAM_REMINDER_SLASH_COMMANDS, TELEGRAM_REFLECTION_SLASH_COMMANDS, TELEGRAM_PUBLIC_BOT_COMMAND_NAMES, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TELEGRAM_CHANNEL_DMN_SWEEP_MS, TELEGRAM_CHANNEL_DMN_IDLE_AFTER_MS, TELEGRAM_CHANNEL_DMN_MIN_INTERVAL_MS, TELEGRAM_CHANNEL_DMN_MIN_MESSAGES, TELEGRAM_ALLOWED_UPDATES, TELEGRAM_DEFAULT_LONG_POLL_TIMEOUT_SECONDS, TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
645987
+ var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTATING_GROUPS, DEFAULT_TELEGRAM_TOOL_GROUP_POLICY, TELEGRAM_TOOL_BUTTON_LABELS, TELEGRAM_SAFETY_PROMPT, ADMIN_DM_PROMPT, ADMIN_GROUP_PROMPT, TELEGRAM_PUBLIC_SOUL_PROFILE, TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT, TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT, TELEGRAM_PUBLIC_VISION_STACK_CONTRACT, TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT, GROUP_REPLY_DISCRETION_PROMPT, TELEGRAM_CHAT_MODE_PROMPT, ADMIN_CHAT_PROFILE_PROMPT, TELEGRAM_ACTION_RESPONSE_CONTRACT, TELEGRAM_EXTERNAL_ACQUISITION_CONTRACT, TELEGRAM_LINK_INTEGRITY_CONTRACT, TELEGRAM_INTERACTION_DECISION_RESPONSE_FORMAT, TELEGRAM_INTERACTION_DECISION_MINIMAL_SCHEMA, TELEGRAM_INTERACTION_DECISION_REPAIR_SCHEMA, TELEGRAM_CHAT_REPLY_RESPONSE_FORMAT, TELEGRAM_SPACED_URL_RE, TELEGRAM_HTTP_URL_RE, TELEGRAM_STUCK_SELF_TALK_PREFIXES, TELEGRAM_CHAT_HISTORY_LIMIT, TELEGRAM_CONTEXT_RECENT_DEFAULT, TELEGRAM_CONTEXT_LINE_LIMIT, TELEGRAM_CONTEXT_SAMPLE_LIMIT, TELEGRAM_MEMORY_CARD_LIMIT, TELEGRAM_MEMORY_NOTE_LIMIT, TELEGRAM_ASSOCIATIVE_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_USER_FACT_LIMIT, TELEGRAM_ASSOCIATIVE_ACTION_LIMIT, TELEGRAM_ASSOCIATIVE_RELATION_LIMIT, TELEGRAM_MEMORY_STOPWORDS, TELEGRAM_MEMORY_GENERIC_QUERY_TOKENS, TELEGRAM_SUB_AGENT_BOUNDED_OPTIONS, TELEGRAM_PUBLIC_FAST_OPTIONS, TELEGRAM_ADMIN_EVIDENCE_OPTIONS, TELEGRAM_SUB_AGENT_DEFAULT_LIMIT, TELEGRAM_SUB_AGENT_MAX_LIMIT, TELEGRAM_SUB_AGENT_BURST_CONTEXT_LIMIT, TELEGRAM_ADMIN_LIVE_PANEL_PAGES, TELEGRAM_ADMIN_LIVE_MUTATION_TOOLS, TELEGRAM_PUBLIC_HELP_COMMANDS2, TELEGRAM_REMINDER_SLASH_COMMANDS, TELEGRAM_REFLECTION_SLASH_COMMANDS, TELEGRAM_PUBLIC_BOT_COMMAND_NAMES, TELEGRAM_IMAGE_EXTENSIONS, MEDIA_CACHE_TTL_MS, TELEGRAM_CHANNEL_DMN_SWEEP_MS, TELEGRAM_CHANNEL_DMN_IDLE_AFTER_MS, TELEGRAM_CHANNEL_DMN_MIN_INTERVAL_MS, TELEGRAM_CHANNEL_DMN_MIN_MESSAGES, TELEGRAM_ALLOWED_UPDATES, TELEGRAM_DEFAULT_LONG_POLL_TIMEOUT_SECONDS, TELEGRAM_ROUTER_AUTO_MIN_PARAMETERS_B, TELEGRAM_PUBLIC_TOOL_QUOTAS, TelegramBridge;
645418
645988
  var init_telegram_bridge = __esm({
645419
645989
  "packages/cli/src/tui/telegram-bridge.ts"() {
645420
645990
  "use strict";
@@ -645630,12 +646200,21 @@ Public Telegram vision and media stack
645630
646200
 
645631
646201
  Public Telegram runs have the full scoped media-analysis stack for media posted in this chat:
645632
646202
  - Use telegram_media_recent to find recent scoped media, then use path/media aliases 'reply' and 'latest' instead of exposing local paths to users.
645633
- - Use ocr_image_advanced for complex textual imagery: screenshots, dense documents, forms, receipts, scans, diagrams with labels, low-contrast photos, or uneven lighting.
645634
- - Use ocr for quick image text extraction, image_read for image metadata + OCR + multimodal image payload, and vision for captioning, visual QA, object detection, or pointing.
646203
+ - For image questions, prefer telegram_image_analyze first. It resolves omitted/reply/latest media, starts with low-fidelity image intake, uses basic OCR as the text extraction probe, escalates to advanced OCR when text is dense or under-extracted, and escalates to Moondream vision when visual QA/captioning is needed.
646204
+ - Use ocr for quick image text extraction, ocr_image_advanced when basic OCR shows dense or degraded text, image_read for image metadata + multimodal image payload, and vision for direct Moondream captioning, visual QA, object detection, or pointing.
645635
646205
  - Use pdf_to_text for embedded-text PDFs and ocr_pdf for scanned PDFs.
645636
646206
  - Use video_understand and transcribe_file for video/audio media posted in this chat.
645637
646207
  - Use identity_memory for explicit user-provided identity assertions, staged next-image names, and "who is this?" recall from scoped media. Do not guess real identities from images.
645638
646208
  - These tools are current-chat scoped. Never inspect arbitrary local files, reveal local paths, or claim access to media outside this Telegram chat scope.
646209
+ `.trim();
646210
+ TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT = `
646211
+ Evidence sufficiency contract
646212
+
646213
+ - Before making a factual claim, identify whether the answer is already supported by the supplied Telegram context, scoped memory, attached media extraction, or fresh tool/web evidence.
646214
+ - Use action/tools when the answer depends on current or recent external facts, volatile public events, named people or organizations in news-like claims, media extraction, source verification, or the user's wording asks you to find/check/look up something.
646215
+ - Quick-chat may answer only when the reply is conversational, based on supplied context, or based on stable common knowledge that is unlikely to have changed.
646216
+ - If a media tool call fails or lacks an argument, recover through telegram_image_analyze, telegram_media_recent, or the reply/latest aliases before telling the user you cannot inspect the media.
646217
+ - Do not fill evidence gaps with plausible memory. If evidence is missing and tools are unavailable, say what is missing instead of fabricating.
645639
646218
  `.trim();
645640
646219
  GROUP_REPLY_DISCRETION_PROMPT = `
645641
646220
  Reply discretion: you are in a group chat. The live router selected this turn
@@ -649477,6 +650056,31 @@ ${mediaContext}` : ""
649477
650056
  }
649478
650057
  return true;
649479
650058
  }
650059
+ telegramScopedMediaParameters(parameters, fields, description) {
650060
+ const base3 = parameters ?? {};
650061
+ const baseRecord = base3;
650062
+ const rawProperties = baseRecord["properties"];
650063
+ const properties = rawProperties && typeof rawProperties === "object" && !Array.isArray(rawProperties) ? { ...rawProperties } : {};
650064
+ for (const field2 of fields) {
650065
+ const property = properties[field2];
650066
+ if (property && typeof property === "object" && !Array.isArray(property)) {
650067
+ const currentDescription = typeof property["description"] === "string" ? String(property["description"]) : "";
650068
+ properties[field2] = {
650069
+ ...property,
650070
+ description: [currentDescription, description].filter(Boolean).join(" ")
650071
+ };
650072
+ }
650073
+ }
650074
+ const required = Array.isArray(baseRecord["required"]) ? baseRecord["required"].filter((item) => typeof item === "string" && !fields.includes(item)) : void 0;
650075
+ const rest = { ...baseRecord };
650076
+ delete rest["properties"];
650077
+ delete rest["required"];
650078
+ return {
650079
+ ...rest,
650080
+ properties,
650081
+ ...required && required.length > 0 ? { required } : {}
650082
+ };
650083
+ }
649480
650084
  resolveTelegramScopedMediaPath(rawValue, chatId, currentMsg, kind) {
649481
650085
  const raw = String(rawValue ?? "").trim();
649482
650086
  const repoRoot = this.repoRoot || ".";
@@ -650671,6 +651275,7 @@ ${lines.join("\n")}`);
650671
651275
  toolContext,
650672
651276
  authorityContext: [
650673
651277
  baseContract,
651278
+ TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT,
650674
651279
  TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT,
650675
651280
  TELEGRAM_PUBLIC_VISION_STACK_CONTRACT
650676
651281
  ].join("\n\n"),
@@ -651578,10 +652183,10 @@ ${retryText}`,
651578
652183
  })).filter((model) => Boolean(model.name)) : [];
651579
652184
  }
651580
652185
  telegramModelParameterBillions(model) {
651581
- const haystack = `${model.name} ${model.parameterSize ?? ""}`.toLowerCase();
651582
- const billion = haystack.match(/(\d+(?:\.\d+)?)\s*(?:b|bn)\b/);
652186
+ const haystack2 = `${model.name} ${model.parameterSize ?? ""}`.toLowerCase();
652187
+ const billion = haystack2.match(/(\d+(?:\.\d+)?)\s*(?:b|bn)\b/);
651583
652188
  if (billion) return Number(billion[1]);
651584
- const million = haystack.match(/(\d+(?:\.\d+)?)\s*m\b/);
652189
+ const million = haystack2.match(/(\d+(?:\.\d+)?)\s*m\b/);
651585
652190
  if (million) return Number(million[1]) / 1e3;
651586
652191
  return null;
651587
652192
  }
@@ -651844,6 +652449,8 @@ ${stimulationProbe.context}`,
651844
652449
  `- chat: a short conversational answer can be produced without tools.`,
651845
652450
  `- action: tools, workspace context, media processing, web lookup, delegation, or a multi-step agent loop may be needed.`,
651846
652451
  `Route discipline: infer whether the current request can be completed as immediate conversation or needs an external capability. Do not route from keyword categories.`,
652452
+ `Evidence sufficiency: choose chat only when the answer is supported by supplied Telegram context, scoped memory, attached media context, or stable common knowledge. Choose action when answering would require web lookup, media extraction, current/recent public facts, named person/organization/news verification, or tool recovery.`,
652453
+ `Do not answer volatile external claims from model memory on the fast path. Route to action so web/media tools can gather evidence.`,
651847
652454
  ``,
651848
652455
  `Reply discretion: make a human-like attention decision from the full social context. Observe the message, relationship stream, reply graph, conversation momentum, prior bot involvement, speaker intent, and notification-like signals, then decide whether a visible reply would be natural.`,
651849
652456
  `No hard triggers: direct address, @mentions, name/identity references, private-chat delivery, replies, active threads, and stimulation score are evidence only. They may raise or lower salience, but none guarantees should_reply=true or should_reply=false.`,
@@ -652359,6 +652966,7 @@ Profile: ${profile}
652359
652966
  Tool context: ${toolContext}
652360
652967
  ${chatLabel}`,
652361
652968
  TELEGRAM_ACTION_RESPONSE_CONTRACT,
652969
+ TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT,
652362
652970
  TELEGRAM_LINK_INTEGRITY_CONTRACT
652363
652971
  ];
652364
652972
  sections.push(conversationStream);
@@ -652392,6 +653000,8 @@ ${TELEGRAM_PUBLIC_SOUL_PROFILE}
652392
653000
 
652393
653001
  ${TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT}
652394
653002
 
653003
+ ${TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT}
653004
+
652395
653005
  ${TELEGRAM_PUBLIC_VISION_STACK_CONTRACT}
652396
653006
 
652397
653007
  ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
@@ -652404,6 +653014,8 @@ ${TELEGRAM_PUBLIC_SOUL_PROFILE}
652404
653014
 
652405
653015
  ${TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT}
652406
653016
 
653017
+ ${TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT}
653018
+
652407
653019
  ${TELEGRAM_PUBLIC_VISION_STACK_CONTRACT}
652408
653020
 
652409
653021
  ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
@@ -653041,7 +653653,9 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
653041
653653
  return state.messageId ?? null;
653042
653654
  }
653043
653655
  telegramAdminRunCompleted(subAgent) {
653044
- return subAgent.runnerCompleted === true || subAgent.completionBoundarySeen;
653656
+ if (subAgent.runnerStatus === "incomplete_verification") return false;
653657
+ if (subAgent.runnerStatus === "completed") return true;
653658
+ return subAgent.runnerCompleted === true;
653045
653659
  }
653046
653660
  telegramAdminLastRunSignals(subAgent) {
653047
653661
  const state = subAgent.adminLivePanelNonce ? this.telegramAdminLivePanels.get(subAgent.adminLivePanelNonce) : void 0;
@@ -653060,18 +653674,49 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`);
653060
653674
  ].filter(Boolean).join(", ");
653061
653675
  const summary = cleanTelegramVisibleReply(subAgent.runnerSummary || "");
653062
653676
  const signals = this.telegramAdminLastRunSignals(subAgent);
653677
+ const verificationIncomplete = subAgent.runnerStatus === "incomplete_verification";
653063
653678
  const parts = [
653064
- `INCOMPLETE: admin run exited before task_complete${stats ? ` after ${stats}` : ""}.`,
653065
- "This is not a completed task. The run should be resumed or retried; no successful completion boundary was observed.",
653066
- signals ? `Last observed tool/status:
653067
- ${signals}` : "",
653068
- finalText ? `Last visible draft:
653069
- ${finalText}` : "",
653070
- summary ? `Runner summary:
653071
- ${summary}` : ""
653679
+ `Done:
653680
+ No completed result.`,
653681
+ `Verified:
653682
+ ${verificationIncomplete ? `INCOMPLETE_VERIFICATION: admin run stopped with missing completion evidence${stats ? ` after ${stats}` : ""}.` : `INCOMPLETE: admin run exited before task_complete${stats ? ` after ${stats}` : ""}.`}`,
653683
+ `Not verified / blocked:
653684
+ ${verificationIncomplete ? "Required verification evidence was still missing after repeated completion attempts." : "No successful completion boundary was observed."}${summary ? `
653685
+
653686
+ Runner summary:
653687
+ ${summary}` : ""}${finalText ? `
653688
+
653689
+ Last visible draft:
653690
+ ${finalText}` : ""}`,
653691
+ `Evidence:
653692
+ ${signals || "No final validating tool/status signal was available."}`
653072
653693
  ].filter(Boolean);
653073
653694
  return parts.join("\n\n");
653074
653695
  }
653696
+ telegramAdminCompletionRunText(subAgent, finalText) {
653697
+ const summary = cleanTelegramVisibleReply(subAgent.runnerSummary || "");
653698
+ const signals = this.telegramAdminLastRunSignals(subAgent);
653699
+ const stats = [
653700
+ typeof subAgent.runnerTurns === "number" ? `${subAgent.runnerTurns} turn(s)` : "",
653701
+ typeof subAgent.runnerToolCalls === "number" ? `${subAgent.runnerToolCalls} tool call(s)` : ""
653702
+ ].filter(Boolean).join(", ");
653703
+ const done = finalText || summary || "Run completed.";
653704
+ const verified = [
653705
+ `Backend status: ${subAgent.runnerStatus || (subAgent.runnerCompleted ? "completed" : "unknown")}.`,
653706
+ stats ? `Run shape: ${stats}.` : "",
653707
+ summary && summary !== finalText ? `Runner summary: ${summary}` : ""
653708
+ ].filter(Boolean).join("\n");
653709
+ return [
653710
+ `Done:
653711
+ ${done}`,
653712
+ `Verified:
653713
+ ${verified || "Completion boundary observed."}`,
653714
+ `Not verified / blocked:
653715
+ None reported by the runner.`,
653716
+ `Evidence:
653717
+ ${signals || summary || "Canonical runner status reported completed."}`
653718
+ ].join("\n\n");
653719
+ }
653075
653720
  pruneTelegramContextExplorers() {
653076
653721
  const now = Date.now();
653077
653722
  for (const [id, state] of this.telegramContextExplorerStates) {
@@ -653723,6 +654368,18 @@ Join: ${newUrl}`);
653723
654368
  return;
653724
654369
  }
653725
654370
  if (!finalText) {
654371
+ if (isAdminDM && this.telegramAdminRunCompleted(subAgent)) {
654372
+ const deliveredFinalText2 = this.telegramAdminCompletionRunText(subAgent, "");
654373
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${deliveredFinalText2}`);
654374
+ this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
654375
+ if (!msg.guestQueryId) {
654376
+ await this.finalizeTelegramAdminLivePanel(subAgent, msg, deliveredFinalText2, "completed");
654377
+ } else if (subAgent.liveMessageId) {
654378
+ await this.deleteLiveMessage(msg.chatId, subAgent.liveMessageId).catch(() => {
654379
+ });
654380
+ }
654381
+ return;
654382
+ }
653726
654383
  if (msg.chatType !== "private") {
653727
654384
  this.maybeLogTelegramGroupSkip(msg, "discretion: skipped reply");
653728
654385
  } else {
@@ -653742,17 +654399,18 @@ Join: ${newUrl}`);
653742
654399
  await subAgent.liveMessagePromise.catch(() => {
653743
654400
  });
653744
654401
  }
653745
- const finalHtml = convertMarkdownToTelegramHTML(finalText);
653746
- const contextExplorerState = !isAdminDM && msg.chatType !== "private" && !msg.guestQueryId ? this.buildTelegramContextExplorerState(msg, subAgent, finalHtml, finalText) : null;
654402
+ const deliveredFinalText = isAdminDM ? this.telegramAdminCompletionRunText(subAgent, finalText) : finalText;
654403
+ const finalHtml = convertMarkdownToTelegramHTML(deliveredFinalText);
654404
+ const contextExplorerState = !isAdminDM && msg.chatType !== "private" && !msg.guestQueryId ? this.buildTelegramContextExplorerState(msg, subAgent, finalHtml, deliveredFinalText) : null;
653747
654405
  const contextExplorerReplyMarkup = contextExplorerState ? this.telegramContextExplorerReplyMarkup(contextExplorerState.id) : void 0;
653748
- const sentMessageId = isAdminDM && !msg.guestQueryId ? await this.finalizeTelegramAdminLivePanel(subAgent, msg, finalText, "completed") : await this.sendOrEditFinalTelegramHTML(msg, finalHtml, subAgent.liveMessageId, contextExplorerReplyMarkup);
654406
+ const sentMessageId = isAdminDM && !msg.guestQueryId ? await this.finalizeTelegramAdminLivePanel(subAgent, msg, deliveredFinalText, "completed") : await this.sendOrEditFinalTelegramHTML(msg, finalHtml, subAgent.liveMessageId, contextExplorerReplyMarkup);
653749
654407
  if (contextExplorerState && sentMessageId !== null) {
653750
654408
  this.pruneTelegramContextExplorers();
653751
654409
  contextExplorerState.messageId = sentMessageId;
653752
654410
  this.telegramContextExplorerStates.set(contextExplorerState.id, contextExplorerState);
653753
654411
  }
653754
654412
  if (sentMessageId !== null || msg.guestQueryId) {
653755
- this.recordTelegramAssistantMessage(msg, finalText, subAgentProfile, {
654413
+ this.recordTelegramAssistantMessage(msg, deliveredFinalText, subAgentProfile, {
653756
654414
  messageId: sentMessageId,
653757
654415
  replyToMessageId: msg.chatType !== "private" ? msg.messageId : void 0
653758
654416
  });
@@ -653762,11 +654420,11 @@ Join: ${newUrl}`);
653762
654420
  await this.sendGeneratedArtifactsFromSubAgent(
653763
654421
  msg,
653764
654422
  subAgent,
653765
- finalText,
654423
+ deliveredFinalText,
653766
654424
  Boolean(subAgent.liveMessageId && !msg.guestQueryId)
653767
654425
  );
653768
- this.tuiWrite(() => renderTelegramSubAgentComplete(msg.username, finalText));
653769
- this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${finalText}`);
654426
+ this.tuiWrite(() => renderTelegramSubAgentComplete(msg.username, deliveredFinalText));
654427
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${deliveredFinalText}`);
653770
654428
  this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
653771
654429
  if (shouldDeferNotes) {
653772
654430
  this.deliverTelegramPostReplyNotes(
@@ -653776,7 +654434,7 @@ Join: ${newUrl}`);
653776
654434
  decision2,
653777
654435
  this.telegramMessageIdentitySalienceSignals(msg),
653778
654436
  daydreamOpportunities,
653779
- finalText
654437
+ deliveredFinalText
653780
654438
  );
653781
654439
  }
653782
654440
  } catch (err) {
@@ -653886,20 +654544,22 @@ Join: ${newUrl}`);
653886
654544
  return;
653887
654545
  }
653888
654546
  if (!finalText) {
654547
+ const deliveredFinalText2 = this.telegramAdminCompletionRunText(subAgent, "");
653889
654548
  if (!msg.guestQueryId) {
653890
- await this.finalizeTelegramAdminLivePanel(subAgent, msg, "", "completed");
654549
+ await this.finalizeTelegramAdminLivePanel(subAgent, msg, deliveredFinalText2, "completed");
653891
654550
  } else if (subAgent.liveMessageId) {
653892
654551
  await this.deleteLiveMessage(msg.chatId, subAgent.liveMessageId).catch(() => {
653893
654552
  });
653894
654553
  }
653895
- this.subAgentViewCallbacks?.onWrite(subAgent.viewId, "completed: no model reply");
654554
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${deliveredFinalText2}`);
653896
654555
  this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
653897
654556
  return;
653898
654557
  }
653899
- const finalHtml = convertMarkdownToTelegramHTML(finalText);
653900
- const sentMessageId = !msg.guestQueryId ? await this.finalizeTelegramAdminLivePanel(subAgent, msg, finalText, "completed") : await this.sendOrEditFinalTelegramHTML(msg, finalHtml, subAgent.liveMessageId);
654558
+ const deliveredFinalText = this.telegramAdminCompletionRunText(subAgent, finalText);
654559
+ const finalHtml = convertMarkdownToTelegramHTML(deliveredFinalText);
654560
+ const sentMessageId = !msg.guestQueryId ? await this.finalizeTelegramAdminLivePanel(subAgent, msg, deliveredFinalText, "completed") : await this.sendOrEditFinalTelegramHTML(msg, finalHtml, subAgent.liveMessageId);
653901
654561
  if (sentMessageId !== null || msg.guestQueryId) {
653902
- this.recordTelegramAssistantMessage(msg, finalText, "chat", {
654562
+ this.recordTelegramAssistantMessage(msg, deliveredFinalText, "chat", {
653903
654563
  messageId: sentMessageId,
653904
654564
  replyToMessageId: msg.chatType !== "private" ? msg.messageId : void 0
653905
654565
  });
@@ -653909,10 +654569,10 @@ Join: ${newUrl}`);
653909
654569
  await this.sendGeneratedArtifactsFromSubAgent(
653910
654570
  msg,
653911
654571
  subAgent,
653912
- finalText,
654572
+ deliveredFinalText,
653913
654573
  Boolean(subAgent.liveMessageId && !msg.guestQueryId)
653914
654574
  );
653915
- this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${finalText}`);
654575
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `completed: ${deliveredFinalText}`);
653916
654576
  this.subAgentViewCallbacks?.onStatus(subAgent.viewId, "completed");
653917
654577
  } catch (err) {
653918
654578
  if (subAgent.typingInterval) {
@@ -654120,6 +654780,8 @@ ${TELEGRAM_PUBLIC_VISION_STACK_CONTRACT}`;
654120
654780
  role: "system",
654121
654781
  content: `${TELEGRAM_CHAT_MODE_PROMPT}
654122
654782
 
654783
+ ${TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT}
654784
+
654123
654785
  ${TELEGRAM_LINK_INTEGRITY_CONTRACT}
654124
654786
 
654125
654787
  ## Runtime Context
@@ -654467,6 +655129,8 @@ ${GROUP_REPLY_DISCRETION_PROMPT}` : "";
654467
655129
 
654468
655130
  ${TELEGRAM_ACTION_RESPONSE_CONTRACT}
654469
655131
 
655132
+ ${TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT}
655133
+
654470
655134
  ${TELEGRAM_LINK_INTEGRITY_CONTRACT}
654471
655135
 
654472
655136
  ${TELEGRAM_EXTERNAL_ACQUISITION_CONTRACT}
@@ -654483,7 +655147,8 @@ ${currentTelegramPrompt}`;
654483
655147
  "You can remember facts about users and retrieve them later. Durable associative memory in the prompt includes participant profiles, relationships, scoped facts, and prior actions retained across days, sessions, and Omnius updates. You also have web_search and web_fetch to look up information.",
654484
655148
  TELEGRAM_LINK_INTEGRITY_CONTRACT,
654485
655149
  "If a user explicitly states a durable preference for reply cadence/order, call telegram_preference_set. Do not infer or classify reply-mode preferences from keywords, style, tone, or task type.",
654486
- "You have the full scoped Telegram media-analysis stack by default: telegram_media_recent, image_read, ocr, ocr_image_advanced, vision, pdf_to_text, ocr_pdf, transcribe_file, video_understand, audio_analyze, and identity_memory. For complex textual imagery, screenshots, forms, scans, or dense labels, prefer ocr_image_advanced after resolving media with path='reply' or path='latest'.",
655150
+ TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT,
655151
+ "You have the full scoped Telegram media-analysis stack by default: telegram_image_analyze, telegram_media_recent, image_read, ocr, ocr_image_advanced, vision, pdf_to_text, ocr_pdf, transcribe_file, video_understand, audio_analyze, and identity_memory. For image questions, prefer telegram_image_analyze first; it resolves omitted/reply/latest media, starts with low-fidelity image intake, uses basic OCR as the text extraction probe, escalates to advanced OCR when text is dense or under-extracted, and escalates to Moondream vision when visual QA/captioning is needed.",
654487
655152
  formatIdentityMemoryContext(chatLabel || "Telegram private chat"),
654488
655153
  reminderToolContract,
654489
655154
  "If the user asks you to create an image, audio file, video, 3D/CAD model, or document artifact, create it with the scoped creative tools. Freshly generated artifacts are recorded and automatically attached to this Telegram chat when the turn completes, so do not call telegram_send_file for those same artifacts unless the user asked for a specific caption, existing/unrecorded file, or non-default target.",
@@ -654543,10 +655208,14 @@ ${creativeWorkspace}` : ""}`;
654543
655208
  };
654544
655209
  const result = await runner.run(userPrompt, systemCtx);
654545
655210
  subAgent.runnerCompleted = result.completed;
655211
+ subAgent.runnerStatus = result.status;
654546
655212
  subAgent.runnerTurns = result.turns;
654547
655213
  subAgent.runnerToolCalls = result.toolCalls;
654548
655214
  subAgent.runnerSummary = result.summary;
654549
- if (result.completed) subAgent.completionBoundarySeen = true;
655215
+ if (result.status === "completed") subAgent.completionBoundarySeen = true;
655216
+ if (result.status === "incomplete_verification") {
655217
+ subAgent.completionBoundarySeen = false;
655218
+ }
654550
655219
  return selectTelegramFinalResponse({
654551
655220
  visibleReplyText: subAgent.visibleReplyText,
654552
655221
  assistantText: subAgent.assistantText,
@@ -654769,9 +655438,9 @@ ${result.llmContent ?? result.output}` };
654769
655438
  if (effectiveUserId !== void 0 && ids.includes(effectiveUserId)) return true;
654770
655439
  const usernames = (Array.isArray(card.usernames) ? card.usernames : []).map((name10) => name10.replace(/^@/, "").toLowerCase());
654771
655440
  if (effectiveUsername && usernames.includes(effectiveUsername)) return true;
654772
- const haystack = [card.title, card.speakers.join(" "), card.notes.join(" ")].join(" ").toLowerCase();
654773
- if (effectiveUserId !== void 0 && haystack.includes(`user:${effectiveUserId}`)) return true;
654774
- if (effectiveUsername && haystack.includes(`@${effectiveUsername}`)) return true;
655441
+ const haystack2 = [card.title, card.speakers.join(" "), card.notes.join(" ")].join(" ").toLowerCase();
655442
+ if (effectiveUserId !== void 0 && haystack2.includes(`user:${effectiveUserId}`)) return true;
655443
+ if (effectiveUsername && haystack2.includes(`@${effectiveUsername}`)) return true;
654775
655444
  return false;
654776
655445
  });
654777
655446
  const queryTokens = telegramMemoryTokens(query);
@@ -654959,6 +655628,7 @@ ${lines.join("\n")}`
654959
655628
  return {
654960
655629
  ...tool,
654961
655630
  description: "Read only images from this Telegram chat's media cache or creative workspace. Use path='reply' for the replied-to image or path='latest' for the most recent chat image.",
655631
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["path"], "In Telegram scope this is optional; omit it to use the replied-to image first, otherwise the latest chat image."),
654962
655632
  execute: async (args) => {
654963
655633
  const resolved = this.resolveTelegramScopedMediaPath(args["path"], chatId, currentMsg, "image");
654964
655634
  if (!resolved.ok) return { success: false, output: "", error: resolved.error };
@@ -654970,6 +655640,7 @@ ${lines.join("\n")}`
654970
655640
  return {
654971
655641
  ...tool,
654972
655642
  description: "Extract text only from images in this Telegram chat's media cache or creative workspace. Use path='reply' or path='latest' for chat media references.",
655643
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["path"], "In Telegram scope this is optional; omit it to use the replied-to image first, otherwise the latest chat image."),
654973
655644
  execute: async (args) => {
654974
655645
  const resolved = this.resolveTelegramScopedMediaPath(args["path"], chatId, currentMsg, "image");
654975
655646
  if (!resolved.ok) return { success: false, output: "", error: resolved.error };
@@ -654981,6 +655652,7 @@ ${lines.join("\n")}`
654981
655652
  return {
654982
655653
  ...tool,
654983
655654
  description: "Analyze only images from this Telegram chat's media cache or creative workspace. Use image='reply' for the replied-to image or image='latest' for the most recent chat image.",
655655
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["image"], "In Telegram scope this is optional; omit it to use the replied-to image first, otherwise the latest chat image."),
654984
655656
  execute: async (args) => {
654985
655657
  const resolved = this.resolveTelegramScopedMediaPath(args["image"], chatId, currentMsg, "image");
654986
655658
  if (!resolved.ok) return { success: false, output: "", error: resolved.error };
@@ -654992,6 +655664,7 @@ ${lines.join("\n")}`
654992
655664
  return {
654993
655665
  ...tool,
654994
655666
  description: "Advanced OCR only for images in this Telegram chat's media cache or creative workspace. Batch directory mode is disabled in public Telegram scope.",
655667
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["image"], "In Telegram scope this is optional; omit it to use the replied-to image first, otherwise the latest chat image."),
654995
655668
  execute: async (args) => {
654996
655669
  if (args["batch"] === true) return { success: false, output: "", error: "Batch directory OCR is not available in public Telegram scope." };
654997
655670
  const resolved = this.resolveTelegramScopedMediaPath(args["image"], chatId, currentMsg, "image");
@@ -655010,6 +655683,7 @@ ${lines.join("\n")}`
655010
655683
  return {
655011
655684
  ...tool,
655012
655685
  description: "Transcribe only audio/video files from this Telegram chat's media cache or creative workspace. Use path='reply' or path='latest' for chat media references.",
655686
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["path"], "In Telegram scope this is optional; omit it to use the replied-to audio/video first, otherwise the latest transcribable chat media."),
655013
655687
  execute: async (args) => {
655014
655688
  const resolved = this.resolveTelegramScopedMediaPath(args["path"], chatId, currentMsg, "transcribable");
655015
655689
  if (!resolved.ok) return { success: false, output: "", error: resolved.error };
@@ -655021,6 +655695,7 @@ ${lines.join("\n")}`
655021
655695
  return {
655022
655696
  ...tool,
655023
655697
  description: "Extract text only from PDFs in this Telegram chat's media cache or creative workspace. Use path='reply' or path='latest' for chat document references.",
655698
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["path"], "In Telegram scope this is optional; omit it to use the replied-to PDF first, otherwise the latest chat PDF."),
655024
655699
  execute: async (args) => {
655025
655700
  const resolved = this.resolveTelegramScopedMediaPath(args["path"], chatId, currentMsg, "pdf");
655026
655701
  if (!resolved.ok) return { success: false, output: "", error: resolved.error };
@@ -655032,6 +655707,7 @@ ${lines.join("\n")}`
655032
655707
  return {
655033
655708
  ...tool,
655034
655709
  description: "OCR only PDFs from this Telegram chat's media cache or creative workspace. Output, when requested, is forced into this chat's creative workspace.",
655710
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["input"], "In Telegram scope this is optional; omit it to use the replied-to PDF first, otherwise the latest chat PDF."),
655035
655711
  execute: async (args) => {
655036
655712
  const input = this.resolveTelegramScopedMediaPath(args["input"], chatId, currentMsg, "pdf");
655037
655713
  if (!input.ok) return { success: false, output: "", error: input.error };
@@ -655049,6 +655725,7 @@ ${lines.join("\n")}`
655049
655725
  return {
655050
655726
  ...tool,
655051
655727
  description: "Analyze only video files from this Telegram chat's media cache or creative workspace. URL download is disabled in public Telegram scope; use path='reply' or path='latest'.",
655728
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["path"], "In Telegram scope this is optional; omit it to use the replied-to video first, otherwise the latest chat video."),
655052
655729
  execute: async (args) => {
655053
655730
  if (args["url"]) return { success: false, output: "", error: "URL video analysis is not available in public Telegram scope. Use a video posted in this chat." };
655054
655731
  const resolved = this.resolveTelegramScopedMediaPath(args["path"], chatId, currentMsg, "video");
@@ -655061,6 +655738,7 @@ ${lines.join("\n")}`
655061
655738
  return {
655062
655739
  ...tool,
655063
655740
  description: "Analyze only audio files from this Telegram chat's media cache or creative workspace. Microphone/listen mode is disabled in public Telegram scope.",
655741
+ parameters: this.telegramScopedMediaParameters(tool.parameters, ["file", "path"], "In Telegram scope file/path is optional; omit it to use the replied-to audio first, otherwise the latest chat audio."),
655064
655742
  execute: async (args) => {
655065
655743
  if (String(args["action"] || "").toLowerCase() === "listen") {
655066
655744
  return { success: false, output: "", error: "Continuous microphone listening is not available in Telegram public scope." };
@@ -655139,6 +655817,8 @@ ${lines.join("\n")}`
655139
655817
 
655140
655818
  ${TELEGRAM_PUBLIC_MEMORY_SCOPE_CONTRACT}
655141
655819
 
655820
+ ${TELEGRAM_EVIDENCE_SUFFICIENCY_CONTRACT}
655821
+
655142
655822
  ${TELEGRAM_PUBLIC_VISION_STACK_CONTRACT}
655143
655823
 
655144
655824
  ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}
@@ -655246,6 +655926,7 @@ Scoped workspace: ${scopedRoot}`,
655246
655926
  new WebSearchTool(),
655247
655927
  new WebCrawlTool(repoRoot),
655248
655928
  // Vision/OCR tools
655929
+ this.buildTelegramImageAnalyzeTool(repoRoot, chatId, msg),
655249
655930
  new ImageReadTool(repoRoot),
655250
655931
  new OCRTool(repoRoot),
655251
655932
  new VisionTool(repoRoot),
@@ -655304,6 +655985,7 @@ Scoped workspace: ${scopedRoot}`,
655304
655985
  new StructuredReadTool(repoRoot),
655305
655986
  new StructuredFileTool(repoRoot),
655306
655987
  new CodeSandboxTool(repoRoot),
655988
+ this.buildTelegramImageAnalyzeTool(repoRoot, chatId, msg),
655307
655989
  new ImageReadTool(repoRoot),
655308
655990
  new ScreenshotTool(repoRoot),
655309
655991
  new OCRTool(repoRoot),
@@ -655424,7 +656106,7 @@ Scoped workspace: ${scopedRoot}`,
655424
656106
  }
655425
656107
  telegramPublicQuotaKind(toolName) {
655426
656108
  if (toolName === "web_fetch") return "web";
655427
- if (/^(image_read|ocr|ocr_image_advanced|ocr_pdf|pdf_to_text|vision|transcribe_file|video_understand|audio_analyze)$/.test(toolName)) return "media";
656109
+ if (/^(telegram_image_analyze|image_read|ocr|ocr_image_advanced|ocr_pdf|pdf_to_text|vision|transcribe_file|video_understand|audio_analyze)$/.test(toolName)) return "media";
655428
656110
  if (toolName === "generate_video") return "video-generation";
655429
656111
  if (/^(generate_image|generate_audio|generate_model|generate_tts|create_audio_file)$/.test(toolName)) return "generation";
655430
656112
  if (toolName === "telegram_send_file") return "upload";
@@ -656728,11 +657410,144 @@ Scoped workspace: ${scopedRoot}`,
656728
657410
  }
656729
657411
  };
656730
657412
  }
657413
+ buildTelegramImageAnalyzeTool(repoRoot, chatId, currentMsg) {
657414
+ const bridge = this;
657415
+ return {
657416
+ name: "telegram_image_analyze",
657417
+ description: [
657418
+ "Analyze an image from the current Telegram chat using a staged evidence ladder.",
657419
+ "Omit image, or use image='reply', image='latest', message_id:<id>, or a listed basename.",
657420
+ "The tool starts with low-fidelity image intake, uses basic OCR as the text extraction probe, escalates to advanced OCR when text is dense or under-extracted, and escalates to Moondream vision for visual QA/captioning."
657421
+ ].join(" "),
657422
+ parameters: {
657423
+ type: "object",
657424
+ properties: {
657425
+ image: {
657426
+ type: "string",
657427
+ description: "Optional Telegram media reference. Omit for replied-to image first, otherwise latest image in this chat."
657428
+ },
657429
+ question: {
657430
+ type: "string",
657431
+ description: "Optional visual question to answer about the image."
657432
+ },
657433
+ detail: {
657434
+ type: "string",
657435
+ enum: ["auto", "text", "visual", "full"],
657436
+ description: "auto chooses stages from observed extraction signal; text emphasizes OCR; visual emphasizes Moondream; full runs both."
657437
+ }
657438
+ }
657439
+ },
657440
+ async execute(args) {
657441
+ const start2 = performance.now();
657442
+ const resolved = bridge.resolveTelegramScopedMediaPath(args["image"], chatId, currentMsg, "image");
657443
+ if (!resolved.ok) {
657444
+ return { success: false, output: "", error: resolved.error, durationMs: performance.now() - start2 };
657445
+ }
657446
+ const detail = normalizeTelegramImageAnalyzeDetail(args["detail"]);
657447
+ const question = String(args["question"] ?? args["prompt"] ?? currentMsg?.text ?? "").trim();
657448
+ const stageLines = [
657449
+ `Telegram image analysis: media=${basename35(resolved.path)} detail=${detail}`,
657450
+ "Stage ladder: low_fidelity_image_read -> basic OCR probe -> advanced OCR when text density/under-extraction warrants it -> Moondream vision when visual QA/captioning is warranted."
657451
+ ];
657452
+ const llmParts = [];
657453
+ const runStage = async (name10, reason, fn) => {
657454
+ const result = await fn();
657455
+ const body = result.success ? truncateTelegramStageOutput(result.output || result.llmContent || "") : `ERROR: ${result.error || result.output || "stage failed"}`;
657456
+ stageLines.push(`
657457
+ ## ${name10}
657458
+ Reason: ${reason}
657459
+ ${body}`);
657460
+ llmParts.push(`## ${name10}
657461
+ Reason: ${reason}
657462
+ ${result.llmContent ?? result.output ?? ""}${result.success ? "" : `
657463
+ ERROR: ${result.error || "stage failed"}`}`);
657464
+ return result;
657465
+ };
657466
+ const imageRead = await runStage(
657467
+ "low_fidelity_image_read",
657468
+ "Always start with scoped image metadata and a multimodal image payload for the model.",
657469
+ () => new ImageReadTool(repoRoot).execute({
657470
+ path: resolved.path,
657471
+ ocr: false,
657472
+ max_size_kb: typeof args["max_size_kb"] === "number" ? args["max_size_kb"] : 10240
657473
+ })
657474
+ );
657475
+ const textRequested = detail === "text" || detail === "full";
657476
+ const visualRequested = detail === "visual" || detail === "full";
657477
+ const shouldRunTextProbe = detail !== "visual";
657478
+ let textStage = null;
657479
+ let textSignal = telegramTextExtractionSignal("");
657480
+ if (shouldRunTextProbe) {
657481
+ textStage = await runStage(
657482
+ "ocr",
657483
+ "After low-fidelity intake, basic OCR measures whether text extraction is sufficient before any heavier escalation.",
657484
+ () => new OCRTool(repoRoot).execute({
657485
+ path: resolved.path,
657486
+ language: typeof args["language"] === "string" ? args["language"] : "eng"
657487
+ })
657488
+ );
657489
+ textSignal = telegramTextExtractionSignal(textStage.output ?? "");
657490
+ stageLines.push(
657491
+ `
657492
+ Text extraction signal: chars=${textSignal.chars}, lines=${textSignal.lines}, longest_line=${textSignal.longestLine}, dense=${textSignal.dense ? "yes" : "no"}.`
657493
+ );
657494
+ llmParts.push(`Text extraction signal: ${JSON.stringify(textSignal)}`);
657495
+ const shouldUseAdvancedOcr = detail === "full" || textSignal.dense || textRequested && !textSignal.present;
657496
+ if (shouldUseAdvancedOcr) {
657497
+ textStage = await runStage(
657498
+ "ocr_image_advanced",
657499
+ textSignal.dense ? "Basic OCR observed dense text, so multi-pass OCR is warranted." : "The request emphasized text extraction and basic intake did not provide enough text.",
657500
+ () => new OcrImageAdvancedTool(repoRoot).execute({
657501
+ image: resolved.path,
657502
+ language: typeof args["language"] === "string" ? args["language"] : "eng"
657503
+ })
657504
+ );
657505
+ const advancedSignal = telegramTextExtractionSignal(textStage.output ?? "");
657506
+ stageLines.push(
657507
+ `
657508
+ Advanced text extraction signal: chars=${advancedSignal.chars}, lines=${advancedSignal.lines}, longest_line=${advancedSignal.longestLine}, dense=${advancedSignal.dense ? "yes" : "no"}.`
657509
+ );
657510
+ llmParts.push(`Advanced text extraction signal: ${JSON.stringify(advancedSignal)}`);
657511
+ if (advancedSignal.present || !textSignal.present) textSignal = advancedSignal;
657512
+ }
657513
+ } else {
657514
+ stageLines.push("\n## OCR skipped\nReason: Visual detail was explicitly requested and text extraction was not needed.");
657515
+ llmParts.push("## OCR skipped\nReason: Visual detail was explicitly requested and text extraction was not needed.");
657516
+ }
657517
+ const shouldRunVision = visualRequested || Boolean(question && detail !== "text") || !textSignal.present && detail !== "text";
657518
+ let visionStage = null;
657519
+ if (shouldRunVision) {
657520
+ visionStage = await runStage(
657521
+ "vision_moondream",
657522
+ question ? "A visual question is present, so Moondream visual QA is warranted after lower-cost intake." : "Text extraction did not provide enough content or visual detail was requested, so Moondream captioning is warranted.",
657523
+ () => new VisionTool(repoRoot).execute({
657524
+ image: resolved.path,
657525
+ action: question ? "query" : "caption",
657526
+ ...question ? { prompt: question } : {},
657527
+ length: "normal"
657528
+ })
657529
+ );
657530
+ } else {
657531
+ stageLines.push("\n## vision_moondream skipped\nReason: OCR/text extraction produced sufficient evidence for the requested detail.");
657532
+ llmParts.push("## vision_moondream skipped\nReason: OCR/text extraction produced sufficient evidence for the requested detail.");
657533
+ }
657534
+ const anySuccess = imageRead.success || Boolean(textStage?.success) || Boolean(visionStage?.success);
657535
+ const output = stageLines.join("\n");
657536
+ return {
657537
+ success: anySuccess,
657538
+ output,
657539
+ llmContent: llmParts.join("\n\n"),
657540
+ error: anySuccess ? void 0 : "Telegram image analysis could not extract usable image evidence.",
657541
+ durationMs: performance.now() - start2
657542
+ };
657543
+ }
657544
+ };
657545
+ }
656731
657546
  buildTelegramMediaRecentTool(chatId, currentMsg) {
656732
657547
  const bridge = this;
656733
657548
  return {
656734
657549
  name: "telegram_media_recent",
656735
- description: "List recent media files available in this Telegram chat scope, including safe aliases for image_read, ocr, ocr_image_advanced, vision, identity_memory, transcribe_file, pdf_to_text, video_understand, and audio_analyze.",
657550
+ description: "List recent media files available in this Telegram chat scope, including safe aliases for telegram_image_analyze, image_read, ocr, ocr_image_advanced, vision, identity_memory, transcribe_file, pdf_to_text, video_understand, and audio_analyze.",
656736
657551
  parameters: {
656737
657552
  type: "object",
656738
657553
  properties: {
@@ -657140,7 +657955,7 @@ ${knownList}` : "Private-user telegram_send_file target must be this DM or a kno
657140
657955
  description = `[${sourceLabel}image received: path_alias=${mediaAlias}${safeCaption}
657141
657956
  ${visionContext}]`;
657142
657957
  } else {
657143
- description = `[${sourceLabel}image received: path_alias=${mediaAlias}${safeCaption}. Use path='${source === "reply" ? "reply" : "latest"}' or path='${mediaAlias}' with image_read, ocr, ocr_image_advanced, vision, or identity_memory.]`;
657958
+ description = `[${sourceLabel}image received: path_alias=${mediaAlias}${safeCaption}. Use image='${source === "reply" ? "reply" : "latest"}' or image='${mediaAlias}' with telegram_image_analyze, or use path/image aliases with image_read, ocr, ocr_image_advanced, vision, or identity_memory.]`;
657144
657959
  }
657145
657960
  const ingestPayload = this.telegramMemoryIngestPayload(msg, media, localPath, source, cacheEntry.extractedContent);
657146
657961
  let visualIdentityContext = "";
@@ -657399,13 +658214,13 @@ ${text}`.trim());
657399
658214
  }
657400
658215
  }
657401
658216
  async sendMediaReferenceStrict(chatId, media, options2 = {}) {
657402
- const { method, field } = mediaTelegramMethod(media.kind);
658217
+ const { method, field: field2 } = mediaTelegramMethod(media.kind);
657403
658218
  const caption = options2.caption?.trim();
657404
658219
  const replyParameters = telegramReplyParameters(options2.replyToMessageId);
657405
658220
  if (media.source === "url") {
657406
658221
  const result2 = await this.apiCall(method, {
657407
658222
  chat_id: chatId,
657408
- [field]: media.value,
658223
+ [field2]: media.value,
657409
658224
  ...caption ? { caption } : {},
657410
658225
  ...replyParameters ? { reply_parameters: replyParameters } : {}
657411
658226
  });
@@ -657434,7 +658249,7 @@ ${text}`.trim());
657434
658249
  parts.push(Buffer.from(`--${boundary}\r
657435
658250
  `));
657436
658251
  parts.push(Buffer.from(
657437
- `Content-Disposition: form-data; name="${field}"; filename="${filename}"\r
658252
+ `Content-Disposition: form-data; name="${field2}"; filename="${filename}"\r
657438
658253
  Content-Type: ${contentType}\r
657439
658254
  \r
657440
658255
  `
@@ -657683,9 +658498,9 @@ Content-Type: ${contentType}\r
657683
658498
  for (const [name10, value2] of Object.entries(fields)) {
657684
658499
  addField(name10, value2);
657685
658500
  }
657686
- for (const [field, pathOrFileId] of Object.entries(files)) {
658501
+ for (const [field2, pathOrFileId] of Object.entries(files)) {
657687
658502
  if (!existsSync131(pathOrFileId)) {
657688
- addField(field, pathOrFileId);
658503
+ addField(field2, pathOrFileId);
657689
658504
  continue;
657690
658505
  }
657691
658506
  const buffer2 = readFileSync108(pathOrFileId);
@@ -657693,8 +658508,8 @@ Content-Type: ${contentType}\r
657693
658508
  parts.push(Buffer.from(`--${boundary}\r
657694
658509
  `));
657695
658510
  parts.push(Buffer.from(
657696
- `Content-Disposition: form-data; name="${field}"; filename="${filename}"\r
657697
- Content-Type: ${mimeForPath(pathOrFileId, field === "photo" ? "image" : "video")}\r
658511
+ `Content-Disposition: form-data; name="${field2}"; filename="${filename}"\r
658512
+ Content-Type: ${mimeForPath(pathOrFileId, field2 === "photo" ? "image" : "video")}\r
657698
658513
  \r
657699
658514
  `
657700
658515
  ));