@autorag/librarian 2.9.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +57 -2
  2. package/dist/agent/agent.d.ts +27 -21
  3. package/dist/agent/answer-citations.d.ts +22 -0
  4. package/dist/agent/answer-guidelines.d.ts +9 -9
  5. package/dist/agent/citations.d.ts +35 -23
  6. package/dist/agent/evidence-ledger.d.ts +7 -12
  7. package/dist/agent/index.d.ts +2 -2
  8. package/dist/agent/{emit-results-tool.d.ts → results.d.ts} +5 -40
  9. package/dist/agent/search-documents.d.ts +14 -19
  10. package/dist/agent/self-config.d.ts +1 -1
  11. package/dist/cli/commands/report.d.ts +1 -1
  12. package/dist/cli/commands/tui.d.ts +3 -2
  13. package/dist/cli/index.js +1466 -984
  14. package/dist/cloud/authorize.d.ts +12 -0
  15. package/dist/cloud/callback-server.d.ts +33 -0
  16. package/dist/cloud/callback.d.ts +23 -0
  17. package/dist/cloud/config.d.ts +23 -0
  18. package/dist/cloud/errors.d.ts +46 -0
  19. package/dist/cloud/index.d.ts +12 -0
  20. package/dist/cloud/models.d.ts +32 -0
  21. package/dist/cloud/oauth-login.d.ts +22 -0
  22. package/dist/cloud/pkce.d.ts +20 -0
  23. package/dist/cloud/provider.d.ts +40 -0
  24. package/dist/cloud/token.d.ts +22 -0
  25. package/dist/core.d.ts +2 -5
  26. package/dist/core.js +1341 -918
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +1463 -928
  29. package/dist/mcp/index.js +1404 -925
  30. package/dist/minsync/client.d.ts +1 -1
  31. package/dist/minsync/installer.d.ts +1 -1
  32. package/dist/observability/run-log.d.ts +1 -1
  33. package/dist/retrieval/index.d.ts +1 -1
  34. package/dist/retrieval/types.d.ts +0 -23
  35. package/package.json +1 -1
  36. package/skills/autorag-lite-setup/SKILL.md +1 -1
  37. package/skills/autorag-setup/SKILL.md +2 -2
  38. package/dist/agent/fast-answer-tool.d.ts +0 -56
package/dist/index.js CHANGED
@@ -5606,7 +5606,7 @@ function isGitHubAsset(value) {
5606
5606
  function isRecord5(value) {
5607
5607
  return typeof value === "object" && value !== null;
5608
5608
  }
5609
- var LATEST_RELEASE_URL = "https://api.github.com/repos/NomaDamas/MinSync/releases/latest", SHA256_HEX_PATTERN, MINSYNC_VERSION = "0.4.5", MINSYNC_CARGO_INSTALL_TIMEOUT_MS, CARGO_PROBE_TIMEOUT_MS = 5000, MinSyncReleaseError;
5609
+ var LATEST_RELEASE_URL = "https://api.github.com/repos/NomaDamas/MinSync/releases/latest", SHA256_HEX_PATTERN, MINSYNC_VERSION = "0.4.6", MINSYNC_CARGO_INSTALL_TIMEOUT_MS, CARGO_PROBE_TIMEOUT_MS = 5000, MinSyncReleaseError;
5610
5610
  var init_installer2 = __esm(() => {
5611
5611
  init_process();
5612
5612
  SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
@@ -8040,8 +8040,398 @@ var init_model_auth = __esm(() => {
8040
8040
  };
8041
8041
  });
8042
8042
 
8043
+ // src/agent/citations.ts
8044
+ function isAsciiDigit(code) {
8045
+ return code >= 48 && code <= 57;
8046
+ }
8047
+ function digitsEndAt(text, from) {
8048
+ let end = from;
8049
+ while (end < text.length && isAsciiDigit(text.charCodeAt(end)))
8050
+ end += 1;
8051
+ return end;
8052
+ }
8053
+ function continuesAsProse(answer, from) {
8054
+ if (answer[from] !== " " && answer[from] !== " ")
8055
+ return false;
8056
+ const next = answer.codePointAt(from + 1);
8057
+ return next !== undefined && /[\p{L}\p{N}]/u.test(String.fromCodePoint(next));
8058
+ }
8059
+ function evidenceMarkerAt(answer, index) {
8060
+ const ids = [];
8061
+ let cursor = index + 1;
8062
+ for (;; ) {
8063
+ if (answer[cursor] !== "e")
8064
+ return;
8065
+ const digitsEnd = digitsEndAt(answer, cursor + 1);
8066
+ if (digitsEnd === cursor + 1)
8067
+ return;
8068
+ ids.push(answer.slice(cursor, digitsEnd));
8069
+ cursor = digitsEnd;
8070
+ if (answer[cursor] === "]")
8071
+ return { ids, end: cursor + 1 };
8072
+ if (answer[cursor] !== ",")
8073
+ return;
8074
+ cursor += 1;
8075
+ while (answer[cursor] === " " || answer[cursor] === "\t")
8076
+ cursor += 1;
8077
+ }
8078
+ }
8079
+ function filePathFrom(raw) {
8080
+ const trimmed = raw.trim();
8081
+ return trimmed.startsWith("<") && trimmed.endsWith(">") ? trimmed.slice(1, -1).trim() : trimmed;
8082
+ }
8083
+ function fileMarkerAt(answer, index, isFile) {
8084
+ if (!answer.startsWith(FILE_MARKER_PREFIX, index))
8085
+ return;
8086
+ const bodyStart = index + FILE_MARKER_PREFIX.length;
8087
+ let closer = answer.indexOf("]", bodyStart);
8088
+ for (let attempt = 0;closer !== -1 && attempt < MAX_FILE_MARKER_CLOSERS; attempt++) {
8089
+ const path = filePathFrom(answer.slice(bodyStart, closer));
8090
+ if (path.length > 0 && isFile(path))
8091
+ return { path, end: closer + 1 };
8092
+ closer = answer.indexOf("]", closer + 1);
8093
+ }
8094
+ return;
8095
+ }
8096
+ function answerMarkers(answer, isFile = () => false) {
8097
+ const markers = [];
8098
+ let floor = 0;
8099
+ let closeIndex = -1;
8100
+ let index = 0;
8101
+ const leadingStart = (from) => {
8102
+ let start = from;
8103
+ while (start > floor && (answer[start - 1] === " " || answer[start - 1] === "\t"))
8104
+ start -= 1;
8105
+ return start;
8106
+ };
8107
+ while (index < answer.length) {
8108
+ const char = answer[index];
8109
+ if (char === "(" && answer[index + 1] === "<") {
8110
+ if (closeIndex < index + 2) {
8111
+ const found = answer.indexOf(">", index + 2);
8112
+ closeIndex = found === -1 ? answer.length : found;
8113
+ }
8114
+ if (answer[closeIndex + 1] === ")") {
8115
+ index = closeIndex + 2;
8116
+ floor = index;
8117
+ continue;
8118
+ }
8119
+ index += 1;
8120
+ continue;
8121
+ }
8122
+ if (char === "[") {
8123
+ const digitsEnd = digitsEndAt(answer, index + 1);
8124
+ if (digitsEnd > index + 1 && answer[digitsEnd] === "]" && answer[digitsEnd + 1] !== "(" && !continuesAsProse(answer, digitsEnd + 1)) {
8125
+ markers.push({
8126
+ kind: "number",
8127
+ start: leadingStart(index),
8128
+ end: digitsEnd + 1,
8129
+ number: Number(answer.slice(index + 1, digitsEnd))
8130
+ });
8131
+ index = digitsEnd + 1;
8132
+ floor = index;
8133
+ continue;
8134
+ }
8135
+ const evidence = evidenceMarkerAt(answer, index);
8136
+ if (evidence !== undefined && answer[evidence.end] !== "(") {
8137
+ markers.push({ kind: "evidence", start: leadingStart(index), end: evidence.end, ids: evidence.ids });
8138
+ index = evidence.end;
8139
+ floor = index;
8140
+ continue;
8141
+ }
8142
+ const file = fileMarkerAt(answer, index, isFile);
8143
+ if (file !== undefined && answer[file.end] !== "(") {
8144
+ markers.push({ kind: "file", start: leadingStart(index), end: file.end, path: file.path });
8145
+ index = file.end;
8146
+ floor = index;
8147
+ continue;
8148
+ }
8149
+ }
8150
+ index += 1;
8151
+ }
8152
+ return markers;
8153
+ }
8154
+ function stripUnresolvedCitations(answer, results) {
8155
+ const known = new Set(results.map((result) => result.number));
8156
+ const unresolved = new Set;
8157
+ let stripped = "";
8158
+ let cursor = 0;
8159
+ for (const marker of answerMarkers(answer)) {
8160
+ if (marker.kind !== "number" || known.has(marker.number))
8161
+ continue;
8162
+ unresolved.add(marker.number);
8163
+ stripped += answer.slice(cursor, marker.start);
8164
+ cursor = marker.end;
8165
+ }
8166
+ if (unresolved.size === 0)
8167
+ return { answer, unresolved: [] };
8168
+ return { answer: stripped + answer.slice(cursor), unresolved: [...unresolved].sort((a, b) => a - b) };
8169
+ }
8170
+ function formatCitationList(numbers) {
8171
+ return numbers.length === 0 ? "none" : numbers.map((number) => `[${number}]`).join(", ");
8172
+ }
8173
+ function duplicateNumbers(sortedNumbers) {
8174
+ const duplicates = [];
8175
+ for (let index = 1;index < sortedNumbers.length; index++) {
8176
+ const number = sortedNumbers[index];
8177
+ if (number === sortedNumbers[index - 1] && duplicates[duplicates.length - 1] !== number)
8178
+ duplicates.push(number);
8179
+ }
8180
+ return duplicates;
8181
+ }
8182
+ function assertResultsMappingOneToOne(label, results, mapping) {
8183
+ const resultNumbers = results.map((result) => result.number).sort((a, b) => a - b);
8184
+ const mappingNumbers = mapping.map((entry) => entry.number).sort((a, b) => a - b);
8185
+ const resultDuplicates = duplicateNumbers(resultNumbers);
8186
+ const mappingDuplicates = duplicateNumbers(mappingNumbers);
8187
+ const sameNumbers = resultNumbers.length === mappingNumbers.length && resultNumbers.every((number, index) => number === mappingNumbers[index]);
8188
+ if (sameNumbers && resultDuplicates.length === 0 && mappingDuplicates.length === 0)
8189
+ return;
8190
+ const duplicateNotes = [
8191
+ resultDuplicates.length > 0 ? `results repeat ${formatCitationList(resultDuplicates)}` : undefined,
8192
+ mappingDuplicates.length > 0 ? `mapping repeats ${formatCitationList(mappingDuplicates)}` : undefined
8193
+ ].filter((note) => note !== undefined);
8194
+ throw new Error(`${label}: result numbers and mapping numbers must be one-to-one, but results contain ${formatCitationList(resultNumbers)} ` + `and mapping contains ${formatCitationList(mappingNumbers)}` + (duplicateNotes.length > 0 ? ` (${duplicateNotes.join("; ")})` : "") + ". Give every result a unique number with exactly one mapping entry carrying the same number and no mapping entry without a result.");
8195
+ }
8196
+ var MAX_FILE_MARKER_CLOSERS = 8, FILE_MARKER_PREFIX = "[file:";
8197
+
8198
+ // src/agent/evidence-ledger.ts
8199
+ import { createHash as createHash10 } from "node:crypto";
8200
+ import { closeSync as closeSync2, openSync as openSync2, readSync, statSync } from "node:fs";
8201
+ import { isAbsolute as isAbsolute6 } from "node:path";
8202
+ function metadataString(metadata, key) {
8203
+ const value = metadata[key];
8204
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
8205
+ }
8206
+ function metadataNumber(metadata, key) {
8207
+ const value = metadata[key];
8208
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
8209
+ }
8210
+ function isRegularFile2(path) {
8211
+ try {
8212
+ return statSync(path).isFile();
8213
+ } catch {
8214
+ return false;
8215
+ }
8216
+ }
8217
+ function readFileExcerpt(path) {
8218
+ let descriptor;
8219
+ try {
8220
+ descriptor = openSync2(path, "r");
8221
+ const buffer = Buffer.alloc(MAX_CONTENT_CHARS * 4);
8222
+ const bytes = readSync(descriptor, buffer, 0, buffer.length, 0);
8223
+ const head = buffer.subarray(0, bytes);
8224
+ return head.includes(0) ? path : head.toString("utf8").slice(0, MAX_CONTENT_CHARS);
8225
+ } catch {
8226
+ return path;
8227
+ } finally {
8228
+ if (descriptor !== undefined)
8229
+ closeSync2(descriptor);
8230
+ }
8231
+ }
8232
+ function toEvidenceRef(entry) {
8233
+ return {
8234
+ method: entry.method,
8235
+ source: entry.source,
8236
+ content: entry.content,
8237
+ retrieverMix: [...entry.retrieverMix],
8238
+ ...entry.retrievalResultId !== undefined ? { retrievalResultId: entry.retrievalResultId } : {},
8239
+ ...entry.chunkIndex !== undefined ? { chunkIndex: entry.chunkIndex } : {},
8240
+ ...entry.lineNumber !== undefined ? { lineNumber: entry.lineNumber } : {},
8241
+ ...entry.parserType !== undefined ? { parserType: entry.parserType } : {},
8242
+ ...entry.documentType !== undefined ? { documentType: entry.documentType } : {},
8243
+ ...entry.documentArea !== undefined ? { documentArea: entry.documentArea } : {},
8244
+ ...entry.evidenceType !== undefined ? { evidenceType: entry.evidenceType } : {},
8245
+ ...entry.evidenceLocation !== undefined ? { evidenceLocation: entry.evidenceLocation } : {}
8246
+ };
8247
+ }
8248
+
8249
+ class EvidenceLedger {
8250
+ entries = [];
8251
+ byKey = new Map;
8252
+ byId = new Map;
8253
+ lastOrdinal = 0;
8254
+ register(input) {
8255
+ const content = input.content.slice(0, MAX_CONTENT_CHARS);
8256
+ const digest = createHash10("sha256").update(input.content.replace(/\s+/gu, " ").trim()).digest("hex");
8257
+ const key = `${input.source}\x00${digest}`;
8258
+ const existing = this.byKey.get(key);
8259
+ if (existing !== undefined) {
8260
+ if (!existing.retrieverMix.includes(input.method))
8261
+ existing.retrieverMix.push(input.method);
8262
+ return existing.id;
8263
+ }
8264
+ const entry = {
8265
+ ...input,
8266
+ content,
8267
+ id: `e${++this.lastOrdinal}`,
8268
+ retrieverMix: [input.method]
8269
+ };
8270
+ this.entries.push(entry);
8271
+ this.byKey.set(key, entry);
8272
+ this.byId.set(entry.id, entry);
8273
+ return entry.id;
8274
+ }
8275
+ registerResult(tool, result) {
8276
+ const metadata = result.metadata;
8277
+ const chunkIndex = metadataNumber(metadata, "chunkIndex");
8278
+ const lineNumber = metadataNumber(metadata, "lineNumber");
8279
+ const parserType = metadataString(metadata, "parserType");
8280
+ const documentType = metadataString(metadata, "documentType");
8281
+ const documentArea = metadataString(metadata, "documentArea");
8282
+ const evidenceType = metadataString(metadata, "evidenceType");
8283
+ const evidenceLocation = metadataString(metadata, "evidenceLocation");
8284
+ return this.register({
8285
+ method: metadataString(metadata, "method") ?? tool,
8286
+ source: result.source,
8287
+ content: result.content,
8288
+ retrievalResultId: result.id,
8289
+ ...chunkIndex !== undefined ? { chunkIndex } : {},
8290
+ ...lineNumber !== undefined ? { lineNumber } : {},
8291
+ ...parserType !== undefined ? { parserType } : {},
8292
+ ...documentType !== undefined ? { documentType } : {},
8293
+ ...documentArea !== undefined ? { documentArea } : {},
8294
+ ...evidenceType !== undefined ? { evidenceType } : {},
8295
+ ...evidenceLocation !== undefined ? { evidenceLocation } : {}
8296
+ });
8297
+ }
8298
+ lookup(raw, options) {
8299
+ const trimmed = raw.trim();
8300
+ const ref = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1).trim() : trimmed;
8301
+ const byId = this.byId.get(ref);
8302
+ if (byId !== undefined)
8303
+ return [toEvidenceRef(byId)];
8304
+ const bySource = this.entries.filter((entry) => entry.source === ref);
8305
+ if (bySource.length > 0)
8306
+ return bySource.map(toEvidenceRef);
8307
+ if (options.allowLocalFiles && isAbsolute6(ref) && isRegularFile2(ref)) {
8308
+ return [{ method: "bash", source: ref, content: readFileExcerpt(ref) }];
8309
+ }
8310
+ return [];
8311
+ }
8312
+ clear() {
8313
+ this.entries = [];
8314
+ this.byKey.clear();
8315
+ this.byId.clear();
8316
+ }
8317
+ }
8318
+ var MAX_CONTENT_CHARS = 2000;
8319
+ var init_evidence_ledger = () => {};
8320
+
8321
+ // src/agent/answer-citations.ts
8322
+ import { isAbsolute as isAbsolute7 } from "node:path";
8323
+ function claimBefore(text, end) {
8324
+ const window = text.slice(Math.max(0, end - CLAIM_LOOKBACK_CHARS), end);
8325
+ const lineStart = window.lastIndexOf(`
8326
+ `) + 1;
8327
+ const line = window.slice(lineStart).replace(EVIDENCE_MARKER_TEXT, "");
8328
+ let start = 0;
8329
+ for (let index = line.length - 2;index >= 0; index--) {
8330
+ if (SENTENCE_END.test(line.charAt(index)) && /\s/u.test(line.charAt(index + 1))) {
8331
+ start = index + 2;
8332
+ break;
8333
+ }
8334
+ }
8335
+ const claim = line.slice(start).replace(LEADING_LIST_MARK, "").replace(/\s+/gu, " ").trim();
8336
+ return claim.length > MAX_CLAIM_CHARS ? `${claim.slice(0, MAX_CLAIM_CHARS)}…` : claim;
8337
+ }
8338
+ function deriveResultsFromAnswer(text, ledger, options) {
8339
+ const isFile = (path) => options.allowLocalFiles && isAbsolute7(path) && isRegularFile2(path);
8340
+ const sources = new Map;
8341
+ const dropped = new Set;
8342
+ let answer = "";
8343
+ let cursor = 0;
8344
+ let lastEmitted;
8345
+ const cite = (reference, claimEnd) => {
8346
+ const refs = ledger.lookup(reference, options);
8347
+ const [primary] = refs;
8348
+ if (primary === undefined) {
8349
+ dropped.add(reference);
8350
+ return;
8351
+ }
8352
+ let cited = sources.get(primary.source);
8353
+ if (cited === undefined) {
8354
+ cited = { number: sources.size + 1, refs: [], chunkKeys: new Set, claim: claimBefore(text, claimEnd) };
8355
+ sources.set(primary.source, cited);
8356
+ }
8357
+ for (const ref of refs) {
8358
+ const chunkKey = `${ref.source}\x00${ref.content ?? ""}`;
8359
+ if (cited.chunkKeys.has(chunkKey))
8360
+ continue;
8361
+ cited.chunkKeys.add(chunkKey);
8362
+ cited.refs.push(ref);
8363
+ }
8364
+ return cited.number;
8365
+ };
8366
+ for (const marker of answerMarkers(text, isFile)) {
8367
+ answer += text.slice(cursor, marker.start);
8368
+ cursor = marker.end;
8369
+ if (marker.kind === "number") {
8370
+ dropped.add(`[${marker.number}]`);
8371
+ continue;
8372
+ }
8373
+ const references = marker.kind === "evidence" ? marker.ids : [`file:${marker.path}`];
8374
+ const numbers = [];
8375
+ for (const reference of references) {
8376
+ const number = cite(marker.kind === "file" ? marker.path : reference, marker.start);
8377
+ if (number !== undefined && !numbers.includes(number))
8378
+ numbers.push(number);
8379
+ }
8380
+ if (numbers.length === 0)
8381
+ continue;
8382
+ const adjacent = lastEmitted !== undefined && text.slice(lastEmitted.end, marker.start).trim() === "";
8383
+ const fresh = numbers.filter((number) => !(adjacent && lastEmitted?.number === number));
8384
+ lastEmitted = { number: numbers[numbers.length - 1], end: marker.end };
8385
+ if (fresh.length === 0)
8386
+ continue;
8387
+ const leading = LEADING_BLANK.exec(text.slice(marker.start, marker.end))?.[0] ?? "";
8388
+ answer += leading + fresh.map((number) => `[${number}]`).join("");
8389
+ }
8390
+ answer += text.slice(cursor);
8391
+ const results = [];
8392
+ const mapping = [];
8393
+ for (const [source, cited] of sources) {
8394
+ const [primary] = cited.refs;
8395
+ if (primary === undefined)
8396
+ continue;
8397
+ results.push({
8398
+ number: cited.number,
8399
+ title: source.split(/[\\/]/u).filter((part) => part.length > 0).pop() ?? source,
8400
+ summary: cited.claim,
8401
+ evidence: cited.refs.map((ref) => {
8402
+ const excerpt = (ref.content ?? "").replace(/\s+/gu, " ").trim().slice(0, MAX_EXCERPT_CHARS);
8403
+ return ref.lineNumber !== undefined ? { excerpt, lineNumber: ref.lineNumber } : { excerpt };
8404
+ })
8405
+ });
8406
+ mapping.push({
8407
+ number: cited.number,
8408
+ source,
8409
+ method: primary.method,
8410
+ content: primary.content ?? "",
8411
+ evidenceRefs: cited.refs
8412
+ });
8413
+ }
8414
+ const diagnostics = dropped.size === 0 ? [] : [
8415
+ {
8416
+ code: "citation-without-result",
8417
+ severity: "warning",
8418
+ message: `Dropped ${dropped.size} answer citation(s) that matched no evidence retrieved in this run: ${[...dropped].join(", ")}. Every remaining citation resolves to a recorded source.`,
8419
+ source: "agent"
8420
+ }
8421
+ ];
8422
+ return { details: { answer: answer.trim(), results, mapping, warnings: [] }, diagnostics };
8423
+ }
8424
+ var MAX_EXCERPT_CHARS = 400, MAX_CLAIM_CHARS = 280, CLAIM_LOOKBACK_CHARS = 600, SENTENCE_END, LEADING_LIST_MARK, EVIDENCE_MARKER_TEXT, LEADING_BLANK;
8425
+ var init_answer_citations = __esm(() => {
8426
+ init_evidence_ledger();
8427
+ SENTENCE_END = /[.!?。!?]/u;
8428
+ LEADING_LIST_MARK = /^[\s\-*•>]+/u;
8429
+ EVIDENCE_MARKER_TEXT = /\[(?:e\d+(?:,\s*)?)+\]|\[file:[^\]]*\]/gu;
8430
+ LEADING_BLANK = /^[ \t]*/u;
8431
+ });
8432
+
8043
8433
  // src/agent/answer-guidelines.ts
8044
- var ANSWER_IMAGE_EMBED_RULE = "**Images**: when a retrieved result is itself an image file (png, jpg, jpeg, gif, webp, svg, bmp, avif, heic, tiff) and showing it answers the question, embed it in `answer` as a markdown image on its own line: `![short description](<absolute source path>)`, followed by its citation, e.g. `![Q3 revenue chart](</data/reports/q3 chart.png>) [2]`. Use only the real source path of a result in `results`/`mapping`. Never invent a path, use relative paths, or embed remote URLs. Apart from these image embeds, the no-file-paths rule stands.", ANSWER_IMAGE_DELTA_RULE = "An image already embedded in the first answer must not be embedded again.", ANSWER_CITATION_RULE = "**Citation numbers**: every bracketed citation [n] in `answer` must be the `number` of a result you emit in `results` of the same call. Numbers shown in retrieval candidates or in an earlier first answer are NOT citation numbers — renumber against your own `results`, and add a result for any evidence you cite.";
8434
+ var ANSWER_IMAGE_EMBED_RULE = "**Images**: when a retrieved result is itself an image file (png, jpg, jpeg, gif, webp, svg, bmp, avif, heic, tiff) and showing it answers the question, embed it in the answer as a markdown image on its own line: `![short description](<absolute source path>)`, followed by its citation, e.g. `![Q3 revenue chart](</data/reports/q3 chart.png>) [e2]`. Use only the real source path of retrieved evidence. Never invent a path, use relative paths, or embed remote URLs. Apart from these image embeds, the no-file-paths rule stands.", ANSWER_IMAGE_DELTA_RULE = "An image already embedded in the first answer must not be embedded again.", ANSWER_CITATION_RULE = "**Citations**: cite supporting evidence inline with the evidence id shown next to each retrieved result, in square brackets (e.g. [e3], or [e3][e7] for two). Copy ids exactly; never invent one. For a local file you opened yourself with `bash`, cite `[file:<absolute path>]`. Cite the evidence that backs a sentence at the end of that sentence. Do not cite numbers, paths, or anything else.";
8045
8435
 
8046
8436
  // src/agent/datasource-skill.ts
8047
8437
  import { Type as Type2 } from "typebox";
@@ -8242,230 +8632,8 @@ var init_dupey_tool = __esm(() => {
8242
8632
  scanDuplicateDocumentsSchema = Type3.Object({});
8243
8633
  });
8244
8634
 
8245
- // src/agent/citations.ts
8246
- function isAsciiDigit(code) {
8247
- return code >= 48 && code <= 57;
8248
- }
8249
- function citationMarkers(answer) {
8250
- const markers = [];
8251
- let floor = 0;
8252
- let closeIndex = -1;
8253
- let index = 0;
8254
- while (index < answer.length) {
8255
- const char = answer[index];
8256
- if (char === "(" && answer[index + 1] === "<") {
8257
- if (closeIndex < index + 2) {
8258
- const found = answer.indexOf(">", index + 2);
8259
- closeIndex = found === -1 ? answer.length : found;
8260
- }
8261
- if (answer[closeIndex + 1] === ")") {
8262
- index = closeIndex + 2;
8263
- floor = index;
8264
- continue;
8265
- }
8266
- index += 1;
8267
- continue;
8268
- }
8269
- if (char === "[") {
8270
- let digitsEnd = index + 1;
8271
- while (digitsEnd < answer.length && isAsciiDigit(answer.charCodeAt(digitsEnd)))
8272
- digitsEnd += 1;
8273
- if (digitsEnd > index + 1 && answer[digitsEnd] === "]" && answer[digitsEnd + 1] !== "(") {
8274
- let start = index;
8275
- while (start > floor && (answer[start - 1] === " " || answer[start - 1] === "\t"))
8276
- start -= 1;
8277
- markers.push({ start, end: digitsEnd + 1, number: Number(answer.slice(index + 1, digitsEnd)) });
8278
- index = digitsEnd + 1;
8279
- floor = index;
8280
- continue;
8281
- }
8282
- }
8283
- index += 1;
8284
- }
8285
- return markers;
8286
- }
8287
- function unresolvedCitations(answer, results) {
8288
- const known = new Set(results.map((result) => result.number));
8289
- const unresolved = new Set;
8290
- for (const marker of citationMarkers(answer)) {
8291
- if (!known.has(marker.number))
8292
- unresolved.add(marker.number);
8293
- }
8294
- return [...unresolved].sort((a, b) => a - b);
8295
- }
8296
- function stripUnresolvedCitations(answer, results) {
8297
- const known = new Set(results.map((result) => result.number));
8298
- const unresolved = new Set;
8299
- let stripped = "";
8300
- let cursor = 0;
8301
- for (const marker of citationMarkers(answer)) {
8302
- if (known.has(marker.number))
8303
- continue;
8304
- unresolved.add(marker.number);
8305
- stripped += answer.slice(cursor, marker.start);
8306
- cursor = marker.end;
8307
- }
8308
- if (unresolved.size === 0)
8309
- return { answer, unresolved: [] };
8310
- return { answer: stripped + answer.slice(cursor), unresolved: [...unresolved].sort((a, b) => a - b) };
8311
- }
8312
- function formatCitationList(numbers) {
8313
- return numbers.length === 0 ? "none" : numbers.map((number) => `[${number}]`).join(", ");
8314
- }
8315
- function duplicateNumbers(sortedNumbers) {
8316
- const duplicates = [];
8317
- for (let index = 1;index < sortedNumbers.length; index++) {
8318
- const number = sortedNumbers[index];
8319
- if (number === sortedNumbers[index - 1] && duplicates[duplicates.length - 1] !== number)
8320
- duplicates.push(number);
8321
- }
8322
- return duplicates;
8323
- }
8324
- function assertUniqueResultNumbers(label, results) {
8325
- const duplicates = duplicateNumbers(results.map((result) => result.number).sort((a, b) => a - b));
8326
- if (duplicates.length === 0)
8327
- return;
8328
- throw new Error(`${label}: result numbers must be unique, but results repeat ${formatCitationList(duplicates)}. Give every result its own number and re-emit.`);
8329
- }
8330
- function assertResultsMappingOneToOne(label, results, mapping) {
8331
- const resultNumbers = results.map((result) => result.number).sort((a, b) => a - b);
8332
- const mappingNumbers = mapping.map((entry) => entry.number).sort((a, b) => a - b);
8333
- const resultDuplicates = duplicateNumbers(resultNumbers);
8334
- const mappingDuplicates = duplicateNumbers(mappingNumbers);
8335
- const sameNumbers = resultNumbers.length === mappingNumbers.length && resultNumbers.every((number, index) => number === mappingNumbers[index]);
8336
- if (sameNumbers && resultDuplicates.length === 0 && mappingDuplicates.length === 0)
8337
- return;
8338
- const duplicateNotes = [
8339
- resultDuplicates.length > 0 ? `results repeat ${formatCitationList(resultDuplicates)}` : undefined,
8340
- mappingDuplicates.length > 0 ? `mapping repeats ${formatCitationList(mappingDuplicates)}` : undefined
8341
- ].filter((note) => note !== undefined);
8342
- throw new Error(`${label}: result numbers and mapping numbers must be one-to-one, but results contain ${formatCitationList(resultNumbers)} ` + `and mapping contains ${formatCitationList(mappingNumbers)}` + (duplicateNotes.length > 0 ? ` (${duplicateNotes.join("; ")})` : "") + ". Give every result a unique number with exactly one mapping entry carrying the same number and no mapping entry without a result. Re-emit with consistent numbering.");
8343
- }
8344
- function assertCitationsResolve(label, answer, results) {
8345
- const unresolved = unresolvedCitations(answer, results);
8346
- if (unresolved.length === 0)
8347
- return;
8348
- const emitted = [...new Set(results.map((result) => result.number))].sort((a, b) => a - b);
8349
- throw new Error(`${label}: answer cites ${formatCitationList(unresolved)} but results only contain ${formatCitationList(emitted)}. ` + "Every bracketed citation in answer must be the number of a result in results of this same call; " + "candidate numbers from retrieval context or an earlier answer are not citation numbers. Re-emit with consistent numbering.");
8350
- }
8351
-
8352
- // src/agent/emit-results-tool.ts
8353
- import { Type as Type4 } from "typebox";
8354
- function createEmitResultsTool(capture, options) {
8355
- return {
8356
- name: EMIT_AUTORAG_RESULTS_TOOL_NAME,
8357
- label: "Emit AutoRAG Results",
8358
- description: "Return the final structured AutoRAG answer. Call this exactly once as your last action after searching, reading, and curating. Cite each result's supporting evidence in its refs, using the evidence ids shown next to retrieved results (e.g. e3); the source paths are attached for you. A call whose answer cites a number missing from results, whose result numbers repeat, or whose refs name evidence no tool returned is rejected; fix it and call again.",
8359
- parameters: emitResultsSchema,
8360
- async execute(_toolCallId, params) {
8361
- assertCitationsResolve(EMIT_AUTORAG_RESULTS_TOOL_NAME, params.answer, params.results);
8362
- assertUniqueResultNumbers(EMIT_AUTORAG_RESULTS_TOOL_NAME, params.results);
8363
- const mapping = params.results.map((result) => {
8364
- const evidenceRefs = options.ledger.resolve(result.refs, {
8365
- label: EMIT_AUTORAG_RESULTS_TOOL_NAME,
8366
- number: result.number,
8367
- fallbackContent: result.evidence.map((evidence) => evidence.excerpt).join(`
8368
- `) || result.summary,
8369
- allowLocalFiles: options.allowLocalFiles
8370
- });
8371
- const primary = evidenceRefs[0];
8372
- if (primary === undefined) {
8373
- throw new Error(`${EMIT_AUTORAG_RESULTS_TOOL_NAME}: result ${result.number} resolved no evidence. Give it at least one valid ref.`);
8374
- }
8375
- return {
8376
- number: result.number,
8377
- source: primary.source,
8378
- method: primary.method,
8379
- content: primary.content ?? "",
8380
- evidenceRefs
8381
- };
8382
- });
8383
- const details = {
8384
- answer: params.answer,
8385
- results: params.results.map((result) => ({
8386
- number: result.number,
8387
- title: result.title,
8388
- summary: result.summary,
8389
- evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
8390
- confidence: result.confidence
8391
- })),
8392
- mapping,
8393
- warnings: params.warnings ?? []
8394
- };
8395
- capture(details);
8396
- return {
8397
- content: [{ type: "text", text: "AutoRAG results emitted." }],
8398
- details,
8399
- terminate: true
8400
- };
8401
- }
8402
- };
8403
- }
8404
- var EMIT_AUTORAG_RESULTS_TOOL_NAME = "emit_autorag_results", evidenceRefSchema, answerSchema, warningsSchema, curatedResultFields, emitResultsSchema, reportSchema;
8405
- var init_emit_results_tool = __esm(() => {
8406
- evidenceRefSchema = Type4.Object({
8407
- method: Type4.String({ description: "Retrieval method namespace for this evidence chunk" }),
8408
- source: Type4.String({ description: "Internal opaque source identifier for this evidence chunk" }),
8409
- excerpt: Type4.Optional(Type4.String({ description: "Evidence excerpt used for stable ID normalization" })),
8410
- content: Type4.Optional(Type4.String({ description: "Evidence content used for stable ID normalization" })),
8411
- retrievalResultId: Type4.Optional(Type4.String({ description: "Backend retrieval ID when path-opaque and stable" })),
8412
- chunkIndex: Type4.Optional(Type4.Integer({ description: "Chunk index, if available" })),
8413
- lineNumber: Type4.Optional(Type4.Integer({ description: "Line number, if available" })),
8414
- stableEvidenceId: Type4.Optional(Type4.String({ description: "Stable evidence ID, if already normalized" })),
8415
- retrieverMix: Type4.Optional(Type4.Array(Type4.String({ maxLength: 64 }), {
8416
- description: "Retrievers that contributed to this result",
8417
- maxItems: 8
8418
- })),
8419
- parserType: Type4.Optional(Type4.String({ description: "Parser that produced this evidence", maxLength: 120 })),
8420
- documentType: Type4.Optional(Type4.String({ description: "Document type, if known", maxLength: 120 })),
8421
- documentArea: Type4.Optional(Type4.String({ description: "Document collection area, if known", maxLength: 120 })),
8422
- evidenceType: Type4.Optional(Type4.String({ description: "Evidence type, if known", maxLength: 120 })),
8423
- evidenceLocation: Type4.Optional(Type4.String({ description: "Human-readable evidence location", maxLength: 120 })),
8424
- confidence: Type4.Optional(Type4.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
8425
- });
8426
- answerSchema = Type4.String({
8427
- description: `Answer for the caller. When a first answer was already delivered to the caller during this run, this MUST contain only the corrections and newly verified findings relative to it — never restate the first answer; otherwise it is the complete answer. At most 5 bullet points (plus optional explanation); reference results by bracketed number (e.g. [1], [2]) without file paths or raw chunk text, except the image-embed exception below. ${ANSWER_CITATION_RULE} ${ANSWER_IMAGE_EMBED_RULE} ${ANSWER_IMAGE_DELTA_RULE}`
8428
- });
8429
- warningsSchema = Type4.Optional(Type4.Array(Type4.String(), { description: "Optional warnings about this result set" }));
8430
- curatedResultFields = {
8431
- number: Type4.Integer({ description: "1-based result number" }),
8432
- title: Type4.String({ description: "Short name of the curated knowledge unit" }),
8433
- summary: Type4.String({ description: "Key insight: purpose, details, and line range" }),
8434
- evidence: Type4.Array(Type4.Object({
8435
- excerpt: Type4.String({ description: "Supporting excerpt" }),
8436
- lineNumber: Type4.Optional(Type4.Integer({ description: "Line number of the excerpt, if known" }))
8437
- })),
8438
- confidence: Type4.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
8439
- };
8440
- emitResultsSchema = Type4.Object({
8441
- answer: answerSchema,
8442
- results: Type4.Array(Type4.Object({
8443
- ...curatedResultFields,
8444
- refs: Type4.Array(Type4.String(), {
8445
- minItems: 1,
8446
- description: "Evidence ids supporting this result, copied from the ids shown next to retrieved results (e.g. e3). For a local file you opened yourself with bash, give its absolute path instead."
8447
- })
8448
- }), { description: "Numbered curated knowledge units." }),
8449
- warnings: warningsSchema
8450
- });
8451
- reportSchema = Type4.Object({
8452
- answer: answerSchema,
8453
- results: Type4.Array(Type4.Object(curatedResultFields), { description: "Numbered curated knowledge units." }),
8454
- mapping: Type4.Array(Type4.Object({
8455
- number: Type4.Integer({ description: "Matches the result number this entry maps" }),
8456
- source: Type4.String({ description: "Source identifier — a real file path or a datasource id" }),
8457
- method: Type4.String({ description: "Retrieval method or tool that produced the source" }),
8458
- content: Type4.String({ description: "Raw content snippet of the evidence behind this result" }),
8459
- evidenceRefs: Type4.Optional(Type4.Array(evidenceRefSchema, {
8460
- description: "Hidden evidence chunk references supporting this curated result"
8461
- }))
8462
- }), { description: "Internal number -> source/method mapping. One entry per result number." }),
8463
- warnings: warningsSchema
8464
- });
8465
- });
8466
-
8467
8635
  // src/agent/everything-search-tool.ts
8468
- import { Type as Type5 } from "typebox";
8636
+ import { Type as Type4 } from "typebox";
8469
8637
  function createEverythingSearchTool(provider) {
8470
8638
  return {
8471
8639
  name: EVERYTHING_SEARCH_TOOL_NAME,
@@ -8517,28 +8685,28 @@ ${lines.join(`
8517
8685
  }
8518
8686
  var EVERYTHING_SEARCH_TOOL_NAME = "everything_search", MAX_RESULTS_CAP2 = 1000, DEFAULT_MAX_RESULTS3 = 100, everythingSearchSchema;
8519
8687
  var init_everything_search_tool = __esm(() => {
8520
- everythingSearchSchema = Type5.Object({
8521
- query: Type5.String({
8688
+ everythingSearchSchema = Type4.Object({
8689
+ query: Type4.String({
8522
8690
  description: 'Everything search syntax over file and folder names: space = AND, | = OR, ! = NOT, "quoted phrase", wildcards (*.pdf), ext:pdf;docx, dm:thisweek, size:>10mb, parent:<folder>, path fragments like \\reports\\ when matchPath is true.'
8523
8691
  }),
8524
- regex: Type5.Optional(Type5.Boolean({ description: "Treat query as a regular expression." })),
8525
- matchCase: Type5.Optional(Type5.Boolean()),
8526
- matchPath: Type5.Optional(Type5.Boolean({ description: "Match against the full path instead of the name." })),
8527
- wholeWord: Type5.Optional(Type5.Boolean()),
8528
- kind: Type5.Optional(Type5.Union([Type5.Literal("files"), Type5.Literal("folders")])),
8529
- path: Type5.Optional(Type5.String({ description: "Absolute folder to search within." })),
8530
- sort: Type5.Optional(Type5.Union([
8531
- Type5.Literal("name-ascending"),
8532
- Type5.Literal("name-descending"),
8533
- Type5.Literal("path-ascending"),
8534
- Type5.Literal("path-descending"),
8535
- Type5.Literal("size-ascending"),
8536
- Type5.Literal("size-descending"),
8537
- Type5.Literal("date-modified-ascending"),
8538
- Type5.Literal("date-modified-descending")
8692
+ regex: Type4.Optional(Type4.Boolean({ description: "Treat query as a regular expression." })),
8693
+ matchCase: Type4.Optional(Type4.Boolean()),
8694
+ matchPath: Type4.Optional(Type4.Boolean({ description: "Match against the full path instead of the name." })),
8695
+ wholeWord: Type4.Optional(Type4.Boolean()),
8696
+ kind: Type4.Optional(Type4.Union([Type4.Literal("files"), Type4.Literal("folders")])),
8697
+ path: Type4.Optional(Type4.String({ description: "Absolute folder to search within." })),
8698
+ sort: Type4.Optional(Type4.Union([
8699
+ Type4.Literal("name-ascending"),
8700
+ Type4.Literal("name-descending"),
8701
+ Type4.Literal("path-ascending"),
8702
+ Type4.Literal("path-descending"),
8703
+ Type4.Literal("size-ascending"),
8704
+ Type4.Literal("size-descending"),
8705
+ Type4.Literal("date-modified-ascending"),
8706
+ Type4.Literal("date-modified-descending")
8539
8707
  ])),
8540
- offset: Type5.Optional(Type5.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
8541
- maxResults: Type5.Optional(Type5.Integer({
8708
+ offset: Type4.Optional(Type4.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
8709
+ maxResults: Type4.Optional(Type4.Integer({
8542
8710
  minimum: 1,
8543
8711
  description: `Maximum results (default ${DEFAULT_MAX_RESULTS3}, cap ${MAX_RESULTS_CAP2}).`
8544
8712
  }))
@@ -8670,146 +8838,6 @@ var init_evidence_judgment = __esm(() => {
8670
8838
  };
8671
8839
  });
8672
8840
 
8673
- // src/agent/evidence-ledger.ts
8674
- import { createHash as createHash10 } from "node:crypto";
8675
- import { statSync } from "node:fs";
8676
- import { isAbsolute as isAbsolute6 } from "node:path";
8677
- function metadataString(metadata, key) {
8678
- const value = metadata[key];
8679
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
8680
- }
8681
- function metadataNumber(metadata, key) {
8682
- const value = metadata[key];
8683
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
8684
- }
8685
- function isRegularFile2(path) {
8686
- try {
8687
- return statSync(path).isFile();
8688
- } catch {
8689
- return false;
8690
- }
8691
- }
8692
- function toEvidenceRef(entry) {
8693
- return {
8694
- method: entry.method,
8695
- source: entry.source,
8696
- content: entry.content,
8697
- retrieverMix: [...entry.retrieverMix],
8698
- ...entry.retrievalResultId !== undefined ? { retrievalResultId: entry.retrievalResultId } : {},
8699
- ...entry.chunkIndex !== undefined ? { chunkIndex: entry.chunkIndex } : {},
8700
- ...entry.lineNumber !== undefined ? { lineNumber: entry.lineNumber } : {},
8701
- ...entry.parserType !== undefined ? { parserType: entry.parserType } : {},
8702
- ...entry.documentType !== undefined ? { documentType: entry.documentType } : {},
8703
- ...entry.documentArea !== undefined ? { documentArea: entry.documentArea } : {},
8704
- ...entry.evidenceType !== undefined ? { evidenceType: entry.evidenceType } : {},
8705
- ...entry.evidenceLocation !== undefined ? { evidenceLocation: entry.evidenceLocation } : {}
8706
- };
8707
- }
8708
-
8709
- class EvidenceLedger {
8710
- entries = [];
8711
- byKey = new Map;
8712
- byId = new Map;
8713
- lastOrdinal = 0;
8714
- register(input) {
8715
- const content = input.content.slice(0, MAX_CONTENT_CHARS);
8716
- const digest = createHash10("sha256").update(input.content.replace(/\s+/gu, " ").trim()).digest("hex");
8717
- const key = `${input.source}\x00${digest}`;
8718
- const existing = this.byKey.get(key);
8719
- if (existing !== undefined) {
8720
- if (!existing.retrieverMix.includes(input.method))
8721
- existing.retrieverMix.push(input.method);
8722
- return existing.id;
8723
- }
8724
- const entry = {
8725
- ...input,
8726
- content,
8727
- id: `e${++this.lastOrdinal}`,
8728
- retrieverMix: [input.method]
8729
- };
8730
- this.entries.push(entry);
8731
- this.byKey.set(key, entry);
8732
- this.byId.set(entry.id, entry);
8733
- return entry.id;
8734
- }
8735
- registerResult(tool, result) {
8736
- const metadata = result.metadata;
8737
- const chunkIndex = metadataNumber(metadata, "chunkIndex");
8738
- const lineNumber = metadataNumber(metadata, "lineNumber");
8739
- const parserType = metadataString(metadata, "parserType");
8740
- const documentType = metadataString(metadata, "documentType");
8741
- const documentArea = metadataString(metadata, "documentArea");
8742
- const evidenceType = metadataString(metadata, "evidenceType");
8743
- const evidenceLocation = metadataString(metadata, "evidenceLocation");
8744
- return this.register({
8745
- method: metadataString(metadata, "method") ?? tool,
8746
- source: result.source,
8747
- content: result.content,
8748
- retrievalResultId: result.id,
8749
- ...chunkIndex !== undefined ? { chunkIndex } : {},
8750
- ...lineNumber !== undefined ? { lineNumber } : {},
8751
- ...parserType !== undefined ? { parserType } : {},
8752
- ...documentType !== undefined ? { documentType } : {},
8753
- ...documentArea !== undefined ? { documentArea } : {},
8754
- ...evidenceType !== undefined ? { evidenceType } : {},
8755
- ...evidenceLocation !== undefined ? { evidenceLocation } : {}
8756
- });
8757
- }
8758
- resolve(refs, options) {
8759
- const resolved = [];
8760
- const seen = new Set;
8761
- const push = (entry) => {
8762
- if (seen.has(entry.id))
8763
- return;
8764
- seen.add(entry.id);
8765
- resolved.push(toEvidenceRef(entry));
8766
- };
8767
- for (const raw of refs) {
8768
- const trimmed = raw.trim();
8769
- const ref = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1).trim() : trimmed;
8770
- const byId = this.byId.get(ref);
8771
- if (byId !== undefined) {
8772
- push(byId);
8773
- continue;
8774
- }
8775
- const bySource = this.entries.filter((entry) => entry.source === ref);
8776
- if (bySource.length > 0) {
8777
- for (const entry of bySource)
8778
- push(entry);
8779
- continue;
8780
- }
8781
- if (options.allowLocalFiles && isAbsolute6(ref) && isRegularFile2(ref)) {
8782
- const key = `file\x00${ref}`;
8783
- if (seen.has(key))
8784
- continue;
8785
- seen.add(key);
8786
- resolved.push({
8787
- method: "bash",
8788
- source: ref,
8789
- content: (options.fallbackContent.trim() || ref).slice(0, MAX_CONTENT_CHARS)
8790
- });
8791
- continue;
8792
- }
8793
- throw new Error(this.unresolvedMessage(ref, EVIDENCE_ID_PATTERN.test(ref), options));
8794
- }
8795
- return resolved;
8796
- }
8797
- clear() {
8798
- this.entries = [];
8799
- this.byKey.clear();
8800
- this.byId.clear();
8801
- }
8802
- unresolvedMessage(ref, looksLikeId, options) {
8803
- const known = this.entries.length === 0 ? "No search or fetch has returned evidence in this run yet." : `Evidence ids issued in this run: ${this.entries[0]?.id}${this.entries.length > 1 ? `..${this.entries[this.entries.length - 1]?.id}` : ""}.`;
8804
- const local = options.allowLocalFiles ? " For a file you opened yourself with bash, pass its absolute path." : "";
8805
- return `${options.label}: result ${options.number} cites evidence "${ref}" that no tool returned in this run` + `${looksLikeId ? " (unknown evidence id)" : ""}. ${known} ` + `Cite only the evidence ids shown next to retrieved results (e.g. e3).${local} Re-emit with valid refs.`;
8806
- }
8807
- }
8808
- var MAX_CONTENT_CHARS = 2000, EVIDENCE_ID_PATTERN;
8809
- var init_evidence_ledger = __esm(() => {
8810
- EVIDENCE_ID_PATTERN = /^e\d+$/u;
8811
- });
8812
-
8813
8841
  // src/agent/evidence-origins.ts
8814
8842
  function normalize3(text) {
8815
8843
  return text.normalize("NFC").toLowerCase().replace(/\s+/g, " ").trim();
@@ -8910,168 +8938,688 @@ class EvidenceOriginIndex {
8910
8938
  }
8911
8939
  return;
8912
8940
  }
8913
- clear() {
8914
- this.candidates.length = 0;
8915
- this.seen.clear();
8941
+ clear() {
8942
+ this.candidates.length = 0;
8943
+ this.seen.clear();
8944
+ }
8945
+ }
8946
+ var MAX_CANDIDATES = 2000, MAX_CONTENT_LENGTH = 4000, MIN_MATCH_LENGTH = 12;
8947
+
8948
+ // src/agent/fsearch-search-tool.ts
8949
+ import { Type as Type5 } from "typebox";
8950
+ function createFSearchSearchTool(provider) {
8951
+ return {
8952
+ name: FSEARCH_SEARCH_TOOL_NAME,
8953
+ label: "FSearch Search",
8954
+ description: "Instantly find files and folders by name, extension, path, size, or modified date across the configured search folders using fsearch-cli/FSearch (macOS/Linux), falling back to a slow filesystem walk when fsearch-cli is not installed. Returns absolute paths; read file contents with bash.",
8955
+ parameters: fsearchSearchSchema,
8956
+ async execute(_toolCallId, params) {
8957
+ const query = params.query.trim();
8958
+ if (query.length === 0) {
8959
+ return {
8960
+ content: [{ type: "text", text: "FSearch query was empty; nothing searched." }],
8961
+ details: { method: FSEARCH_SEARCH_TOOL_NAME, resultCount: 0, sources: [], results: [] }
8962
+ };
8963
+ }
8964
+ const request = {
8965
+ ...params,
8966
+ query,
8967
+ maxResults: Math.min(params.maxResults ?? DEFAULT_MAX_RESULTS4, MAX_RESULTS_CAP3)
8968
+ };
8969
+ const result = await provider.searchFsearch(request);
8970
+ if (!result.ok) {
8971
+ return {
8972
+ content: [{ type: "text", text: `FSearch ${result.reason}: ${result.message}` }],
8973
+ details: { method: FSEARCH_SEARCH_TOOL_NAME, resultCount: 0, sources: [], results: [] }
8974
+ };
8975
+ }
8976
+ const lines = result.results.map((entry, index) => {
8977
+ const parts = [`[${index + 1}] ${entry.type} ${entry.path}`];
8978
+ if (entry.size !== undefined)
8979
+ parts.push(`size=${entry.size}`);
8980
+ if (entry.dateModified !== undefined)
8981
+ parts.push(`modified=${entry.dateModified}`);
8982
+ return parts.join(" ");
8983
+ });
8984
+ const backendLabel = result.backend === "walk" ? "FSearch slow filesystem walk (fsearch-cli unavailable)" : "FSearch";
8985
+ const limitNote = result.backend === "fsearch-cli" && (result.total ?? 0) > lines.length && lines.length === request.maxResults ? ` of ${result.total} total (limit reached; narrow the query or page with offset)` : "";
8986
+ const noteSuffix = result.note !== undefined ? `
8987
+ ${result.note}` : "";
8988
+ const text = lines.length === 0 ? `${backendLabel} found no files or folders matching: ${query}${noteSuffix}` : `${backendLabel} found ${lines.length} item(s)${limitNote}:
8989
+ ${lines.join(`
8990
+ `)}${noteSuffix}`;
8991
+ return {
8992
+ content: [{ type: "text", text }],
8993
+ details: {
8994
+ method: FSEARCH_SEARCH_TOOL_NAME,
8995
+ resultCount: result.results.length,
8996
+ sources: result.results.map((entry) => entry.path),
8997
+ results: result.results.map((entry, index) => ({ source: entry.path, excerpt: lines[index] }))
8998
+ }
8999
+ };
9000
+ }
9001
+ };
9002
+ }
9003
+ var FSEARCH_SEARCH_TOOL_NAME = "fsearch_search", MAX_RESULTS_CAP3 = 1000, DEFAULT_MAX_RESULTS4 = 100, fsearchSearchSchema;
9004
+ var init_fsearch_search_tool = __esm(() => {
9005
+ fsearchSearchSchema = Type5.Object({
9006
+ query: Type5.String({
9007
+ description: 'FSearch query syntax over file and folder names: space = AND, OR keyword = OR (never the pipe |), ! = NOT, "quoted phrase", wildcards (*.pdf), ext:pdf;docx, size:>10mb, path:<fragment>, case:, regex:. When the slow-walk fallback answers (fsearch-cli not installed), only substring/regex name matching applies.'
9008
+ }),
9009
+ regex: Type5.Optional(Type5.Boolean({ description: "Treat query as a regular expression." })),
9010
+ matchCase: Type5.Optional(Type5.Boolean()),
9011
+ matchPath: Type5.Optional(Type5.Boolean({ description: "Match against the full path instead of the name." })),
9012
+ kind: Type5.Optional(Type5.Union([Type5.Literal("files"), Type5.Literal("folders")])),
9013
+ path: Type5.Optional(Type5.String({ description: "Absolute folder to search within." })),
9014
+ sort: Type5.Optional(Type5.Union([
9015
+ Type5.Literal("name-ascending"),
9016
+ Type5.Literal("name-descending"),
9017
+ Type5.Literal("path-ascending"),
9018
+ Type5.Literal("path-descending"),
9019
+ Type5.Literal("size-ascending"),
9020
+ Type5.Literal("size-descending"),
9021
+ Type5.Literal("date-modified-ascending"),
9022
+ Type5.Literal("date-modified-descending")
9023
+ ])),
9024
+ offset: Type5.Optional(Type5.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
9025
+ maxResults: Type5.Optional(Type5.Integer({
9026
+ minimum: 1,
9027
+ description: `Maximum results (default ${DEFAULT_MAX_RESULTS4}, cap ${MAX_RESULTS_CAP3}).`
9028
+ }))
9029
+ });
9030
+ });
9031
+
9032
+ // src/cloud/config.ts
9033
+ function normalizeBaseUrl(value) {
9034
+ const trimmed = value.trim();
9035
+ let end = trimmed.length;
9036
+ while (end > 0 && trimmed.charCodeAt(end - 1) === 47)
9037
+ end--;
9038
+ return trimmed.slice(0, end);
9039
+ }
9040
+ function resolveBaseUrl(env) {
9041
+ const configured = env[AUTORAG_BASE_URL_ENV];
9042
+ const value = typeof configured === "string" && configured.trim() !== "" ? configured : DEFAULT_BASE_URL;
9043
+ return normalizeBaseUrl(value);
9044
+ }
9045
+ var PROVIDER_ID = "autorag", PROVIDER_NAME = "AutoRAG", DEFAULT_BASE_URL = "https://api.dazziapp.com", AUTORAG_BASE_URL_ENV = "AUTORAG_BASE_URL", AUTORAG_API_KEY_ENV = "AUTORAG_API_KEY", API_PATH = "/v1", MODELS_PATH = "/v1/models", AUTHORIZE_PATH = "/desktop/authorize", TOKEN_PATH = "/api/desktop/token", OAUTH_CLIENT_ID = "agent", API_KEY_CONFIG_VALUE;
9046
+ var init_config = __esm(() => {
9047
+ API_KEY_CONFIG_VALUE = `$${AUTORAG_API_KEY_ENV}`;
9048
+ });
9049
+
9050
+ // src/cloud/errors.ts
9051
+ function extractErrorPayload(body) {
9052
+ if (typeof body !== "object" || body === null)
9053
+ return {};
9054
+ const record = body;
9055
+ const error = record.error;
9056
+ if (typeof error === "string")
9057
+ return error.length > 0 ? { message: error } : {};
9058
+ if (typeof error === "object" && error !== null) {
9059
+ const inner = error;
9060
+ const payload = {};
9061
+ if (typeof inner.message === "string")
9062
+ payload.message = inner.message;
9063
+ if (typeof inner.code === "string")
9064
+ payload.code = inner.code;
9065
+ if (typeof inner.type === "string")
9066
+ payload.type = inner.type;
9067
+ return payload;
9068
+ }
9069
+ return typeof record.message === "string" ? { message: record.message } : {};
9070
+ }
9071
+ var AutoragError, AutoragOAuthError, AutoragHttpError;
9072
+ var init_errors3 = __esm(() => {
9073
+ AutoragError = class AutoragError extends Error {
9074
+ constructor(message, options) {
9075
+ super(message, options);
9076
+ this.name = "AutoragError";
9077
+ }
9078
+ };
9079
+ AutoragOAuthError = class AutoragOAuthError extends AutoragError {
9080
+ constructor(message, options) {
9081
+ super(message, options);
9082
+ this.name = "AutoragOAuthError";
9083
+ }
9084
+ };
9085
+ AutoragHttpError = class AutoragHttpError extends AutoragError {
9086
+ status;
9087
+ code;
9088
+ type;
9089
+ constructor(message, options) {
9090
+ super(message, { cause: options.cause });
9091
+ this.name = "AutoragHttpError";
9092
+ this.status = options.status;
9093
+ if (options.code !== undefined)
9094
+ this.code = options.code;
9095
+ if (options.type !== undefined)
9096
+ this.type = options.type;
9097
+ }
9098
+ };
9099
+ });
9100
+
9101
+ // src/cloud/models.ts
9102
+ function resolveCredentialKey(credential) {
9103
+ if (credential === undefined)
9104
+ return;
9105
+ const value = credential.type === "oauth" ? credential.access : credential.key;
9106
+ return typeof value === "string" && value !== "" ? value : undefined;
9107
+ }
9108
+ async function fetchModels(options) {
9109
+ const doFetch = options.fetchImpl ?? fetch;
9110
+ let response;
9111
+ try {
9112
+ response = await doFetch(`${normalizeBaseUrl(options.baseUrl)}${MODELS_PATH}`, {
9113
+ headers: { authorization: `Bearer ${options.apiKey}`, accept: "application/json" },
9114
+ signal: options.signal
9115
+ });
9116
+ } catch (cause) {
9117
+ if (options.signal?.aborted) {
9118
+ throw new AutoragOAuthError("AutoRAG model refresh was cancelled.", { cause });
9119
+ }
9120
+ throw new AutoragOAuthError(`AutoRAG model listing could not reach ${normalizeBaseUrl(options.baseUrl)}.`, {
9121
+ cause
9122
+ });
9123
+ }
9124
+ let body;
9125
+ try {
9126
+ body = await response.json();
9127
+ } catch {
9128
+ body = undefined;
9129
+ }
9130
+ if (!response.ok)
9131
+ throw mapModelsError(response.status, body);
9132
+ return mapServerModels(body);
9133
+ }
9134
+ function mapModelsError(status, body) {
9135
+ const payload = extractErrorPayload(body);
9136
+ if (status === 401) {
9137
+ return new AutoragHttpError("AutoRAG rejected the API key (HTTP 401). Run /login again or set AUTORAG_API_KEY.", {
9138
+ status,
9139
+ code: payload.code ?? "unauthorized",
9140
+ type: payload.type
9141
+ });
9142
+ }
9143
+ const reason = payload.message ?? "the server returned no error message";
9144
+ return new AutoragHttpError(`AutoRAG model listing failed (HTTP ${status}): ${reason}`, {
9145
+ status,
9146
+ code: payload.code,
9147
+ type: payload.type
9148
+ });
9149
+ }
9150
+ function mapServerModels(payload) {
9151
+ if (typeof payload !== "object" || payload === null)
9152
+ return [];
9153
+ const data = payload.data;
9154
+ if (!Array.isArray(data))
9155
+ return [];
9156
+ const models = [];
9157
+ for (const entry of data) {
9158
+ if (typeof entry !== "object" || entry === null)
9159
+ continue;
9160
+ const model = mapServerModel(entry);
9161
+ if (model !== undefined)
9162
+ models.push(model);
9163
+ }
9164
+ return models;
9165
+ }
9166
+ function mapServerModel(entry) {
9167
+ const id = readString2(entry.id);
9168
+ if (id === undefined)
9169
+ return;
9170
+ return {
9171
+ type: "chat",
9172
+ id,
9173
+ name: readString2(entry.name) ?? id,
9174
+ input: readInputModalities(entry.input_modalities),
9175
+ cost: readPricing(entry.pricing),
9176
+ reasoning: entry.reasoning === true,
9177
+ contextWindow: readPositiveNumber(entry.context_window) ?? DEFAULT_CONTEXT_WINDOW,
9178
+ maxTokens: readPositiveNumber(entry.max_output_tokens) ?? DEFAULT_MAX_TOKENS
9179
+ };
9180
+ }
9181
+ function buildStoreEntry(models, providerId, baseUrl) {
9182
+ const stored = [];
9183
+ for (const model of models) {
9184
+ if (model.type === "image" || model.type === "classifier")
9185
+ continue;
9186
+ stored.push({
9187
+ type: "chat",
9188
+ id: model.id,
9189
+ name: model.name,
9190
+ api: model.api ?? "openai-responses",
9191
+ provider: providerId,
9192
+ baseUrl: model.baseUrl ?? baseUrl,
9193
+ input: model.input,
9194
+ cost: model.cost,
9195
+ reasoning: model.reasoning,
9196
+ contextWindow: model.contextWindow,
9197
+ maxTokens: model.maxTokens
9198
+ });
9199
+ }
9200
+ return { models: stored, checkedAt: Date.now() };
9201
+ }
9202
+ function modelsFromStore(stored) {
9203
+ if (stored === undefined)
9204
+ return [];
9205
+ const models = [];
9206
+ for (const entry of stored.models) {
9207
+ if (entry.type === "image" || entry.type === "classifier")
9208
+ continue;
9209
+ models.push({
9210
+ type: "chat",
9211
+ id: entry.id,
9212
+ name: entry.name,
9213
+ input: entry.input,
9214
+ cost: entry.cost,
9215
+ reasoning: entry.reasoning,
9216
+ contextWindow: entry.contextWindow,
9217
+ maxTokens: entry.maxTokens
9218
+ });
9219
+ }
9220
+ return models;
9221
+ }
9222
+ function readString2(value) {
9223
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
9224
+ }
9225
+ function readPositiveNumber(value) {
9226
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
9227
+ }
9228
+ function readInputModalities(value) {
9229
+ if (!Array.isArray(value))
9230
+ return ["text"];
9231
+ const modalities = value.filter((item) => item === "text" || item === "image");
9232
+ const unique = Array.from(new Set(modalities));
9233
+ return unique.length > 0 ? unique : ["text"];
9234
+ }
9235
+ function readPricing(value) {
9236
+ const pricing = typeof value === "object" && value !== null ? value : {};
9237
+ return {
9238
+ input: readPositiveNumber(pricing.input) ?? 0,
9239
+ output: readPositiveNumber(pricing.output) ?? 0,
9240
+ cacheRead: readPositiveNumber(pricing.cache_read) ?? 0,
9241
+ cacheWrite: readPositiveNumber(pricing.cache_write) ?? 0
9242
+ };
9243
+ }
9244
+ var DEFAULT_CONTEXT_WINDOW = 128000, DEFAULT_MAX_TOKENS = 16384;
9245
+ var init_models = __esm(() => {
9246
+ init_config();
9247
+ init_errors3();
9248
+ });
9249
+
9250
+ // src/cloud/authorize.ts
9251
+ function buildAuthorizeUrl(params) {
9252
+ const url = new URL(`${normalizeBaseUrl(params.baseUrl)}${AUTHORIZE_PATH}`);
9253
+ url.searchParams.set("client", OAUTH_CLIENT_ID);
9254
+ url.searchParams.set("redirect_uri", params.redirectUri);
9255
+ url.searchParams.set("state", params.state);
9256
+ url.searchParams.set("code_challenge", params.codeChallenge);
9257
+ url.searchParams.set("code_challenge_method", "S256");
9258
+ return url.toString();
9259
+ }
9260
+ var init_authorize = __esm(() => {
9261
+ init_config();
9262
+ });
9263
+
9264
+ // src/cloud/callback.ts
9265
+ function parseCallbackQuery(params) {
9266
+ const result = {};
9267
+ const code = params.get("code");
9268
+ const error = params.get("error");
9269
+ const state = params.get("state");
9270
+ if (code !== null && code !== "")
9271
+ result.code = code;
9272
+ if (error !== null && error !== "")
9273
+ result.error = error;
9274
+ if (state !== null && state !== "")
9275
+ result.state = state;
9276
+ return result;
9277
+ }
9278
+ function parseCallbackInput(input) {
9279
+ const trimmed = input.trim();
9280
+ if (trimmed === "") {
9281
+ throw new AutoragOAuthError("AutoRAG sign-in failed: nothing was pasted.");
9282
+ }
9283
+ if (/^https?:\/\//i.test(trimmed)) {
9284
+ try {
9285
+ return parseCallbackQuery(new URL(trimmed).searchParams);
9286
+ } catch {
9287
+ throw new AutoragOAuthError("AutoRAG sign-in failed: the pasted URL is not valid.");
9288
+ }
9289
+ }
9290
+ const query = trimmed.startsWith("?") ? trimmed.slice(1) : trimmed;
9291
+ if (!query.includes(" ")) {
9292
+ const params = new URLSearchParams(query);
9293
+ if (params.has("code") || params.has("error") || params.has("state")) {
9294
+ return parseCallbackQuery(params);
9295
+ }
9296
+ }
9297
+ return { code: trimmed };
9298
+ }
9299
+ function requireAuthorizationCode(result, expectedState) {
9300
+ if (result.state !== undefined && result.state !== expectedState) {
9301
+ throw new AutoragOAuthError("AutoRAG sign-in failed: state mismatch (the callback did not originate from this login attempt).");
9302
+ }
9303
+ if (result.error !== undefined) {
9304
+ throw new AutoragOAuthError(result.error === "access_denied" ? "AutoRAG sign-in was cancelled in the browser." : `AutoRAG sign-in failed: ${result.error}.`);
9305
+ }
9306
+ if (result.code === undefined) {
9307
+ throw new AutoragOAuthError("AutoRAG sign-in failed: the callback carried no authorization code.");
9308
+ }
9309
+ return { code: result.code };
9310
+ }
9311
+ var init_callback = __esm(() => {
9312
+ init_errors3();
9313
+ });
9314
+
9315
+ // src/cloud/callback-server.ts
9316
+ import { createServer as createServer3 } from "node:http";
9317
+ function createDeferred() {
9318
+ let resolve;
9319
+ let reject;
9320
+ const promise = new Promise((res, rej) => {
9321
+ resolve = res;
9322
+ reject = rej;
9323
+ });
9324
+ return { promise, resolve, reject };
9325
+ }
9326
+ function renderCallbackPage(failed) {
9327
+ const message = failed ? "AutoRAG sign-in did not complete. You can close this tab and try again." : "Signed in to AutoRAG. You can close this tab.";
9328
+ return [
9329
+ "<!doctype html>",
9330
+ '<html lang="en">',
9331
+ "<head>",
9332
+ '<meta charset="utf-8">',
9333
+ '<meta name="viewport" content="width=device-width, initial-scale=1">',
9334
+ "<title>AutoRAG</title>",
9335
+ "</head>",
9336
+ '<body style="font-family: system-ui, sans-serif; margin: 4rem auto; max-width: 32rem; text-align: center;">',
9337
+ `<p>${message}</p>`,
9338
+ "</body>",
9339
+ "</html>"
9340
+ ].join(`
9341
+ `);
9342
+ }
9343
+ function startCallbackServer(options) {
9344
+ const host = options.host ?? "127.0.0.1";
9345
+ const timeoutMs = options.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS;
9346
+ const server = createServer3();
9347
+ const started = createDeferred();
9348
+ const callback = createDeferred();
9349
+ callback.promise.catch(() => {});
9350
+ let finished = false;
9351
+ let startSettled = false;
9352
+ let timer;
9353
+ function cleanup() {
9354
+ clearTimeout(timer);
9355
+ options.signal?.removeEventListener("abort", onAbort);
9356
+ if (server.listening) {
9357
+ server.closeAllConnections();
9358
+ server.close();
9359
+ }
9360
+ }
9361
+ function fail(error) {
9362
+ if (finished)
9363
+ return;
9364
+ finished = true;
9365
+ cleanup();
9366
+ callback.reject(error);
9367
+ }
9368
+ function onAbort() {
9369
+ fail(new AutoragOAuthError("AutoRAG sign-in was cancelled."));
9370
+ }
9371
+ server.on("request", (req, res) => {
9372
+ const url = new URL(req.url ?? "/", `http://${host}`);
9373
+ if (req.method !== "GET" || url.pathname !== CALLBACK_PATH) {
9374
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
9375
+ res.end("Not found");
9376
+ return;
9377
+ }
9378
+ if (finished) {
9379
+ res.writeHead(410, { "content-type": "text/plain; charset=utf-8" });
9380
+ res.end("Callback already handled");
9381
+ return;
9382
+ }
9383
+ const params = url.searchParams;
9384
+ const code = params.get("code");
9385
+ const oauthError = params.get("error");
9386
+ const hasResponse = code !== null && code !== "" || oauthError !== null && oauthError !== "";
9387
+ if (params.get("state") !== options.state || !hasResponse) {
9388
+ res.writeHead(400, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
9389
+ res.end(renderCallbackPage(true));
9390
+ return;
9391
+ }
9392
+ finished = true;
9393
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
9394
+ res.end(renderCallbackPage(params.has("error")));
9395
+ cleanup();
9396
+ callback.resolve(params);
9397
+ });
9398
+ server.on("error", (error) => {
9399
+ const wrapped = error instanceof Error ? error : new Error(String(error));
9400
+ if (!startSettled) {
9401
+ startSettled = true;
9402
+ cleanup();
9403
+ started.reject(wrapped);
9404
+ return;
9405
+ }
9406
+ fail(wrapped);
9407
+ });
9408
+ server.listen(0, host, () => {
9409
+ const address = server.address();
9410
+ const port = typeof address === "object" && address !== null ? address.port : 0;
9411
+ const redirectUri = `http://${host}:${port}${CALLBACK_PATH}`;
9412
+ timer = setTimeout(() => fail(new AutoragOAuthError("AutoRAG sign-in timed out waiting for the browser callback.")), timeoutMs);
9413
+ if (options.signal?.aborted)
9414
+ onAbort();
9415
+ else
9416
+ options.signal?.addEventListener("abort", onAbort, { once: true });
9417
+ startSettled = true;
9418
+ options.onListening?.(redirectUri);
9419
+ started.resolve({
9420
+ redirectUri,
9421
+ waitForCallback: () => callback.promise,
9422
+ close: () => {
9423
+ if (!finished)
9424
+ fail(new AutoragOAuthError("AutoRAG sign-in was cancelled."));
9425
+ }
9426
+ });
9427
+ });
9428
+ return started.promise;
9429
+ }
9430
+ var CALLBACK_PATH = "/callback", DEFAULT_LOGIN_TIMEOUT_MS;
9431
+ var init_callback_server = __esm(() => {
9432
+ init_errors3();
9433
+ DEFAULT_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
9434
+ });
9435
+
9436
+ // src/cloud/pkce.ts
9437
+ import { createHash as createHash11, randomBytes } from "node:crypto";
9438
+ function base64UrlEncode(bytes) {
9439
+ return Buffer.from(bytes).toString("base64url");
9440
+ }
9441
+ function createCodeChallenge(verifier) {
9442
+ return base64UrlEncode(createHash11("sha256").update(verifier, "ascii").digest());
9443
+ }
9444
+ function createCodeVerifier(byteLength = 32) {
9445
+ return base64UrlEncode(randomBytes(byteLength));
9446
+ }
9447
+ function createState(byteLength = 24) {
9448
+ return base64UrlEncode(randomBytes(byteLength));
9449
+ }
9450
+ function createPkcePair(byteLength = 32) {
9451
+ const verifier = createCodeVerifier(byteLength);
9452
+ return { verifier, challenge: createCodeChallenge(verifier) };
9453
+ }
9454
+ var init_pkce = () => {};
9455
+
9456
+ // src/cloud/token.ts
9457
+ function mapTokenExchangeError(status, body) {
9458
+ const payload = extractErrorPayload(body);
9459
+ const reason = payload.message ?? "the server returned no error message";
9460
+ return new AutoragHttpError(`AutoRAG token exchange failed (HTTP ${status}): ${reason}`, {
9461
+ status,
9462
+ code: payload.code,
9463
+ type: payload.type
9464
+ });
9465
+ }
9466
+ async function exchangeCodeForToken(options) {
9467
+ const doFetch = options.fetchImpl ?? fetch;
9468
+ let response;
9469
+ try {
9470
+ response = await doFetch(`${normalizeBaseUrl(options.baseUrl)}${TOKEN_PATH}`, {
9471
+ method: "POST",
9472
+ headers: { "content-type": "application/json", accept: "application/json" },
9473
+ body: JSON.stringify({
9474
+ code: options.code,
9475
+ code_verifier: options.codeVerifier,
9476
+ redirect_uri: options.redirectUri
9477
+ }),
9478
+ signal: options.signal
9479
+ });
9480
+ } catch (cause) {
9481
+ if (options.signal?.aborted) {
9482
+ throw new AutoragOAuthError("AutoRAG sign-in was cancelled.", { cause });
9483
+ }
9484
+ throw new AutoragOAuthError(`AutoRAG token exchange could not reach ${normalizeBaseUrl(options.baseUrl)}.`, {
9485
+ cause
9486
+ });
9487
+ }
9488
+ let body;
9489
+ try {
9490
+ body = await response.json();
9491
+ } catch {
9492
+ body = undefined;
9493
+ }
9494
+ if (!response.ok)
9495
+ throw mapTokenExchangeError(response.status, body);
9496
+ const accessToken = readAccessToken(body);
9497
+ if (accessToken === undefined) {
9498
+ throw new AutoragOAuthError("AutoRAG token exchange succeeded but returned no access token.");
8916
9499
  }
9500
+ const email = readEmail(body);
9501
+ return email === undefined ? { accessToken } : { accessToken, email };
8917
9502
  }
8918
- var MAX_CANDIDATES = 2000, MAX_CONTENT_LENGTH = 4000, MIN_MATCH_LENGTH = 12;
8919
-
8920
- // src/agent/fast-answer-tool.ts
8921
- import { Type as Type6 } from "typebox";
8922
- function createEmitFastAnswerTool(capture, options) {
8923
- return {
8924
- name: EMIT_FAST_ANSWER_TOOL_NAME,
8925
- label: "Emit Fast Answer",
8926
- description: "Deliver the immediate first answer to the user. Call this exactly once during the fast phase with a complete, self-contained answer built only from the baseline retrieval evidence. Do not call any other tool before this one. The run continues afterwards for verification. A call whose answer cites a number missing from results, or whose refs name evidence that was not provided, is rejected; fix it and call again.",
8927
- parameters: fastAnswerSchema,
8928
- async execute(_toolCallId, params) {
8929
- assertCitationsResolve(EMIT_FAST_ANSWER_TOOL_NAME, params.answer, params.results);
8930
- const evidenceRefs = [];
8931
- for (const result of params.results) {
8932
- if (result.refs === undefined || result.refs.length === 0)
8933
- continue;
8934
- const refs = options.ledger.resolve(result.refs, {
8935
- label: EMIT_FAST_ANSWER_TOOL_NAME,
8936
- number: result.number,
8937
- fallbackContent: result.summary,
8938
- allowLocalFiles: false
8939
- });
8940
- if (refs.length > 0)
8941
- evidenceRefs.push({ number: result.number, refs });
8942
- }
8943
- const details = {
8944
- answer: params.answer,
8945
- results: params.results.map((result) => ({
8946
- number: result.number,
8947
- title: result.title,
8948
- summary: result.summary,
8949
- evidence: (result.evidence ?? []).map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
8950
- ...result.confidence !== undefined ? { confidence: result.confidence } : {}
8951
- })),
8952
- sources: evidenceRefs.flatMap((entry) => {
8953
- const [primary] = entry.refs;
8954
- return primary === undefined ? [] : [{ number: entry.number, source: primary.source }];
8955
- }),
8956
- evidenceRefs
8957
- };
8958
- capture(details);
8959
- return {
8960
- content: [
8961
- {
8962
- type: "text",
8963
- text: "Fast answer delivered to the user. Stop now; a deeper verification pass follows separately."
8964
- }
8965
- ],
8966
- details
8967
- };
8968
- }
8969
- };
9503
+ function readAccessToken(body) {
9504
+ if (typeof body !== "object" || body === null)
9505
+ return;
9506
+ const value = body.access_token;
9507
+ return typeof value === "string" && value !== "" ? value : undefined;
8970
9508
  }
8971
- var EMIT_FAST_ANSWER_TOOL_NAME = "emit_fast_answer", fastAnswerSchema;
8972
- var init_fast_answer_tool = __esm(() => {
8973
- fastAnswerSchema = Type6.Object({
8974
- answer: Type6.String({
8975
- description: `Complete, self-contained first answer for the caller in at most 5 bullet points (plus optional explanation), produced immediately from baseline retrieval evidence. Reference results by bracketed number (e.g. [1], [2]) without file paths or raw chunk text, except the image-embed exception below. ${ANSWER_CITATION_RULE} ${ANSWER_IMAGE_EMBED_RULE}`
8976
- }),
8977
- results: Type6.Array(Type6.Object({
8978
- number: Type6.Integer({ description: "1-based result number" }),
8979
- title: Type6.String({ description: "Short name of the knowledge unit" }),
8980
- summary: Type6.String({ description: "Key insight backing the first answer" }),
8981
- evidence: Type6.Optional(Type6.Array(Type6.Object({
8982
- excerpt: Type6.String({ description: "Supporting excerpt" }),
8983
- lineNumber: Type6.Optional(Type6.Integer({ description: "Line number of the excerpt, if known" }))
8984
- }))),
8985
- confidence: Type6.Optional(Type6.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })),
8986
- refs: Type6.Optional(Type6.Array(Type6.String(), {
8987
- description: "Evidence ids from the baseline evidence that support this result (e.g. e3). The source path is attached for you. Omit only when no baseline evidence backs the result."
8988
- }))
8989
- }), { description: "Numbered knowledge units backing the first answer." })
9509
+ function readEmail(body) {
9510
+ if (typeof body !== "object" || body === null)
9511
+ return;
9512
+ const value = body.email;
9513
+ return typeof value === "string" && value !== "" ? value : undefined;
9514
+ }
9515
+ var init_token = __esm(() => {
9516
+ init_config();
9517
+ init_errors3();
9518
+ });
9519
+
9520
+ // src/cloud/oauth-login.ts
9521
+ function refreshAutoragCredentials(credentials) {
9522
+ return credentials;
9523
+ }
9524
+ async function loginAutorag(callbacks, options) {
9525
+ const { verifier, challenge } = createPkcePair();
9526
+ const state = createState();
9527
+ const server = await startCallbackServer({
9528
+ state,
9529
+ timeoutMs: options.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS,
9530
+ signal: callbacks.signal
8990
9531
  });
9532
+ try {
9533
+ callbacks.onAuth({
9534
+ url: buildAuthorizeUrl({
9535
+ baseUrl: options.baseUrl,
9536
+ redirectUri: server.redirectUri,
9537
+ state,
9538
+ codeChallenge: challenge
9539
+ }),
9540
+ instructions: `Waiting for the AutoRAG sign-in callback on ${server.redirectUri}. If the browser cannot reach this machine, paste the final redirect URL or the code instead.`
9541
+ });
9542
+ callbacks.onProgress?.(`Listening for the AutoRAG sign-in callback on ${server.redirectUri}`);
9543
+ const outcome = await Promise.race([
9544
+ server.waitForCallback().then((params) => ({ params })),
9545
+ callbacks.onPrompt({
9546
+ message: "Complete the AutoRAG sign-in in your browser, or paste the final redirect URL / authorization code here:",
9547
+ placeholder: server.redirectUri,
9548
+ allowEmpty: true
9549
+ }).then((value) => ({ value }))
9550
+ ]);
9551
+ const parsed = "params" in outcome ? parseCallbackQuery(outcome.params) : parseCallbackInput(outcome.value);
9552
+ const { code } = requireAuthorizationCode(parsed, state);
9553
+ const token = await exchangeCodeForToken({
9554
+ baseUrl: options.baseUrl,
9555
+ code,
9556
+ codeVerifier: verifier,
9557
+ redirectUri: server.redirectUri,
9558
+ signal: callbacks.signal,
9559
+ fetchImpl: options.fetchImpl
9560
+ });
9561
+ return {
9562
+ access: token.accessToken,
9563
+ refresh: "",
9564
+ expires: Number.MAX_SAFE_INTEGER,
9565
+ ...token.email !== undefined ? { email: token.email } : {}
9566
+ };
9567
+ } finally {
9568
+ server.close();
9569
+ }
9570
+ }
9571
+ var init_oauth_login = __esm(() => {
9572
+ init_authorize();
9573
+ init_callback();
9574
+ init_callback_server();
9575
+ init_pkce();
9576
+ init_token();
8991
9577
  });
8992
9578
 
8993
- // src/agent/fsearch-search-tool.ts
8994
- import { Type as Type7 } from "typebox";
8995
- function createFSearchSearchTool(provider) {
9579
+ // src/cloud/provider.ts
9580
+ async function refreshAutoragModels(context, endpoints) {
9581
+ const stored = modelsFromStore(context.stored);
9582
+ const apiKey = resolveCredentialKey(context.credential);
9583
+ if (!context.allowNetwork || apiKey === undefined)
9584
+ return stored;
9585
+ let models;
9586
+ try {
9587
+ models = await fetchModels({ baseUrl: endpoints.baseUrl, apiKey, signal: context.signal });
9588
+ } catch {
9589
+ return stored;
9590
+ }
9591
+ if (models.length === 0)
9592
+ return stored;
9593
+ try {
9594
+ await context.publish({ persist: buildStoreEntry(models, PROVIDER_ID, endpoints.apiBaseUrl) });
9595
+ } catch {}
9596
+ return models;
9597
+ }
9598
+ function createAutoRAGProviderConfig(env = process.env) {
9599
+ const baseUrl = resolveBaseUrl(env);
9600
+ const endpoints = { baseUrl, apiBaseUrl: `${baseUrl}${API_PATH}` };
8996
9601
  return {
8997
- name: FSEARCH_SEARCH_TOOL_NAME,
8998
- label: "FSearch Search",
8999
- description: "Instantly find files and folders by name, extension, path, size, or modified date across the configured search folders using fsearch-cli/FSearch (macOS/Linux), falling back to a slow filesystem walk when fsearch-cli is not installed. Returns absolute paths; read file contents with bash.",
9000
- parameters: fsearchSearchSchema,
9001
- async execute(_toolCallId, params) {
9002
- const query = params.query.trim();
9003
- if (query.length === 0) {
9004
- return {
9005
- content: [{ type: "text", text: "FSearch query was empty; nothing searched." }],
9006
- details: { method: FSEARCH_SEARCH_TOOL_NAME, resultCount: 0, sources: [], results: [] }
9007
- };
9008
- }
9009
- const request = {
9010
- ...params,
9011
- query,
9012
- maxResults: Math.min(params.maxResults ?? DEFAULT_MAX_RESULTS4, MAX_RESULTS_CAP3)
9013
- };
9014
- const result = await provider.searchFsearch(request);
9015
- if (!result.ok) {
9016
- return {
9017
- content: [{ type: "text", text: `FSearch ${result.reason}: ${result.message}` }],
9018
- details: { method: FSEARCH_SEARCH_TOOL_NAME, resultCount: 0, sources: [], results: [] }
9019
- };
9020
- }
9021
- const lines = result.results.map((entry, index) => {
9022
- const parts = [`[${index + 1}] ${entry.type} ${entry.path}`];
9023
- if (entry.size !== undefined)
9024
- parts.push(`size=${entry.size}`);
9025
- if (entry.dateModified !== undefined)
9026
- parts.push(`modified=${entry.dateModified}`);
9027
- return parts.join(" ");
9028
- });
9029
- const backendLabel = result.backend === "walk" ? "FSearch slow filesystem walk (fsearch-cli unavailable)" : "FSearch";
9030
- const limitNote = result.backend === "fsearch-cli" && (result.total ?? 0) > lines.length && lines.length === request.maxResults ? ` of ${result.total} total (limit reached; narrow the query or page with offset)` : "";
9031
- const noteSuffix = result.note !== undefined ? `
9032
- ${result.note}` : "";
9033
- const text = lines.length === 0 ? `${backendLabel} found no files or folders matching: ${query}${noteSuffix}` : `${backendLabel} found ${lines.length} item(s)${limitNote}:
9034
- ${lines.join(`
9035
- `)}${noteSuffix}`;
9036
- return {
9037
- content: [{ type: "text", text }],
9038
- details: {
9039
- method: FSEARCH_SEARCH_TOOL_NAME,
9040
- resultCount: result.results.length,
9041
- sources: result.results.map((entry) => entry.path),
9042
- results: result.results.map((entry, index) => ({ source: entry.path, excerpt: lines[index] }))
9043
- }
9044
- };
9045
- }
9602
+ name: PROVIDER_NAME,
9603
+ baseUrl: endpoints.apiBaseUrl,
9604
+ api: "openai-responses",
9605
+ apiKey: API_KEY_CONFIG_VALUE,
9606
+ oauth: {
9607
+ name: PROVIDER_NAME,
9608
+ login: (callbacks) => loginAutorag(callbacks, { baseUrl }),
9609
+ refreshToken: async (credentials) => refreshAutoragCredentials(credentials),
9610
+ getApiKey: (credentials) => credentials.access
9611
+ },
9612
+ refreshModels: (context) => refreshAutoragModels(context, endpoints)
9046
9613
  };
9047
9614
  }
9048
- var FSEARCH_SEARCH_TOOL_NAME = "fsearch_search", MAX_RESULTS_CAP3 = 1000, DEFAULT_MAX_RESULTS4 = 100, fsearchSearchSchema;
9049
- var init_fsearch_search_tool = __esm(() => {
9050
- fsearchSearchSchema = Type7.Object({
9051
- query: Type7.String({
9052
- description: 'FSearch query syntax over file and folder names: space = AND, OR keyword = OR (never the pipe |), ! = NOT, "quoted phrase", wildcards (*.pdf), ext:pdf;docx, size:>10mb, path:<fragment>, case:, regex:. When the slow-walk fallback answers (fsearch-cli not installed), only substring/regex name matching applies.'
9053
- }),
9054
- regex: Type7.Optional(Type7.Boolean({ description: "Treat query as a regular expression." })),
9055
- matchCase: Type7.Optional(Type7.Boolean()),
9056
- matchPath: Type7.Optional(Type7.Boolean({ description: "Match against the full path instead of the name." })),
9057
- kind: Type7.Optional(Type7.Union([Type7.Literal("files"), Type7.Literal("folders")])),
9058
- path: Type7.Optional(Type7.String({ description: "Absolute folder to search within." })),
9059
- sort: Type7.Optional(Type7.Union([
9060
- Type7.Literal("name-ascending"),
9061
- Type7.Literal("name-descending"),
9062
- Type7.Literal("path-ascending"),
9063
- Type7.Literal("path-descending"),
9064
- Type7.Literal("size-ascending"),
9065
- Type7.Literal("size-descending"),
9066
- Type7.Literal("date-modified-ascending"),
9067
- Type7.Literal("date-modified-descending")
9068
- ])),
9069
- offset: Type7.Optional(Type7.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
9070
- maxResults: Type7.Optional(Type7.Integer({
9071
- minimum: 1,
9072
- description: `Maximum results (default ${DEFAULT_MAX_RESULTS4}, cap ${MAX_RESULTS_CAP3}).`
9073
- }))
9074
- });
9615
+ async function registerAutoRAGProvider(runtime, env = process.env) {
9616
+ runtime.registerProvider(PROVIDER_ID, createAutoRAGProviderConfig(env));
9617
+ await runtime.refresh({ allowNetwork: false, providers: [PROVIDER_ID] });
9618
+ }
9619
+ var init_provider = __esm(() => {
9620
+ init_config();
9621
+ init_models();
9622
+ init_oauth_login();
9075
9623
  });
9076
9624
 
9077
9625
  // src/agent/pi-session.ts
@@ -9200,6 +9748,7 @@ async function createAutoRAGPiSession(options) {
9200
9748
  authPath: join21(agentDir, "auth.json"),
9201
9749
  modelsPath: join21(agentDir, "models.json")
9202
9750
  });
9751
+ await registerAutoRAGProvider(modelRuntime);
9203
9752
  await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
9204
9753
  const customTools = [...options.customTools];
9205
9754
  const extensionToolNames = [...options.extensionToolNames ?? []];
@@ -9249,6 +9798,7 @@ async function createAutoRAGPiInteractiveRuntime(options) {
9249
9798
  authPath: join21(agentDir, "auth.json"),
9250
9799
  modelsPath: join21(agentDir, "models.json")
9251
9800
  });
9801
+ await registerAutoRAGProvider(modelRuntime);
9252
9802
  await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
9253
9803
  const sessionManager = options.sessionPath ? SessionManager.open(options.sessionPath, options.sessionDir, options.cwd) : SessionManager.create(options.cwd, options.sessionDir);
9254
9804
  const createRuntime = async ({
@@ -9298,12 +9848,13 @@ async function createAutoRAGPiInteractiveRuntime(options) {
9298
9848
  }
9299
9849
  var PI_BUILTIN_TOOL_NAMES, EMBEDDED_AUTH_MARKER = "<autorag-embedded-model>";
9300
9850
  var init_pi_session = __esm(() => {
9851
+ init_provider();
9301
9852
  PI_BUILTIN_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
9302
9853
  });
9303
9854
 
9304
9855
  // src/agent/jev-extension.ts
9305
9856
  import { Jev } from "jev-use";
9306
- import { Type as Type8 } from "typebox";
9857
+ import { Type as Type6 } from "typebox";
9307
9858
  function createJevJudge(options = {}) {
9308
9859
  let client;
9309
9860
  return async (state, questions, callOptions = {}) => {
@@ -9356,32 +9907,32 @@ var JEV_TOOL_NAME = "jev", OPENROUTER_DEFAULT_MODEL = "typesafe/jev-1.13", BACKE
9356
9907
  var init_jev_extension = __esm(() => {
9357
9908
  init_pi_session();
9358
9909
  BACKEND_DEFAULT_MODEL = { openrouter: OPENROUTER_DEFAULT_MODEL };
9359
- jevQuestionSchema = Type8.Object({
9360
- id: Type8.Optional(Type8.String({ description: "Caller-assigned id, echoed back in the verdict" })),
9361
- type: Type8.Union([Type8.Literal("noul"), Type8.Literal("choice"), Type8.Literal("score")], {
9910
+ jevQuestionSchema = Type6.Object({
9911
+ id: Type6.Optional(Type6.String({ description: "Caller-assigned id, echoed back in the verdict" })),
9912
+ type: Type6.Union([Type6.Literal("noul"), Type6.Literal("choice"), Type6.Literal("score")], {
9362
9913
  description: "noul = P(yes), choice = pick one option, score = ordered level index"
9363
9914
  }),
9364
- question: Type8.String({
9915
+ question: Type6.String({
9365
9916
  minLength: 1,
9366
9917
  description: "One narrow question about the state. Jev answers exactly this."
9367
9918
  }),
9368
- options: Type8.Optional(Type8.Union([Type8.Array(Type8.String()), Type8.Record(Type8.String(), Type8.String())], {
9919
+ options: Type6.Optional(Type6.Union([Type6.Array(Type6.String()), Type6.Record(Type6.String(), Type6.String())], {
9369
9920
  description: "choice only: at least two option labels (or label -> meaning)"
9370
9921
  })),
9371
- levels: Type8.Optional(Type8.Array(Type8.String(), {
9922
+ levels: Type6.Optional(Type6.Array(Type6.String(), {
9372
9923
  description: "score only: at least two ordered level descriptions; the answer indexes into them"
9373
9924
  })),
9374
- criteria: Type8.Optional(Type8.Object({ true: Type8.String(), false: Type8.String() }, { description: "noul only: what yes and no mean, to sharpen calibration" }))
9925
+ criteria: Type6.Optional(Type6.Object({ true: Type6.String(), false: Type6.String() }, { description: "noul only: what yes and no mean, to sharpen calibration" }))
9375
9926
  });
9376
- jevParameters = Type8.Object({
9377
- state: Type8.Unknown({
9927
+ jevParameters = Type6.Object({
9928
+ state: Type6.Unknown({
9378
9929
  description: "Text, JSON object, or JSON array Jev should judge. Keep it small and self-contained."
9379
9930
  }),
9380
- questions: Type8.Array(jevQuestionSchema, {
9931
+ questions: Type6.Array(jevQuestionSchema, {
9381
9932
  minItems: 1,
9382
9933
  description: "Named questions, all evaluated against the same state in one batched request."
9383
9934
  }),
9384
- confidence_threshold: Type8.Optional(Type8.Number({
9935
+ confidence_threshold: Type6.Optional(Type6.Number({
9385
9936
  minimum: 0,
9386
9937
  maximum: 1,
9387
9938
  description: "Escalate any verdict below this confidence; omitted uses jev-use's per-source defaults"
@@ -9390,7 +9941,7 @@ var init_jev_extension = __esm(() => {
9390
9941
  });
9391
9942
 
9392
9943
  // src/agent/jikji-find-tool.ts
9393
- import { Type as Type9 } from "typebox";
9944
+ import { Type as Type7 } from "typebox";
9394
9945
  function createJikjiFindTool(provider, ledger = new EvidenceLedger) {
9395
9946
  return {
9396
9947
  name: JIKJI_FIND_TOOL_NAME,
@@ -9521,10 +10072,10 @@ function formatDirective(policy) {
9521
10072
  var JIKJI_FIND_TOOL_NAME = "jikji_find", jikjiFindSchema;
9522
10073
  var init_jikji_find_tool = __esm(() => {
9523
10074
  init_evidence_ledger();
9524
- jikjiFindSchema = Type9.Object({
9525
- query: Type9.String({ description: "Query for Jikji local file discovery." }),
9526
- topK: Type9.Optional(Type9.Integer({ description: "Maximum number of answer paths / candidates to return." })),
9527
- first: Type9.Optional(Type9.Boolean({ description: "Return only the first/best answer." }))
10075
+ jikjiFindSchema = Type7.Object({
10076
+ query: Type7.String({ description: "Query for Jikji local file discovery." }),
10077
+ topK: Type7.Optional(Type7.Integer({ description: "Maximum number of answer paths / candidates to return." })),
10078
+ first: Type7.Optional(Type7.Boolean({ description: "Return only the first/best answer." }))
9528
10079
  });
9529
10080
  });
9530
10081
 
@@ -10493,57 +11044,57 @@ var init_policy = __esm(() => {
10493
11044
  });
10494
11045
 
10495
11046
  // src/p2p/wire.ts
10496
- import { Type as Type10 } from "typebox";
11047
+ import { Type as Type8 } from "typebox";
10497
11048
  var PeerRefusalCodeSchema, PeerDiagnosticSchema, PeerFileEntrySchema, PeerResultEntrySchema, PeerQueryRequestSchema, PeerQueryResponseSchema;
10498
11049
  var init_wire = __esm(() => {
10499
- PeerRefusalCodeSchema = Type10.Union([
10500
- Type10.Literal("auth-error"),
10501
- Type10.Literal("replay-rejected"),
10502
- Type10.Literal("rate-limited"),
10503
- Type10.Literal("injection-detected"),
10504
- Type10.Literal("policy-denied"),
10505
- Type10.Literal("queue-full"),
10506
- Type10.Literal("internal-error")
11050
+ PeerRefusalCodeSchema = Type8.Union([
11051
+ Type8.Literal("auth-error"),
11052
+ Type8.Literal("replay-rejected"),
11053
+ Type8.Literal("rate-limited"),
11054
+ Type8.Literal("injection-detected"),
11055
+ Type8.Literal("policy-denied"),
11056
+ Type8.Literal("queue-full"),
11057
+ Type8.Literal("internal-error")
10507
11058
  ]);
10508
- PeerDiagnosticSchema = Type10.Object({
10509
- code: Type10.String({ minLength: 1, description: "Diagnostic or refusal code" }),
10510
- message: Type10.String({ description: "Human-readable diagnostic message" })
11059
+ PeerDiagnosticSchema = Type8.Object({
11060
+ code: Type8.String({ minLength: 1, description: "Diagnostic or refusal code" }),
11061
+ message: Type8.String({ description: "Human-readable diagnostic message" })
10511
11062
  });
10512
- PeerFileEntrySchema = Type10.Object({
10513
- source: Type10.String({
11063
+ PeerFileEntrySchema = Type8.Object({
11064
+ source: Type8.String({
10514
11065
  description: "Canonical retrieval source identifier"
10515
11066
  }),
10516
- contentBase64: Type10.String({ description: "Base64-encoded file content" }),
10517
- redacted: Type10.Boolean({ description: "Whether the content was PII-redacted" })
11067
+ contentBase64: Type8.String({ description: "Base64-encoded file content" }),
11068
+ redacted: Type8.Boolean({ description: "Whether the content was PII-redacted" })
10518
11069
  });
10519
- PeerResultEntrySchema = Type10.Object({
10520
- number: Type10.Integer({ minimum: 1, description: "1-based result number" }),
10521
- title: Type10.String({ minLength: 1, description: "Short title of the result" }),
10522
- summary: Type10.String({ description: "Key insight summary" }),
10523
- source: Type10.String({
11070
+ PeerResultEntrySchema = Type8.Object({
11071
+ number: Type8.Integer({ minimum: 1, description: "1-based result number" }),
11072
+ title: Type8.String({ minLength: 1, description: "Short title of the result" }),
11073
+ summary: Type8.String({ description: "Key insight summary" }),
11074
+ source: Type8.String({
10524
11075
  description: "Canonical retrieval source identifier"
10525
11076
  }),
10526
- excerpt: Type10.String({ description: "Supporting excerpt" })
11077
+ excerpt: Type8.String({ description: "Supporting excerpt" })
10527
11078
  });
10528
- PeerQueryRequestSchema = Type10.Object({
10529
- v: Type10.Literal(1, { description: "Protocol version" }),
10530
- query: Type10.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
10531
- topK: Type10.Optional(Type10.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
10532
- scope: Type10.Optional(Type10.String({ description: "Optional search scope hint" }))
11079
+ PeerQueryRequestSchema = Type8.Object({
11080
+ v: Type8.Literal(1, { description: "Protocol version" }),
11081
+ query: Type8.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
11082
+ topK: Type8.Optional(Type8.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
11083
+ scope: Type8.Optional(Type8.String({ description: "Optional search scope hint" }))
10533
11084
  });
10534
- PeerQueryResponseSchema = Type10.Object({
10535
- v: Type10.Literal(1, { description: "Protocol version" }),
10536
- status: Type10.Union([Type10.Literal("ok"), Type10.Literal("rejected")], {
11085
+ PeerQueryResponseSchema = Type8.Object({
11086
+ v: Type8.Literal(1, { description: "Protocol version" }),
11087
+ status: Type8.Union([Type8.Literal("ok"), Type8.Literal("rejected")], {
10537
11088
  description: "Response status"
10538
11089
  }),
10539
- answer: Type10.String({ description: "Curated answer text" }),
10540
- results: Type10.Array(PeerResultEntrySchema, {
11090
+ answer: Type8.String({ description: "Curated answer text" }),
11091
+ results: Type8.Array(PeerResultEntrySchema, {
10541
11092
  description: "Curated result entries with opaque source ids"
10542
11093
  }),
10543
- files: Type10.Array(PeerFileEntrySchema, {
11094
+ files: Type8.Array(PeerFileEntrySchema, {
10544
11095
  description: "Attached original files with opaque source ids"
10545
11096
  }),
10546
- diagnostics: Type10.Array(PeerDiagnosticSchema, {
11097
+ diagnostics: Type8.Array(PeerDiagnosticSchema, {
10547
11098
  description: "Diagnostic messages (degraded-mode, rejection reasons, etc.)"
10548
11099
  })
10549
11100
  });
@@ -10790,7 +11341,7 @@ var init_simplex_query_store = __esm(() => {
10790
11341
  // src/p2p/simplex-server.ts
10791
11342
  import { existsSync as existsSync19, mkdirSync as mkdirSync15, readFileSync as readFileSync16, writeFileSync as writeFileSync13 } from "node:fs";
10792
11343
  import { join as join26 } from "node:path";
10793
- import { Type as Type11 } from "typebox";
11344
+ import { Type as Type9 } from "typebox";
10794
11345
  import { Value as Value2 } from "typebox/value";
10795
11346
  function targetTokens(value) {
10796
11347
  return new Set((value.toLocaleLowerCase().match(TARGET_TOKEN_PATTERN) ?? []).filter((token) => token.length > 1));
@@ -11104,11 +11655,11 @@ var init_simplex_server = __esm(() => {
11104
11655
  shareBytes: false,
11105
11656
  redact: true
11106
11657
  };
11107
- SimplexWireEnvelopeSchema = Type11.Object({
11108
- v: Type11.Literal(1, { description: "Envelope version" }),
11109
- kind: Type11.Union([Type11.Literal("query"), Type11.Literal("response")], { description: "Payload kind" }),
11110
- id: Type11.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
11111
- payload: Type11.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
11658
+ SimplexWireEnvelopeSchema = Type9.Object({
11659
+ v: Type9.Literal(1, { description: "Envelope version" }),
11660
+ kind: Type9.Union([Type9.Literal("query"), Type9.Literal("response")], { description: "Payload kind" }),
11661
+ id: Type9.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
11662
+ payload: Type9.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
11112
11663
  });
11113
11664
  TARGET_TOKEN_PATTERN = /[\p{L}\p{N}]+/gu;
11114
11665
  PEERS_DIR = join26(".autorag", "p2p");
@@ -11121,7 +11672,7 @@ var init_simplex_server = __esm(() => {
11121
11672
  });
11122
11673
 
11123
11674
  // src/agent/peer-target-tool.ts
11124
- import { Type as Type12 } from "typebox";
11675
+ import { Type as Type10 } from "typebox";
11125
11676
  function createRecommendPeerTargetsTool(workspacePath) {
11126
11677
  return {
11127
11678
  name: RECOMMEND_PEER_TARGETS_TOOL_NAME,
@@ -11154,8 +11705,8 @@ function createRecommendPeerTargetsTool(workspacePath) {
11154
11705
  var RECOMMEND_PEER_TARGETS_TOOL_NAME = "recommend_peer_targets", recommendPeerTargetsSchema;
11155
11706
  var init_peer_target_tool = __esm(() => {
11156
11707
  init_simplex_server();
11157
- recommendPeerTargetsSchema = Type12.Object({
11158
- query: Type12.String({ description: "Question or topic to match against local peer personas." })
11708
+ recommendPeerTargetsSchema = Type10.Object({
11709
+ query: Type10.String({ description: "Question or topic to match against local peer personas." })
11159
11710
  });
11160
11711
  });
11161
11712
 
@@ -11231,7 +11782,7 @@ var MAX_DECOMPOSED_QUERIES = 5;
11231
11782
  var init_query_decomposition = () => {};
11232
11783
 
11233
11784
  // src/agent/query-peer-tool.ts
11234
- import { Type as Type13 } from "typebox";
11785
+ import { Type as Type11 } from "typebox";
11235
11786
  function failure(alias, message) {
11236
11787
  const details = { method: "query_peer_agent", ok: false, alias, message };
11237
11788
  return { content: [{ type: "text", text: message }], details };
@@ -11346,11 +11897,11 @@ var init_query_peer_tool = __esm(() => {
11346
11897
  init_simplex_query_store();
11347
11898
  init_simplex_server();
11348
11899
  init_evidence_ledger();
11349
- queryPeerAgentSchema = Type13.Object({
11350
- alias: Type13.String({ minLength: 1 }),
11351
- query: Type13.String({ minLength: 1, maxLength: 4096 }),
11352
- topK: Type13.Optional(Type13.Integer({ minimum: 1, maximum: 20 })),
11353
- scope: Type13.Optional(Type13.String())
11900
+ queryPeerAgentSchema = Type11.Object({
11901
+ alias: Type11.String({ minLength: 1 }),
11902
+ query: Type11.String({ minLength: 1, maxLength: 4096 }),
11903
+ topK: Type11.Optional(Type11.Integer({ minimum: 1, maximum: 20 })),
11904
+ scope: Type11.Optional(Type11.String())
11354
11905
  });
11355
11906
  });
11356
11907
 
@@ -11617,29 +12168,29 @@ function reconcileCitations(answer, results) {
11617
12168
  ]
11618
12169
  };
11619
12170
  }
11620
- function createPreliminarySearchDocumentsResponse(sessionId, query, details, diagnostics = []) {
11621
- const sourceByNumber = new Map(details.sources.map((entry) => [entry.number, entry.source]));
11622
- const results = details.results.map((result) => ({
12171
+ function toSearchResults(details, sourceByNumber) {
12172
+ return details.results.map((result) => ({
11623
12173
  number: result.number,
11624
12174
  title: result.title,
11625
12175
  summary: result.summary,
11626
12176
  evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
11627
- confidence: confidenceFrom(result.confidence ?? 0.5),
12177
+ ...result.confidence !== undefined ? { confidence: confidenceFrom(result.confidence) } : {},
11628
12178
  source: sourceByNumber.get(result.number)
11629
12179
  }));
11630
- const citations = reconcileCitations(details.answer, results);
12180
+ }
12181
+ function createPreliminarySearchDocumentsResponse(sessionId, query, details, diagnostics = []) {
12182
+ const sourceByNumber = new Map(details.mapping.map((entry) => [entry.number, entry.source]));
11631
12183
  return {
11632
12184
  sessionId,
11633
12185
  query,
11634
- results,
11635
- answer: citations.answer,
12186
+ results: toSearchResults(details, sourceByNumber),
12187
+ answer: details.answer,
11636
12188
  searched: details.results.length,
11637
12189
  warnings: [],
11638
- diagnostics: [...citations.diagnostics, ...diagnostics]
12190
+ diagnostics: [...diagnostics]
11639
12191
  };
11640
12192
  }
11641
- function createEmptySearchDocumentsResponse(sessionId, query, sessions, diagnostics = []) {
11642
- sessions.set(sessionId, { query, registry: new Map });
12193
+ function createEmptySearchDocumentsResponse(sessionId, query, diagnostics = []) {
11643
12194
  return {
11644
12195
  sessionId,
11645
12196
  query,
@@ -11655,7 +12206,7 @@ function normalizeEntryEvidenceRefs(entry) {
11655
12206
  const derivedRetrieverMix = Array.from(new Set(rawRefs.map((ref) => ref.method)));
11656
12207
  return rawRefs.map((ref) => {
11657
12208
  if (ref.excerpt === undefined && ref.content === undefined) {
11658
- throw new Error("emit_autorag_results: every evidenceRef must include excerpt or content");
12209
+ throw new Error("results: every evidenceRef must include excerpt or content");
11659
12210
  }
11660
12211
  return normalizeSessionEvidenceRef({
11661
12212
  method: ref.method,
@@ -11676,19 +12227,11 @@ function normalizeEntryEvidenceRefs(entry) {
11676
12227
  });
11677
12228
  });
11678
12229
  }
11679
- function recordStructuredResultsSession(sessionId, query, details, sessions, memory, componentDiagnostics = [], options = {}) {
11680
- assertResultsMappingOneToOne("emit_autorag_results", details.results, details.mapping);
11681
- const registry = new Map;
12230
+ function recordStructuredResultsSession(sessionId, query, details, memory, componentDiagnostics = [], options = {}) {
12231
+ assertResultsMappingOneToOne("results", details.results, details.mapping);
11682
12232
  const memoryResults = [];
11683
12233
  for (const entry of details.mapping) {
11684
12234
  const evidenceRefs = normalizeEntryEvidenceRefs(entry);
11685
- registry.set(entry.number, {
11686
- index: entry.number,
11687
- content: entry.content,
11688
- source: entry.source,
11689
- method: entry.method,
11690
- evidenceRefs
11691
- });
11692
12235
  const emittedResult = details.results.find((result) => result.number === entry.number);
11693
12236
  memoryResults.push({
11694
12237
  number: entry.number,
@@ -11697,23 +12240,15 @@ function recordStructuredResultsSession(sessionId, query, details, sessions, mem
11697
12240
  content: entry.content,
11698
12241
  method: entry.method,
11699
12242
  source: entry.source,
11700
- ...emittedResult !== undefined ? { confidence: confidenceFrom(emittedResult.confidence) } : {},
12243
+ ...emittedResult?.confidence !== undefined ? { confidence: confidenceFrom(emittedResult.confidence) } : {},
11701
12244
  evidenceRefs
11702
12245
  });
11703
12246
  }
11704
- sessions.set(sessionId, { query, registry });
11705
12247
  if (!options.isolateMemory) {
11706
12248
  memory.recordCuratedResultsSession({ sessionId, query, results: memoryResults });
11707
12249
  memory.save();
11708
12250
  }
11709
- const results = details.results.map((result) => ({
11710
- number: result.number,
11711
- title: result.title,
11712
- summary: result.summary,
11713
- evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
11714
- confidence: confidenceFrom(result.confidence),
11715
- source: registry.get(result.number)?.source || undefined
11716
- }));
12251
+ const results = toSearchResults(details, new Map(details.mapping.map((entry) => [entry.number, entry.source || undefined])));
11717
12252
  const citations = reconcileCitations(details.answer, results);
11718
12253
  const answer = citations.answer;
11719
12254
  const diagnostics = [...citations.diagnostics];
@@ -11743,7 +12278,7 @@ var init_search_documents = __esm(() => {
11743
12278
  });
11744
12279
 
11745
12280
  // src/agent/search-all-tool.ts
11746
- import { Type as Type14 } from "typebox";
12281
+ import { Type as Type12 } from "typebox";
11747
12282
  function createSearchAllDocumentsTool(provider, ledger = new EvidenceLedger) {
11748
12283
  return {
11749
12284
  name: SEARCH_ALL_DOCUMENTS_TOOL_NAME,
@@ -11798,17 +12333,17 @@ var SEARCH_ALL_DOCUMENTS_TOOL_NAME = "search_all_documents", searchAllSchema;
11798
12333
  var init_search_all_tool = __esm(() => {
11799
12334
  init_evidence_ledger();
11800
12335
  init_search_documents();
11801
- searchAllSchema = Type14.Object({
11802
- query: Type14.String({ description: "Query to search across all configured retrieval methods." }),
11803
- topK: Type14.Optional(Type14.Integer({
12336
+ searchAllSchema = Type12.Object({
12337
+ query: Type12.String({ description: "Query to search across all configured retrieval methods." }),
12338
+ topK: Type12.Optional(Type12.Integer({
11804
12339
  description: "Upper bound on returned evidence. Omit it to receive every distinct chunk the methods found; set it only when you deliberately want a shorter list."
11805
12340
  })),
11806
- scope: Type14.Optional(Type14.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
12341
+ scope: Type12.Optional(Type12.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
11807
12342
  });
11808
12343
  });
11809
12344
 
11810
12345
  // src/agent/search-minsync-tool.ts
11811
- import { Type as Type15 } from "typebox";
12346
+ import { Type as Type13 } from "typebox";
11812
12347
  function createSearchMinSyncDocumentsTool(getMethod, resolveScope = (scope) => scope, ledger = new EvidenceLedger) {
11813
12348
  return {
11814
12349
  name: SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
@@ -11858,12 +12393,12 @@ var SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME = "semantic_search_local_docs", searchMin
11858
12393
  var init_search_minsync_tool = __esm(() => {
11859
12394
  init_evidence_ledger();
11860
12395
  init_search_documents();
11861
- searchMinSyncSchema = Type15.Object({
11862
- query: Type15.String({
12396
+ searchMinSyncSchema = Type13.Object({
12397
+ query: Type13.String({
11863
12398
  description: "Semantic query to search parsed document mirrors with MinSync vector retrieval."
11864
12399
  }),
11865
- topK: Type15.Optional(Type15.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
11866
- scope: Type15.Optional(Type15.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
12400
+ topK: Type13.Optional(Type13.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
12401
+ scope: Type13.Optional(Type13.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
11867
12402
  });
11868
12403
  });
11869
12404
 
@@ -11881,7 +12416,7 @@ function datasourceSearchToolName(datasourceId) {
11881
12416
  }
11882
12417
 
11883
12418
  // src/agent/search-single-datasource-tool.ts
11884
- import { Type as Type16 } from "typebox";
12419
+ import { Type as Type14 } from "typebox";
11885
12420
  function createSingleDatasourceSearchTools(provider, specs, ledger = new EvidenceLedger) {
11886
12421
  return specs.map((spec) => createTool(provider, spec, ledger));
11887
12422
  }
@@ -11947,10 +12482,10 @@ var init_search_single_datasource_tool = __esm(() => {
11947
12482
  init_evidence_ledger();
11948
12483
  init_search_documents();
11949
12484
  singleDatasourceToolName = datasourceSearchToolName;
11950
- searchSingleDatasourceSchema = Type16.Object({
11951
- query: Type16.String({ description: "Query to search within this datasource connection." }),
11952
- topK: Type16.Optional(Type16.Integer({ description: "Maximum number of chunks to return. Defaults to 20." })),
11953
- scope: Type16.Optional(Type16.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
12485
+ searchSingleDatasourceSchema = Type14.Object({
12486
+ query: Type14.String({ description: "Query to search within this datasource connection." }),
12487
+ topK: Type14.Optional(Type14.Integer({ description: "Maximum number of chunks to return. Defaults to 20." })),
12488
+ scope: Type14.Optional(Type14.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
11954
12489
  });
11955
12490
  });
11956
12491
 
@@ -12035,7 +12570,7 @@ ${input.skill}
12035
12570
 
12036
12571
  ${input.query}
12037
12572
 
12038
- ` + `When done, call emit_autorag_results exactly once with: \`answer\` = a short report of what you changed (field: old → new), what you verified and how, ` + `and anything that still needs the user (for example an unset API-key environment variable, by name only); \`results\` = []. ` + `If you changed nothing, say why.`;
12573
+ ` + `When done, reply with a short report as your final message, with no tool call: what you changed (field: old → new), what you verified and how, ` + `and anything that still needs the user (for example an unset API-key environment variable, by name only). ` + `If you changed nothing, say why.`;
12039
12574
  }
12040
12575
  var SETUP_SKILL_RELATIVE_PATH;
12041
12576
  var init_self_config = __esm(() => {
@@ -12066,7 +12601,6 @@ function buildSystemPrompt(config) {
12066
12601
  toolLine(config, "check_memory", "inspect evidence earlier searches found for similar questions"),
12067
12602
  toolLine(config, "recommend_peer_targets", "recommend local peer personas to ask about a topic without contacting them"),
12068
12603
  toolLine(config, "query_peer_agent", "ask one trusted peer agent over SimpleX"),
12069
- toolLine(config, "emit_autorag_results", "return the final structured answer with evidence ids for each result"),
12070
12604
  ...config.toolNames.filter((name) => name.startsWith("search_datasource_")).map((name) => `- **${name}**: search only the ${name.slice("search_datasource_".length).replace(/_/g, "-")} datasource connection, spawning no other datasource CLIs`),
12071
12605
  ...config.toolNames.filter((name) => ![
12072
12606
  "bash",
@@ -12082,8 +12616,7 @@ function buildSystemPrompt(config) {
12082
12616
  "jev",
12083
12617
  "check_memory",
12084
12618
  "recommend_peer_targets",
12085
- "query_peer_agent",
12086
- "emit_autorag_results"
12619
+ "query_peer_agent"
12087
12620
  ].includes(name) && !name.startsWith("search_datasource_")).map((name) => `- **${name}**: caller-provided tool`)
12088
12621
  ].filter((line) => line !== undefined);
12089
12622
  const manifests = config.manifests.length === 0 ? "" : `
@@ -12147,12 +12680,12 @@ Your job is to retrieve candidates, read the relevant source material directly,
12147
12680
  ## Workflow
12148
12681
 
12149
12682
  Searches follow a progressive, two-phase loop:
12150
- 1. **PLAN & FAST ANSWER** — Decide whether the query is answerable from general knowledge or memory. When baseline retrieval evidence is provided, produce and emit a complete, self-contained immediate first answer via \`emit_fast_answer\` right away from that evidence without calling tools or waiting.
12683
+ 1. **PLAN & FAST ANSWER** — Decide whether the query is answerable from general knowledge or memory. When baseline retrieval evidence is provided, write a complete, self-contained immediate first answer from that evidence as your reply, right away, without calling tools or waiting.
12151
12684
  2. **EXPLORE & RETRIEVE** — Immediately following the fast answer, begin deeper exploration: ${discovery ? `use ${discovery} actively to locate relevant files and folders, and ` : ""}fan out across MinSync lexical/vector/hybrid retrieval, combined retrieval, and datasource search to expand candidates and fill evidence gaps.
12152
12685
  3. **READ & VERIFY** — Use \`bash\` to open and verify relevant local files directly when needed, and in local sessions to organize files when the user asks (see File Organization); rely on Jikji and retrieval rather than blind directory browsing.
12153
12686
  4. **JUDGE & RESOLVE** — Evaluate relevance, sufficiency, conflicts, and temporal context. When search results or evidence contain conflicting information, treat the freshest (most recent) information as authoritative and correct.
12154
12687
  5. **CURATE** — Produce concise numbered knowledge units grounded in source evidence.
12155
- 6. **FINALIZE** — Call \`emit_autorag_results\` exactly once as the final action.
12688
+ 6. **FINALIZE** — End with the final answer as a plain reply, with no tool call. Earlier replies that are followed by a tool call are progress notes; only the last reply is the answer.
12156
12689
 
12157
12690
  ## Available Tools
12158
12691
 
@@ -12197,17 +12730,17 @@ ${fsearch}
12197
12730
  ${manifests}
12198
12731
  ## Output Format
12199
12732
 
12200
- Call \`emit_autorag_results\` exactly once with:
12201
- - \`answer\`: the curated answer for the caller following the Answer Guidelines below. When a first answer was already delivered to the caller during this run, include only corrections and newly verified findings — never restate the first answer; otherwise give the complete answer. Reference results by bracketed numbers such as [1] and [2].
12202
- - \`results\`: curated units with number, title, summary, evidence, confidence, and \`refs\`.
12203
- - \`refs\`: for every result, the evidence ids (such as \`e3\`) shown next to the retrieved results that support it; for a local file you opened yourself with \`bash\`, its absolute path. The source, method, and chunk are attached from these ids; never type a path or copy a chunk to describe a source.
12733
+ Your answer is your final reply, written as plain text, never as a tool call. Cite evidence inline with the ids the retrieval tools print next to each result:
12734
+ - Put the id in square brackets at the end of the sentence it supports, e.g. \`The cap is 28% [e3].\` Use \`[e3][e7]\` or \`[e3, e7]\` for several. Copy ids exactly as printed; never invent one.
12735
+ - For a local file you opened yourself with \`bash\`, cite \`[file:<absolute path>]\`.
12736
+ - The harness resolves every id to its recorded source, number the citations \`[1]\`, \`[2]\`, … in order of first appearance, and attaches the sources for you. Never type a source path, a chunk, or a citation number yourself.
12737
+ - A citation whose id no tool returned in this run is dropped, so cite only ids you saw.
12204
12738
 
12205
12739
  ## Answer Guidelines
12206
12740
 
12207
12741
  - **Complete vs. delta answer**: When no first answer reached the caller, give the complete core answer. When a first answer was already delivered, return only the delta against it — corrections and newly verified findings — and never repeat its unchanged content; if nothing changed, confirm the first answer in one short line.
12208
12742
  - **Bullet-point core answer**: Provide the core answer to the user's question in at most 5 bullet points. If additional explanation or context is necessary, append it after the bullet points.
12209
- - **Direct answer only**: The caller only needs the answer to their question. Never include specific file paths, datasource descriptions, or retrieval mechanics/principles in \`answer\` (source paths are attached to each result from the evidence ids you cite in \`refs\`).
12210
- - **Citation style**: Cite supporting evidence chunks using bracketed numbers only (e.g. [1], [2]). Do not quote raw chunk text or mention source paths directly in \`answer\`.
12743
+ - **Direct answer only**: The caller only needs the answer to their question. Never include specific file paths, datasource descriptions, or retrieval mechanics/principles in the answer (source paths are attached to each citation from the evidence ids you cite). Do not quote raw chunk text.
12211
12744
  - ${ANSWER_CITATION_RULE}
12212
12745
  - ${ANSWER_IMAGE_EMBED_RULE} ${ANSWER_IMAGE_DELTA_RULE}
12213
12746
  - **No per-source negative reports**: Never report individual negative findings per source (e.g. "no information found in Slack" or "checked Drive but found nothing"). Simply omit unproductive sources from the answer and focus on what was found or provide a concise overall conclusion.
@@ -12220,7 +12753,7 @@ Call \`emit_autorag_results\` exactly once with:
12220
12753
  - **Curate, don't dump**: return useful knowledge units, not raw search output.
12221
12754
  - **Address intent**: answer the caller's actual need.
12222
12755
  - **Preserve traceability**: cite evidence by the ids retrieval tools show, so source paths and excerpts are attached for you.
12223
- - **Finalize once**: the structured result tool is the final action.
12756
+ - **Finalize once**: the last reply, with no tool call, is the final answer.
12224
12757
  `;
12225
12758
  }
12226
12759
  var init_system_prompt = __esm(() => {
@@ -14207,7 +14740,7 @@ var init_render = __esm(() => {
14207
14740
  });
14208
14741
 
14209
14742
  // src/agent/web-fetch-tool.ts
14210
- import { Type as Type17 } from "typebox";
14743
+ import { Type as Type15 } from "typebox";
14211
14744
  function truncateHead(output, maxBytes, maxLines) {
14212
14745
  const lines = output.split(`
14213
14746
  `);
@@ -14311,9 +14844,9 @@ var init_web_fetch_tool = __esm(() => {
14311
14844
  init_render();
14312
14845
  init_evidence_ledger();
14313
14846
  FETCH_MAX_OUTPUT_BYTES = 50 * 1024;
14314
- webFetchSchema = Type17.Object({
14315
- url: Type17.String({ description: "The http(s) URL to fetch and read." }),
14316
- raw: Type17.Optional(Type17.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
14847
+ webFetchSchema = Type15.Object({
14848
+ url: Type15.String({ description: "The http(s) URL to fetch and read." }),
14849
+ raw: Type15.Optional(Type15.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
14317
14850
  });
14318
14851
  });
14319
14852
 
@@ -15272,7 +15805,7 @@ function parseResponse(data) {
15272
15805
  } : {}
15273
15806
  };
15274
15807
  }
15275
- var DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com", API_VERSION = "v1beta", DEFAULT_MODEL = "gemini-3.8-flash", MAX_RESPONSE_BYTES, MAX_ERROR_BYTES, GeminiProvider;
15808
+ var DEFAULT_BASE_URL2 = "https://generativelanguage.googleapis.com", API_VERSION = "v1beta", DEFAULT_MODEL = "gemini-3.8-flash", MAX_RESPONSE_BYTES, MAX_ERROR_BYTES, GeminiProvider;
15276
15809
  var init_gemini = __esm(() => {
15277
15810
  init_model_auth();
15278
15811
  init_query();
@@ -15294,7 +15827,7 @@ var init_gemini = __esm(() => {
15294
15827
  const model = envCredential("GEMINI_SEARCH_MODEL") ?? (credential.source === "injected" ? credential.modelId : undefined) ?? DEFAULT_MODEL;
15295
15828
  const parsed = params.parsedQuery ?? parseSearchQuery(params.query);
15296
15829
  const query = parsed.hasDirectives ? formatQuery(parsed, GOOGLE_QUERY_SYNTAX) : params.query;
15297
- const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
15830
+ const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/+$/, "");
15298
15831
  const fetchImpl = params.fetch ?? fetch;
15299
15832
  const response = await fetchImpl(`${baseUrl}/${API_VERSION}/models/${model}:generateContent`, {
15300
15833
  method: "POST",
@@ -15439,7 +15972,7 @@ function parseResponse2(response) {
15439
15972
  ...response.id !== undefined ? { requestId: response.id } : {}
15440
15973
  };
15441
15974
  }
15442
- var DEFAULT_BASE_URL2 = "https://api.anthropic.com", DEFAULT_MODEL2 = "claude-haiku-5-5", DEFAULT_MAX_TOKENS = 4096, MAX_RESPONSE_BYTES2, MAX_ERROR_BYTES2, WEB_SEARCH_TOOL_TYPE = "web_search_20250305", ANTHROPIC_QUERY_SYNTAX, AnthropicProvider;
15975
+ var DEFAULT_BASE_URL3 = "https://api.anthropic.com", DEFAULT_MODEL2 = "claude-haiku-5-5", DEFAULT_MAX_TOKENS2 = 4096, MAX_RESPONSE_BYTES2, MAX_ERROR_BYTES2, WEB_SEARCH_TOOL_TYPE = "web_search_20250305", ANTHROPIC_QUERY_SYNTAX, AnthropicProvider;
15443
15976
  var init_anthropic = __esm(() => {
15444
15977
  init_model_auth();
15445
15978
  init_query();
@@ -15470,7 +16003,7 @@ var init_anthropic = __esm(() => {
15470
16003
  const model = envCredential("ANTHROPIC_SEARCH_MODEL") ?? (credential.source === "injected" ? credential.modelId : undefined) ?? DEFAULT_MODEL2;
15471
16004
  const parsed = params.parsedQuery ?? parseSearchQuery(params.query);
15472
16005
  const plan = planQuery(params.query, parsed);
15473
- const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/+$/, "");
16006
+ const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL3).replace(/\/+$/, "");
15474
16007
  const fetchImpl = params.fetch ?? fetch;
15475
16008
  const response = await fetchImpl(`${baseUrl}/v1/messages?beta=true`, {
15476
16009
  method: "POST",
@@ -15482,7 +16015,7 @@ var init_anthropic = __esm(() => {
15482
16015
  },
15483
16016
  body: JSON.stringify({
15484
16017
  model,
15485
- max_tokens: params.maxOutputTokens ?? DEFAULT_MAX_TOKENS,
16018
+ max_tokens: params.maxOutputTokens ?? DEFAULT_MAX_TOKENS2,
15486
16019
  ...params.systemPrompt ? { system: params.systemPrompt } : {},
15487
16020
  messages: [{ role: "user", content: plan.query }],
15488
16021
  tools: [
@@ -17565,7 +18098,7 @@ async function searchPublicWeb(params, deadlines = {}) {
17565
18098
  }
17566
18099
  var PUBLIC_ENGINE_IDS, DEFAULT_NUM_RESULTS8 = 15, MAX_NUM_RESULTS8 = 30, SOFT_DEADLINE_MS = 5000, HARD_DEADLINE_MS = 30000, PublicWebProvider;
17567
18100
  var init_public = __esm(() => {
17568
- init_provider();
18101
+ init_provider2();
17569
18102
  init_types3();
17570
18103
  init_utils();
17571
18104
  PUBLIC_ENGINE_IDS = [
@@ -17639,7 +18172,7 @@ function resolveProviderCandidates(routing = {}) {
17639
18172
  return candidates;
17640
18173
  }
17641
18174
  var PROVIDER_META, instanceCache;
17642
- var init_provider = __esm(() => {
18175
+ var init_provider2 = __esm(() => {
17643
18176
  init_types3();
17644
18177
  init_types3();
17645
18178
  PROVIDER_META = {
@@ -17825,15 +18358,15 @@ async function executeWebSearch(params, options = {}) {
17825
18358
  }
17826
18359
  var TOTAL_TIMEOUT_MULTIPLIER = 2;
17827
18360
  var init_search = __esm(() => {
17828
- init_provider();
18361
+ init_provider2();
17829
18362
  init_query();
17830
18363
  init_types3();
17831
- init_provider();
18364
+ init_provider2();
17832
18365
  init_types3();
17833
18366
  });
17834
18367
 
17835
18368
  // src/agent/web-search-tool.ts
17836
- import { Type as Type18 } from "typebox";
18369
+ import { Type as Type16 } from "typebox";
17837
18370
  function createWebSearchTool(options = {}, ledger = new EvidenceLedger) {
17838
18371
  return {
17839
18372
  name: WEB_SEARCH_TOOL_NAME,
@@ -17909,15 +18442,15 @@ var WEB_SEARCH_TOOL_NAME = "web_search", webSearchSchema;
17909
18442
  var init_web_search_tool = __esm(() => {
17910
18443
  init_search();
17911
18444
  init_evidence_ledger();
17912
- webSearchSchema = Type18.Object({
17913
- query: Type18.String({
18445
+ webSearchSchema = Type16.Object({
18446
+ query: Type16.String({
17914
18447
  description: 'Search query. Supports Google-style directives: site:/-site:, after:/before: (YYYY-MM-DD), inurl:, intitle:, filetype:, "exact phrase", -term, OR.'
17915
18448
  }),
17916
- recency: Type18.Optional(Type18.Union([Type18.Literal("day"), Type18.Literal("week"), Type18.Literal("month"), Type18.Literal("year")], {
18449
+ recency: Type16.Optional(Type16.Union([Type16.Literal("day"), Type16.Literal("week"), Type16.Literal("month"), Type16.Literal("year")], {
17917
18450
  description: "Optional recency window for results (pure time filter)."
17918
18451
  })),
17919
- limit: Type18.Optional(Type18.Integer({ description: "Maximum number of results to return." })),
17920
- num_search_results: Type18.Optional(Type18.Integer({ description: "Alias for limit (result count hint)." }))
18452
+ limit: Type16.Optional(Type16.Integer({ description: "Maximum number of results to return." })),
18453
+ num_search_results: Type16.Optional(Type16.Integer({ description: "Alias for limit (result count hint)." }))
17921
18454
  });
17922
18455
  });
17923
18456
 
@@ -17964,10 +18497,7 @@ class AutoRAGAgent {
17964
18497
  runLogger;
17965
18498
  lastQuery;
17966
18499
  lastSessionId;
17967
- sessions = new Map;
17968
18500
  activeRun = false;
17969
- resultCapture;
17970
- interactiveFastAnswerCallback;
17971
18501
  modelNativeSearchAuth;
17972
18502
  retrievalTrace = [];
17973
18503
  evidenceLedger = new EvidenceLedger;
@@ -18129,10 +18659,6 @@ class AutoRAGAgent {
18129
18659
  const searchMinSyncTool = createSearchMinSyncDocumentsTool(() => this.remoteFilteredRetrievalMethod(this.minSyncMethod), (scope) => this.resolveRetrievalScope(scope), this.evidenceLedger);
18130
18660
  const searchAllTool = createSearchAllDocumentsTool(this, this.evidenceLedger);
18131
18661
  const loadDatasourceSkillTool = createLoadDatasourceSkillTool(this);
18132
- const emitResultsTool = createEmitResultsTool((details) => this.resultCapture?.(details), {
18133
- ledger: this.evidenceLedger,
18134
- allowLocalFiles: !this.remoteSession
18135
- });
18136
18662
  const scanDuplicateDocumentsTool = this.dupeyOptions === false ? undefined : createScanDuplicateDocumentsTool(this);
18137
18663
  this.jevJudge = options.jev === undefined || options.jev === false || this.remoteSession ? undefined : createJevJudge(options.jev);
18138
18664
  this.jevExtension = this.jevJudge === undefined ? undefined : createJevExtension(this.jevJudge);
@@ -18167,8 +18693,6 @@ class AutoRAGAgent {
18167
18693
  "check_memory",
18168
18694
  ...singleDatasourceTools.map((tool) => tool.name),
18169
18695
  LOAD_DATASOURCE_SKILL_TOOL_NAME,
18170
- EMIT_AUTORAG_RESULTS_TOOL_NAME,
18171
- EMIT_FAST_ANSWER_TOOL_NAME,
18172
18696
  SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
18173
18697
  SEARCH_ALL_DOCUMENTS_TOOL_NAME,
18174
18698
  JIKJI_FIND_TOOL_NAME,
@@ -18199,7 +18723,6 @@ class AutoRAGAgent {
18199
18723
  loadDatasourceSkillTool,
18200
18724
  ...webSearchTool !== undefined ? [webSearchTool] : [],
18201
18725
  ...webFetchTool !== undefined ? [webFetchTool] : [],
18202
- emitResultsTool,
18203
18726
  ...scanDuplicateDocumentsTool !== undefined ? [scanDuplicateDocumentsTool] : [],
18204
18727
  ...jikjiFindTool !== undefined ? [jikjiFindTool] : [],
18205
18728
  ...everythingSearchTool !== undefined ? [everythingSearchTool] : [],
@@ -18346,12 +18869,11 @@ ${context.text}
18346
18869
  source: "memory"
18347
18870
  };
18348
18871
  }
18349
- const registry = this.sessions.get(sessionId)?.registry;
18350
18872
  const resultByNumber = new Map(details.results.map((result) => [result.number, result]));
18351
18873
  const units = [];
18352
18874
  for (const entry of details.mapping) {
18353
18875
  const result = resultByNumber.get(entry.number);
18354
- const refs = registry?.get(entry.number)?.evidenceRefs ?? [];
18876
+ const refs = normalizeEntryEvidenceRefs(entry);
18355
18877
  if (result === undefined || refs.length === 0)
18356
18878
  continue;
18357
18879
  for (const ref of refs) {
@@ -18432,7 +18954,7 @@ ${context.text}
18432
18954
  providerApiKeys: { [local.provider]: local.apiKey }
18433
18955
  };
18434
18956
  }
18435
- async createSearchSession(resolved, systemPrompt, extraTools = []) {
18957
+ async createSearchSession(resolved, systemPrompt) {
18436
18958
  if (this.boundPiRuntime !== undefined) {
18437
18959
  const session = this.boundPiRuntime.session;
18438
18960
  return {
@@ -18452,10 +18974,7 @@ ${context.text}
18452
18974
  apiKey: resolved.apiKey,
18453
18975
  providerApiKeys: resolved.providerApiKeys,
18454
18976
  getSystemPrompt: () => systemPrompt,
18455
- customTools: [
18456
- ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
18457
- ...extraTools
18458
- ],
18977
+ customTools: this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
18459
18978
  remoteSession: this.remoteSession,
18460
18979
  contextTransform: (messages) => this.withMemoryContext(messages),
18461
18980
  ...this.jevExtension !== undefined ? { extensionFactories: [this.jevExtension], extensionToolNames: [JEV_TOOL_NAME] } : {}
@@ -18536,19 +19055,12 @@ ${context.text}
18536
19055
  modelId: this.boundPiRuntime?.session.model?.id ?? resolved?.model.id
18537
19056
  })),
18538
19057
  contextTransform: (messages) => this.withMemoryContext(messages),
18539
- customTools: [
18540
- ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
18541
- createEmitFastAnswerTool((details) => this.interactiveFastAnswerCallback?.(details), {
18542
- ledger: this.evidenceLedger
18543
- })
18544
- ],
19058
+ customTools: this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
18545
19059
  onQuery: (query, pi) => this.runInteractivePiQuery(query, pi),
18546
- inactiveToolNames: [EMIT_FAST_ANSWER_TOOL_NAME],
18547
19060
  ...this.jevExtension !== undefined ? { extensionFactories: [this.jevExtension], extensionToolNames: [JEV_TOOL_NAME] } : {},
18548
19061
  ...this.updateNotice === undefined ? {} : { updateNotice: this.updateNotice }
18549
19062
  });
18550
19063
  this.boundPiRuntime = runtime.runtime;
18551
- runtime.runtime.session.setActiveToolsByName(runtime.runtime.session.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
18552
19064
  const dispose = runtime.dispose;
18553
19065
  return {
18554
19066
  ...runtime,
@@ -18559,17 +19071,14 @@ ${context.text}
18559
19071
  }
18560
19072
  };
18561
19073
  }
19074
+ deriveAnswer(text) {
19075
+ const derived = deriveResultsFromAnswer(text, this.evidenceLedger, { allowLocalFiles: !this.remoteSession });
19076
+ this.routingDiagnostics.push(...derived.diagnostics);
19077
+ return derived.details;
19078
+ }
18562
19079
  async runInteractivePiQuery(query, pi) {
18563
19080
  pi.setSessionName(query.slice(0, 80));
18564
- for await (const event of this.searchDocumentsStream(query)) {
18565
- const text = event.type === "progress" ? event.text : event.response.answer;
18566
- pi.sendMessage({
18567
- customType: `autorag.${event.type}`,
18568
- content: [{ type: "text", text }],
18569
- display: true,
18570
- details: event
18571
- }, { triggerTurn: false });
18572
- }
19081
+ for await (const _event of this.searchDocumentsStream(query)) {}
18573
19082
  }
18574
19083
  abort() {
18575
19084
  this.activeSession?.abort();
@@ -18600,11 +19109,6 @@ ${context.text}
18600
19109
  this.refreshing = false;
18601
19110
  }
18602
19111
  }
18603
- getResultRegistry(sessionId) {
18604
- const sid = sessionId ?? this.lastSessionId;
18605
- const session = sid ? this.sessions.get(sid) : undefined;
18606
- return session?.registry ?? new Map;
18607
- }
18608
19112
  async searchDocuments(query, options = {}) {
18609
19113
  if (this.activeRun) {
18610
19114
  throw new Error("AutoRAG agent is busy; await the in-flight searchDocuments() call before starting another");
@@ -18616,7 +19120,7 @@ ${context.text}
18616
19120
  if (trimmedQuery.length === 0) {
18617
19121
  this.lastQuery = trimmedQuery;
18618
19122
  this.lastSessionId = sessionId;
18619
- return createEmptySearchDocumentsResponse(sessionId, trimmedQuery, this.sessions, this.startupDiagnostics);
19123
+ return createEmptySearchDocumentsResponse(sessionId, trimmedQuery, this.startupDiagnostics);
18620
19124
  }
18621
19125
  options = this.normalizeRetrievalOptions(options);
18622
19126
  if (this.remoteSession && options.observedSources !== undefined)
@@ -18652,11 +19156,7 @@ ${context.text}
18652
19156
  publishPreliminary(details);
18653
19157
  };
18654
19158
  let session;
18655
- this.interactiveFastAnswerCallback = emitPreliminary;
18656
19159
  let unsubscribers = [];
18657
- this.resultCapture = (details) => {
18658
- captured = details;
18659
- };
18660
19160
  let searchStarted = false;
18661
19161
  try {
18662
19162
  const resolved = await this.resolveSessionModel();
@@ -18674,7 +19174,7 @@ ${context.text}
18674
19174
  model: resolved.model.id
18675
19175
  });
18676
19176
  searchStarted = true;
18677
- session = await this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })), [createEmitFastAnswerTool(emitPreliminary, { ledger: this.evidenceLedger })]);
19177
+ session = await this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })));
18678
19178
  this.activeSession = session;
18679
19179
  unsubscribers = this.configureSearchSession(session);
18680
19180
  let timeout;
@@ -18683,45 +19183,36 @@ ${context.text}
18683
19183
  await Promise.race([
18684
19184
  (async () => {
18685
19185
  const plan = await this.planQuery(trimmedQuery, resolved, planAbort.signal);
18686
- const sessionAgent = session.piSession;
18687
19186
  const activeSession = session;
18688
- const activateFastPhase = () => {
18689
- if (sessionAgent !== undefined) {
18690
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.fastThinkingLevel));
18691
- sessionAgent.setActiveToolsByName([
18692
- ...sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME),
18693
- EMIT_FAST_ANSWER_TOOL_NAME
18694
- ]);
18695
- } else {
18696
- activeSession.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.fastThinkingLevel);
18697
- activeSession.agent.state.tools = [
18698
- ...this.tools,
18699
- { name: EMIT_FAST_ANSWER_TOOL_NAME }
18700
- ];
18701
- }
19187
+ const sessionAgent = activeSession.piSession;
19188
+ const transcript = () => sessionAgent?.messages ?? activeSession.agent.state.messages;
19189
+ const setThinking = (level) => {
19190
+ const clamped = clampThinkingLevel(resolved.model, level);
19191
+ if (sessionAgent !== undefined)
19192
+ sessionAgent.setThinkingLevel(clamped);
19193
+ else
19194
+ activeSession.agent.state.thinkingLevel = clamped;
18702
19195
  };
18703
19196
  if (plan.route === "config" && plan.selfConfigSkill !== undefined && this.selfConfig !== undefined) {
18704
19197
  selfConfigRun = true;
18705
19198
  mkdirSync17(this.workspaceProjectRoot, { recursive: true });
18706
19199
  const previousTools = sessionAgent?.getActiveToolNames();
18707
- if (sessionAgent !== undefined) {
18708
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.finalThinkingLevel));
18709
- sessionAgent.setActiveToolsByName([...PI_BUILTIN_TOOL_NAMES, EMIT_AUTORAG_RESULTS_TOOL_NAME]);
18710
- } else {
18711
- activeSession.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
18712
- activeSession.agent.state.tools = this.tools.filter((tool) => tool.name === EMIT_AUTORAG_RESULTS_TOOL_NAME);
18713
- }
19200
+ setThinking(this.finalThinkingLevel);
19201
+ if (sessionAgent !== undefined)
19202
+ sessionAgent.setActiveToolsByName([...PI_BUILTIN_TOOL_NAMES]);
19203
+ else
19204
+ activeSession.agent.state.tools = [];
18714
19205
  const configBefore = snapshotConfigFile(this.selfConfig.configPath);
18715
19206
  try {
18716
- await session.prompt(buildSelfConfigPrompt({
19207
+ await activeSession.prompt(buildSelfConfigPrompt({
18717
19208
  query: trimmedQuery,
18718
19209
  configPath: this.selfConfig.configPath,
18719
19210
  agentDir: this.piAgentDir ?? getAgentDir2(),
18720
19211
  skill: plan.selfConfigSkill
18721
19212
  }));
18722
- if (captured === undefined && !planAbort.signal.aborted && lastModelRequestError(session.piSession?.messages ?? session.agent.state.messages) === undefined) {
18723
- await session.prompt(buildFinalEmitReminder());
18724
- }
19213
+ const report = finalAnswerText(transcript());
19214
+ if (report !== undefined)
19215
+ captured = this.deriveAnswer(report);
18725
19216
  const rolledBack = await rollbackIfBroken(this.selfConfig, configBefore);
18726
19217
  if (rolledBack !== undefined) {
18727
19218
  this.routingDiagnostics.push({
@@ -18730,11 +19221,10 @@ ${context.text}
18730
19221
  message: `The edited config did not validate, so the previous config was restored. ${rolledBack}`,
18731
19222
  source: "self-config"
18732
19223
  });
18733
- const emitted = captured;
18734
- if (emitted !== undefined) {
19224
+ if (captured !== undefined) {
18735
19225
  captured = {
18736
- ...emitted,
18737
- answer: `${emitted.answer}
19226
+ ...captured,
19227
+ answer: `${captured.answer}
18738
19228
 
18739
19229
  Warning: the edited config did not validate, so the previous config was restored (nothing was changed). Problem: ${rolledBack}`
18740
19230
  };
@@ -18748,49 +19238,35 @@ Warning: the edited config did not validate, so the previous config was restored
18748
19238
  return;
18749
19239
  }
18750
19240
  if (plan.route === "direct") {
18751
- activateFastPhase();
18752
- await session.prompt(this.buildDirectAnswerPrompt(trimmedQuery));
18753
- const answer = fastCaptured?.answer ?? lastAssistantText(session.piSession?.messages ?? session.agent.state.messages);
19241
+ setThinking(this.fastThinkingLevel);
19242
+ await activeSession.prompt(this.buildDirectAnswerPrompt(trimmedQuery));
19243
+ const answer = finalAnswerText(transcript());
18754
19244
  if (answer !== undefined)
18755
- captured = { answer, results: [], mapping: [], warnings: [] };
19245
+ captured = this.deriveAnswer(answer);
18756
19246
  return;
18757
19247
  }
18758
19248
  const baseline = await this.prefetchInitialRetrievalContext(trimmedQuery, plan.queries, options, plan.datasources);
18759
- activateFastPhase();
18760
- await session.prompt(this.buildFastAnswerPrompt(trimmedQuery, options, baseline));
18761
- let preliminary = fastCaptured;
18762
- if (preliminary === undefined) {
18763
- const text = lastAssistantText(session.piSession?.messages ?? session.agent.state.messages);
18764
- if (text !== undefined)
18765
- preliminary = { answer: text, results: [], sources: [], evidenceRefs: [] };
18766
- }
18767
- if (preliminary !== undefined)
18768
- emitPreliminary(preliminary);
18769
- if (captured !== undefined)
18770
- return;
19249
+ setThinking(this.fastThinkingLevel);
19250
+ await activeSession.prompt(this.buildFastAnswerPrompt(trimmedQuery, options, baseline));
19251
+ const fastText = finalAnswerText(transcript());
19252
+ const preliminary = fastText === undefined ? undefined : this.deriveAnswer(fastText);
18771
19253
  if (preliminary !== undefined) {
19254
+ emitPreliminary(preliminary);
18772
19255
  const followUp = await this.shouldFollowUp(trimmedQuery, preliminary);
18773
19256
  if (planAbort.signal.aborted)
18774
19257
  return;
18775
19258
  if (!followUp) {
18776
- captured = fastAnswerAsFinal(preliminary);
19259
+ captured = preliminary;
18777
19260
  return;
18778
19261
  }
18779
- }
18780
- if (preliminary !== undefined)
18781
19262
  publishPreliminary(preliminary);
18782
- if (sessionAgent !== undefined) {
18783
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.finalThinkingLevel));
18784
- sessionAgent.setActiveToolsByName(sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
18785
- } else {
18786
- session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
18787
- session.agent.state.tools = [...this.tools];
18788
19263
  }
19264
+ setThinking(this.finalThinkingLevel);
18789
19265
  const fastAnswerDelivered = preliminary !== undefined && this.preliminaryCallback !== undefined;
18790
- await session.prompt(this.buildRefinementPrompt(trimmedQuery, options, preliminary, fastAnswerDelivered));
18791
- if (captured === undefined && !planAbort.signal.aborted && this.searchToolCallCount < this.maxSearchToolCalls && lastModelRequestError(session.piSession?.messages ?? session.agent.state.messages) === undefined) {
18792
- await session.prompt(buildFinalEmitReminder());
18793
- }
19266
+ await activeSession.prompt(this.buildRefinementPrompt(trimmedQuery, options, fastText, fastAnswerDelivered));
19267
+ const finalText = finalAnswerText(transcript());
19268
+ if (finalText !== undefined)
19269
+ captured = this.deriveAnswer(finalText);
18794
19270
  })(),
18795
19271
  new Promise((resolve, reject) => {
18796
19272
  timeout = setTimeout(() => {
@@ -18810,7 +19286,7 @@ Warning: the edited config did not validate, so the previous config was restored
18810
19286
  clearTimeout(timeout);
18811
19287
  }
18812
19288
  if (captured === undefined && timedOutAfterFastAnswer && fastCaptured !== undefined) {
18813
- const response = recordStructuredResultsSession(sessionId, trimmedQuery, fastAnswerAsFinal(fastCaptured), this.sessions, this.memory, [
19289
+ const response = recordStructuredResultsSession(sessionId, trimmedQuery, fastCaptured, this.memory, [
18814
19290
  ...this.collectComponentDiagnostics(),
18815
19291
  {
18816
19292
  code: "search-timeout",
@@ -18844,15 +19320,15 @@ Warning: the edited config did not validate, so the previous config was restored
18844
19320
  sessionId,
18845
19321
  query: trimmedQuery,
18846
19322
  results: [],
18847
- answer: buildMissingFinalEmitAnswer(trimmedQuery, reason, this.retrievalTrace, modelError),
19323
+ answer: buildMissingFinalAnswer(trimmedQuery, reason, this.retrievalTrace, modelError),
18848
19324
  searched: this.retrievalTrace.reduce((total, entry) => total + entry.resultCount, 0),
18849
19325
  warnings: [],
18850
19326
  diagnostics: [
18851
19327
  ...this.collectComponentDiagnostics(),
18852
19328
  {
18853
- code: "missing-final-emit",
19329
+ code: "no-final-answer",
18854
19330
  severity: "warning",
18855
- message: "The agent ended its run without calling emit_autorag_results; returning a degraded response that carries the run's retrieval trace."
19331
+ message: "The agent ended its run without a final answer message; returning a degraded response that carries the run's retrieval trace."
18856
19332
  },
18857
19333
  ...modelError === undefined ? [] : [
18858
19334
  {
@@ -18898,7 +19374,7 @@ Warning: the edited config did not validate, so the previous config was restored
18898
19374
  source: "agent"
18899
19375
  });
18900
19376
  }
18901
- const recorded = recordStructuredResultsSession(sessionId, trimmedQuery, captured, this.sessions, this.memory, componentDiagnostics, { isolateMemory: this.remoteSession || selfConfigRun });
19377
+ const recorded = recordStructuredResultsSession(sessionId, trimmedQuery, captured, this.memory, componentDiagnostics, { isolateMemory: this.remoteSession || selfConfigRun });
18902
19378
  const memoryDiagnostic = selfConfigRun ? undefined : await this.recordJudgedEvidence(sessionId, trimmedQuery, captured);
18903
19379
  const response = memoryDiagnostic === undefined ? recorded : { ...recorded, diagnostics: [...recorded.diagnostics ?? [], memoryDiagnostic] };
18904
19380
  this.runLogger.write({
@@ -18939,36 +19415,25 @@ Warning: the edited config did not validate, so the previous config was restored
18939
19415
  });
18940
19416
  }
18941
19417
  this.activeSession = undefined;
18942
- this.resultCapture = undefined;
18943
19418
  this.activeRetrievalOptions = undefined;
18944
19419
  this.preliminaryCallback = undefined;
18945
- if (this.interactiveFastAnswerCallback === emitPreliminary)
18946
- this.interactiveFastAnswerCallback = undefined;
18947
19420
  this.activeRun = false;
18948
19421
  this.memoryContextCache = undefined;
18949
19422
  }
18950
19423
  }
18951
19424
  async* searchDocumentsStream(query, options = {}) {
18952
19425
  const queue = [];
18953
- let progressBuffer = "";
18954
19426
  let wake;
18955
19427
  let settled = false;
18956
19428
  const unsubscribe = this.subscribe((event) => {
18957
- if (event.type !== "message_update" || event.assistantMessageEvent.type !== "text_delta")
19429
+ if (event.type !== "message_end" || event.message.role !== "assistant")
18958
19430
  return;
18959
- const text = event.assistantMessageEvent.delta;
18960
- if (text.trim().length === 0)
19431
+ if (event.message.stopReason !== "toolUse")
18961
19432
  return;
18962
- progressBuffer += text;
18963
- if (!/[.!?。!?]\s*$/u.test(progressBuffer))
19433
+ const text = event.message.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
19434
+ if (text === "")
18964
19435
  return;
18965
- queue.push({
18966
- type: "progress",
18967
- sessionId: this.lastSessionId ?? "",
18968
- query: query.trim(),
18969
- text: progressBuffer
18970
- });
18971
- progressBuffer = "";
19436
+ queue.push({ type: "progress", sessionId: this.lastSessionId ?? "", query: query.trim(), text });
18972
19437
  wake?.();
18973
19438
  wake = undefined;
18974
19439
  });
@@ -18984,15 +19449,6 @@ Warning: the edited config did not validate, so the previous config was restored
18984
19449
  wake = undefined;
18985
19450
  };
18986
19451
  const run = this.searchDocuments(query, options).then((response) => {
18987
- if (progressBuffer.trim() !== "") {
18988
- queue.push({
18989
- type: "progress",
18990
- sessionId: this.lastSessionId ?? "",
18991
- query: query.trim(),
18992
- text: progressBuffer
18993
- });
18994
- progressBuffer = "";
18995
- }
18996
19452
  queue.push({ type: "complete", response });
18997
19453
  }).catch((error) => {
18998
19454
  settled = true;
@@ -19383,7 +19839,7 @@ ${result.content.replace(/\s+/gu, " ")}`).join(`
19383
19839
  }
19384
19840
  }
19385
19841
  buildFastAnswerPrompt(query, options, baseline) {
19386
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} knowledge units.` : "";
19842
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
19387
19843
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
19388
19844
  return `Answer this original query immediately: ${query}${limit}${scope}
19389
19845
 
@@ -19395,21 +19851,18 @@ ${baseline}
19395
19851
  ` + `Formatting and content rules for the answer:
19396
19852
  ` + `- Provide the core answer to the user's question in at most 5 bullet points. If additional explanation is necessary, append it after the bullet points.
19397
19853
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
19398
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
19399
19854
  ` + `- ${ANSWER_CITATION_RULE}
19400
19855
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
19401
19856
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack" or "checked Drive but found nothing").
19402
19857
  ` + `- When evidence conflicts, treat the freshest (most recent) information as the correct source of truth.
19403
19858
  ` + `- If information is incomplete or uncertain, acknowledge it briefly without lengthy explanations, stating that it is difficult to answer fully with the given information and searching continues. If there are partial clues or leads (even if not the exact answer), mention those clues concisely.
19404
19859
 
19405
- ` + `Call emit_fast_answer exactly once with the answer, its numbered knowledge units, and the evidence ids (e.g. e3) from the baseline evidence that back each unit in refs, then stop.`;
19860
+ ` + `Write the answer as your reply, then stop.`;
19406
19861
  }
19407
19862
  buildDirectAnswerPrompt(query) {
19408
19863
  return `Answer this query directly from your own general knowledge: ${query}
19409
19864
 
19410
- ` + `It needs no search: it is general knowledge, simple reasoning, or conversation. Do NOT call any search, retrieval, web, or file-reading tools. ` + `Reply naturally and concisely; for small talk, just respond conversationally. Do not cite sources or mention retrieval.
19411
-
19412
- ` + `Call emit_fast_answer exactly once with the answer and an empty results list, then stop.`;
19865
+ ` + `It needs no search: it is general knowledge, simple reasoning, or conversation. Do NOT call any search, retrieval, web, or file-reading tools. ` + `Reply naturally and concisely; for small talk, just respond conversationally. Do not cite sources or mention retrieval.`;
19413
19866
  }
19414
19867
  discoveryHint(sentence) {
19415
19868
  const names = this.tools.map((tool) => tool.name).filter((name) => name === JIKJI_FIND_TOOL_NAME || name === EVERYTHING_SEARCH_TOOL_NAME);
@@ -19423,22 +19876,20 @@ ${baseline}
19423
19876
  return `When local evidence is missing, thin, or possibly outdated — or the question concerns current events, recent releases, prices, or other public facts — use ${WEB_SEARCH_TOOL_NAME}${fetch2} to confirm or correct claims and fill gaps; use URLs as result sources for web-derived evidence. `;
19424
19877
  }
19425
19878
  buildRefinementPrompt(query, options, fastAnswer, fastAnswerDelivered) {
19426
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} curated results.` : "";
19879
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
19427
19880
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
19428
19881
  const firstAnswer = formatFirstAnswerContext(fastAnswer, fastAnswerDelivered);
19429
- const answerRules = fastAnswerDelivered ? `Formatting and content rules for the final \`answer\` (DELTA ONLY):
19430
- ` + `- The user already has the first answer above. \`answer\` MUST contain only the delta against it: (a) corrections to anything in the first answer that is wrong, unsupported, or outdated, and (b) newly verified findings that were not present in the first answer.
19882
+ const answerRules = fastAnswerDelivered ? `Formatting and content rules for your final answer (DELTA ONLY):
19883
+ ` + `- The user already has the first answer above. Your final answer MUST contain only the delta against it: (a) corrections to anything in the first answer that is wrong, unsupported, or outdated, and (b) newly verified findings that were not present in the first answer.
19431
19884
  ` + `- NEVER restate or re-list first-answer facts that remain correct, and never repeat its bullet list.
19432
19885
  ` + `- Mark each item clearly as a correction or as a new finding.
19433
19886
  ` + `- If verification changed nothing and found nothing new, say so in one short line (the first answer is confirmed as-is) instead of restating it.
19434
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
19435
- ` + `- ${ANSWER_CITATION_RULE} A correction or new finding that relies on a first-answer unit must re-emit that evidence as a result of this call and cite its new number.
19887
+ ` + `- ${ANSWER_CITATION_RULE} A correction or new finding that relies on evidence the first answer cited must cite that evidence's id again.
19436
19888
  ` + `- ${ANSWER_IMAGE_EMBED_RULE} ${ANSWER_IMAGE_DELTA_RULE}
19437
19889
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
19438
19890
  ` + `- When evidence conflicts, treat the freshest (most recent) information as the correct source of truth.` : `Formatting and content rules for the final answer (COMPLETE — no first answer reached the caller):
19439
19891
  ` + `- Provide the core answer to the user's question in at most 5 bullet points. If additional explanation is necessary, append it after the bullet points.
19440
19892
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
19441
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
19442
19893
  ` + `- ${ANSWER_CITATION_RULE}
19443
19894
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
19444
19895
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
@@ -19447,35 +19898,34 @@ ${baseline}
19447
19898
 
19448
19899
  ` + `${firstAnswer}
19449
19900
 
19450
- ` + `Now verify it rigorously. ${this.discoveryHint((tools) => `Actively use ${tools} when discovering or exploring local files and folders. `)}Check important claims against source files with bash when needed, correct anything wrong or unsupported, fill gaps with retrieval tools, and resolve conflicts and freshness. ${this.webFallbackHint()}` + `Cite the evidence ids (e.g. e3) shown next to retrieved results in each result's refs; for a local file you opened yourself with bash, give its absolute path.
19901
+ ` + `Now verify it rigorously. ${this.discoveryHint((tools) => `Actively use ${tools} when discovering or exploring local files and folders. `)}Check important claims against source files with bash when needed, correct anything wrong or unsupported, fill gaps with retrieval tools, and resolve conflicts and freshness. ${this.webFallbackHint()}
19451
19902
 
19452
19903
  ` + `${answerRules}
19453
19904
 
19454
- ` + `Do not use broad grep/find or recursive filesystem scans: only inspect a path or narrow neighborhood surfaced by retrieval, and only when evidence clearly points there. ` + `Avoid spinning repeated near-identical queries against the same datasource; once additional attempts stop surfacing new evidence, conclude from the evidence available. ` + `If more search is needed, first write a brief 1–2 line progress update stating the best current hypothesis and what you are checking next, then call retrieval tools. ` + `When finished, call ${EMIT_AUTORAG_RESULTS_TOOL_NAME} exactly once as your final action with the curated ` + `results, each citing its supporting evidence ids in refs.`;
19905
+ ` + `Do not use broad grep/find or recursive filesystem scans: only inspect a path or narrow neighborhood surfaced by retrieval, and only when evidence clearly points there. ` + `Avoid spinning repeated near-identical queries against the same datasource; once additional attempts stop surfacing new evidence, conclude from the evidence available. ` + `If more search is needed, first write a brief 1–2 line progress update stating the best current hypothesis and what you are checking next, then call retrieval tools. ` + `When finished, reply with the final answer and no tool call: that last reply is what the user receives, so keep progress notes out of it.`;
19455
19906
  }
19456
19907
  buildSearchPrompt(query, options, initialRetrievalContext) {
19457
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} curated results.` : "";
19908
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
19458
19909
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
19459
19910
  return `Find and curate information for this original query: ${query}${limit}${scope}
19460
19911
 
19461
- ` + `Start by deciding whether this is answerable from general knowledge or memory. If it is a generic, stable question, answer it immediately without retrieval and emit the structured result. ` + `Otherwise, baseline MinSync and Jikji retrieval is already running in parallel; do not emit final results until its next message arrives.
19912
+ ` + `Start by deciding whether this is answerable from general knowledge or memory. If it is a generic, stable question, answer it immediately without retrieval. ` + `Otherwise, baseline MinSync and Jikji retrieval is already running in parallel; do not give the final answer until its next message arrives.
19462
19913
 
19463
19914
  ` + `Baseline retrieval context:
19464
19915
  ${initialRetrievalContext ?? "Pending; continue only with a brief progress statement."}
19465
19916
 
19466
- ` + `Treat candidates as unverified evidence, verify important claims against source files when needed, and use additional tools when needed. ` + `Judge relevance, conflicts, freshness, and sufficiency in this agent loop. Cite the evidence ids (e.g. e3) shown next to retrieved results in each result's refs.
19917
+ ` + `Treat candidates as unverified evidence, verify important claims against source files when needed, and use additional tools when needed. ` + `Judge relevance, conflicts, freshness, and sufficiency in this agent loop.
19467
19918
 
19468
19919
  ` + `Formatting and content rules for the answer:
19469
19920
  ` + `- Provide the core answer to the user's question in at most 5 bullet points. If additional explanation is necessary, append it after the bullet points.
19470
19921
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
19471
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
19472
19922
  ` + `- ${ANSWER_CITATION_RULE}
19473
19923
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
19474
19924
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
19475
19925
  ` + `- When evidence conflicts, treat the freshest (most recent) information as the correct source of truth.
19476
19926
  ` + `- If information is incomplete or uncertain, acknowledge it briefly without lengthy explanations. If there are partial clues or leads, mention them concisely.
19477
19927
 
19478
- ` + `${this.discoveryHint((tools) => `When exploring local files and folders, actively use ${tools} rather than exploratory bash commands. `)}If more search is needed, first write a brief 1–2 line progress update stating the best current hypothesis and what you are checking next, then call retrieval tools. ` + `Never repeat a generic status message. Do not use broad grep/find or recursive filesystem scans: only inspect a path or narrow neighborhood surfaced by retrieval, and only when evidence clearly points there. ` + `Avoid spinning repeated near-identical queries against the same datasource; once additional attempts stop surfacing new evidence, conclude from the evidence available. ` + `When finished, call ${EMIT_AUTORAG_RESULTS_TOOL_NAME} exactly once as your final action with the curated ` + `results, each citing its supporting evidence ids in refs.`;
19928
+ ` + `${this.discoveryHint((tools) => `When exploring local files and folders, actively use ${tools} rather than exploratory bash commands. `)}If more search is needed, first write a brief 1–2 line progress update stating the best current hypothesis and what you are checking next, then call retrieval tools. ` + `Never repeat a generic status message. Do not use broad grep/find or recursive filesystem scans: only inspect a path or narrow neighborhood surfaced by retrieval, and only when evidence clearly points there. ` + `Avoid spinning repeated near-identical queries against the same datasource; once additional attempts stop surfacing new evidence, conclude from the evidence available. ` + `When finished, reply with the final answer and no tool call: that last reply is what the user receives, so keep progress notes out of it.`;
19479
19929
  }
19480
19930
  async refresh(force = false, opts) {
19481
19931
  const methods = opts?.methods;
@@ -20107,57 +20557,21 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
20107
20557
  function formatRerankedBaseline(results, evidenceIds) {
20108
20558
  const lines = results.map((result, index) => `[${evidenceIds[index]}] ${result.source}
20109
20559
  ${result.content.replace(/\s+/gu, " ")}`);
20110
- return `Reranked initial candidates (ordered by relevance to the query; cite evidence by its [eN] id in refs):
20560
+ return `Reranked initial candidates (ordered by relevance to the query; cite evidence by its [eN] id):
20111
20561
  ${lines.join(`
20112
20562
  `)}`;
20113
20563
  }
20114
- function fastAnswerAsFinal(fastAnswer) {
20115
- const refsByNumber = new Map(fastAnswer.evidenceRefs.map((entry) => [entry.number, entry.refs]));
20116
- return {
20117
- answer: fastAnswer.answer,
20118
- results: fastAnswer.results.map((result) => ({
20119
- number: result.number,
20120
- title: result.title,
20121
- summary: result.summary,
20122
- evidence: result.evidence,
20123
- confidence: result.confidence ?? 0.5
20124
- })),
20125
- mapping: fastAnswer.results.map((result) => {
20126
- const refs = refsByNumber.get(result.number) ?? [];
20127
- const primary = refs[0];
20128
- return {
20129
- number: result.number,
20130
- source: primary?.source ?? "",
20131
- method: primary?.method ?? EMIT_FAST_ANSWER_TOOL_NAME,
20132
- content: primary?.content ?? (result.evidence.map((evidence) => evidence.excerpt).join(`
20133
- `) || result.summary),
20134
- evidenceRefs: refs
20135
- };
20136
- }),
20137
- warnings: []
20138
- };
20139
- }
20140
20564
  function formatFirstAnswerContext(fastAnswer, delivered) {
20141
20565
  if (fastAnswer === undefined) {
20142
20566
  return "(the fast phase produced no answer — write the complete answer)";
20143
20567
  }
20144
- const header = delivered ? "The user has ALREADY received this immediate first answer:" : "An internal first-pass draft was produced but was NOT shown to the caller; write the complete answer:";
20145
- const units = fastAnswer.results.length === 0 ? "" : `
20146
-
20147
- Numbered units of that first answer (its own numbering — NOT citation numbers for your final answer; cite only the results you emit):
20148
- ${fastAnswer.results.map((result) => `[${result.number}] ${result.title} — ${result.summary}`).join(`
20149
- `)}`;
20150
- const sources = fastAnswer.sources.length === 0 ? "" : `
20151
-
20152
- Sources of that first answer:
20153
- ${fastAnswer.sources.map((entry) => `[${entry.number}] -> ${entry.source}`).join(`
20154
- `)}`;
20568
+ const header = delivered ? "The user has ALREADY received this immediate first answer (its citations were renumbered for the user; the [eN] ids below are still valid for you):" : "An internal first-pass draft was produced but was NOT shown to the caller; write the complete answer:";
20155
20569
  return `${header}
20156
- ${fastAnswer.answer}${units}${sources}`;
20570
+ ${fastAnswer}`;
20157
20571
  }
20158
- function buildMissingFinalEmitAnswer(query, reason, trace, modelError) {
20572
+ function buildMissingFinalAnswer(query, reason, trace, modelError) {
20159
20573
  const lines = [
20160
- `The search run for "${query}" ended without finalized results: the agent ended its run without calling emit_autorag_results, so no curated answer is available within the configured search range.`,
20574
+ `The search run for "${query}" ended without a final answer: the agent stopped before writing one, so no curated answer is available within the configured search range.`,
20161
20575
  ...modelError === undefined ? [] : [`The model request failed: ${modelError}`],
20162
20576
  ...reason === undefined ? modelError === undefined ? ["The agent did not record why it stopped."] : [] : [`The agent's last note before stopping: "${reason.length > 500 ? `${reason.slice(0, 500)}…` : reason}"`],
20163
20577
  modelError === undefined ? "Next steps: broaden the configured searchPaths, connect additional datasources via the datasources configuration, or retry with a narrower or different query." : "Next steps: fix the model provider error above (rate limit, quota, credentials, or model id) and retry the same query.",
@@ -20178,8 +20592,17 @@ function lastModelRequestError(messages) {
20178
20592
  }
20179
20593
  return;
20180
20594
  }
20181
- function buildFinalEmitReminder() {
20182
- return `You ended without calling ${EMIT_AUTORAG_RESULTS_TOOL_NAME}, so the user has not received your verified answer. ` + `Do not search again. Call ${EMIT_AUTORAG_RESULTS_TOOL_NAME} now, exactly once, with the answer you just wrote, ` + `its numbered results, each with the evidence ids (refs) of the sources you used (a local file you opened yourself: its absolute path). ` + `If verification found nothing usable, call it with an answer that says so and an empty results list.`;
20595
+ function finalAnswerText(messages) {
20596
+ for (let index = messages.length - 1;index >= 0; index--) {
20597
+ const message = messages[index];
20598
+ if (message.role !== "assistant")
20599
+ continue;
20600
+ if (message.stopReason !== "stop")
20601
+ return;
20602
+ const text = message.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
20603
+ return text === "" ? undefined : text;
20604
+ }
20605
+ return;
20183
20606
  }
20184
20607
  function lastAssistantText(messages) {
20185
20608
  for (let index = messages.length - 1;index >= 0; index--) {
@@ -20341,13 +20764,12 @@ var init_agent = __esm(() => {
20341
20764
  init_rerank();
20342
20765
  init_scope();
20343
20766
  init_model_auth();
20767
+ init_answer_citations();
20344
20768
  init_datasource_skill();
20345
20769
  init_dupey_tool();
20346
- init_emit_results_tool();
20347
20770
  init_everything_search_tool();
20348
20771
  init_evidence_judgment();
20349
20772
  init_evidence_ledger();
20350
- init_fast_answer_tool();
20351
20773
  init_fsearch_search_tool();
20352
20774
  init_jev_extension();
20353
20775
  init_jikji_find_tool();
@@ -20392,6 +20814,60 @@ var init_agent = __esm(() => {
20392
20814
  };
20393
20815
  });
20394
20816
 
20817
+ // src/agent/results.ts
20818
+ import { Type as Type17 } from "typebox";
20819
+ var evidenceRefSchema, answerSchema, warningsSchema, curatedResultFields, reportSchema;
20820
+ var init_results = __esm(() => {
20821
+ evidenceRefSchema = Type17.Object({
20822
+ method: Type17.String({ description: "Retrieval method namespace for this evidence chunk" }),
20823
+ source: Type17.String({ description: "Internal opaque source identifier for this evidence chunk" }),
20824
+ excerpt: Type17.Optional(Type17.String({ description: "Evidence excerpt used for stable ID normalization" })),
20825
+ content: Type17.Optional(Type17.String({ description: "Evidence content used for stable ID normalization" })),
20826
+ retrievalResultId: Type17.Optional(Type17.String({ description: "Backend retrieval ID when path-opaque and stable" })),
20827
+ chunkIndex: Type17.Optional(Type17.Integer({ description: "Chunk index, if available" })),
20828
+ lineNumber: Type17.Optional(Type17.Integer({ description: "Line number, if available" })),
20829
+ stableEvidenceId: Type17.Optional(Type17.String({ description: "Stable evidence ID, if already normalized" })),
20830
+ retrieverMix: Type17.Optional(Type17.Array(Type17.String({ maxLength: 64 }), {
20831
+ description: "Retrievers that contributed to this result",
20832
+ maxItems: 8
20833
+ })),
20834
+ parserType: Type17.Optional(Type17.String({ description: "Parser that produced this evidence", maxLength: 120 })),
20835
+ documentType: Type17.Optional(Type17.String({ description: "Document type, if known", maxLength: 120 })),
20836
+ documentArea: Type17.Optional(Type17.String({ description: "Document collection area, if known", maxLength: 120 })),
20837
+ evidenceType: Type17.Optional(Type17.String({ description: "Evidence type, if known", maxLength: 120 })),
20838
+ evidenceLocation: Type17.Optional(Type17.String({ description: "Human-readable evidence location", maxLength: 120 })),
20839
+ confidence: Type17.Optional(Type17.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
20840
+ });
20841
+ answerSchema = Type17.String({
20842
+ description: `Answer for the caller. At most 5 bullet points (plus optional explanation); reference results by bracketed number (e.g. [1], [2]) without file paths or raw chunk text, except the image-embed exception below. ${ANSWER_CITATION_RULE} ${ANSWER_IMAGE_EMBED_RULE}`
20843
+ });
20844
+ warningsSchema = Type17.Optional(Type17.Array(Type17.String(), { description: "Optional warnings about this result set" }));
20845
+ curatedResultFields = {
20846
+ number: Type17.Integer({ description: "1-based result number" }),
20847
+ title: Type17.String({ description: "Short name of the curated knowledge unit" }),
20848
+ summary: Type17.String({ description: "Key insight: purpose, details, and line range" }),
20849
+ evidence: Type17.Array(Type17.Object({
20850
+ excerpt: Type17.String({ description: "Supporting excerpt" }),
20851
+ lineNumber: Type17.Optional(Type17.Integer({ description: "Line number of the excerpt, if known" }))
20852
+ })),
20853
+ confidence: Type17.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
20854
+ };
20855
+ reportSchema = Type17.Object({
20856
+ answer: answerSchema,
20857
+ results: Type17.Array(Type17.Object(curatedResultFields), { description: "Numbered curated knowledge units." }),
20858
+ mapping: Type17.Array(Type17.Object({
20859
+ number: Type17.Integer({ description: "Matches the result number this entry maps" }),
20860
+ source: Type17.String({ description: "Source identifier — a real file path or a datasource id" }),
20861
+ method: Type17.String({ description: "Retrieval method or tool that produced the source" }),
20862
+ content: Type17.String({ description: "Raw content snippet of the evidence behind this result" }),
20863
+ evidenceRefs: Type17.Optional(Type17.Array(evidenceRefSchema, {
20864
+ description: "Hidden evidence chunk references supporting this curated result"
20865
+ }))
20866
+ }), { description: "Internal number -> source/method mapping. One entry per result number." }),
20867
+ warnings: warningsSchema
20868
+ });
20869
+ });
20870
+
20395
20871
  // src/datasource/aliased-skill.ts
20396
20872
  class AliasedDatasourceSkill {
20397
20873
  skill;
@@ -20789,7 +21265,7 @@ function datasourceCliError(datasourceId, command, failure) {
20789
21265
  return new DatasourceCliError(datasourceId, command, failure);
20790
21266
  }
20791
21267
  var DatasourceCliError;
20792
- var init_errors3 = __esm(() => {
21268
+ var init_errors4 = __esm(() => {
20793
21269
  DatasourceCliError = class DatasourceCliError extends Error {
20794
21270
  datasourceId;
20795
21271
  command;
@@ -20881,7 +21357,7 @@ function toResult(hit, source, mode, instanceId) {
20881
21357
  };
20882
21358
  }
20883
21359
  var init_methods = __esm(() => {
20884
- init_errors3();
21360
+ init_errors4();
20885
21361
  init_scope2();
20886
21362
  });
20887
21363
 
@@ -21475,7 +21951,7 @@ var init_rclone_connector = __esm(() => {
21475
21951
  });
21476
21952
 
21477
21953
  // src/datasource/connector.ts
21478
- import { createHash as createHash11 } from "node:crypto";
21954
+ import { createHash as createHash12 } from "node:crypto";
21479
21955
  function connectorFailureToDiagnosticCode(reason) {
21480
21956
  switch (reason) {
21481
21957
  case "auth":
@@ -21509,7 +21985,7 @@ function sanitizeIdSegment(value) {
21509
21985
  const cleaned = normalized.slice(start, end);
21510
21986
  if (cleaned === value && cleaned.length > 0 && cleaned.length <= 80)
21511
21987
  return cleaned;
21512
- const hash = createHash11("sha256").update(value).digest("hex").slice(0, 8);
21988
+ const hash = createHash12("sha256").update(value).digest("hex").slice(0, 8);
21513
21989
  const stem = cleaned.slice(0, 60);
21514
21990
  return stem.length > 0 ? `${stem}-${hash}` : hash;
21515
21991
  }
@@ -22708,7 +23184,7 @@ function toRetrievalResult(hit, source, methodName, instanceId, mode, diagnostic
22708
23184
  }
22709
23185
  var DISCORD_DATASOURCE_ID = "discord", DEFAULT_DISCORD_TAGS, DEFAULT_TOP_K2 = 20;
22710
23186
  var init_methods2 = __esm(() => {
22711
- init_errors3();
23187
+ init_errors4();
22712
23188
  init_scope2();
22713
23189
  init_paths3();
22714
23190
  DEFAULT_DISCORD_TAGS = ["discord", "chat", "pii"];
@@ -23006,7 +23482,7 @@ class GitHubConnector {
23006
23482
  if (repos.length === 0)
23007
23483
  return { ok: false, reason: "not-configured", message: "no repositories configured" };
23008
23484
  const token = resolveToken(this.options.token, this.options.tokenEnv ?? DEFAULT_TOKEN_ENV);
23009
- const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL3;
23485
+ const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL4;
23010
23486
  const request = {
23011
23487
  headers: {
23012
23488
  Accept: "application/vnd.github+json",
@@ -23079,7 +23555,7 @@ ${body}` : title,
23079
23555
  return { ok: true, documents, ...warnings.length > 0 ? { warnings } : {} };
23080
23556
  }
23081
23557
  }
23082
- var DEFAULT_BASE_URL3 = "https://api.github.com", DEFAULT_TOKEN_ENV = "GITHUB_TOKEN", DEFAULT_MAX_PAGES = 10, DEFAULT_MAX_DOCUMENTS2 = 500;
23558
+ var DEFAULT_BASE_URL4 = "https://api.github.com", DEFAULT_TOKEN_ENV = "GITHUB_TOKEN", DEFAULT_MAX_PAGES = 10, DEFAULT_MAX_DOCUMENTS2 = 500;
23083
23559
  var init_connector2 = () => {};
23084
23560
 
23085
23561
  // src/datasource/skills/github/skill.ts
@@ -23146,7 +23622,7 @@ class GitHubGistConnector {
23146
23622
  message: "no GitHub token: set GITHUB_TOKEN (or connector.tokenEnv) or authenticate the gh CLI"
23147
23623
  };
23148
23624
  }
23149
- const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL4;
23625
+ const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL5;
23150
23626
  const request = {
23151
23627
  headers: {
23152
23628
  Accept: "application/vnd.github+json",
@@ -23295,15 +23771,15 @@ ${content}`);
23295
23771
  }
23296
23772
  };
23297
23773
  }
23298
- var DEFAULT_BASE_URL4 = "https://api.github.com", DEFAULT_TOKEN_ENV2 = "GITHUB_TOKEN", DEFAULT_MAX_PAGES2 = 10, DEFAULT_MAX_GISTS = 500, GH_TOKEN_TIMEOUT_MS = 5000, STATE_VERSION = 1;
23774
+ var DEFAULT_BASE_URL5 = "https://api.github.com", DEFAULT_TOKEN_ENV2 = "GITHUB_TOKEN", DEFAULT_MAX_PAGES2 = 10, DEFAULT_MAX_GISTS = 500, GH_TOKEN_TIMEOUT_MS = 5000, STATE_VERSION = 1;
23299
23775
  var init_connector3 = () => {};
23300
23776
 
23301
23777
  // src/datasource/skills/github-gist/semantic.ts
23302
- import { createHash as createHash12 } from "node:crypto";
23778
+ import { createHash as createHash13 } from "node:crypto";
23303
23779
  import { existsSync as existsSync26, mkdirSync as mkdirSync22, readFileSync as readFileSync23, writeFileSync as writeFileSync21 } from "node:fs";
23304
23780
  import { dirname as dirname21 } from "node:path";
23305
23781
  function contentHash(chunk) {
23306
- return createHash12("sha256").update(`${chunk.title ?? ""}
23782
+ return createHash13("sha256").update(`${chunk.title ?? ""}
23307
23783
  ${chunk.content}`).digest("hex");
23308
23784
  }
23309
23785
  function sameIdentity(a, b) {
@@ -24233,7 +24709,7 @@ function isRemoteEmbedder(value) {
24233
24709
  }
24234
24710
  var CHAT_TAG = "lark:chat", DOCS_TAG = "lark:docs", DEFAULT_TAGS2, REMOTE_NOTE = "remote-search datasource: no local mirror";
24235
24711
  var init_skill6 = __esm(() => {
24236
- init_errors3();
24712
+ init_errors4();
24237
24713
  init_scope2();
24238
24714
  init_client7();
24239
24715
  DEFAULT_TAGS2 = [CHAT_TAG, DOCS_TAG];
@@ -24761,7 +25237,7 @@ function toRetrievalResult2(hit, source, methodName, instanceId, mode) {
24761
25237
  }
24762
25238
  var KAKAO_DATASOURCE_ID = "kakao", DEFAULT_KAKAO_TAGS, DEFAULT_TOP_K4 = 20;
24763
25239
  var init_methods3 = __esm(() => {
24764
- init_errors3();
25240
+ init_errors4();
24765
25241
  init_paths4();
24766
25242
  DEFAULT_KAKAO_TAGS = ["kakaotalk", "personal", "pii"];
24767
25243
  });
@@ -25115,7 +25591,7 @@ function ensurePrivateMailcrawlDataDir(path) {
25115
25591
  if (process.platform !== "win32")
25116
25592
  chmodSync(path, 448);
25117
25593
  }
25118
- var init_config = () => {};
25594
+ var init_config2 = () => {};
25119
25595
 
25120
25596
  // src/datasource/skills/mailcrawl/client.ts
25121
25597
  import { spawn as spawn15 } from "node:child_process";
@@ -25441,7 +25917,7 @@ function truncateUtf8(value, maxBytes) {
25441
25917
  var DEFAULT_BINARY4 = "mailcrawl", DEFAULT_SEARCH_TIMEOUT_MS3 = 60000, DEFAULT_INDEX_TIMEOUT_MS3 = 1800000, DEFAULT_MAX_BUFFER_BYTES4 = 1048576, LOOPBACK_HOSTS2, SAFE_ENV_KEYS2, SAFE_MAILCRAWL_ENV_KEYS, REMOTE_EMBEDDING_ENV_KEYS;
25442
25918
  var init_client9 = __esm(() => {
25443
25919
  init_portable_spawn();
25444
- init_config();
25920
+ init_config2();
25445
25921
  LOOPBACK_HOSTS2 = new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
25446
25922
  SAFE_ENV_KEYS2 = new Set(["HOME", "LANG", "LC_ALL", "PATH", "TMPDIR", "TMP", "TEMP", "NO_COLOR"]);
25447
25923
  SAFE_MAILCRAWL_ENV_KEYS = new Set([
@@ -25540,7 +26016,7 @@ class MailcrawlMethod {
25540
26016
  }
25541
26017
  var modes, MAILCRAWL_MODES;
25542
26018
  var init_methods4 = __esm(() => {
25543
- init_errors3();
26019
+ init_errors4();
25544
26020
  init_scope2();
25545
26021
  modes = ["bm25", "semantic", "hybrid"];
25546
26022
  MAILCRAWL_MODES = modes;
@@ -25688,7 +26164,7 @@ var TAGS;
25688
26164
  var init_skill9 = __esm(() => {
25689
26165
  init_scope2();
25690
26166
  init_client9();
25691
- init_config();
26167
+ init_config2();
25692
26168
  init_methods4();
25693
26169
  TAGS = ["mailcrawl", "email", "pii"];
25694
26170
  });
@@ -25908,7 +26384,7 @@ function failureCode2(reason) {
25908
26384
  }
25909
26385
  var DEFAULT_INSTANCE_ID5 = "default", DEFAULT_POLLING_INTERVAL_MS4;
25910
26386
  var init_crawler_skill = __esm(() => {
25911
- init_errors3();
26387
+ init_errors4();
25912
26388
  init_scope2();
25913
26389
  DEFAULT_POLLING_INTERVAL_MS4 = 15 * 60 * 1000;
25914
26390
  });
@@ -26094,7 +26570,7 @@ var DEFAULT_QMD_BINARY = "qmd", DEFAULT_QMD_TIMEOUT_MS = 60000, DEFAULT_QMD_MAX_
26094
26570
  // src/datasource/skills/obsidian/client.ts
26095
26571
  import { spawn as spawn16 } from "node:child_process";
26096
26572
  import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync22 } from "node:fs";
26097
- import { isAbsolute as isAbsolute7, resolve as resolve14 } from "node:path";
26573
+ import { isAbsolute as isAbsolute8, resolve as resolve14 } from "node:path";
26098
26574
 
26099
26575
  class QmdClient {
26100
26576
  options;
@@ -26190,7 +26666,7 @@ function resolveVaultPath(vaultPath) {
26190
26666
  if (vaultPath === undefined || vaultPath.trim().length === 0)
26191
26667
  return;
26192
26668
  const trimmed = vaultPath.trim();
26193
- return isAbsolute7(trimmed) ? trimmed : resolve14(trimmed);
26669
+ return isAbsolute8(trimmed) ? trimmed : resolve14(trimmed);
26194
26670
  }
26195
26671
  function controlledEnv5(options) {
26196
26672
  const instanceId = options.instanceId ?? "default";
@@ -26546,7 +27022,7 @@ function toRetrievalResult3(hit, source, methodName, instanceId, mode) {
26546
27022
  }
26547
27023
  var OBSIDIAN_DATASOURCE_ID = "obsidian", DEFAULT_OBSIDIAN_TAGS, DEFAULT_TOP_K5 = 20;
26548
27024
  var init_methods5 = __esm(() => {
26549
- init_errors3();
27025
+ init_errors4();
26550
27026
  init_scope2();
26551
27027
  DEFAULT_OBSIDIAN_TAGS = ["obsidian", "notes"];
26552
27028
  });
@@ -27084,7 +27560,7 @@ var init_slack = __esm(() => {
27084
27560
 
27085
27561
  // src/datasource/skills/spotlight/connector.ts
27086
27562
  import { spawn as spawn17 } from "node:child_process";
27087
- import { createHash as createHash13 } from "node:crypto";
27563
+ import { createHash as createHash14 } from "node:crypto";
27088
27564
  import { readFile as fsReadFile, stat as stat7 } from "node:fs/promises";
27089
27565
  import { basename as basename13, extname as extname8 } from "node:path";
27090
27566
 
@@ -27169,7 +27645,7 @@ class SpotlightConnector {
27169
27645
  if (content.length === 0)
27170
27646
  continue;
27171
27647
  documents.push({
27172
- docId: createHash13("sha256").update(path).digest("hex").slice(0, 16),
27648
+ docId: createHash14("sha256").update(path).digest("hex").slice(0, 16),
27173
27649
  hierarchy: ["files"],
27174
27650
  title: basename13(path),
27175
27651
  content,
@@ -27764,7 +28240,7 @@ var init_factory = __esm(() => {
27764
28240
  // src/cli/config.ts
27765
28241
  import { randomUUID as randomUUID9 } from "node:crypto";
27766
28242
  import { existsSync as existsSync28, mkdirSync as mkdirSync25, readFileSync as readFileSync24, renameSync as renameSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync23 } from "node:fs";
27767
- import { basename as basename14, dirname as dirname23, isAbsolute as isAbsolute8, join as join36, resolve as resolve15 } from "node:path";
28243
+ import { basename as basename14, dirname as dirname23, isAbsolute as isAbsolute9, join as join36, resolve as resolve15 } from "node:path";
27768
28244
  import { findEnvKeys, getEnvApiKey } from "@earendil-works/pi-ai/compat";
27769
28245
  import { getAgentDir as getAgentDir3, ModelRuntime as ModelRuntime2, SettingsManager as SettingsManager2 } from "@earendil-works/pi-coding-agent";
27770
28246
  function resolveConfigPath(input) {
@@ -27892,7 +28368,7 @@ function resolveSearchPaths(searchPaths, origin) {
27892
28368
  return searchPaths.map((searchPath) => resolvePersistedPath(searchPath, origin));
27893
28369
  }
27894
28370
  function resolvePersistedPath(path, origin) {
27895
- return isAbsolute8(path) ? path : resolve15(origin, path);
28371
+ return isAbsolute9(path) ? path : resolve15(origin, path);
27896
28372
  }
27897
28373
  function normalizeLegacyConfigPaths(partial, origin) {
27898
28374
  const workspacePath = resolvePersistedPath(partial.workspacePath ?? ".", origin);
@@ -28732,11 +29208,15 @@ function getModelRuntime(agentDir) {
28732
29208
  const cached = modelRuntimeCache.get(agentDir);
28733
29209
  if (cached !== undefined)
28734
29210
  return cached;
28735
- const created = ModelRuntime2.create({
28736
- authPath: join36(agentDir, "auth.json"),
28737
- modelsPath: join36(agentDir, "models.json"),
28738
- allowModelNetwork: false
28739
- });
29211
+ const created = (async () => {
29212
+ const runtime = await ModelRuntime2.create({
29213
+ authPath: join36(agentDir, "auth.json"),
29214
+ modelsPath: join36(agentDir, "models.json"),
29215
+ allowModelNetwork: false
29216
+ });
29217
+ await registerAutoRAGProvider(runtime);
29218
+ return runtime;
29219
+ })();
28740
29220
  modelRuntimeCache.set(agentDir, created);
28741
29221
  created.catch(() => {
28742
29222
  modelRuntimeCache.delete(agentDir);
@@ -29065,8 +29545,9 @@ function writeDefaultConfig(path, partial, opts = {}) {
29065
29545
  }
29066
29546
  }
29067
29547
  var DEFAULT_CONFIG_FILENAME = "config.json", LEGACY_CONFIG_FILENAME = "autorag.config.json", CONFIG_LOCK_RETRY_MS = 10, CONFIG_LOCK_TIMEOUT_MS = 1e4, CONFIG_LOCK_STALE_MS = 30000, ConfigError, MINSYNC_REQUIRED_MESSAGE = "MinSync is required and cannot be disabled; remove `minSync: false` / `minSync.enabled: false` from the config.", AGENT_MODEL_APIS, AGENT_MODEL_INPUTS, API_KEY_ENV_PATTERN2, POSITIVE_INT_FIELDS, EMBEDDER_ALLOWLIST, MINSYNC_ALLOWLIST, MINSYNC_LEGACY_IGNORED, P2P_ALLOWLIST, P2P_QUOTA_ALLOWLIST, LIMITS_ALLOWLIST, LIMITS_PREFETCH_ALLOWLIST, JEV_CONFIG_FIELDS, JEV_BACKEND_NAMES, DEFAULT_JEV_BACKEND = "openrouter", DEFAULT_QUERY_DECOMPOSITION_MODEL, RERANK_ALLOWLIST, UNKNOWN_MODEL_HINT = "Add baseUrl (and optional api/apiKeyEnv) for an OpenAI-compatible endpoint outside the pi-ai catalog, or use a pi-ai catalog model id.", modelRuntimeCache;
29068
- var init_config2 = __esm(() => {
29548
+ var init_config3 = __esm(() => {
29069
29549
  init_local_model();
29550
+ init_provider();
29070
29551
  init_home();
29071
29552
  init_factory();
29072
29553
  init_file_lock();
@@ -29161,7 +29642,6 @@ class AutoRAGLite {
29161
29642
  agent;
29162
29643
  retrievalEngine;
29163
29644
  memory;
29164
- sessions = new Map;
29165
29645
  constructor(config) {
29166
29646
  this.config = config;
29167
29647
  const agentOptions = buildAgentOptions(config);
@@ -29216,14 +29696,11 @@ class AutoRAGLite {
29216
29696
  return this.retrievalEngine.retrieveByMethod(query, options);
29217
29697
  }
29218
29698
  recordStructuredResultsSession(sessionId, query, details) {
29219
- return recordStructuredResultsSession(sessionId, query, details, this.sessions, this.memory);
29699
+ return recordStructuredResultsSession(sessionId, query, details, this.memory);
29220
29700
  }
29221
29701
  recordReport(query, details) {
29222
29702
  return this.recordStructuredResultsSession(randomUUID10(), query, details);
29223
29703
  }
29224
- getResultRegistry(sessionId) {
29225
- return this.sessions.get(sessionId)?.registry ?? new Map;
29226
- }
29227
29704
  getMemorySchema() {
29228
29705
  return structuredClone(this.memory.getSchema());
29229
29706
  }
@@ -29241,9 +29718,9 @@ function createAutoRAGLite(options = {}) {
29241
29718
  var init_core = __esm(() => {
29242
29719
  init_agent();
29243
29720
  init_search_documents();
29244
- init_config2();
29721
+ init_config3();
29245
29722
  init_memory();
29246
- init_config2();
29723
+ init_config3();
29247
29724
  });
29248
29725
 
29249
29726
  // src/cli/output.ts
@@ -29417,7 +29894,8 @@ function searchEnvelope(resp, debug) {
29417
29894
  if (r.source !== undefined)
29418
29895
  base.source = r.source;
29419
29896
  if (debug) {
29420
- base.confidence = r.confidence;
29897
+ if (r.confidence !== undefined)
29898
+ base.confidence = r.confidence;
29421
29899
  base.evidence = r.evidence.map((e) => {
29422
29900
  const ev = { excerpt: e.excerpt };
29423
29901
  if (e.lineNumber !== undefined)
@@ -29454,7 +29932,8 @@ function renderSearchHuman(resp, debug) {
29454
29932
  if (r.summary)
29455
29933
  lines.push(` ${r.summary}`);
29456
29934
  if (debug) {
29457
- lines.push(` confidence: ${r.confidence}`);
29935
+ if (r.confidence !== undefined)
29936
+ lines.push(` confidence: ${r.confidence}`);
29458
29937
  for (const ev of r.evidence) {
29459
29938
  const ln = ev.lineNumber !== undefined ? ` (line ${ev.lineNumber})` : "";
29460
29939
  lines.push(` evidence${ln}: ${ev.excerpt}`);
@@ -29686,7 +30165,7 @@ async function runEvidence(ctx) {
29686
30165
  }
29687
30166
  var init_evidence = __esm(() => {
29688
30167
  init_memory();
29689
- init_config2();
30168
+ init_config3();
29690
30169
  });
29691
30170
 
29692
30171
  // src/cli/commands/report.ts
@@ -29784,9 +30263,9 @@ async function runReport(ctx) {
29784
30263
  }
29785
30264
  var MAX_REPORTED_SCHEMA_ERRORS = 8;
29786
30265
  var init_report = __esm(() => {
29787
- init_emit_results_tool();
30266
+ init_results();
29788
30267
  init_core();
29789
- init_config2();
30268
+ init_config3();
29790
30269
  });
29791
30270
 
29792
30271
  // src/mirror/index.ts
@@ -29803,10 +30282,10 @@ init_agent();
29803
30282
  init_agent();
29804
30283
  init_datasource_skill();
29805
30284
  init_dupey_tool();
29806
- init_emit_results_tool();
29807
30285
  init_jev_extension();
29808
30286
  init_jikji_find_tool();
29809
30287
  init_query_peer_tool();
30288
+ init_results();
29810
30289
  init_search_all_tool();
29811
30290
  init_search_minsync_tool();
29812
30291
  init_search_single_datasource_tool();
@@ -29814,6 +30293,20 @@ init_system_prompt();
29814
30293
 
29815
30294
  // src/index.ts
29816
30295
  init_system_prompt();
30296
+
30297
+ // src/cloud/index.ts
30298
+ init_authorize();
30299
+ init_callback();
30300
+ init_callback_server();
30301
+ init_config();
30302
+ init_errors3();
30303
+ init_models();
30304
+ init_oauth_login();
30305
+ init_pkce();
30306
+ init_provider();
30307
+ init_token();
30308
+
30309
+ // src/index.ts
29817
30310
  init_core();
29818
30311
 
29819
30312
  // src/datasource/index.ts
@@ -30020,7 +30513,7 @@ import { z as z2 } from "zod";
30020
30513
  // src/filesystem/name-search.ts
30021
30514
  import { realpathSync as realpathSync6 } from "node:fs";
30022
30515
  import { lstat, readdir as readdir4 } from "node:fs/promises";
30023
- import { basename as basename15, dirname as dirname24, isAbsolute as isAbsolute9, join as join37, relative as relative6, resolve as resolve16, sep as sep7 } from "node:path";
30516
+ import { basename as basename15, dirname as dirname24, isAbsolute as isAbsolute10, join as join37, relative as relative6, resolve as resolve16, sep as sep7 } from "node:path";
30024
30517
  var SKIP_DIR_NAMES2 = {
30025
30518
  ".git": true,
30026
30519
  ".autorag": true,
@@ -30167,7 +30660,7 @@ async function pinConfiguredRoots(roots, diagnostics) {
30167
30660
  return outermost;
30168
30661
  }
30169
30662
  async function resolveRequestRoots(requestRoot, pinnedRoots) {
30170
- const candidates = isAbsolute9(requestRoot) ? [requestRoot] : pinnedRoots.map((root) => resolve16(root, requestRoot));
30663
+ const candidates = isAbsolute10(requestRoot) ? [requestRoot] : pinnedRoots.map((root) => resolve16(root, requestRoot));
30171
30664
  const allowed = [];
30172
30665
  for (const candidate of candidates) {
30173
30666
  let real;
@@ -30720,20 +31213,33 @@ init_minsync();
30720
31213
  init_mirror();
30721
31214
  init_parser();
30722
31215
  export {
31216
+ API_KEY_CONFIG_VALUE,
31217
+ API_PATH,
31218
+ AUTHORIZE_PATH,
31219
+ AUTORAG_API_KEY_ENV,
31220
+ AUTORAG_BASE_URL_ENV,
30723
31221
  AliasedDatasourceSkill,
30724
31222
  AutoRAGAgent,
30725
31223
  AutoRAGLite,
31224
+ AutoragError,
31225
+ AutoragHttpError,
31226
+ AutoragOAuthError,
30726
31227
  BUILTIN_DATASOURCE_SKILL_NAMES,
30727
31228
  BUILTIN_OCR_LANGUAGES,
31229
+ CALLBACK_PATH,
30728
31230
  CLOUD_DRIVE_SKILL_DEFINITION,
30729
31231
  CloudDriveSkill,
30730
31232
  ConnectorDatasourceSkill,
30731
31233
  ConnectorLexicalMethod,
30732
31234
  DATASOURCE_CHUNKS_SEGMENT,
31235
+ DEFAULT_BASE_URL,
31236
+ DEFAULT_CONTEXT_WINDOW,
30733
31237
  DEFAULT_DISCRAWL_EMBEDDING_MODEL,
30734
31238
  DEFAULT_DISCRAWL_MODE,
30735
31239
  DEFAULT_JIKJI_OPTIONS,
31240
+ DEFAULT_LOGIN_TIMEOUT_MS,
30736
31241
  DEFAULT_MAX_SOURCE_BYTES,
31242
+ DEFAULT_MAX_TOKENS,
30737
31243
  DEFAULT_MINSYNC_EMBEDDER_CONFIG,
30738
31244
  DEFAULT_MINSYNC_EMBEDDER_DIMENSION,
30739
31245
  DEFAULT_MINSYNC_EMBEDDER_ID,
@@ -30749,7 +31255,6 @@ export {
30749
31255
  DiscrawlSemanticMethod,
30750
31256
  DiscrawlSkill,
30751
31257
  DupeyCliError,
30752
- EMIT_AUTORAG_RESULTS_TOOL_NAME,
30753
31258
  ENGLISH_ONLY_EMBEDDING_MODELS,
30754
31259
  EVIDENCE_SUPPORT_THRESHOLD,
30755
31260
  EmlParser,
@@ -30777,6 +31282,7 @@ export {
30777
31282
  MINSYNC_SUBDIR,
30778
31283
  MINSYNC_SURFACE,
30779
31284
  MINSYNC_VERSION,
31285
+ MODELS_PATH,
30780
31286
  MailExportConnector,
30781
31287
  MailExportSkill,
30782
31288
  MailcrawlClient,
@@ -30790,10 +31296,13 @@ export {
30790
31296
  MinSyncVectorMethod,
30791
31297
  NotcrawlClient,
30792
31298
  NotionSkill,
31299
+ OAUTH_CLIENT_ID,
30793
31300
  ObsidianBm25Method,
30794
31301
  ObsidianSemanticMethod,
30795
31302
  ObsidianSkill,
30796
31303
  OpenRouterReranker,
31304
+ PROVIDER_ID,
31305
+ PROVIDER_NAME,
30797
31306
  ParallelRetriever,
30798
31307
  ParseError,
30799
31308
  Parser,
@@ -30815,13 +31324,16 @@ export {
30815
31324
  SlacrawlClient,
30816
31325
  SpotlightConnector,
30817
31326
  SpotlightSkill,
31327
+ TOKEN_PATH,
30818
31328
  TelecrawlClient,
30819
31329
  TelecrawlSkill,
30820
31330
  WacrawlClient,
30821
31331
  WacrawlSkill,
31332
+ base64UrlEncode,
30822
31333
  bm25Scores,
30823
31334
  boundDiagnosticText2 as boundDiagnosticText,
30824
31335
  buildAgentOptions,
31336
+ buildAuthorizeUrl,
30825
31337
  buildDatasourceChunkSource,
30826
31338
  buildDatasourceInstanceSource,
30827
31339
  buildDatasourceSkills,
@@ -30830,16 +31342,21 @@ export {
30830
31342
  buildFSearchIndexArgs,
30831
31343
  buildFSearchSearchArgs,
30832
31344
  buildMinSyncPathMap,
31345
+ buildStoreEntry,
30833
31346
  buildSystemPrompt,
30834
31347
  cachedJikjiBinaryPath,
30835
31348
  configuredVectorDimension,
30836
31349
  connectorFailureToDiagnosticCode,
30837
31350
  createAutoRAGLite,
30838
31351
  createAutoRAGMcpServer,
31352
+ createAutoRAGProviderConfig,
30839
31353
  createCheckMemoryTool,
31354
+ createCodeChallenge,
31355
+ createCodeVerifier,
30840
31356
  createDefaultParserRegistry,
30841
- createEmitResultsTool,
31357
+ createPkcePair,
30842
31358
  createReranker,
31359
+ createState,
30843
31360
  createTesseractOcrProvider,
30844
31361
  datasourceChunkStorePath,
30845
31362
  datasourceSourceHasFragment,
@@ -30847,7 +31364,6 @@ export {
30847
31364
  derivedDatasourceIds,
30848
31365
  describeRetrievalError,
30849
31366
  detectMirrorStaleness,
30850
- emitResultsSchema,
30851
31367
  emptyMirrorIndex,
30852
31368
  ensureEverythingBinaries,
30853
31369
  ensureJikjiBinary,
@@ -30856,8 +31372,11 @@ export {
30856
31372
  everythingArch,
30857
31373
  everythingBinaryPaths,
30858
31374
  everythingInstanceName,
31375
+ exchangeCodeForToken,
30859
31376
  executableName,
31377
+ extractErrorPayload,
30860
31378
  fetchLatestMinSyncRelease,
31379
+ fetchModels,
30861
31380
  filterDatasourceScope,
30862
31381
  findSimilarQuestions,
30863
31382
  fsearchSocketPath,
@@ -30874,20 +31393,29 @@ export {
30874
31393
  loadManifests,
30875
31394
  loadMemoryContext,
30876
31395
  loadMirrorIndex,
31396
+ loginAutorag,
30877
31397
  lookupExecutableInPath,
30878
31398
  mapDatasourceDiagnostic,
30879
31399
  mapDatasourceDiagnostics,
30880
31400
  mapJikjiPath,
31401
+ mapModelsError,
31402
+ mapServerModel,
31403
+ mapServerModels,
31404
+ mapTokenExchangeError,
30881
31405
  matchesDatasourceScope,
30882
31406
  matchesVirtualPathScope,
30883
31407
  minSyncConfigPath,
30884
31408
  minSyncDocumentPath,
30885
31409
  minSyncEmbeddingIdentityPath,
30886
31410
  minSyncWorkspaceRoot,
31411
+ modelsFromStore,
31412
+ normalizeBaseUrl,
30887
31413
  normalizeJikjiAnswerPath,
30888
31414
  normalizeSessionEvidenceRef,
30889
31415
  normalizeVirtualPath2 as normalizeVirtualPath,
30890
31416
  normalizeVirtualPathScope,
31417
+ parseCallbackInput,
31418
+ parseCallbackQuery,
30891
31419
  parseCronExpr,
30892
31420
  parseEverythingJson,
30893
31421
  parseFSearchJsonLines,
@@ -30897,11 +31425,17 @@ export {
30897
31425
  parsedMirrorRoot,
30898
31426
  parsedOutputPath,
30899
31427
  planJikjiSourceRoots,
31428
+ refreshAutoragCredentials,
31429
+ refreshAutoragModels,
30900
31430
  refreshReadinessPath,
31431
+ registerAutoRAGProvider,
30901
31432
  renderMemoryContext,
30902
31433
  reportSchema,
31434
+ requireAuthorizationCode,
31435
+ resolveBaseUrl,
30903
31436
  resolveConfig,
30904
31437
  resolveConfigReadOnly,
31438
+ resolveCredentialKey,
30905
31439
  resolveEverythingBundleDir,
30906
31440
  resolveParserOptions,
30907
31441
  resolveReturnedPath,
@@ -30913,6 +31447,7 @@ export {
30913
31447
  scanWithDupey,
30914
31448
  selectExactDuplicateExclusions,
30915
31449
  selectReleaseAsset,
31450
+ startCallbackServer,
30916
31451
  syncMinSyncWorkspace,
30917
31452
  syncParsedMirrors,
30918
31453
  tokenize,