@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/cli/index.js CHANGED
@@ -1394,7 +1394,8 @@ function searchEnvelope(resp, debug) {
1394
1394
  if (r.source !== undefined)
1395
1395
  base.source = r.source;
1396
1396
  if (debug) {
1397
- base.confidence = r.confidence;
1397
+ if (r.confidence !== undefined)
1398
+ base.confidence = r.confidence;
1398
1399
  base.evidence = r.evidence.map((e) => {
1399
1400
  const ev = { excerpt: e.excerpt };
1400
1401
  if (e.lineNumber !== undefined)
@@ -1431,7 +1432,8 @@ function renderSearchHuman(resp, debug) {
1431
1432
  if (r.summary)
1432
1433
  lines.push(` ${r.summary}`);
1433
1434
  if (debug) {
1434
- lines.push(` confidence: ${r.confidence}`);
1435
+ if (r.confidence !== undefined)
1436
+ lines.push(` confidence: ${r.confidence}`);
1435
1437
  for (const ev of r.evidence) {
1436
1438
  const ln = ev.lineNumber !== undefined ? ` (line ${ev.lineNumber})` : "";
1437
1439
  lines.push(` evidence${ln}: ${ev.excerpt}`);
@@ -1712,6 +1714,599 @@ function loadLocalAutoRAGModel(options = {}) {
1712
1714
  var DEFAULT_MODEL_ID = "gpt-5.6-sol";
1713
1715
  var init_local_model = () => {};
1714
1716
 
1717
+ // src/cloud/config.ts
1718
+ function normalizeBaseUrl(value) {
1719
+ const trimmed = value.trim();
1720
+ let end = trimmed.length;
1721
+ while (end > 0 && trimmed.charCodeAt(end - 1) === 47)
1722
+ end--;
1723
+ return trimmed.slice(0, end);
1724
+ }
1725
+ function resolveBaseUrl(env) {
1726
+ const configured = env[AUTORAG_BASE_URL_ENV];
1727
+ const value = typeof configured === "string" && configured.trim() !== "" ? configured : DEFAULT_BASE_URL;
1728
+ return normalizeBaseUrl(value);
1729
+ }
1730
+ 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;
1731
+ var init_config = __esm(() => {
1732
+ API_KEY_CONFIG_VALUE = `$${AUTORAG_API_KEY_ENV}`;
1733
+ });
1734
+
1735
+ // src/cloud/errors.ts
1736
+ function extractErrorPayload(body) {
1737
+ if (typeof body !== "object" || body === null)
1738
+ return {};
1739
+ const record = body;
1740
+ const error = record.error;
1741
+ if (typeof error === "string")
1742
+ return error.length > 0 ? { message: error } : {};
1743
+ if (typeof error === "object" && error !== null) {
1744
+ const inner = error;
1745
+ const payload = {};
1746
+ if (typeof inner.message === "string")
1747
+ payload.message = inner.message;
1748
+ if (typeof inner.code === "string")
1749
+ payload.code = inner.code;
1750
+ if (typeof inner.type === "string")
1751
+ payload.type = inner.type;
1752
+ return payload;
1753
+ }
1754
+ return typeof record.message === "string" ? { message: record.message } : {};
1755
+ }
1756
+ var AutoragError, AutoragOAuthError, AutoragHttpError;
1757
+ var init_errors = __esm(() => {
1758
+ AutoragError = class AutoragError extends Error {
1759
+ constructor(message, options) {
1760
+ super(message, options);
1761
+ this.name = "AutoragError";
1762
+ }
1763
+ };
1764
+ AutoragOAuthError = class AutoragOAuthError extends AutoragError {
1765
+ constructor(message, options) {
1766
+ super(message, options);
1767
+ this.name = "AutoragOAuthError";
1768
+ }
1769
+ };
1770
+ AutoragHttpError = class AutoragHttpError extends AutoragError {
1771
+ status;
1772
+ code;
1773
+ type;
1774
+ constructor(message, options) {
1775
+ super(message, { cause: options.cause });
1776
+ this.name = "AutoragHttpError";
1777
+ this.status = options.status;
1778
+ if (options.code !== undefined)
1779
+ this.code = options.code;
1780
+ if (options.type !== undefined)
1781
+ this.type = options.type;
1782
+ }
1783
+ };
1784
+ });
1785
+
1786
+ // src/cloud/models.ts
1787
+ function resolveCredentialKey(credential) {
1788
+ if (credential === undefined)
1789
+ return;
1790
+ const value = credential.type === "oauth" ? credential.access : credential.key;
1791
+ return typeof value === "string" && value !== "" ? value : undefined;
1792
+ }
1793
+ async function fetchModels(options) {
1794
+ const doFetch = options.fetchImpl ?? fetch;
1795
+ let response;
1796
+ try {
1797
+ response = await doFetch(`${normalizeBaseUrl(options.baseUrl)}${MODELS_PATH}`, {
1798
+ headers: { authorization: `Bearer ${options.apiKey}`, accept: "application/json" },
1799
+ signal: options.signal
1800
+ });
1801
+ } catch (cause) {
1802
+ if (options.signal?.aborted) {
1803
+ throw new AutoragOAuthError("AutoRAG model refresh was cancelled.", { cause });
1804
+ }
1805
+ throw new AutoragOAuthError(`AutoRAG model listing could not reach ${normalizeBaseUrl(options.baseUrl)}.`, {
1806
+ cause
1807
+ });
1808
+ }
1809
+ let body;
1810
+ try {
1811
+ body = await response.json();
1812
+ } catch {
1813
+ body = undefined;
1814
+ }
1815
+ if (!response.ok)
1816
+ throw mapModelsError(response.status, body);
1817
+ return mapServerModels(body);
1818
+ }
1819
+ function mapModelsError(status, body) {
1820
+ const payload = extractErrorPayload(body);
1821
+ if (status === 401) {
1822
+ return new AutoragHttpError("AutoRAG rejected the API key (HTTP 401). Run /login again or set AUTORAG_API_KEY.", {
1823
+ status,
1824
+ code: payload.code ?? "unauthorized",
1825
+ type: payload.type
1826
+ });
1827
+ }
1828
+ const reason = payload.message ?? "the server returned no error message";
1829
+ return new AutoragHttpError(`AutoRAG model listing failed (HTTP ${status}): ${reason}`, {
1830
+ status,
1831
+ code: payload.code,
1832
+ type: payload.type
1833
+ });
1834
+ }
1835
+ function mapServerModels(payload) {
1836
+ if (typeof payload !== "object" || payload === null)
1837
+ return [];
1838
+ const data = payload.data;
1839
+ if (!Array.isArray(data))
1840
+ return [];
1841
+ const models = [];
1842
+ for (const entry of data) {
1843
+ if (typeof entry !== "object" || entry === null)
1844
+ continue;
1845
+ const model = mapServerModel(entry);
1846
+ if (model !== undefined)
1847
+ models.push(model);
1848
+ }
1849
+ return models;
1850
+ }
1851
+ function mapServerModel(entry) {
1852
+ const id = readString(entry.id);
1853
+ if (id === undefined)
1854
+ return;
1855
+ return {
1856
+ type: "chat",
1857
+ id,
1858
+ name: readString(entry.name) ?? id,
1859
+ input: readInputModalities(entry.input_modalities),
1860
+ cost: readPricing(entry.pricing),
1861
+ reasoning: entry.reasoning === true,
1862
+ contextWindow: readPositiveNumber(entry.context_window) ?? DEFAULT_CONTEXT_WINDOW,
1863
+ maxTokens: readPositiveNumber(entry.max_output_tokens) ?? DEFAULT_MAX_TOKENS
1864
+ };
1865
+ }
1866
+ function buildStoreEntry(models, providerId, baseUrl) {
1867
+ const stored = [];
1868
+ for (const model of models) {
1869
+ if (model.type === "image" || model.type === "classifier")
1870
+ continue;
1871
+ stored.push({
1872
+ type: "chat",
1873
+ id: model.id,
1874
+ name: model.name,
1875
+ api: model.api ?? "openai-responses",
1876
+ provider: providerId,
1877
+ baseUrl: model.baseUrl ?? baseUrl,
1878
+ input: model.input,
1879
+ cost: model.cost,
1880
+ reasoning: model.reasoning,
1881
+ contextWindow: model.contextWindow,
1882
+ maxTokens: model.maxTokens
1883
+ });
1884
+ }
1885
+ return { models: stored, checkedAt: Date.now() };
1886
+ }
1887
+ function modelsFromStore(stored) {
1888
+ if (stored === undefined)
1889
+ return [];
1890
+ const models = [];
1891
+ for (const entry of stored.models) {
1892
+ if (entry.type === "image" || entry.type === "classifier")
1893
+ continue;
1894
+ models.push({
1895
+ type: "chat",
1896
+ id: entry.id,
1897
+ name: entry.name,
1898
+ input: entry.input,
1899
+ cost: entry.cost,
1900
+ reasoning: entry.reasoning,
1901
+ contextWindow: entry.contextWindow,
1902
+ maxTokens: entry.maxTokens
1903
+ });
1904
+ }
1905
+ return models;
1906
+ }
1907
+ function readString(value) {
1908
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
1909
+ }
1910
+ function readPositiveNumber(value) {
1911
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
1912
+ }
1913
+ function readInputModalities(value) {
1914
+ if (!Array.isArray(value))
1915
+ return ["text"];
1916
+ const modalities = value.filter((item) => item === "text" || item === "image");
1917
+ const unique = Array.from(new Set(modalities));
1918
+ return unique.length > 0 ? unique : ["text"];
1919
+ }
1920
+ function readPricing(value) {
1921
+ const pricing = typeof value === "object" && value !== null ? value : {};
1922
+ return {
1923
+ input: readPositiveNumber(pricing.input) ?? 0,
1924
+ output: readPositiveNumber(pricing.output) ?? 0,
1925
+ cacheRead: readPositiveNumber(pricing.cache_read) ?? 0,
1926
+ cacheWrite: readPositiveNumber(pricing.cache_write) ?? 0
1927
+ };
1928
+ }
1929
+ var DEFAULT_CONTEXT_WINDOW = 128000, DEFAULT_MAX_TOKENS = 16384;
1930
+ var init_models = __esm(() => {
1931
+ init_config();
1932
+ init_errors();
1933
+ });
1934
+
1935
+ // src/cloud/authorize.ts
1936
+ function buildAuthorizeUrl(params) {
1937
+ const url = new URL(`${normalizeBaseUrl(params.baseUrl)}${AUTHORIZE_PATH}`);
1938
+ url.searchParams.set("client", OAUTH_CLIENT_ID);
1939
+ url.searchParams.set("redirect_uri", params.redirectUri);
1940
+ url.searchParams.set("state", params.state);
1941
+ url.searchParams.set("code_challenge", params.codeChallenge);
1942
+ url.searchParams.set("code_challenge_method", "S256");
1943
+ return url.toString();
1944
+ }
1945
+ var init_authorize = __esm(() => {
1946
+ init_config();
1947
+ });
1948
+
1949
+ // src/cloud/callback.ts
1950
+ function parseCallbackQuery(params) {
1951
+ const result = {};
1952
+ const code = params.get("code");
1953
+ const error = params.get("error");
1954
+ const state = params.get("state");
1955
+ if (code !== null && code !== "")
1956
+ result.code = code;
1957
+ if (error !== null && error !== "")
1958
+ result.error = error;
1959
+ if (state !== null && state !== "")
1960
+ result.state = state;
1961
+ return result;
1962
+ }
1963
+ function parseCallbackInput(input) {
1964
+ const trimmed = input.trim();
1965
+ if (trimmed === "") {
1966
+ throw new AutoragOAuthError("AutoRAG sign-in failed: nothing was pasted.");
1967
+ }
1968
+ if (/^https?:\/\//i.test(trimmed)) {
1969
+ try {
1970
+ return parseCallbackQuery(new URL(trimmed).searchParams);
1971
+ } catch {
1972
+ throw new AutoragOAuthError("AutoRAG sign-in failed: the pasted URL is not valid.");
1973
+ }
1974
+ }
1975
+ const query = trimmed.startsWith("?") ? trimmed.slice(1) : trimmed;
1976
+ if (!query.includes(" ")) {
1977
+ const params = new URLSearchParams(query);
1978
+ if (params.has("code") || params.has("error") || params.has("state")) {
1979
+ return parseCallbackQuery(params);
1980
+ }
1981
+ }
1982
+ return { code: trimmed };
1983
+ }
1984
+ function requireAuthorizationCode(result, expectedState) {
1985
+ if (result.state !== undefined && result.state !== expectedState) {
1986
+ throw new AutoragOAuthError("AutoRAG sign-in failed: state mismatch (the callback did not originate from this login attempt).");
1987
+ }
1988
+ if (result.error !== undefined) {
1989
+ throw new AutoragOAuthError(result.error === "access_denied" ? "AutoRAG sign-in was cancelled in the browser." : `AutoRAG sign-in failed: ${result.error}.`);
1990
+ }
1991
+ if (result.code === undefined) {
1992
+ throw new AutoragOAuthError("AutoRAG sign-in failed: the callback carried no authorization code.");
1993
+ }
1994
+ return { code: result.code };
1995
+ }
1996
+ var init_callback = __esm(() => {
1997
+ init_errors();
1998
+ });
1999
+
2000
+ // src/cloud/callback-server.ts
2001
+ import { createServer as createServer3 } from "node:http";
2002
+ function createDeferred() {
2003
+ let resolve;
2004
+ let reject;
2005
+ const promise = new Promise((res, rej) => {
2006
+ resolve = res;
2007
+ reject = rej;
2008
+ });
2009
+ return { promise, resolve, reject };
2010
+ }
2011
+ function renderCallbackPage(failed) {
2012
+ 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.";
2013
+ return [
2014
+ "<!doctype html>",
2015
+ '<html lang="en">',
2016
+ "<head>",
2017
+ '<meta charset="utf-8">',
2018
+ '<meta name="viewport" content="width=device-width, initial-scale=1">',
2019
+ "<title>AutoRAG</title>",
2020
+ "</head>",
2021
+ '<body style="font-family: system-ui, sans-serif; margin: 4rem auto; max-width: 32rem; text-align: center;">',
2022
+ `<p>${message}</p>`,
2023
+ "</body>",
2024
+ "</html>"
2025
+ ].join(`
2026
+ `);
2027
+ }
2028
+ function startCallbackServer(options) {
2029
+ const host = options.host ?? "127.0.0.1";
2030
+ const timeoutMs = options.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS;
2031
+ const server = createServer3();
2032
+ const started = createDeferred();
2033
+ const callback = createDeferred();
2034
+ callback.promise.catch(() => {});
2035
+ let finished = false;
2036
+ let startSettled = false;
2037
+ let timer;
2038
+ function cleanup() {
2039
+ clearTimeout(timer);
2040
+ options.signal?.removeEventListener("abort", onAbort);
2041
+ if (server.listening) {
2042
+ server.closeAllConnections();
2043
+ server.close();
2044
+ }
2045
+ }
2046
+ function fail(error) {
2047
+ if (finished)
2048
+ return;
2049
+ finished = true;
2050
+ cleanup();
2051
+ callback.reject(error);
2052
+ }
2053
+ function onAbort() {
2054
+ fail(new AutoragOAuthError("AutoRAG sign-in was cancelled."));
2055
+ }
2056
+ server.on("request", (req, res) => {
2057
+ const url = new URL(req.url ?? "/", `http://${host}`);
2058
+ if (req.method !== "GET" || url.pathname !== CALLBACK_PATH) {
2059
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
2060
+ res.end("Not found");
2061
+ return;
2062
+ }
2063
+ if (finished) {
2064
+ res.writeHead(410, { "content-type": "text/plain; charset=utf-8" });
2065
+ res.end("Callback already handled");
2066
+ return;
2067
+ }
2068
+ const params = url.searchParams;
2069
+ const code = params.get("code");
2070
+ const oauthError = params.get("error");
2071
+ const hasResponse = code !== null && code !== "" || oauthError !== null && oauthError !== "";
2072
+ if (params.get("state") !== options.state || !hasResponse) {
2073
+ res.writeHead(400, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
2074
+ res.end(renderCallbackPage(true));
2075
+ return;
2076
+ }
2077
+ finished = true;
2078
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
2079
+ res.end(renderCallbackPage(params.has("error")));
2080
+ cleanup();
2081
+ callback.resolve(params);
2082
+ });
2083
+ server.on("error", (error) => {
2084
+ const wrapped = error instanceof Error ? error : new Error(String(error));
2085
+ if (!startSettled) {
2086
+ startSettled = true;
2087
+ cleanup();
2088
+ started.reject(wrapped);
2089
+ return;
2090
+ }
2091
+ fail(wrapped);
2092
+ });
2093
+ server.listen(0, host, () => {
2094
+ const address = server.address();
2095
+ const port = typeof address === "object" && address !== null ? address.port : 0;
2096
+ const redirectUri = `http://${host}:${port}${CALLBACK_PATH}`;
2097
+ timer = setTimeout(() => fail(new AutoragOAuthError("AutoRAG sign-in timed out waiting for the browser callback.")), timeoutMs);
2098
+ if (options.signal?.aborted)
2099
+ onAbort();
2100
+ else
2101
+ options.signal?.addEventListener("abort", onAbort, { once: true });
2102
+ startSettled = true;
2103
+ options.onListening?.(redirectUri);
2104
+ started.resolve({
2105
+ redirectUri,
2106
+ waitForCallback: () => callback.promise,
2107
+ close: () => {
2108
+ if (!finished)
2109
+ fail(new AutoragOAuthError("AutoRAG sign-in was cancelled."));
2110
+ }
2111
+ });
2112
+ });
2113
+ return started.promise;
2114
+ }
2115
+ var CALLBACK_PATH = "/callback", DEFAULT_LOGIN_TIMEOUT_MS;
2116
+ var init_callback_server = __esm(() => {
2117
+ init_errors();
2118
+ DEFAULT_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
2119
+ });
2120
+
2121
+ // src/cloud/pkce.ts
2122
+ import { createHash as createHash2, randomBytes } from "node:crypto";
2123
+ function base64UrlEncode(bytes) {
2124
+ return Buffer.from(bytes).toString("base64url");
2125
+ }
2126
+ function createCodeChallenge(verifier) {
2127
+ return base64UrlEncode(createHash2("sha256").update(verifier, "ascii").digest());
2128
+ }
2129
+ function createCodeVerifier(byteLength = 32) {
2130
+ return base64UrlEncode(randomBytes(byteLength));
2131
+ }
2132
+ function createState(byteLength = 24) {
2133
+ return base64UrlEncode(randomBytes(byteLength));
2134
+ }
2135
+ function createPkcePair(byteLength = 32) {
2136
+ const verifier = createCodeVerifier(byteLength);
2137
+ return { verifier, challenge: createCodeChallenge(verifier) };
2138
+ }
2139
+ var init_pkce = () => {};
2140
+
2141
+ // src/cloud/token.ts
2142
+ function mapTokenExchangeError(status, body) {
2143
+ const payload = extractErrorPayload(body);
2144
+ const reason = payload.message ?? "the server returned no error message";
2145
+ return new AutoragHttpError(`AutoRAG token exchange failed (HTTP ${status}): ${reason}`, {
2146
+ status,
2147
+ code: payload.code,
2148
+ type: payload.type
2149
+ });
2150
+ }
2151
+ async function exchangeCodeForToken(options) {
2152
+ const doFetch = options.fetchImpl ?? fetch;
2153
+ let response;
2154
+ try {
2155
+ response = await doFetch(`${normalizeBaseUrl(options.baseUrl)}${TOKEN_PATH}`, {
2156
+ method: "POST",
2157
+ headers: { "content-type": "application/json", accept: "application/json" },
2158
+ body: JSON.stringify({
2159
+ code: options.code,
2160
+ code_verifier: options.codeVerifier,
2161
+ redirect_uri: options.redirectUri
2162
+ }),
2163
+ signal: options.signal
2164
+ });
2165
+ } catch (cause) {
2166
+ if (options.signal?.aborted) {
2167
+ throw new AutoragOAuthError("AutoRAG sign-in was cancelled.", { cause });
2168
+ }
2169
+ throw new AutoragOAuthError(`AutoRAG token exchange could not reach ${normalizeBaseUrl(options.baseUrl)}.`, {
2170
+ cause
2171
+ });
2172
+ }
2173
+ let body;
2174
+ try {
2175
+ body = await response.json();
2176
+ } catch {
2177
+ body = undefined;
2178
+ }
2179
+ if (!response.ok)
2180
+ throw mapTokenExchangeError(response.status, body);
2181
+ const accessToken = readAccessToken(body);
2182
+ if (accessToken === undefined) {
2183
+ throw new AutoragOAuthError("AutoRAG token exchange succeeded but returned no access token.");
2184
+ }
2185
+ const email = readEmail(body);
2186
+ return email === undefined ? { accessToken } : { accessToken, email };
2187
+ }
2188
+ function readAccessToken(body) {
2189
+ if (typeof body !== "object" || body === null)
2190
+ return;
2191
+ const value = body.access_token;
2192
+ return typeof value === "string" && value !== "" ? value : undefined;
2193
+ }
2194
+ function readEmail(body) {
2195
+ if (typeof body !== "object" || body === null)
2196
+ return;
2197
+ const value = body.email;
2198
+ return typeof value === "string" && value !== "" ? value : undefined;
2199
+ }
2200
+ var init_token = __esm(() => {
2201
+ init_config();
2202
+ init_errors();
2203
+ });
2204
+
2205
+ // src/cloud/oauth-login.ts
2206
+ function refreshAutoragCredentials(credentials) {
2207
+ return credentials;
2208
+ }
2209
+ async function loginAutorag(callbacks, options) {
2210
+ const { verifier, challenge } = createPkcePair();
2211
+ const state = createState();
2212
+ const server = await startCallbackServer({
2213
+ state,
2214
+ timeoutMs: options.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS,
2215
+ signal: callbacks.signal
2216
+ });
2217
+ try {
2218
+ callbacks.onAuth({
2219
+ url: buildAuthorizeUrl({
2220
+ baseUrl: options.baseUrl,
2221
+ redirectUri: server.redirectUri,
2222
+ state,
2223
+ codeChallenge: challenge
2224
+ }),
2225
+ 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.`
2226
+ });
2227
+ callbacks.onProgress?.(`Listening for the AutoRAG sign-in callback on ${server.redirectUri}`);
2228
+ const outcome = await Promise.race([
2229
+ server.waitForCallback().then((params) => ({ params })),
2230
+ callbacks.onPrompt({
2231
+ message: "Complete the AutoRAG sign-in in your browser, or paste the final redirect URL / authorization code here:",
2232
+ placeholder: server.redirectUri,
2233
+ allowEmpty: true
2234
+ }).then((value) => ({ value }))
2235
+ ]);
2236
+ const parsed = "params" in outcome ? parseCallbackQuery(outcome.params) : parseCallbackInput(outcome.value);
2237
+ const { code } = requireAuthorizationCode(parsed, state);
2238
+ const token = await exchangeCodeForToken({
2239
+ baseUrl: options.baseUrl,
2240
+ code,
2241
+ codeVerifier: verifier,
2242
+ redirectUri: server.redirectUri,
2243
+ signal: callbacks.signal,
2244
+ fetchImpl: options.fetchImpl
2245
+ });
2246
+ return {
2247
+ access: token.accessToken,
2248
+ refresh: "",
2249
+ expires: Number.MAX_SAFE_INTEGER,
2250
+ ...token.email !== undefined ? { email: token.email } : {}
2251
+ };
2252
+ } finally {
2253
+ server.close();
2254
+ }
2255
+ }
2256
+ var init_oauth_login = __esm(() => {
2257
+ init_authorize();
2258
+ init_callback();
2259
+ init_callback_server();
2260
+ init_pkce();
2261
+ init_token();
2262
+ });
2263
+
2264
+ // src/cloud/provider.ts
2265
+ async function refreshAutoragModels(context, endpoints) {
2266
+ const stored = modelsFromStore(context.stored);
2267
+ const apiKey = resolveCredentialKey(context.credential);
2268
+ if (!context.allowNetwork || apiKey === undefined)
2269
+ return stored;
2270
+ let models;
2271
+ try {
2272
+ models = await fetchModels({ baseUrl: endpoints.baseUrl, apiKey, signal: context.signal });
2273
+ } catch {
2274
+ return stored;
2275
+ }
2276
+ if (models.length === 0)
2277
+ return stored;
2278
+ try {
2279
+ await context.publish({ persist: buildStoreEntry(models, PROVIDER_ID, endpoints.apiBaseUrl) });
2280
+ } catch {}
2281
+ return models;
2282
+ }
2283
+ function createAutoRAGProviderConfig(env = process.env) {
2284
+ const baseUrl = resolveBaseUrl(env);
2285
+ const endpoints = { baseUrl, apiBaseUrl: `${baseUrl}${API_PATH}` };
2286
+ return {
2287
+ name: PROVIDER_NAME,
2288
+ baseUrl: endpoints.apiBaseUrl,
2289
+ api: "openai-responses",
2290
+ apiKey: API_KEY_CONFIG_VALUE,
2291
+ oauth: {
2292
+ name: PROVIDER_NAME,
2293
+ login: (callbacks) => loginAutorag(callbacks, { baseUrl }),
2294
+ refreshToken: async (credentials) => refreshAutoragCredentials(credentials),
2295
+ getApiKey: (credentials) => credentials.access
2296
+ },
2297
+ refreshModels: (context) => refreshAutoragModels(context, endpoints)
2298
+ };
2299
+ }
2300
+ async function registerAutoRAGProvider(runtime, env = process.env) {
2301
+ runtime.registerProvider(PROVIDER_ID, createAutoRAGProviderConfig(env));
2302
+ await runtime.refresh({ allowNetwork: false, providers: [PROVIDER_ID] });
2303
+ }
2304
+ var init_provider = __esm(() => {
2305
+ init_config();
2306
+ init_models();
2307
+ init_oauth_login();
2308
+ });
2309
+
1715
2310
  // src/datasource/tool-naming.ts
1716
2311
  function datasourceSearchToolName(datasourceId) {
1717
2312
  const collapsed = datasourceId.toLowerCase().replace(/[^a-z0-9]+/g, "_");
@@ -2159,7 +2754,7 @@ function datasourceCliError(datasourceId, command, failure) {
2159
2754
  return new DatasourceCliError(datasourceId, command, failure);
2160
2755
  }
2161
2756
  var DatasourceCliError;
2162
- var init_errors = __esm(() => {
2757
+ var init_errors2 = __esm(() => {
2163
2758
  DatasourceCliError = class DatasourceCliError extends Error {
2164
2759
  datasourceId;
2165
2760
  command;
@@ -2275,7 +2870,7 @@ var init_source_paths = __esm(() => {
2275
2870
  });
2276
2871
 
2277
2872
  // src/mirror/paths.ts
2278
- import { createHash as createHash2 } from "node:crypto";
2873
+ import { createHash as createHash3 } from "node:crypto";
2279
2874
  import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
2280
2875
  import { join as join5 } from "node:path";
2281
2876
  function parsedMirrorRoot(root) {
@@ -2285,7 +2880,7 @@ function parsedMirrorIndexPath(root) {
2285
2880
  return join5(parsedMirrorRoot(root), PARSED_INDEX_FILE);
2286
2881
  }
2287
2882
  function parsedOutputPath(root, virtualPath) {
2288
- const digest = createHash2("sha256").update(virtualPath).digest("hex");
2883
+ const digest = createHash3("sha256").update(virtualPath).digest("hex");
2289
2884
  return join5(parsedMirrorRoot(root), PARSED_FILES_SUBDIR, `${digest}.md`);
2290
2885
  }
2291
2886
  function refreshReadinessPath(root) {
@@ -2646,7 +3241,7 @@ function toResult(hit, source, mode, instanceId) {
2646
3241
  };
2647
3242
  }
2648
3243
  var init_methods = __esm(() => {
2649
- init_errors();
3244
+ init_errors2();
2650
3245
  init_scope2();
2651
3246
  });
2652
3247
 
@@ -2829,7 +3424,7 @@ function messageFrom(cause) {
2829
3424
  return "unknown parser failure";
2830
3425
  }
2831
3426
  var ParseError;
2832
- var init_errors2 = __esm(() => {
3427
+ var init_errors3 = __esm(() => {
2833
3428
  ParseError = class ParseError extends Error {
2834
3429
  parserName;
2835
3430
  virtualPath;
@@ -2900,7 +3495,7 @@ function addressText(address) {
2900
3495
  }
2901
3496
  var EmlParser;
2902
3497
  var init_eml = __esm(() => {
2903
- init_errors2();
3498
+ init_errors3();
2904
3499
  init_text();
2905
3500
  EmlParser = class EmlParser extends Parser {
2906
3501
  name = "eml";
@@ -2957,7 +3552,7 @@ var KORDOC_EXTENSIONS, KORDOC_IMAGE_EXTENSIONS, defaultParse = async (bytes, opt
2957
3552
  return { success: false, fileType: result.fileType, error: result.error, code: result.code };
2958
3553
  }, KordocParser;
2959
3554
  var init_kordoc = __esm(() => {
2960
- init_errors2();
3555
+ init_errors3();
2961
3556
  KORDOC_EXTENSIONS = [".hwp", ".hwpx", ".hml", ".hwpml", ".pdf", ".docx", ".xlsx", ".xls"];
2962
3557
  KORDOC_IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".webp"];
2963
3558
  KordocParser = class KordocParser extends Parser {
@@ -3209,7 +3804,7 @@ var init_xml_text = __esm(() => {
3209
3804
  // src/parser/office.ts
3210
3805
  var PptxParser;
3211
3806
  var init_office = __esm(() => {
3212
- init_errors2();
3807
+ init_errors3();
3213
3808
  init_text();
3214
3809
  init_xml_text();
3215
3810
  PptxParser = class PptxParser extends Parser {
@@ -3782,7 +4377,7 @@ function bm25Scores(query, documents) {
3782
4377
  }
3783
4378
 
3784
4379
  // src/datasource/connector.ts
3785
- import { createHash as createHash3 } from "node:crypto";
4380
+ import { createHash as createHash4 } from "node:crypto";
3786
4381
  function connectorFailureToDiagnosticCode(reason) {
3787
4382
  switch (reason) {
3788
4383
  case "auth":
@@ -3816,7 +4411,7 @@ function sanitizeIdSegment(value) {
3816
4411
  const cleaned = normalized.slice(start, end);
3817
4412
  if (cleaned === value && cleaned.length > 0 && cleaned.length <= 80)
3818
4413
  return cleaned;
3819
- const hash = createHash3("sha256").update(value).digest("hex").slice(0, 8);
4414
+ const hash = createHash4("sha256").update(value).digest("hex").slice(0, 8);
3820
4415
  const stem = cleaned.slice(0, 60);
3821
4416
  return stem.length > 0 ? `${stem}-${hash}` : hash;
3822
4417
  }
@@ -5015,7 +5610,7 @@ function toRetrievalResult(hit, source, methodName, instanceId, mode, diagnostic
5015
5610
  }
5016
5611
  var DISCORD_DATASOURCE_ID = "discord", DEFAULT_DISCORD_TAGS, DEFAULT_TOP_K2 = 20;
5017
5612
  var init_methods2 = __esm(() => {
5018
- init_errors();
5613
+ init_errors2();
5019
5614
  init_scope2();
5020
5615
  init_paths2();
5021
5616
  DEFAULT_DISCORD_TAGS = ["discord", "chat", "pii"];
@@ -5313,7 +5908,7 @@ class GitHubConnector {
5313
5908
  if (repos.length === 0)
5314
5909
  return { ok: false, reason: "not-configured", message: "no repositories configured" };
5315
5910
  const token = resolveToken(this.options.token, this.options.tokenEnv ?? DEFAULT_TOKEN_ENV);
5316
- const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL;
5911
+ const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL2;
5317
5912
  const request = {
5318
5913
  headers: {
5319
5914
  Accept: "application/vnd.github+json",
@@ -5386,7 +5981,7 @@ ${body}` : title,
5386
5981
  return { ok: true, documents, ...warnings.length > 0 ? { warnings } : {} };
5387
5982
  }
5388
5983
  }
5389
- var DEFAULT_BASE_URL = "https://api.github.com", DEFAULT_TOKEN_ENV = "GITHUB_TOKEN", DEFAULT_MAX_PAGES = 10, DEFAULT_MAX_DOCUMENTS2 = 500;
5984
+ var DEFAULT_BASE_URL2 = "https://api.github.com", DEFAULT_TOKEN_ENV = "GITHUB_TOKEN", DEFAULT_MAX_PAGES = 10, DEFAULT_MAX_DOCUMENTS2 = 500;
5390
5985
  var init_connector2 = () => {};
5391
5986
 
5392
5987
  // src/datasource/skills/github/skill.ts
@@ -5453,7 +6048,7 @@ class GitHubGistConnector {
5453
6048
  message: "no GitHub token: set GITHUB_TOKEN (or connector.tokenEnv) or authenticate the gh CLI"
5454
6049
  };
5455
6050
  }
5456
- const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL2;
6051
+ const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL3;
5457
6052
  const request = {
5458
6053
  headers: {
5459
6054
  Accept: "application/vnd.github+json",
@@ -5602,15 +6197,15 @@ ${content}`);
5602
6197
  }
5603
6198
  };
5604
6199
  }
5605
- var DEFAULT_BASE_URL2 = "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;
6200
+ var DEFAULT_BASE_URL3 = "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;
5606
6201
  var init_connector3 = () => {};
5607
6202
 
5608
6203
  // src/datasource/skills/github-gist/semantic.ts
5609
- import { createHash as createHash4 } from "node:crypto";
6204
+ import { createHash as createHash5 } from "node:crypto";
5610
6205
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
5611
6206
  import { dirname as dirname8 } from "node:path";
5612
6207
  function contentHash(chunk) {
5613
- return createHash4("sha256").update(`${chunk.title ?? ""}
6208
+ return createHash5("sha256").update(`${chunk.title ?? ""}
5614
6209
  ${chunk.content}`).digest("hex");
5615
6210
  }
5616
6211
  function sameIdentity(a, b) {
@@ -6593,7 +7188,7 @@ function isRemoteEmbedder(value) {
6593
7188
  }
6594
7189
  var CHAT_TAG = "lark:chat", DOCS_TAG = "lark:docs", DEFAULT_TAGS2, REMOTE_NOTE = "remote-search datasource: no local mirror";
6595
7190
  var init_skill6 = __esm(() => {
6596
- init_errors();
7191
+ init_errors2();
6597
7192
  init_scope2();
6598
7193
  init_client3();
6599
7194
  DEFAULT_TAGS2 = [CHAT_TAG, DOCS_TAG];
@@ -7121,7 +7716,7 @@ function toRetrievalResult2(hit, source, methodName, instanceId, mode) {
7121
7716
  }
7122
7717
  var KAKAO_DATASOURCE_ID = "kakao", DEFAULT_KAKAO_TAGS, DEFAULT_TOP_K4 = 20;
7123
7718
  var init_methods3 = __esm(() => {
7124
- init_errors();
7719
+ init_errors2();
7125
7720
  init_paths3();
7126
7721
  DEFAULT_KAKAO_TAGS = ["kakaotalk", "personal", "pii"];
7127
7722
  });
@@ -7516,7 +8111,7 @@ function ensurePrivateMailcrawlDataDir(path) {
7516
8111
  if (process.platform !== "win32")
7517
8112
  chmodSync(path, 448);
7518
8113
  }
7519
- var init_config = () => {};
8114
+ var init_config2 = () => {};
7520
8115
 
7521
8116
  // src/datasource/skills/mailcrawl/client.ts
7522
8117
  import { spawn as spawn7 } from "node:child_process";
@@ -7842,7 +8437,7 @@ function truncateUtf8(value, maxBytes) {
7842
8437
  var DEFAULT_BINARY3 = "mailcrawl", DEFAULT_SEARCH_TIMEOUT_MS2 = 60000, DEFAULT_INDEX_TIMEOUT_MS = 1800000, DEFAULT_MAX_BUFFER_BYTES3 = 1048576, LOOPBACK_HOSTS, SAFE_ENV_KEYS2, SAFE_MAILCRAWL_ENV_KEYS, REMOTE_EMBEDDING_ENV_KEYS;
7843
8438
  var init_client5 = __esm(() => {
7844
8439
  init_portable_spawn();
7845
- init_config();
8440
+ init_config2();
7846
8441
  LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
7847
8442
  SAFE_ENV_KEYS2 = new Set(["HOME", "LANG", "LC_ALL", "PATH", "TMPDIR", "TMP", "TEMP", "NO_COLOR"]);
7848
8443
  SAFE_MAILCRAWL_ENV_KEYS = new Set([
@@ -7941,7 +8536,7 @@ class MailcrawlMethod {
7941
8536
  }
7942
8537
  var modes, MAILCRAWL_MODES;
7943
8538
  var init_methods4 = __esm(() => {
7944
- init_errors();
8539
+ init_errors2();
7945
8540
  init_scope2();
7946
8541
  modes = ["bm25", "semantic", "hybrid"];
7947
8542
  MAILCRAWL_MODES = modes;
@@ -8089,7 +8684,7 @@ var TAGS;
8089
8684
  var init_skill9 = __esm(() => {
8090
8685
  init_scope2();
8091
8686
  init_client5();
8092
- init_config();
8687
+ init_config2();
8093
8688
  init_methods4();
8094
8689
  TAGS = ["mailcrawl", "email", "pii"];
8095
8690
  });
@@ -8309,7 +8904,7 @@ function failureCode2(reason) {
8309
8904
  }
8310
8905
  var DEFAULT_INSTANCE_ID5 = "default", DEFAULT_POLLING_INTERVAL_MS4;
8311
8906
  var init_crawler_skill = __esm(() => {
8312
- init_errors();
8907
+ init_errors2();
8313
8908
  init_scope2();
8314
8909
  DEFAULT_POLLING_INTERVAL_MS4 = 15 * 60 * 1000;
8315
8910
  });
@@ -8947,7 +9542,7 @@ function toRetrievalResult3(hit, source, methodName, instanceId, mode) {
8947
9542
  }
8948
9543
  var OBSIDIAN_DATASOURCE_ID = "obsidian", DEFAULT_OBSIDIAN_TAGS, DEFAULT_TOP_K5 = 20;
8949
9544
  var init_methods5 = __esm(() => {
8950
- init_errors();
9545
+ init_errors2();
8951
9546
  init_scope2();
8952
9547
  DEFAULT_OBSIDIAN_TAGS = ["obsidian", "notes"];
8953
9548
  });
@@ -9485,7 +10080,7 @@ var init_slack = __esm(() => {
9485
10080
 
9486
10081
  // src/datasource/skills/spotlight/connector.ts
9487
10082
  import { spawn as spawn9 } from "node:child_process";
9488
- import { createHash as createHash5 } from "node:crypto";
10083
+ import { createHash as createHash6 } from "node:crypto";
9489
10084
  import { readFile as fsReadFile, stat as stat4 } from "node:fs/promises";
9490
10085
  import { basename as basename6, extname as extname4 } from "node:path";
9491
10086
 
@@ -9570,7 +10165,7 @@ class SpotlightConnector {
9570
10165
  if (content.length === 0)
9571
10166
  continue;
9572
10167
  documents.push({
9573
- docId: createHash5("sha256").update(path).digest("hex").slice(0, 16),
10168
+ docId: createHash6("sha256").update(path).digest("hex").slice(0, 16),
9574
10169
  hierarchy: ["files"],
9575
10170
  title: basename6(path),
9576
10171
  content,
@@ -11637,11 +12232,15 @@ function getModelRuntime(agentDir) {
11637
12232
  const cached = modelRuntimeCache.get(agentDir);
11638
12233
  if (cached !== undefined)
11639
12234
  return cached;
11640
- const created = ModelRuntime.create({
11641
- authPath: join14(agentDir, "auth.json"),
11642
- modelsPath: join14(agentDir, "models.json"),
11643
- allowModelNetwork: false
11644
- });
12235
+ const created = (async () => {
12236
+ const runtime = await ModelRuntime.create({
12237
+ authPath: join14(agentDir, "auth.json"),
12238
+ modelsPath: join14(agentDir, "models.json"),
12239
+ allowModelNetwork: false
12240
+ });
12241
+ await registerAutoRAGProvider(runtime);
12242
+ return runtime;
12243
+ })();
11645
12244
  modelRuntimeCache.set(agentDir, created);
11646
12245
  created.catch(() => {
11647
12246
  modelRuntimeCache.delete(agentDir);
@@ -11970,8 +12569,9 @@ function writeDefaultConfig(path, partial, opts = {}) {
11970
12569
  }
11971
12570
  }
11972
12571
  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_PATTERN, 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;
11973
- var init_config2 = __esm(() => {
12572
+ var init_config3 = __esm(() => {
11974
12573
  init_local_model();
12574
+ init_provider();
11975
12575
  init_home();
11976
12576
  init_factory();
11977
12577
  init_file_lock();
@@ -12211,7 +12811,7 @@ function parseEmbedderFlags(flags) {
12211
12811
  }
12212
12812
  var init_init = __esm(() => {
12213
12813
  init_language();
12214
- init_config2();
12814
+ init_config3();
12215
12815
  });
12216
12816
 
12217
12817
  // src/minsync/embedder-config.ts
@@ -12531,7 +13131,7 @@ var init_setup = __esm(() => {
12531
13131
  init_manifest();
12532
13132
  init_file_lock();
12533
13133
  init_embedder_config();
12534
- init_config2();
13134
+ init_config3();
12535
13135
  BUILTIN_BINARIES = {
12536
13136
  kakao: "lazykatok",
12537
13137
  lark: "lark-cli",
@@ -12589,7 +13189,7 @@ function renderSetup(report) {
12589
13189
  }
12590
13190
  var init_setup2 = __esm(() => {
12591
13191
  init_embedding_runtime();
12592
- init_config2();
13192
+ init_config3();
12593
13193
  init_setup();
12594
13194
  });
12595
13195
 
@@ -12767,7 +13367,7 @@ var init_dupey = __esm(() => {
12767
13367
  });
12768
13368
 
12769
13369
  // src/everything/bundle.ts
12770
- import { createHash as createHash6 } from "node:crypto";
13370
+ import { createHash as createHash7 } from "node:crypto";
12771
13371
  import { existsSync as existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync15, renameSync as renameSync4, rmSync as rmSync2, writeFileSync as writeFileSync10 } from "node:fs";
12772
13372
  import { dirname as dirname12, join as join17 } from "node:path";
12773
13373
  import { fileURLToPath } from "node:url";
@@ -12885,7 +13485,7 @@ function writeAtomic(path, bytes) {
12885
13485
  }
12886
13486
  }
12887
13487
  function sha256(bytes) {
12888
- return createHash6("sha256").update(bytes).digest("hex");
13488
+ return createHash7("sha256").update(bytes).digest("hex");
12889
13489
  }
12890
13490
  function errorMessage(error) {
12891
13491
  return error instanceof Error ? error.message : String(error);
@@ -12895,12 +13495,12 @@ var init_bundle = () => {};
12895
13495
 
12896
13496
  // src/everything/client.ts
12897
13497
  import { spawn as spawn11 } from "node:child_process";
12898
- import { createHash as createHash7 } from "node:crypto";
13498
+ import { createHash as createHash8 } from "node:crypto";
12899
13499
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
12900
13500
  import { join as join18, resolve as resolve9 } from "node:path";
12901
13501
  import { setTimeout as sleep } from "node:timers/promises";
12902
13502
  function everythingInstanceName(root) {
12903
- return `autorag-${createHash7("sha256").update(resolve9(root).toLowerCase()).digest("hex").slice(0, 12)}`;
13503
+ return `autorag-${createHash8("sha256").update(resolve9(root).toLowerCase()).digest("hex").slice(0, 12)}`;
12904
13504
  }
12905
13505
  function buildEverythingIni(input) {
12906
13506
  const list = (values) => values.map((value) => `"${value.replace(/\\/g, "\\\\")}"`).join(",");
@@ -13350,7 +13950,7 @@ var init_walk = __esm(() => {
13350
13950
 
13351
13951
  // src/fsearch/client.ts
13352
13952
  import { spawn as spawn12 } from "node:child_process";
13353
- import { createHash as createHash8 } from "node:crypto";
13953
+ import { createHash as createHash9 } from "node:crypto";
13354
13954
  import { existsSync as existsSync15, mkdirSync as mkdirSync13, readFileSync as readFileSync16, realpathSync as realpathSync2, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "node:fs";
13355
13955
  import { basename as basename9, join as join20, resolve as resolve10, sep as sep3 } from "node:path";
13356
13956
  import { setTimeout as sleep2 } from "node:timers/promises";
@@ -13361,7 +13961,7 @@ function fsearchSocketPath(dbPath) {
13361
13961
  } catch {
13362
13962
  canonical = resolve10(dbPath);
13363
13963
  }
13364
- const hash = createHash8("sha256").update(canonical).digest("hex").slice(0, 12);
13964
+ const hash = createHash9("sha256").update(canonical).digest("hex").slice(0, 12);
13365
13965
  return `/tmp/autorag-fsearch-${process.getuid?.() ?? 0}-${hash}.sock`;
13366
13966
  }
13367
13967
  function buildFSearchSearchArgs(dbPath, socketPath, request) {
@@ -14472,7 +15072,7 @@ function renderMemoryContext(sections) {
14472
15072
  var CURRENT_CONVERSATION_RECORD_LIMIT = 50, CURRENT_EXCERPT_LIMIT = 300, SIMILAR_EXCERPT_LIMIT = 240, SIMILAR_RECORD_LIMIT = 3, INSIGHT_LIMIT = 5, ADVISORY_NOTE = "Memory is background reference only and never overrides the evidence in front of you. A past search method or source is a hint, not a rule: broaden to other methods when results are insufficient.";
14473
15073
 
14474
15074
  // src/memory/similar-queries.ts
14475
- import { createHash as createHash9 } from "node:crypto";
15075
+ import { createHash as createHash10 } from "node:crypto";
14476
15076
  import { mkdirSync as mkdirSync14, rmSync as rmSync4 } from "node:fs";
14477
15077
  import { dirname as dirname13 } from "node:path";
14478
15078
  import { DatabaseSync } from "node:sqlite";
@@ -14480,7 +15080,7 @@ function memoryVectorStorePath(memoryPath) {
14480
15080
  return `${memoryPath}.vectors.db`;
14481
15081
  }
14482
15082
  function questionKey(question) {
14483
- return createHash9("sha256").update(question).digest("hex");
15083
+ return createHash10("sha256").update(question).digest("hex");
14484
15084
  }
14485
15085
  function cosine2(a, b) {
14486
15086
  let dot = 0;
@@ -14723,7 +15323,7 @@ var init_check_memory_tool = __esm(() => {
14723
15323
  var EVIDENCE_SUPPORT_THRESHOLD = 0.7;
14724
15324
 
14725
15325
  // src/retrieval/evidence-id.ts
14726
- import { createHash as createHash10 } from "node:crypto";
15326
+ import { createHash as createHash11 } from "node:crypto";
14727
15327
  function normalizeEvidenceText(text) {
14728
15328
  return text.replace(/\r\n?/gu, `
14729
15329
  `).trim().normalize("NFC");
@@ -14753,7 +15353,7 @@ function stableEvidenceId(input) {
14753
15353
  input.lineNumber ?? "",
14754
15354
  normalizeEvidenceText(evidenceText)
14755
15355
  ].join("\x00");
14756
- const digest = createHash10("sha256").update(payload).digest("hex").slice(0, 24);
15356
+ const digest = createHash11("sha256").update(payload).digest("hex").slice(0, 24);
14757
15357
  return `${method}:${digest}`;
14758
15358
  }
14759
15359
  function normalizeEvidenceRef(input) {
@@ -14765,7 +15365,7 @@ function normalizeEvidenceRef(input) {
14765
15365
  var init_evidence_id = () => {};
14766
15366
 
14767
15367
  // src/memory/memory.ts
14768
- import { createHash as createHash11, randomUUID as randomUUID4 } from "node:crypto";
15368
+ import { createHash as createHash12, randomUUID as randomUUID4 } from "node:crypto";
14769
15369
  import { existsSync as existsSync19, mkdirSync as mkdirSync15, readFileSync as readFileSync18, renameSync as renameSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync13 } from "node:fs";
14770
15370
  import { dirname as dirname14 } from "node:path";
14771
15371
  import { z } from "zod";
@@ -14855,7 +15455,7 @@ function normalizeEvidenceChunkRecord(record) {
14855
15455
  return { ...base, ...normalizeEvidenceContext(record) };
14856
15456
  }
14857
15457
  function hashText(value) {
14858
- return createHash11("sha256").update(value).digest("hex");
15458
+ return createHash12("sha256").update(value).digest("hex");
14859
15459
  }
14860
15460
  function resultId(sessionId, number) {
14861
15461
  return `${sessionId}:${number}`;
@@ -15297,7 +15897,7 @@ function minSyncInstallFailedError(cause) {
15297
15897
  return new MinSyncRequiredError(`MinSync is required but installing the \`minsync\` binary failed: ${detail}. ` + "Install it manually with `cargo install minsync`.");
15298
15898
  }
15299
15899
  var MinSyncRequiredError;
15300
- var init_errors3 = __esm(() => {
15900
+ var init_errors4 = __esm(() => {
15301
15901
  MinSyncRequiredError = class MinSyncRequiredError extends Error {
15302
15902
  constructor(message) {
15303
15903
  super(message);
@@ -15733,7 +16333,7 @@ function isRecord11(value) {
15733
16333
  var MINSYNC_OLLAMA_MIGRATION_MESSAGE = "This workspace uses the legacy 768-dimensional Ollama/TEI embedding path. Reindex explicitly, or pin an explicit profile config before using the new default runtime.", API_KEY_ENV_PATTERN2, MinSyncQueryError;
15734
16334
  var init_client10 = __esm(() => {
15735
16335
  init_embedder_config();
15736
- init_errors3();
16336
+ init_errors4();
15737
16337
  init_local_embedder();
15738
16338
  init_process();
15739
16339
  API_KEY_ENV_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -15755,7 +16355,7 @@ var init_client10 = __esm(() => {
15755
16355
  });
15756
16356
 
15757
16357
  // src/minsync/installer.ts
15758
- import { createHash as createHash12 } from "node:crypto";
16358
+ import { createHash as createHash13 } from "node:crypto";
15759
16359
  import { copyFileSync, createWriteStream as createWriteStream2, existsSync as existsSync21, mkdirSync as mkdirSync16, renameSync as renameSync6, rmSync as rmSync5 } from "node:fs";
15760
16360
  import { chmod as chmod2, mkdtemp } from "node:fs/promises";
15761
16361
  import { get } from "node:https";
@@ -15861,7 +16461,7 @@ async function downloadFile(url, destination) {
15861
16461
  await pipeline(await openHttps(url), createWriteStream2(destination));
15862
16462
  }
15863
16463
  async function verifySha256(path, expected) {
15864
- const hash = createHash12("sha256");
16464
+ const hash = createHash13("sha256");
15865
16465
  const stream = await import("node:fs").then((fs) => fs.createReadStream(path));
15866
16466
  await pipeline(stream, hash);
15867
16467
  const actual = hash.digest("hex");
@@ -15974,7 +16574,7 @@ function isGitHubAsset(value) {
15974
16574
  function isRecord12(value) {
15975
16575
  return typeof value === "object" && value !== null;
15976
16576
  }
15977
- 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;
16577
+ 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;
15978
16578
  var init_installer2 = __esm(() => {
15979
16579
  init_process();
15980
16580
  SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
@@ -16340,7 +16940,7 @@ var init_method = __esm(() => {
16340
16940
  init_embedding_runtime();
16341
16941
  init_scope();
16342
16942
  init_client10();
16343
- init_errors3();
16943
+ init_errors4();
16344
16944
  init_installer2();
16345
16945
  init_paths5();
16346
16946
  init_workspace();
@@ -16366,7 +16966,7 @@ var init_method = __esm(() => {
16366
16966
  var init_minsync = __esm(() => {
16367
16967
  init_client10();
16368
16968
  init_embedder_config();
16369
- init_errors3();
16969
+ init_errors4();
16370
16970
  init_installer2();
16371
16971
  init_local_embedder();
16372
16972
  init_method();
@@ -16688,7 +17288,7 @@ var DEFAULT_MAX_SOURCE_BYTES, MIRROR_CHECKPOINT_EVERY = 25, PRODUCT_ARTIFACT_FIL
16688
17288
  var init_sync = __esm(() => {
16689
17289
  init_source_paths();
16690
17290
  init_defaults();
16691
- init_errors2();
17291
+ init_errors3();
16692
17292
  init_text();
16693
17293
  init_index_store();
16694
17294
  init_paths();
@@ -17372,7 +17972,7 @@ var init_simplex_transport = __esm(() => {
17372
17972
  var init_parser = __esm(() => {
17373
17973
  init_defaults();
17374
17974
  init_eml();
17375
- init_errors2();
17975
+ init_errors3();
17376
17976
  init_kordoc();
17377
17977
  init_ocr_engines();
17378
17978
  init_office();
@@ -17515,7 +18115,7 @@ class ParallelRetriever {
17515
18115
  }
17516
18116
  var SAME_SOURCE_CORROBORATION_BONUS = 0.15, MAX_CORROBORATION_BONUS = 0.3;
17517
18117
  var init_merger = __esm(() => {
17518
- init_errors3();
18118
+ init_errors4();
17519
18119
  init_skip();
17520
18120
  });
17521
18121
 
@@ -17767,13 +18367,403 @@ var init_model_auth = __esm(() => {
17767
18367
  };
17768
18368
  });
17769
18369
 
17770
- // src/agent/answer-guidelines.ts
17771
- 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.";
17772
-
17773
- // src/agent/datasource-skill.ts
17774
- import { Type as Type2 } from "typebox";
17775
- function escapeXml(value) {
17776
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
18370
+ // src/agent/citations.ts
18371
+ function isAsciiDigit(code) {
18372
+ return code >= 48 && code <= 57;
18373
+ }
18374
+ function digitsEndAt(text, from) {
18375
+ let end = from;
18376
+ while (end < text.length && isAsciiDigit(text.charCodeAt(end)))
18377
+ end += 1;
18378
+ return end;
18379
+ }
18380
+ function continuesAsProse(answer, from) {
18381
+ if (answer[from] !== " " && answer[from] !== " ")
18382
+ return false;
18383
+ const next = answer.codePointAt(from + 1);
18384
+ return next !== undefined && /[\p{L}\p{N}]/u.test(String.fromCodePoint(next));
18385
+ }
18386
+ function evidenceMarkerAt(answer, index) {
18387
+ const ids = [];
18388
+ let cursor = index + 1;
18389
+ for (;; ) {
18390
+ if (answer[cursor] !== "e")
18391
+ return;
18392
+ const digitsEnd = digitsEndAt(answer, cursor + 1);
18393
+ if (digitsEnd === cursor + 1)
18394
+ return;
18395
+ ids.push(answer.slice(cursor, digitsEnd));
18396
+ cursor = digitsEnd;
18397
+ if (answer[cursor] === "]")
18398
+ return { ids, end: cursor + 1 };
18399
+ if (answer[cursor] !== ",")
18400
+ return;
18401
+ cursor += 1;
18402
+ while (answer[cursor] === " " || answer[cursor] === "\t")
18403
+ cursor += 1;
18404
+ }
18405
+ }
18406
+ function filePathFrom(raw) {
18407
+ const trimmed = raw.trim();
18408
+ return trimmed.startsWith("<") && trimmed.endsWith(">") ? trimmed.slice(1, -1).trim() : trimmed;
18409
+ }
18410
+ function fileMarkerAt(answer, index, isFile) {
18411
+ if (!answer.startsWith(FILE_MARKER_PREFIX, index))
18412
+ return;
18413
+ const bodyStart = index + FILE_MARKER_PREFIX.length;
18414
+ let closer = answer.indexOf("]", bodyStart);
18415
+ for (let attempt = 0;closer !== -1 && attempt < MAX_FILE_MARKER_CLOSERS; attempt++) {
18416
+ const path = filePathFrom(answer.slice(bodyStart, closer));
18417
+ if (path.length > 0 && isFile(path))
18418
+ return { path, end: closer + 1 };
18419
+ closer = answer.indexOf("]", closer + 1);
18420
+ }
18421
+ return;
18422
+ }
18423
+ function answerMarkers(answer, isFile = () => false) {
18424
+ const markers = [];
18425
+ let floor = 0;
18426
+ let closeIndex = -1;
18427
+ let index = 0;
18428
+ const leadingStart = (from) => {
18429
+ let start = from;
18430
+ while (start > floor && (answer[start - 1] === " " || answer[start - 1] === "\t"))
18431
+ start -= 1;
18432
+ return start;
18433
+ };
18434
+ while (index < answer.length) {
18435
+ const char = answer[index];
18436
+ if (char === "(" && answer[index + 1] === "<") {
18437
+ if (closeIndex < index + 2) {
18438
+ const found = answer.indexOf(">", index + 2);
18439
+ closeIndex = found === -1 ? answer.length : found;
18440
+ }
18441
+ if (answer[closeIndex + 1] === ")") {
18442
+ index = closeIndex + 2;
18443
+ floor = index;
18444
+ continue;
18445
+ }
18446
+ index += 1;
18447
+ continue;
18448
+ }
18449
+ if (char === "[") {
18450
+ const digitsEnd = digitsEndAt(answer, index + 1);
18451
+ if (digitsEnd > index + 1 && answer[digitsEnd] === "]" && answer[digitsEnd + 1] !== "(" && !continuesAsProse(answer, digitsEnd + 1)) {
18452
+ markers.push({
18453
+ kind: "number",
18454
+ start: leadingStart(index),
18455
+ end: digitsEnd + 1,
18456
+ number: Number(answer.slice(index + 1, digitsEnd))
18457
+ });
18458
+ index = digitsEnd + 1;
18459
+ floor = index;
18460
+ continue;
18461
+ }
18462
+ const evidence = evidenceMarkerAt(answer, index);
18463
+ if (evidence !== undefined && answer[evidence.end] !== "(") {
18464
+ markers.push({ kind: "evidence", start: leadingStart(index), end: evidence.end, ids: evidence.ids });
18465
+ index = evidence.end;
18466
+ floor = index;
18467
+ continue;
18468
+ }
18469
+ const file = fileMarkerAt(answer, index, isFile);
18470
+ if (file !== undefined && answer[file.end] !== "(") {
18471
+ markers.push({ kind: "file", start: leadingStart(index), end: file.end, path: file.path });
18472
+ index = file.end;
18473
+ floor = index;
18474
+ continue;
18475
+ }
18476
+ }
18477
+ index += 1;
18478
+ }
18479
+ return markers;
18480
+ }
18481
+ function stripUnresolvedCitations(answer, results) {
18482
+ const known = new Set(results.map((result) => result.number));
18483
+ const unresolved = new Set;
18484
+ let stripped = "";
18485
+ let cursor = 0;
18486
+ for (const marker of answerMarkers(answer)) {
18487
+ if (marker.kind !== "number" || known.has(marker.number))
18488
+ continue;
18489
+ unresolved.add(marker.number);
18490
+ stripped += answer.slice(cursor, marker.start);
18491
+ cursor = marker.end;
18492
+ }
18493
+ if (unresolved.size === 0)
18494
+ return { answer, unresolved: [] };
18495
+ return { answer: stripped + answer.slice(cursor), unresolved: [...unresolved].sort((a, b) => a - b) };
18496
+ }
18497
+ function formatCitationList(numbers) {
18498
+ return numbers.length === 0 ? "none" : numbers.map((number) => `[${number}]`).join(", ");
18499
+ }
18500
+ function duplicateNumbers(sortedNumbers) {
18501
+ const duplicates = [];
18502
+ for (let index = 1;index < sortedNumbers.length; index++) {
18503
+ const number = sortedNumbers[index];
18504
+ if (number === sortedNumbers[index - 1] && duplicates[duplicates.length - 1] !== number)
18505
+ duplicates.push(number);
18506
+ }
18507
+ return duplicates;
18508
+ }
18509
+ function assertResultsMappingOneToOne(label, results, mapping) {
18510
+ const resultNumbers = results.map((result) => result.number).sort((a, b) => a - b);
18511
+ const mappingNumbers = mapping.map((entry) => entry.number).sort((a, b) => a - b);
18512
+ const resultDuplicates = duplicateNumbers(resultNumbers);
18513
+ const mappingDuplicates = duplicateNumbers(mappingNumbers);
18514
+ const sameNumbers = resultNumbers.length === mappingNumbers.length && resultNumbers.every((number, index) => number === mappingNumbers[index]);
18515
+ if (sameNumbers && resultDuplicates.length === 0 && mappingDuplicates.length === 0)
18516
+ return;
18517
+ const duplicateNotes = [
18518
+ resultDuplicates.length > 0 ? `results repeat ${formatCitationList(resultDuplicates)}` : undefined,
18519
+ mappingDuplicates.length > 0 ? `mapping repeats ${formatCitationList(mappingDuplicates)}` : undefined
18520
+ ].filter((note) => note !== undefined);
18521
+ 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.");
18522
+ }
18523
+ var MAX_FILE_MARKER_CLOSERS = 8, FILE_MARKER_PREFIX = "[file:";
18524
+
18525
+ // src/agent/evidence-ledger.ts
18526
+ import { createHash as createHash14 } from "node:crypto";
18527
+ import { closeSync as closeSync2, openSync as openSync2, readSync, statSync } from "node:fs";
18528
+ import { isAbsolute as isAbsolute9 } from "node:path";
18529
+ function metadataString(metadata, key) {
18530
+ const value = metadata[key];
18531
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
18532
+ }
18533
+ function metadataNumber(metadata, key) {
18534
+ const value = metadata[key];
18535
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
18536
+ }
18537
+ function isRegularFile2(path) {
18538
+ try {
18539
+ return statSync(path).isFile();
18540
+ } catch {
18541
+ return false;
18542
+ }
18543
+ }
18544
+ function readFileExcerpt(path) {
18545
+ let descriptor;
18546
+ try {
18547
+ descriptor = openSync2(path, "r");
18548
+ const buffer = Buffer.alloc(MAX_CONTENT_CHARS4 * 4);
18549
+ const bytes = readSync(descriptor, buffer, 0, buffer.length, 0);
18550
+ const head = buffer.subarray(0, bytes);
18551
+ return head.includes(0) ? path : head.toString("utf8").slice(0, MAX_CONTENT_CHARS4);
18552
+ } catch {
18553
+ return path;
18554
+ } finally {
18555
+ if (descriptor !== undefined)
18556
+ closeSync2(descriptor);
18557
+ }
18558
+ }
18559
+ function toEvidenceRef(entry) {
18560
+ return {
18561
+ method: entry.method,
18562
+ source: entry.source,
18563
+ content: entry.content,
18564
+ retrieverMix: [...entry.retrieverMix],
18565
+ ...entry.retrievalResultId !== undefined ? { retrievalResultId: entry.retrievalResultId } : {},
18566
+ ...entry.chunkIndex !== undefined ? { chunkIndex: entry.chunkIndex } : {},
18567
+ ...entry.lineNumber !== undefined ? { lineNumber: entry.lineNumber } : {},
18568
+ ...entry.parserType !== undefined ? { parserType: entry.parserType } : {},
18569
+ ...entry.documentType !== undefined ? { documentType: entry.documentType } : {},
18570
+ ...entry.documentArea !== undefined ? { documentArea: entry.documentArea } : {},
18571
+ ...entry.evidenceType !== undefined ? { evidenceType: entry.evidenceType } : {},
18572
+ ...entry.evidenceLocation !== undefined ? { evidenceLocation: entry.evidenceLocation } : {}
18573
+ };
18574
+ }
18575
+
18576
+ class EvidenceLedger {
18577
+ entries = [];
18578
+ byKey = new Map;
18579
+ byId = new Map;
18580
+ lastOrdinal = 0;
18581
+ register(input) {
18582
+ const content = input.content.slice(0, MAX_CONTENT_CHARS4);
18583
+ const digest = createHash14("sha256").update(input.content.replace(/\s+/gu, " ").trim()).digest("hex");
18584
+ const key = `${input.source}\x00${digest}`;
18585
+ const existing = this.byKey.get(key);
18586
+ if (existing !== undefined) {
18587
+ if (!existing.retrieverMix.includes(input.method))
18588
+ existing.retrieverMix.push(input.method);
18589
+ return existing.id;
18590
+ }
18591
+ const entry = {
18592
+ ...input,
18593
+ content,
18594
+ id: `e${++this.lastOrdinal}`,
18595
+ retrieverMix: [input.method]
18596
+ };
18597
+ this.entries.push(entry);
18598
+ this.byKey.set(key, entry);
18599
+ this.byId.set(entry.id, entry);
18600
+ return entry.id;
18601
+ }
18602
+ registerResult(tool, result) {
18603
+ const metadata = result.metadata;
18604
+ const chunkIndex = metadataNumber(metadata, "chunkIndex");
18605
+ const lineNumber = metadataNumber(metadata, "lineNumber");
18606
+ const parserType = metadataString(metadata, "parserType");
18607
+ const documentType = metadataString(metadata, "documentType");
18608
+ const documentArea = metadataString(metadata, "documentArea");
18609
+ const evidenceType = metadataString(metadata, "evidenceType");
18610
+ const evidenceLocation = metadataString(metadata, "evidenceLocation");
18611
+ return this.register({
18612
+ method: metadataString(metadata, "method") ?? tool,
18613
+ source: result.source,
18614
+ content: result.content,
18615
+ retrievalResultId: result.id,
18616
+ ...chunkIndex !== undefined ? { chunkIndex } : {},
18617
+ ...lineNumber !== undefined ? { lineNumber } : {},
18618
+ ...parserType !== undefined ? { parserType } : {},
18619
+ ...documentType !== undefined ? { documentType } : {},
18620
+ ...documentArea !== undefined ? { documentArea } : {},
18621
+ ...evidenceType !== undefined ? { evidenceType } : {},
18622
+ ...evidenceLocation !== undefined ? { evidenceLocation } : {}
18623
+ });
18624
+ }
18625
+ lookup(raw, options) {
18626
+ const trimmed = raw.trim();
18627
+ const ref = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1).trim() : trimmed;
18628
+ const byId = this.byId.get(ref);
18629
+ if (byId !== undefined)
18630
+ return [toEvidenceRef(byId)];
18631
+ const bySource = this.entries.filter((entry) => entry.source === ref);
18632
+ if (bySource.length > 0)
18633
+ return bySource.map(toEvidenceRef);
18634
+ if (options.allowLocalFiles && isAbsolute9(ref) && isRegularFile2(ref)) {
18635
+ return [{ method: "bash", source: ref, content: readFileExcerpt(ref) }];
18636
+ }
18637
+ return [];
18638
+ }
18639
+ clear() {
18640
+ this.entries = [];
18641
+ this.byKey.clear();
18642
+ this.byId.clear();
18643
+ }
18644
+ }
18645
+ var MAX_CONTENT_CHARS4 = 2000;
18646
+ var init_evidence_ledger = () => {};
18647
+
18648
+ // src/agent/answer-citations.ts
18649
+ import { isAbsolute as isAbsolute10 } from "node:path";
18650
+ function claimBefore(text, end) {
18651
+ const window = text.slice(Math.max(0, end - CLAIM_LOOKBACK_CHARS), end);
18652
+ const lineStart = window.lastIndexOf(`
18653
+ `) + 1;
18654
+ const line = window.slice(lineStart).replace(EVIDENCE_MARKER_TEXT, "");
18655
+ let start = 0;
18656
+ for (let index = line.length - 2;index >= 0; index--) {
18657
+ if (SENTENCE_END.test(line.charAt(index)) && /\s/u.test(line.charAt(index + 1))) {
18658
+ start = index + 2;
18659
+ break;
18660
+ }
18661
+ }
18662
+ const claim = line.slice(start).replace(LEADING_LIST_MARK, "").replace(/\s+/gu, " ").trim();
18663
+ return claim.length > MAX_CLAIM_CHARS ? `${claim.slice(0, MAX_CLAIM_CHARS)}…` : claim;
18664
+ }
18665
+ function deriveResultsFromAnswer(text, ledger, options) {
18666
+ const isFile = (path) => options.allowLocalFiles && isAbsolute10(path) && isRegularFile2(path);
18667
+ const sources = new Map;
18668
+ const dropped = new Set;
18669
+ let answer = "";
18670
+ let cursor = 0;
18671
+ let lastEmitted;
18672
+ const cite = (reference, claimEnd) => {
18673
+ const refs = ledger.lookup(reference, options);
18674
+ const [primary] = refs;
18675
+ if (primary === undefined) {
18676
+ dropped.add(reference);
18677
+ return;
18678
+ }
18679
+ let cited = sources.get(primary.source);
18680
+ if (cited === undefined) {
18681
+ cited = { number: sources.size + 1, refs: [], chunkKeys: new Set, claim: claimBefore(text, claimEnd) };
18682
+ sources.set(primary.source, cited);
18683
+ }
18684
+ for (const ref of refs) {
18685
+ const chunkKey = `${ref.source}\x00${ref.content ?? ""}`;
18686
+ if (cited.chunkKeys.has(chunkKey))
18687
+ continue;
18688
+ cited.chunkKeys.add(chunkKey);
18689
+ cited.refs.push(ref);
18690
+ }
18691
+ return cited.number;
18692
+ };
18693
+ for (const marker of answerMarkers(text, isFile)) {
18694
+ answer += text.slice(cursor, marker.start);
18695
+ cursor = marker.end;
18696
+ if (marker.kind === "number") {
18697
+ dropped.add(`[${marker.number}]`);
18698
+ continue;
18699
+ }
18700
+ const references = marker.kind === "evidence" ? marker.ids : [`file:${marker.path}`];
18701
+ const numbers = [];
18702
+ for (const reference of references) {
18703
+ const number = cite(marker.kind === "file" ? marker.path : reference, marker.start);
18704
+ if (number !== undefined && !numbers.includes(number))
18705
+ numbers.push(number);
18706
+ }
18707
+ if (numbers.length === 0)
18708
+ continue;
18709
+ const adjacent = lastEmitted !== undefined && text.slice(lastEmitted.end, marker.start).trim() === "";
18710
+ const fresh = numbers.filter((number) => !(adjacent && lastEmitted?.number === number));
18711
+ lastEmitted = { number: numbers[numbers.length - 1], end: marker.end };
18712
+ if (fresh.length === 0)
18713
+ continue;
18714
+ const leading = LEADING_BLANK.exec(text.slice(marker.start, marker.end))?.[0] ?? "";
18715
+ answer += leading + fresh.map((number) => `[${number}]`).join("");
18716
+ }
18717
+ answer += text.slice(cursor);
18718
+ const results = [];
18719
+ const mapping = [];
18720
+ for (const [source, cited] of sources) {
18721
+ const [primary] = cited.refs;
18722
+ if (primary === undefined)
18723
+ continue;
18724
+ results.push({
18725
+ number: cited.number,
18726
+ title: source.split(/[\\/]/u).filter((part) => part.length > 0).pop() ?? source,
18727
+ summary: cited.claim,
18728
+ evidence: cited.refs.map((ref) => {
18729
+ const excerpt = (ref.content ?? "").replace(/\s+/gu, " ").trim().slice(0, MAX_EXCERPT_CHARS);
18730
+ return ref.lineNumber !== undefined ? { excerpt, lineNumber: ref.lineNumber } : { excerpt };
18731
+ })
18732
+ });
18733
+ mapping.push({
18734
+ number: cited.number,
18735
+ source,
18736
+ method: primary.method,
18737
+ content: primary.content ?? "",
18738
+ evidenceRefs: cited.refs
18739
+ });
18740
+ }
18741
+ const diagnostics = dropped.size === 0 ? [] : [
18742
+ {
18743
+ code: "citation-without-result",
18744
+ severity: "warning",
18745
+ 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.`,
18746
+ source: "agent"
18747
+ }
18748
+ ];
18749
+ return { details: { answer: answer.trim(), results, mapping, warnings: [] }, diagnostics };
18750
+ }
18751
+ var MAX_EXCERPT_CHARS = 400, MAX_CLAIM_CHARS = 280, CLAIM_LOOKBACK_CHARS = 600, SENTENCE_END, LEADING_LIST_MARK, EVIDENCE_MARKER_TEXT, LEADING_BLANK;
18752
+ var init_answer_citations = __esm(() => {
18753
+ init_evidence_ledger();
18754
+ SENTENCE_END = /[.!?。!?]/u;
18755
+ LEADING_LIST_MARK = /^[\s\-*•>]+/u;
18756
+ EVIDENCE_MARKER_TEXT = /\[(?:e\d+(?:,\s*)?)+\]|\[file:[^\]]*\]/gu;
18757
+ LEADING_BLANK = /^[ \t]*/u;
18758
+ });
18759
+
18760
+ // src/agent/answer-guidelines.ts
18761
+ 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.";
18762
+
18763
+ // src/agent/datasource-skill.ts
18764
+ import { Type as Type2 } from "typebox";
18765
+ function escapeXml(value) {
18766
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
17777
18767
  }
17778
18768
  function formatSkillsListing(skills) {
17779
18769
  const lines = [
@@ -17895,7 +18885,7 @@ function renderFamily(family) {
17895
18885
  const members = family.members.length > 0 ? family.members : family.files.map((path) => ({ path }));
17896
18886
  const lines = [` [${family.relation}] family ${family.id}: ${members.length} file(s)`];
17897
18887
  for (const member of members.slice(0, MAX_RENDERED_MEMBERS)) {
17898
- const path = readString(member, "path");
18888
+ const path = readString2(member, "path");
17899
18889
  if (path === undefined)
17900
18890
  continue;
17901
18891
  lines.push(` - ${path}${formatMemberScores(member)}`);
@@ -17913,7 +18903,7 @@ function selectedCandidate(family) {
17913
18903
  const top = ranked[0];
17914
18904
  if (!isKeyedRecord(top))
17915
18905
  return;
17916
- const path = readString(top, "path");
18906
+ const path = readString2(top, "path");
17917
18907
  if (path === undefined)
17918
18908
  return;
17919
18909
  const score = formatScore(readNumber(top, "score"));
@@ -17942,10 +18932,10 @@ function readReasons(source) {
17942
18932
  const rendered = reasons.flatMap((reason) => {
17943
18933
  if (!isKeyedRecord(reason))
17944
18934
  return [];
17945
- const name = readString(reason, "name");
18935
+ const name = readString2(reason, "name");
17946
18936
  if (name === undefined)
17947
18937
  return [];
17948
- const detail = readString(reason, "detail");
18938
+ const detail = readString2(reason, "detail");
17949
18939
  return [detail === undefined ? name : `${name} — ${detail}`];
17950
18940
  });
17951
18941
  return rendered.length === 0 ? "" : `reason: ${rendered.join(", ")}`;
@@ -17953,7 +18943,7 @@ function readReasons(source) {
17953
18943
  function isKeyedRecord(value) {
17954
18944
  return typeof value === "object" && value !== null && !Array.isArray(value);
17955
18945
  }
17956
- function readString(source, key) {
18946
+ function readString2(source, key) {
17957
18947
  const value = source[key];
17958
18948
  return typeof value === "string" ? value : undefined;
17959
18949
  }
@@ -17969,230 +18959,8 @@ var init_dupey_tool = __esm(() => {
17969
18959
  scanDuplicateDocumentsSchema = Type3.Object({});
17970
18960
  });
17971
18961
 
17972
- // src/agent/citations.ts
17973
- function isAsciiDigit(code) {
17974
- return code >= 48 && code <= 57;
17975
- }
17976
- function citationMarkers(answer) {
17977
- const markers = [];
17978
- let floor = 0;
17979
- let closeIndex = -1;
17980
- let index = 0;
17981
- while (index < answer.length) {
17982
- const char = answer[index];
17983
- if (char === "(" && answer[index + 1] === "<") {
17984
- if (closeIndex < index + 2) {
17985
- const found = answer.indexOf(">", index + 2);
17986
- closeIndex = found === -1 ? answer.length : found;
17987
- }
17988
- if (answer[closeIndex + 1] === ")") {
17989
- index = closeIndex + 2;
17990
- floor = index;
17991
- continue;
17992
- }
17993
- index += 1;
17994
- continue;
17995
- }
17996
- if (char === "[") {
17997
- let digitsEnd = index + 1;
17998
- while (digitsEnd < answer.length && isAsciiDigit(answer.charCodeAt(digitsEnd)))
17999
- digitsEnd += 1;
18000
- if (digitsEnd > index + 1 && answer[digitsEnd] === "]" && answer[digitsEnd + 1] !== "(") {
18001
- let start = index;
18002
- while (start > floor && (answer[start - 1] === " " || answer[start - 1] === "\t"))
18003
- start -= 1;
18004
- markers.push({ start, end: digitsEnd + 1, number: Number(answer.slice(index + 1, digitsEnd)) });
18005
- index = digitsEnd + 1;
18006
- floor = index;
18007
- continue;
18008
- }
18009
- }
18010
- index += 1;
18011
- }
18012
- return markers;
18013
- }
18014
- function unresolvedCitations(answer, results) {
18015
- const known = new Set(results.map((result) => result.number));
18016
- const unresolved = new Set;
18017
- for (const marker of citationMarkers(answer)) {
18018
- if (!known.has(marker.number))
18019
- unresolved.add(marker.number);
18020
- }
18021
- return [...unresolved].sort((a, b) => a - b);
18022
- }
18023
- function stripUnresolvedCitations(answer, results) {
18024
- const known = new Set(results.map((result) => result.number));
18025
- const unresolved = new Set;
18026
- let stripped = "";
18027
- let cursor = 0;
18028
- for (const marker of citationMarkers(answer)) {
18029
- if (known.has(marker.number))
18030
- continue;
18031
- unresolved.add(marker.number);
18032
- stripped += answer.slice(cursor, marker.start);
18033
- cursor = marker.end;
18034
- }
18035
- if (unresolved.size === 0)
18036
- return { answer, unresolved: [] };
18037
- return { answer: stripped + answer.slice(cursor), unresolved: [...unresolved].sort((a, b) => a - b) };
18038
- }
18039
- function formatCitationList(numbers) {
18040
- return numbers.length === 0 ? "none" : numbers.map((number) => `[${number}]`).join(", ");
18041
- }
18042
- function duplicateNumbers(sortedNumbers) {
18043
- const duplicates = [];
18044
- for (let index = 1;index < sortedNumbers.length; index++) {
18045
- const number = sortedNumbers[index];
18046
- if (number === sortedNumbers[index - 1] && duplicates[duplicates.length - 1] !== number)
18047
- duplicates.push(number);
18048
- }
18049
- return duplicates;
18050
- }
18051
- function assertUniqueResultNumbers(label, results) {
18052
- const duplicates = duplicateNumbers(results.map((result) => result.number).sort((a, b) => a - b));
18053
- if (duplicates.length === 0)
18054
- return;
18055
- throw new Error(`${label}: result numbers must be unique, but results repeat ${formatCitationList(duplicates)}. Give every result its own number and re-emit.`);
18056
- }
18057
- function assertResultsMappingOneToOne(label, results, mapping) {
18058
- const resultNumbers = results.map((result) => result.number).sort((a, b) => a - b);
18059
- const mappingNumbers = mapping.map((entry) => entry.number).sort((a, b) => a - b);
18060
- const resultDuplicates = duplicateNumbers(resultNumbers);
18061
- const mappingDuplicates = duplicateNumbers(mappingNumbers);
18062
- const sameNumbers = resultNumbers.length === mappingNumbers.length && resultNumbers.every((number, index) => number === mappingNumbers[index]);
18063
- if (sameNumbers && resultDuplicates.length === 0 && mappingDuplicates.length === 0)
18064
- return;
18065
- const duplicateNotes = [
18066
- resultDuplicates.length > 0 ? `results repeat ${formatCitationList(resultDuplicates)}` : undefined,
18067
- mappingDuplicates.length > 0 ? `mapping repeats ${formatCitationList(mappingDuplicates)}` : undefined
18068
- ].filter((note) => note !== undefined);
18069
- 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.");
18070
- }
18071
- function assertCitationsResolve(label, answer, results) {
18072
- const unresolved = unresolvedCitations(answer, results);
18073
- if (unresolved.length === 0)
18074
- return;
18075
- const emitted = [...new Set(results.map((result) => result.number))].sort((a, b) => a - b);
18076
- 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.");
18077
- }
18078
-
18079
- // src/agent/emit-results-tool.ts
18080
- import { Type as Type4 } from "typebox";
18081
- function createEmitResultsTool(capture, options) {
18082
- return {
18083
- name: EMIT_AUTORAG_RESULTS_TOOL_NAME,
18084
- label: "Emit AutoRAG Results",
18085
- 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.",
18086
- parameters: emitResultsSchema,
18087
- async execute(_toolCallId, params) {
18088
- assertCitationsResolve(EMIT_AUTORAG_RESULTS_TOOL_NAME, params.answer, params.results);
18089
- assertUniqueResultNumbers(EMIT_AUTORAG_RESULTS_TOOL_NAME, params.results);
18090
- const mapping = params.results.map((result) => {
18091
- const evidenceRefs = options.ledger.resolve(result.refs, {
18092
- label: EMIT_AUTORAG_RESULTS_TOOL_NAME,
18093
- number: result.number,
18094
- fallbackContent: result.evidence.map((evidence) => evidence.excerpt).join(`
18095
- `) || result.summary,
18096
- allowLocalFiles: options.allowLocalFiles
18097
- });
18098
- const primary = evidenceRefs[0];
18099
- if (primary === undefined) {
18100
- throw new Error(`${EMIT_AUTORAG_RESULTS_TOOL_NAME}: result ${result.number} resolved no evidence. Give it at least one valid ref.`);
18101
- }
18102
- return {
18103
- number: result.number,
18104
- source: primary.source,
18105
- method: primary.method,
18106
- content: primary.content ?? "",
18107
- evidenceRefs
18108
- };
18109
- });
18110
- const details = {
18111
- answer: params.answer,
18112
- results: params.results.map((result) => ({
18113
- number: result.number,
18114
- title: result.title,
18115
- summary: result.summary,
18116
- evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
18117
- confidence: result.confidence
18118
- })),
18119
- mapping,
18120
- warnings: params.warnings ?? []
18121
- };
18122
- capture(details);
18123
- return {
18124
- content: [{ type: "text", text: "AutoRAG results emitted." }],
18125
- details,
18126
- terminate: true
18127
- };
18128
- }
18129
- };
18130
- }
18131
- var EMIT_AUTORAG_RESULTS_TOOL_NAME = "emit_autorag_results", evidenceRefSchema, answerSchema, warningsSchema, curatedResultFields, emitResultsSchema, reportSchema;
18132
- var init_emit_results_tool = __esm(() => {
18133
- evidenceRefSchema = Type4.Object({
18134
- method: Type4.String({ description: "Retrieval method namespace for this evidence chunk" }),
18135
- source: Type4.String({ description: "Internal opaque source identifier for this evidence chunk" }),
18136
- excerpt: Type4.Optional(Type4.String({ description: "Evidence excerpt used for stable ID normalization" })),
18137
- content: Type4.Optional(Type4.String({ description: "Evidence content used for stable ID normalization" })),
18138
- retrievalResultId: Type4.Optional(Type4.String({ description: "Backend retrieval ID when path-opaque and stable" })),
18139
- chunkIndex: Type4.Optional(Type4.Integer({ description: "Chunk index, if available" })),
18140
- lineNumber: Type4.Optional(Type4.Integer({ description: "Line number, if available" })),
18141
- stableEvidenceId: Type4.Optional(Type4.String({ description: "Stable evidence ID, if already normalized" })),
18142
- retrieverMix: Type4.Optional(Type4.Array(Type4.String({ maxLength: 64 }), {
18143
- description: "Retrievers that contributed to this result",
18144
- maxItems: 8
18145
- })),
18146
- parserType: Type4.Optional(Type4.String({ description: "Parser that produced this evidence", maxLength: 120 })),
18147
- documentType: Type4.Optional(Type4.String({ description: "Document type, if known", maxLength: 120 })),
18148
- documentArea: Type4.Optional(Type4.String({ description: "Document collection area, if known", maxLength: 120 })),
18149
- evidenceType: Type4.Optional(Type4.String({ description: "Evidence type, if known", maxLength: 120 })),
18150
- evidenceLocation: Type4.Optional(Type4.String({ description: "Human-readable evidence location", maxLength: 120 })),
18151
- confidence: Type4.Optional(Type4.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
18152
- });
18153
- answerSchema = Type4.String({
18154
- 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}`
18155
- });
18156
- warningsSchema = Type4.Optional(Type4.Array(Type4.String(), { description: "Optional warnings about this result set" }));
18157
- curatedResultFields = {
18158
- number: Type4.Integer({ description: "1-based result number" }),
18159
- title: Type4.String({ description: "Short name of the curated knowledge unit" }),
18160
- summary: Type4.String({ description: "Key insight: purpose, details, and line range" }),
18161
- evidence: Type4.Array(Type4.Object({
18162
- excerpt: Type4.String({ description: "Supporting excerpt" }),
18163
- lineNumber: Type4.Optional(Type4.Integer({ description: "Line number of the excerpt, if known" }))
18164
- })),
18165
- confidence: Type4.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
18166
- };
18167
- emitResultsSchema = Type4.Object({
18168
- answer: answerSchema,
18169
- results: Type4.Array(Type4.Object({
18170
- ...curatedResultFields,
18171
- refs: Type4.Array(Type4.String(), {
18172
- minItems: 1,
18173
- 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."
18174
- })
18175
- }), { description: "Numbered curated knowledge units." }),
18176
- warnings: warningsSchema
18177
- });
18178
- reportSchema = Type4.Object({
18179
- answer: answerSchema,
18180
- results: Type4.Array(Type4.Object(curatedResultFields), { description: "Numbered curated knowledge units." }),
18181
- mapping: Type4.Array(Type4.Object({
18182
- number: Type4.Integer({ description: "Matches the result number this entry maps" }),
18183
- source: Type4.String({ description: "Source identifier — a real file path or a datasource id" }),
18184
- method: Type4.String({ description: "Retrieval method or tool that produced the source" }),
18185
- content: Type4.String({ description: "Raw content snippet of the evidence behind this result" }),
18186
- evidenceRefs: Type4.Optional(Type4.Array(evidenceRefSchema, {
18187
- description: "Hidden evidence chunk references supporting this curated result"
18188
- }))
18189
- }), { description: "Internal number -> source/method mapping. One entry per result number." }),
18190
- warnings: warningsSchema
18191
- });
18192
- });
18193
-
18194
18962
  // src/agent/everything-search-tool.ts
18195
- import { Type as Type5 } from "typebox";
18963
+ import { Type as Type4 } from "typebox";
18196
18964
  function createEverythingSearchTool(provider) {
18197
18965
  return {
18198
18966
  name: EVERYTHING_SEARCH_TOOL_NAME,
@@ -18244,28 +19012,28 @@ ${lines.join(`
18244
19012
  }
18245
19013
  var EVERYTHING_SEARCH_TOOL_NAME = "everything_search", MAX_RESULTS_CAP2 = 1000, DEFAULT_MAX_RESULTS3 = 100, everythingSearchSchema;
18246
19014
  var init_everything_search_tool = __esm(() => {
18247
- everythingSearchSchema = Type5.Object({
18248
- query: Type5.String({
19015
+ everythingSearchSchema = Type4.Object({
19016
+ query: Type4.String({
18249
19017
  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.'
18250
19018
  }),
18251
- regex: Type5.Optional(Type5.Boolean({ description: "Treat query as a regular expression." })),
18252
- matchCase: Type5.Optional(Type5.Boolean()),
18253
- matchPath: Type5.Optional(Type5.Boolean({ description: "Match against the full path instead of the name." })),
18254
- wholeWord: Type5.Optional(Type5.Boolean()),
18255
- kind: Type5.Optional(Type5.Union([Type5.Literal("files"), Type5.Literal("folders")])),
18256
- path: Type5.Optional(Type5.String({ description: "Absolute folder to search within." })),
18257
- sort: Type5.Optional(Type5.Union([
18258
- Type5.Literal("name-ascending"),
18259
- Type5.Literal("name-descending"),
18260
- Type5.Literal("path-ascending"),
18261
- Type5.Literal("path-descending"),
18262
- Type5.Literal("size-ascending"),
18263
- Type5.Literal("size-descending"),
18264
- Type5.Literal("date-modified-ascending"),
18265
- Type5.Literal("date-modified-descending")
19019
+ regex: Type4.Optional(Type4.Boolean({ description: "Treat query as a regular expression." })),
19020
+ matchCase: Type4.Optional(Type4.Boolean()),
19021
+ matchPath: Type4.Optional(Type4.Boolean({ description: "Match against the full path instead of the name." })),
19022
+ wholeWord: Type4.Optional(Type4.Boolean()),
19023
+ kind: Type4.Optional(Type4.Union([Type4.Literal("files"), Type4.Literal("folders")])),
19024
+ path: Type4.Optional(Type4.String({ description: "Absolute folder to search within." })),
19025
+ sort: Type4.Optional(Type4.Union([
19026
+ Type4.Literal("name-ascending"),
19027
+ Type4.Literal("name-descending"),
19028
+ Type4.Literal("path-ascending"),
19029
+ Type4.Literal("path-descending"),
19030
+ Type4.Literal("size-ascending"),
19031
+ Type4.Literal("size-descending"),
19032
+ Type4.Literal("date-modified-ascending"),
19033
+ Type4.Literal("date-modified-descending")
18266
19034
  ])),
18267
- offset: Type5.Optional(Type5.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18268
- maxResults: Type5.Optional(Type5.Integer({
19035
+ offset: Type4.Optional(Type4.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
19036
+ maxResults: Type4.Optional(Type4.Integer({
18269
19037
  minimum: 1,
18270
19038
  description: `Maximum results (default ${DEFAULT_MAX_RESULTS3}, cap ${MAX_RESULTS_CAP2}).`
18271
19039
  }))
@@ -18321,220 +19089,80 @@ function citesResult(sentence, marker) {
18321
19089
  function boundExcerpt(excerpt) {
18322
19090
  if (excerpt.length <= MAX_EVIDENCE_CHARACTERS)
18323
19091
  return excerpt;
18324
- return `${excerpt.slice(0, MAX_EVIDENCE_CHARACTERS - 1)}…`;
18325
- }
18326
- function describeState(input) {
18327
- return [
18328
- STATE_INSTRUCTION,
18329
- `User question: ${JSON.stringify(input.question)}`,
18330
- "Full answer (reference only):",
18331
- input.answer
18332
- ].join(`
18333
- `);
18334
- }
18335
- function evidenceQuestion(unit, input) {
18336
- const sentences = answerSentencesCiting(input.answer, unit.resultNumber);
18337
- const backed = sentences.length > 0 ? `the answer sentence it backs: ${sentences.map((sentence) => JSON.stringify(sentence)).join(" ")}` : `the claim that the answer never cites result [${unit.resultNumber}] (title ${JSON.stringify(unit.title)}, summary ${JSON.stringify(unit.summary)})`;
18338
- return {
18339
- ...EVIDENCE_QUESTION,
18340
- id: evidenceQuestionId(unit.id),
18341
- question: [
18342
- `Does the evidence below directly support ${backed} and is it needed to answer the user's question?`,
18343
- `Search query that surfaced it: ${JSON.stringify(unit.searchQuery)}`,
18344
- `Retrieval method: ${JSON.stringify(unit.method)}`,
18345
- `Evidence: ${JSON.stringify(boundExcerpt(unit.excerpt))}`
18346
- ].join(`
18347
- `)
18348
- };
18349
- }
18350
- async function judgeEvidence(judge, input) {
18351
- if (input.units.length === 0)
18352
- return { probabilities: {}, kept: [] };
18353
- let verdicts;
18354
- try {
18355
- verdicts = (await judge(describeState(input), input.units.map((unit) => evidenceQuestion(unit, input)))).verdicts;
18356
- } catch (error) {
18357
- return { probabilities: {}, kept: [], fallbackReason: error instanceof Error ? error.message : String(error) };
18358
- }
18359
- const byId = {};
18360
- for (const verdict of verdicts)
18361
- byId[verdict.id] = verdict;
18362
- const probabilities = {};
18363
- const kept = [];
18364
- let firstHint;
18365
- for (const unit of input.units) {
18366
- const verdict = byId[evidenceQuestionId(unit.id)];
18367
- if (typeof verdict?.answer !== "number") {
18368
- firstHint ??= verdict?.hint;
18369
- continue;
18370
- }
18371
- probabilities[unit.id] = verdict.answer;
18372
- if (verdict.answer >= EVIDENCE_SUPPORT_THRESHOLD)
18373
- kept.push(unit.id);
18374
- }
18375
- if (Object.keys(probabilities).length === 0) {
18376
- return { probabilities, kept, fallbackReason: firstHint ?? NO_VERDICT_FALLBACK };
18377
- }
18378
- return { probabilities, kept };
18379
- }
18380
- var EVIDENCE_QUESTION_ID_PREFIX = "evidence:", NO_VERDICT_FALLBACK = "Jev returned no usable evidence verdict.", MAX_EVIDENCE_CHARACTERS = 1500, STATE_INSTRUCTION, EVIDENCE_QUESTION, SENTENCE_TERMINATORS;
18381
- var init_evidence_judgment = __esm(() => {
18382
- STATE_INSTRUCTION = [
18383
- "Each question asks whether one piece of evidence really supports answering the user's question.",
18384
- "Judge only that evidence against the sentence it backs; the full answer is shown for reference only."
18385
- ].join(" ");
18386
- EVIDENCE_QUESTION = check("Does the evidence directly support the cited sentence and is it needed to answer the user's question?", {
18387
- true: "The evidence states or confirms what the cited sentence claims about the user's question, and leaving it out would leave that claim unsupported.",
18388
- false: "The evidence is unrelated, only loosely related, redundant noise, or contradicts the cited sentence."
18389
- });
18390
- SENTENCE_TERMINATORS = {
18391
- ".": true,
18392
- "!": true,
18393
- "?": true,
18394
- "。": true,
18395
- "!": true,
18396
- "?": true
18397
- };
18398
- });
18399
-
18400
- // src/agent/evidence-ledger.ts
18401
- import { createHash as createHash13 } from "node:crypto";
18402
- import { statSync } from "node:fs";
18403
- import { isAbsolute as isAbsolute9 } from "node:path";
18404
- function metadataString(metadata, key) {
18405
- const value = metadata[key];
18406
- return typeof value === "string" && value.trim().length > 0 ? value : undefined;
18407
- }
18408
- function metadataNumber(metadata, key) {
18409
- const value = metadata[key];
18410
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
18411
- }
18412
- function isRegularFile2(path) {
18413
- try {
18414
- return statSync(path).isFile();
18415
- } catch {
18416
- return false;
18417
- }
18418
- }
18419
- function toEvidenceRef(entry) {
18420
- return {
18421
- method: entry.method,
18422
- source: entry.source,
18423
- content: entry.content,
18424
- retrieverMix: [...entry.retrieverMix],
18425
- ...entry.retrievalResultId !== undefined ? { retrievalResultId: entry.retrievalResultId } : {},
18426
- ...entry.chunkIndex !== undefined ? { chunkIndex: entry.chunkIndex } : {},
18427
- ...entry.lineNumber !== undefined ? { lineNumber: entry.lineNumber } : {},
18428
- ...entry.parserType !== undefined ? { parserType: entry.parserType } : {},
18429
- ...entry.documentType !== undefined ? { documentType: entry.documentType } : {},
18430
- ...entry.documentArea !== undefined ? { documentArea: entry.documentArea } : {},
18431
- ...entry.evidenceType !== undefined ? { evidenceType: entry.evidenceType } : {},
18432
- ...entry.evidenceLocation !== undefined ? { evidenceLocation: entry.evidenceLocation } : {}
18433
- };
18434
- }
18435
-
18436
- class EvidenceLedger {
18437
- entries = [];
18438
- byKey = new Map;
18439
- byId = new Map;
18440
- lastOrdinal = 0;
18441
- register(input) {
18442
- const content = input.content.slice(0, MAX_CONTENT_CHARS4);
18443
- const digest = createHash13("sha256").update(input.content.replace(/\s+/gu, " ").trim()).digest("hex");
18444
- const key = `${input.source}\x00${digest}`;
18445
- const existing = this.byKey.get(key);
18446
- if (existing !== undefined) {
18447
- if (!existing.retrieverMix.includes(input.method))
18448
- existing.retrieverMix.push(input.method);
18449
- return existing.id;
18450
- }
18451
- const entry = {
18452
- ...input,
18453
- content,
18454
- id: `e${++this.lastOrdinal}`,
18455
- retrieverMix: [input.method]
18456
- };
18457
- this.entries.push(entry);
18458
- this.byKey.set(key, entry);
18459
- this.byId.set(entry.id, entry);
18460
- return entry.id;
18461
- }
18462
- registerResult(tool, result) {
18463
- const metadata = result.metadata;
18464
- const chunkIndex = metadataNumber(metadata, "chunkIndex");
18465
- const lineNumber = metadataNumber(metadata, "lineNumber");
18466
- const parserType = metadataString(metadata, "parserType");
18467
- const documentType = metadataString(metadata, "documentType");
18468
- const documentArea = metadataString(metadata, "documentArea");
18469
- const evidenceType = metadataString(metadata, "evidenceType");
18470
- const evidenceLocation = metadataString(metadata, "evidenceLocation");
18471
- return this.register({
18472
- method: metadataString(metadata, "method") ?? tool,
18473
- source: result.source,
18474
- content: result.content,
18475
- retrievalResultId: result.id,
18476
- ...chunkIndex !== undefined ? { chunkIndex } : {},
18477
- ...lineNumber !== undefined ? { lineNumber } : {},
18478
- ...parserType !== undefined ? { parserType } : {},
18479
- ...documentType !== undefined ? { documentType } : {},
18480
- ...documentArea !== undefined ? { documentArea } : {},
18481
- ...evidenceType !== undefined ? { evidenceType } : {},
18482
- ...evidenceLocation !== undefined ? { evidenceLocation } : {}
18483
- });
19092
+ return `${excerpt.slice(0, MAX_EVIDENCE_CHARACTERS - 1)}…`;
19093
+ }
19094
+ function describeState(input) {
19095
+ return [
19096
+ STATE_INSTRUCTION,
19097
+ `User question: ${JSON.stringify(input.question)}`,
19098
+ "Full answer (reference only):",
19099
+ input.answer
19100
+ ].join(`
19101
+ `);
19102
+ }
19103
+ function evidenceQuestion(unit, input) {
19104
+ const sentences = answerSentencesCiting(input.answer, unit.resultNumber);
19105
+ const backed = sentences.length > 0 ? `the answer sentence it backs: ${sentences.map((sentence) => JSON.stringify(sentence)).join(" ")}` : `the claim that the answer never cites result [${unit.resultNumber}] (title ${JSON.stringify(unit.title)}, summary ${JSON.stringify(unit.summary)})`;
19106
+ return {
19107
+ ...EVIDENCE_QUESTION,
19108
+ id: evidenceQuestionId(unit.id),
19109
+ question: [
19110
+ `Does the evidence below directly support ${backed} and is it needed to answer the user's question?`,
19111
+ `Search query that surfaced it: ${JSON.stringify(unit.searchQuery)}`,
19112
+ `Retrieval method: ${JSON.stringify(unit.method)}`,
19113
+ `Evidence: ${JSON.stringify(boundExcerpt(unit.excerpt))}`
19114
+ ].join(`
19115
+ `)
19116
+ };
19117
+ }
19118
+ async function judgeEvidence(judge, input) {
19119
+ if (input.units.length === 0)
19120
+ return { probabilities: {}, kept: [] };
19121
+ let verdicts;
19122
+ try {
19123
+ verdicts = (await judge(describeState(input), input.units.map((unit) => evidenceQuestion(unit, input)))).verdicts;
19124
+ } catch (error) {
19125
+ return { probabilities: {}, kept: [], fallbackReason: error instanceof Error ? error.message : String(error) };
18484
19126
  }
18485
- resolve(refs, options) {
18486
- const resolved = [];
18487
- const seen = new Set;
18488
- const push = (entry) => {
18489
- if (seen.has(entry.id))
18490
- return;
18491
- seen.add(entry.id);
18492
- resolved.push(toEvidenceRef(entry));
18493
- };
18494
- for (const raw of refs) {
18495
- const trimmed = raw.trim();
18496
- const ref = trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1).trim() : trimmed;
18497
- const byId = this.byId.get(ref);
18498
- if (byId !== undefined) {
18499
- push(byId);
18500
- continue;
18501
- }
18502
- const bySource = this.entries.filter((entry) => entry.source === ref);
18503
- if (bySource.length > 0) {
18504
- for (const entry of bySource)
18505
- push(entry);
18506
- continue;
18507
- }
18508
- if (options.allowLocalFiles && isAbsolute9(ref) && isRegularFile2(ref)) {
18509
- const key = `file\x00${ref}`;
18510
- if (seen.has(key))
18511
- continue;
18512
- seen.add(key);
18513
- resolved.push({
18514
- method: "bash",
18515
- source: ref,
18516
- content: (options.fallbackContent.trim() || ref).slice(0, MAX_CONTENT_CHARS4)
18517
- });
18518
- continue;
18519
- }
18520
- throw new Error(this.unresolvedMessage(ref, EVIDENCE_ID_PATTERN.test(ref), options));
19127
+ const byId = {};
19128
+ for (const verdict of verdicts)
19129
+ byId[verdict.id] = verdict;
19130
+ const probabilities = {};
19131
+ const kept = [];
19132
+ let firstHint;
19133
+ for (const unit of input.units) {
19134
+ const verdict = byId[evidenceQuestionId(unit.id)];
19135
+ if (typeof verdict?.answer !== "number") {
19136
+ firstHint ??= verdict?.hint;
19137
+ continue;
18521
19138
  }
18522
- return resolved;
18523
- }
18524
- clear() {
18525
- this.entries = [];
18526
- this.byKey.clear();
18527
- this.byId.clear();
19139
+ probabilities[unit.id] = verdict.answer;
19140
+ if (verdict.answer >= EVIDENCE_SUPPORT_THRESHOLD)
19141
+ kept.push(unit.id);
18528
19142
  }
18529
- unresolvedMessage(ref, looksLikeId, options) {
18530
- 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}` : ""}.`;
18531
- const local = options.allowLocalFiles ? " For a file you opened yourself with bash, pass its absolute path." : "";
18532
- 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.`;
19143
+ if (Object.keys(probabilities).length === 0) {
19144
+ return { probabilities, kept, fallbackReason: firstHint ?? NO_VERDICT_FALLBACK };
18533
19145
  }
19146
+ return { probabilities, kept };
18534
19147
  }
18535
- var MAX_CONTENT_CHARS4 = 2000, EVIDENCE_ID_PATTERN;
18536
- var init_evidence_ledger = __esm(() => {
18537
- EVIDENCE_ID_PATTERN = /^e\d+$/u;
19148
+ var EVIDENCE_QUESTION_ID_PREFIX = "evidence:", NO_VERDICT_FALLBACK = "Jev returned no usable evidence verdict.", MAX_EVIDENCE_CHARACTERS = 1500, STATE_INSTRUCTION, EVIDENCE_QUESTION, SENTENCE_TERMINATORS;
19149
+ var init_evidence_judgment = __esm(() => {
19150
+ STATE_INSTRUCTION = [
19151
+ "Each question asks whether one piece of evidence really supports answering the user's question.",
19152
+ "Judge only that evidence against the sentence it backs; the full answer is shown for reference only."
19153
+ ].join(" ");
19154
+ EVIDENCE_QUESTION = check("Does the evidence directly support the cited sentence and is it needed to answer the user's question?", {
19155
+ true: "The evidence states or confirms what the cited sentence claims about the user's question, and leaving it out would leave that claim unsupported.",
19156
+ false: "The evidence is unrelated, only loosely related, redundant noise, or contradicts the cited sentence."
19157
+ });
19158
+ SENTENCE_TERMINATORS = {
19159
+ ".": true,
19160
+ "!": true,
19161
+ "?": true,
19162
+ "。": true,
19163
+ "!": true,
19164
+ "?": true
19165
+ };
18538
19166
  });
18539
19167
 
18540
19168
  // src/agent/evidence-origins.ts
@@ -18644,81 +19272,8 @@ class EvidenceOriginIndex {
18644
19272
  }
18645
19273
  var MAX_CANDIDATES = 2000, MAX_CONTENT_LENGTH = 4000, MIN_MATCH_LENGTH = 12;
18646
19274
 
18647
- // src/agent/fast-answer-tool.ts
18648
- import { Type as Type6 } from "typebox";
18649
- function createEmitFastAnswerTool(capture, options) {
18650
- return {
18651
- name: EMIT_FAST_ANSWER_TOOL_NAME,
18652
- label: "Emit Fast Answer",
18653
- 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.",
18654
- parameters: fastAnswerSchema,
18655
- async execute(_toolCallId, params) {
18656
- assertCitationsResolve(EMIT_FAST_ANSWER_TOOL_NAME, params.answer, params.results);
18657
- const evidenceRefs = [];
18658
- for (const result of params.results) {
18659
- if (result.refs === undefined || result.refs.length === 0)
18660
- continue;
18661
- const refs = options.ledger.resolve(result.refs, {
18662
- label: EMIT_FAST_ANSWER_TOOL_NAME,
18663
- number: result.number,
18664
- fallbackContent: result.summary,
18665
- allowLocalFiles: false
18666
- });
18667
- if (refs.length > 0)
18668
- evidenceRefs.push({ number: result.number, refs });
18669
- }
18670
- const details = {
18671
- answer: params.answer,
18672
- results: params.results.map((result) => ({
18673
- number: result.number,
18674
- title: result.title,
18675
- summary: result.summary,
18676
- evidence: (result.evidence ?? []).map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
18677
- ...result.confidence !== undefined ? { confidence: result.confidence } : {}
18678
- })),
18679
- sources: evidenceRefs.flatMap((entry) => {
18680
- const [primary] = entry.refs;
18681
- return primary === undefined ? [] : [{ number: entry.number, source: primary.source }];
18682
- }),
18683
- evidenceRefs
18684
- };
18685
- capture(details);
18686
- return {
18687
- content: [
18688
- {
18689
- type: "text",
18690
- text: "Fast answer delivered to the user. Stop now; a deeper verification pass follows separately."
18691
- }
18692
- ],
18693
- details
18694
- };
18695
- }
18696
- };
18697
- }
18698
- var EMIT_FAST_ANSWER_TOOL_NAME = "emit_fast_answer", fastAnswerSchema;
18699
- var init_fast_answer_tool = __esm(() => {
18700
- fastAnswerSchema = Type6.Object({
18701
- answer: Type6.String({
18702
- 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}`
18703
- }),
18704
- results: Type6.Array(Type6.Object({
18705
- number: Type6.Integer({ description: "1-based result number" }),
18706
- title: Type6.String({ description: "Short name of the knowledge unit" }),
18707
- summary: Type6.String({ description: "Key insight backing the first answer" }),
18708
- evidence: Type6.Optional(Type6.Array(Type6.Object({
18709
- excerpt: Type6.String({ description: "Supporting excerpt" }),
18710
- lineNumber: Type6.Optional(Type6.Integer({ description: "Line number of the excerpt, if known" }))
18711
- }))),
18712
- confidence: Type6.Optional(Type6.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })),
18713
- refs: Type6.Optional(Type6.Array(Type6.String(), {
18714
- 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."
18715
- }))
18716
- }), { description: "Numbered knowledge units backing the first answer." })
18717
- });
18718
- });
18719
-
18720
19275
  // src/agent/fsearch-search-tool.ts
18721
- import { Type as Type7 } from "typebox";
19276
+ import { Type as Type5 } from "typebox";
18722
19277
  function createFSearchSearchTool(provider) {
18723
19278
  return {
18724
19279
  name: FSEARCH_SEARCH_TOOL_NAME,
@@ -18774,27 +19329,27 @@ ${lines.join(`
18774
19329
  }
18775
19330
  var FSEARCH_SEARCH_TOOL_NAME = "fsearch_search", MAX_RESULTS_CAP3 = 1000, DEFAULT_MAX_RESULTS4 = 100, fsearchSearchSchema;
18776
19331
  var init_fsearch_search_tool = __esm(() => {
18777
- fsearchSearchSchema = Type7.Object({
18778
- query: Type7.String({
19332
+ fsearchSearchSchema = Type5.Object({
19333
+ query: Type5.String({
18779
19334
  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.'
18780
19335
  }),
18781
- regex: Type7.Optional(Type7.Boolean({ description: "Treat query as a regular expression." })),
18782
- matchCase: Type7.Optional(Type7.Boolean()),
18783
- matchPath: Type7.Optional(Type7.Boolean({ description: "Match against the full path instead of the name." })),
18784
- kind: Type7.Optional(Type7.Union([Type7.Literal("files"), Type7.Literal("folders")])),
18785
- path: Type7.Optional(Type7.String({ description: "Absolute folder to search within." })),
18786
- sort: Type7.Optional(Type7.Union([
18787
- Type7.Literal("name-ascending"),
18788
- Type7.Literal("name-descending"),
18789
- Type7.Literal("path-ascending"),
18790
- Type7.Literal("path-descending"),
18791
- Type7.Literal("size-ascending"),
18792
- Type7.Literal("size-descending"),
18793
- Type7.Literal("date-modified-ascending"),
18794
- Type7.Literal("date-modified-descending")
19336
+ regex: Type5.Optional(Type5.Boolean({ description: "Treat query as a regular expression." })),
19337
+ matchCase: Type5.Optional(Type5.Boolean()),
19338
+ matchPath: Type5.Optional(Type5.Boolean({ description: "Match against the full path instead of the name." })),
19339
+ kind: Type5.Optional(Type5.Union([Type5.Literal("files"), Type5.Literal("folders")])),
19340
+ path: Type5.Optional(Type5.String({ description: "Absolute folder to search within." })),
19341
+ sort: Type5.Optional(Type5.Union([
19342
+ Type5.Literal("name-ascending"),
19343
+ Type5.Literal("name-descending"),
19344
+ Type5.Literal("path-ascending"),
19345
+ Type5.Literal("path-descending"),
19346
+ Type5.Literal("size-ascending"),
19347
+ Type5.Literal("size-descending"),
19348
+ Type5.Literal("date-modified-ascending"),
19349
+ Type5.Literal("date-modified-descending")
18795
19350
  ])),
18796
- offset: Type7.Optional(Type7.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18797
- maxResults: Type7.Optional(Type7.Integer({
19351
+ offset: Type5.Optional(Type5.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
19352
+ maxResults: Type5.Optional(Type5.Integer({
18798
19353
  minimum: 1,
18799
19354
  description: `Maximum results (default ${DEFAULT_MAX_RESULTS4}, cap ${MAX_RESULTS_CAP3}).`
18800
19355
  }))
@@ -18927,6 +19482,7 @@ async function createAutoRAGPiSession(options) {
18927
19482
  authPath: join30(agentDir, "auth.json"),
18928
19483
  modelsPath: join30(agentDir, "models.json")
18929
19484
  });
19485
+ await registerAutoRAGProvider(modelRuntime);
18930
19486
  await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
18931
19487
  const customTools = [...options.customTools];
18932
19488
  const extensionToolNames = [...options.extensionToolNames ?? []];
@@ -18976,6 +19532,7 @@ async function createAutoRAGPiInteractiveRuntime(options) {
18976
19532
  authPath: join30(agentDir, "auth.json"),
18977
19533
  modelsPath: join30(agentDir, "models.json")
18978
19534
  });
19535
+ await registerAutoRAGProvider(modelRuntime);
18979
19536
  await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
18980
19537
  const sessionManager = options.sessionPath ? SessionManager.open(options.sessionPath, options.sessionDir, options.cwd) : SessionManager.create(options.cwd, options.sessionDir);
18981
19538
  const createRuntime = async ({
@@ -19025,12 +19582,13 @@ async function createAutoRAGPiInteractiveRuntime(options) {
19025
19582
  }
19026
19583
  var PI_BUILTIN_TOOL_NAMES, EMBEDDED_AUTH_MARKER = "<autorag-embedded-model>";
19027
19584
  var init_pi_session = __esm(() => {
19585
+ init_provider();
19028
19586
  PI_BUILTIN_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
19029
19587
  });
19030
19588
 
19031
19589
  // src/agent/jev-extension.ts
19032
19590
  import { Jev } from "jev-use";
19033
- import { Type as Type8 } from "typebox";
19591
+ import { Type as Type6 } from "typebox";
19034
19592
  function createJevJudge(options = {}) {
19035
19593
  let client;
19036
19594
  return async (state, questions, callOptions = {}) => {
@@ -19083,32 +19641,32 @@ var JEV_TOOL_NAME = "jev", OPENROUTER_DEFAULT_MODEL = "typesafe/jev-1.13", BACKE
19083
19641
  var init_jev_extension = __esm(() => {
19084
19642
  init_pi_session();
19085
19643
  BACKEND_DEFAULT_MODEL = { openrouter: OPENROUTER_DEFAULT_MODEL };
19086
- jevQuestionSchema = Type8.Object({
19087
- id: Type8.Optional(Type8.String({ description: "Caller-assigned id, echoed back in the verdict" })),
19088
- type: Type8.Union([Type8.Literal("noul"), Type8.Literal("choice"), Type8.Literal("score")], {
19644
+ jevQuestionSchema = Type6.Object({
19645
+ id: Type6.Optional(Type6.String({ description: "Caller-assigned id, echoed back in the verdict" })),
19646
+ type: Type6.Union([Type6.Literal("noul"), Type6.Literal("choice"), Type6.Literal("score")], {
19089
19647
  description: "noul = P(yes), choice = pick one option, score = ordered level index"
19090
19648
  }),
19091
- question: Type8.String({
19649
+ question: Type6.String({
19092
19650
  minLength: 1,
19093
19651
  description: "One narrow question about the state. Jev answers exactly this."
19094
19652
  }),
19095
- options: Type8.Optional(Type8.Union([Type8.Array(Type8.String()), Type8.Record(Type8.String(), Type8.String())], {
19653
+ options: Type6.Optional(Type6.Union([Type6.Array(Type6.String()), Type6.Record(Type6.String(), Type6.String())], {
19096
19654
  description: "choice only: at least two option labels (or label -> meaning)"
19097
19655
  })),
19098
- levels: Type8.Optional(Type8.Array(Type8.String(), {
19656
+ levels: Type6.Optional(Type6.Array(Type6.String(), {
19099
19657
  description: "score only: at least two ordered level descriptions; the answer indexes into them"
19100
19658
  })),
19101
- criteria: Type8.Optional(Type8.Object({ true: Type8.String(), false: Type8.String() }, { description: "noul only: what yes and no mean, to sharpen calibration" }))
19659
+ criteria: Type6.Optional(Type6.Object({ true: Type6.String(), false: Type6.String() }, { description: "noul only: what yes and no mean, to sharpen calibration" }))
19102
19660
  });
19103
- jevParameters = Type8.Object({
19104
- state: Type8.Unknown({
19661
+ jevParameters = Type6.Object({
19662
+ state: Type6.Unknown({
19105
19663
  description: "Text, JSON object, or JSON array Jev should judge. Keep it small and self-contained."
19106
19664
  }),
19107
- questions: Type8.Array(jevQuestionSchema, {
19665
+ questions: Type6.Array(jevQuestionSchema, {
19108
19666
  minItems: 1,
19109
19667
  description: "Named questions, all evaluated against the same state in one batched request."
19110
19668
  }),
19111
- confidence_threshold: Type8.Optional(Type8.Number({
19669
+ confidence_threshold: Type6.Optional(Type6.Number({
19112
19670
  minimum: 0,
19113
19671
  maximum: 1,
19114
19672
  description: "Escalate any verdict below this confidence; omitted uses jev-use's per-source defaults"
@@ -19117,7 +19675,7 @@ var init_jev_extension = __esm(() => {
19117
19675
  });
19118
19676
 
19119
19677
  // src/agent/jikji-find-tool.ts
19120
- import { Type as Type9 } from "typebox";
19678
+ import { Type as Type7 } from "typebox";
19121
19679
  function createJikjiFindTool(provider, ledger = new EvidenceLedger) {
19122
19680
  return {
19123
19681
  name: JIKJI_FIND_TOOL_NAME,
@@ -19248,10 +19806,10 @@ function formatDirective(policy) {
19248
19806
  var JIKJI_FIND_TOOL_NAME = "jikji_find", jikjiFindSchema;
19249
19807
  var init_jikji_find_tool = __esm(() => {
19250
19808
  init_evidence_ledger();
19251
- jikjiFindSchema = Type9.Object({
19252
- query: Type9.String({ description: "Query for Jikji local file discovery." }),
19253
- topK: Type9.Optional(Type9.Integer({ description: "Maximum number of answer paths / candidates to return." })),
19254
- first: Type9.Optional(Type9.Boolean({ description: "Return only the first/best answer." }))
19809
+ jikjiFindSchema = Type7.Object({
19810
+ query: Type7.String({ description: "Query for Jikji local file discovery." }),
19811
+ topK: Type7.Optional(Type7.Integer({ description: "Maximum number of answer paths / candidates to return." })),
19812
+ first: Type7.Optional(Type7.Boolean({ description: "Return only the first/best answer." }))
19255
19813
  });
19256
19814
  });
19257
19815
 
@@ -20173,57 +20731,57 @@ var init_policy = __esm(() => {
20173
20731
  });
20174
20732
 
20175
20733
  // src/p2p/wire.ts
20176
- import { Type as Type10 } from "typebox";
20734
+ import { Type as Type8 } from "typebox";
20177
20735
  var PeerRefusalCodeSchema, PeerDiagnosticSchema, PeerFileEntrySchema, PeerResultEntrySchema, PeerQueryRequestSchema, PeerQueryResponseSchema;
20178
20736
  var init_wire = __esm(() => {
20179
- PeerRefusalCodeSchema = Type10.Union([
20180
- Type10.Literal("auth-error"),
20181
- Type10.Literal("replay-rejected"),
20182
- Type10.Literal("rate-limited"),
20183
- Type10.Literal("injection-detected"),
20184
- Type10.Literal("policy-denied"),
20185
- Type10.Literal("queue-full"),
20186
- Type10.Literal("internal-error")
20737
+ PeerRefusalCodeSchema = Type8.Union([
20738
+ Type8.Literal("auth-error"),
20739
+ Type8.Literal("replay-rejected"),
20740
+ Type8.Literal("rate-limited"),
20741
+ Type8.Literal("injection-detected"),
20742
+ Type8.Literal("policy-denied"),
20743
+ Type8.Literal("queue-full"),
20744
+ Type8.Literal("internal-error")
20187
20745
  ]);
20188
- PeerDiagnosticSchema = Type10.Object({
20189
- code: Type10.String({ minLength: 1, description: "Diagnostic or refusal code" }),
20190
- message: Type10.String({ description: "Human-readable diagnostic message" })
20746
+ PeerDiagnosticSchema = Type8.Object({
20747
+ code: Type8.String({ minLength: 1, description: "Diagnostic or refusal code" }),
20748
+ message: Type8.String({ description: "Human-readable diagnostic message" })
20191
20749
  });
20192
- PeerFileEntrySchema = Type10.Object({
20193
- source: Type10.String({
20750
+ PeerFileEntrySchema = Type8.Object({
20751
+ source: Type8.String({
20194
20752
  description: "Canonical retrieval source identifier"
20195
20753
  }),
20196
- contentBase64: Type10.String({ description: "Base64-encoded file content" }),
20197
- redacted: Type10.Boolean({ description: "Whether the content was PII-redacted" })
20754
+ contentBase64: Type8.String({ description: "Base64-encoded file content" }),
20755
+ redacted: Type8.Boolean({ description: "Whether the content was PII-redacted" })
20198
20756
  });
20199
- PeerResultEntrySchema = Type10.Object({
20200
- number: Type10.Integer({ minimum: 1, description: "1-based result number" }),
20201
- title: Type10.String({ minLength: 1, description: "Short title of the result" }),
20202
- summary: Type10.String({ description: "Key insight summary" }),
20203
- source: Type10.String({
20757
+ PeerResultEntrySchema = Type8.Object({
20758
+ number: Type8.Integer({ minimum: 1, description: "1-based result number" }),
20759
+ title: Type8.String({ minLength: 1, description: "Short title of the result" }),
20760
+ summary: Type8.String({ description: "Key insight summary" }),
20761
+ source: Type8.String({
20204
20762
  description: "Canonical retrieval source identifier"
20205
20763
  }),
20206
- excerpt: Type10.String({ description: "Supporting excerpt" })
20764
+ excerpt: Type8.String({ description: "Supporting excerpt" })
20207
20765
  });
20208
- PeerQueryRequestSchema = Type10.Object({
20209
- v: Type10.Literal(1, { description: "Protocol version" }),
20210
- query: Type10.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
20211
- topK: Type10.Optional(Type10.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
20212
- scope: Type10.Optional(Type10.String({ description: "Optional search scope hint" }))
20766
+ PeerQueryRequestSchema = Type8.Object({
20767
+ v: Type8.Literal(1, { description: "Protocol version" }),
20768
+ query: Type8.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
20769
+ topK: Type8.Optional(Type8.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
20770
+ scope: Type8.Optional(Type8.String({ description: "Optional search scope hint" }))
20213
20771
  });
20214
- PeerQueryResponseSchema = Type10.Object({
20215
- v: Type10.Literal(1, { description: "Protocol version" }),
20216
- status: Type10.Union([Type10.Literal("ok"), Type10.Literal("rejected")], {
20772
+ PeerQueryResponseSchema = Type8.Object({
20773
+ v: Type8.Literal(1, { description: "Protocol version" }),
20774
+ status: Type8.Union([Type8.Literal("ok"), Type8.Literal("rejected")], {
20217
20775
  description: "Response status"
20218
20776
  }),
20219
- answer: Type10.String({ description: "Curated answer text" }),
20220
- results: Type10.Array(PeerResultEntrySchema, {
20777
+ answer: Type8.String({ description: "Curated answer text" }),
20778
+ results: Type8.Array(PeerResultEntrySchema, {
20221
20779
  description: "Curated result entries with opaque source ids"
20222
20780
  }),
20223
- files: Type10.Array(PeerFileEntrySchema, {
20781
+ files: Type8.Array(PeerFileEntrySchema, {
20224
20782
  description: "Attached original files with opaque source ids"
20225
20783
  }),
20226
- diagnostics: Type10.Array(PeerDiagnosticSchema, {
20784
+ diagnostics: Type8.Array(PeerDiagnosticSchema, {
20227
20785
  description: "Diagnostic messages (degraded-mode, rejection reasons, etc.)"
20228
20786
  })
20229
20787
  });
@@ -20470,7 +21028,7 @@ var init_simplex_query_store = __esm(() => {
20470
21028
  // src/p2p/simplex-server.ts
20471
21029
  import { existsSync as existsSync28, mkdirSync as mkdirSync23, readFileSync as readFileSync24, writeFileSync as writeFileSync20 } from "node:fs";
20472
21030
  import { join as join34 } from "node:path";
20473
- import { Type as Type11 } from "typebox";
21031
+ import { Type as Type9 } from "typebox";
20474
21032
  import { Value as Value2 } from "typebox/value";
20475
21033
  function targetTokens(value) {
20476
21034
  return new Set((value.toLocaleLowerCase().match(TARGET_TOKEN_PATTERN) ?? []).filter((token) => token.length > 1));
@@ -20784,11 +21342,11 @@ var init_simplex_server = __esm(() => {
20784
21342
  shareBytes: false,
20785
21343
  redact: true
20786
21344
  };
20787
- SimplexWireEnvelopeSchema = Type11.Object({
20788
- v: Type11.Literal(1, { description: "Envelope version" }),
20789
- kind: Type11.Union([Type11.Literal("query"), Type11.Literal("response")], { description: "Payload kind" }),
20790
- id: Type11.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
20791
- payload: Type11.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
21345
+ SimplexWireEnvelopeSchema = Type9.Object({
21346
+ v: Type9.Literal(1, { description: "Envelope version" }),
21347
+ kind: Type9.Union([Type9.Literal("query"), Type9.Literal("response")], { description: "Payload kind" }),
21348
+ id: Type9.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
21349
+ payload: Type9.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
20792
21350
  });
20793
21351
  TARGET_TOKEN_PATTERN = /[\p{L}\p{N}]+/gu;
20794
21352
  PEERS_DIR = join34(".autorag", "p2p");
@@ -20801,7 +21359,7 @@ var init_simplex_server = __esm(() => {
20801
21359
  });
20802
21360
 
20803
21361
  // src/agent/peer-target-tool.ts
20804
- import { Type as Type12 } from "typebox";
21362
+ import { Type as Type10 } from "typebox";
20805
21363
  function createRecommendPeerTargetsTool(workspacePath) {
20806
21364
  return {
20807
21365
  name: RECOMMEND_PEER_TARGETS_TOOL_NAME,
@@ -20834,8 +21392,8 @@ function createRecommendPeerTargetsTool(workspacePath) {
20834
21392
  var RECOMMEND_PEER_TARGETS_TOOL_NAME = "recommend_peer_targets", recommendPeerTargetsSchema;
20835
21393
  var init_peer_target_tool = __esm(() => {
20836
21394
  init_simplex_server();
20837
- recommendPeerTargetsSchema = Type12.Object({
20838
- query: Type12.String({ description: "Question or topic to match against local peer personas." })
21395
+ recommendPeerTargetsSchema = Type10.Object({
21396
+ query: Type10.String({ description: "Question or topic to match against local peer personas." })
20839
21397
  });
20840
21398
  });
20841
21399
 
@@ -20911,7 +21469,7 @@ var MAX_DECOMPOSED_QUERIES = 5;
20911
21469
  var init_query_decomposition = () => {};
20912
21470
 
20913
21471
  // src/agent/query-peer-tool.ts
20914
- import { Type as Type13 } from "typebox";
21472
+ import { Type as Type11 } from "typebox";
20915
21473
  function failure4(alias, message) {
20916
21474
  const details = { method: "query_peer_agent", ok: false, alias, message };
20917
21475
  return { content: [{ type: "text", text: message }], details };
@@ -21026,11 +21584,11 @@ var init_query_peer_tool = __esm(() => {
21026
21584
  init_simplex_query_store();
21027
21585
  init_simplex_server();
21028
21586
  init_evidence_ledger();
21029
- queryPeerAgentSchema = Type13.Object({
21030
- alias: Type13.String({ minLength: 1 }),
21031
- query: Type13.String({ minLength: 1, maxLength: 4096 }),
21032
- topK: Type13.Optional(Type13.Integer({ minimum: 1, maximum: 20 })),
21033
- scope: Type13.Optional(Type13.String())
21587
+ queryPeerAgentSchema = Type11.Object({
21588
+ alias: Type11.String({ minLength: 1 }),
21589
+ query: Type11.String({ minLength: 1, maxLength: 4096 }),
21590
+ topK: Type11.Optional(Type11.Integer({ minimum: 1, maximum: 20 })),
21591
+ scope: Type11.Optional(Type11.String())
21034
21592
  });
21035
21593
  });
21036
21594
 
@@ -21297,29 +21855,29 @@ function reconcileCitations(answer, results) {
21297
21855
  ]
21298
21856
  };
21299
21857
  }
21300
- function createPreliminarySearchDocumentsResponse(sessionId, query, details, diagnostics = []) {
21301
- const sourceByNumber = new Map(details.sources.map((entry) => [entry.number, entry.source]));
21302
- const results = details.results.map((result) => ({
21858
+ function toSearchResults(details, sourceByNumber) {
21859
+ return details.results.map((result) => ({
21303
21860
  number: result.number,
21304
21861
  title: result.title,
21305
21862
  summary: result.summary,
21306
21863
  evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
21307
- confidence: confidenceFrom(result.confidence ?? 0.5),
21864
+ ...result.confidence !== undefined ? { confidence: confidenceFrom(result.confidence) } : {},
21308
21865
  source: sourceByNumber.get(result.number)
21309
21866
  }));
21310
- const citations = reconcileCitations(details.answer, results);
21867
+ }
21868
+ function createPreliminarySearchDocumentsResponse(sessionId, query, details, diagnostics = []) {
21869
+ const sourceByNumber = new Map(details.mapping.map((entry) => [entry.number, entry.source]));
21311
21870
  return {
21312
21871
  sessionId,
21313
21872
  query,
21314
- results,
21315
- answer: citations.answer,
21873
+ results: toSearchResults(details, sourceByNumber),
21874
+ answer: details.answer,
21316
21875
  searched: details.results.length,
21317
21876
  warnings: [],
21318
- diagnostics: [...citations.diagnostics, ...diagnostics]
21877
+ diagnostics: [...diagnostics]
21319
21878
  };
21320
21879
  }
21321
- function createEmptySearchDocumentsResponse(sessionId, query, sessions, diagnostics = []) {
21322
- sessions.set(sessionId, { query, registry: new Map });
21880
+ function createEmptySearchDocumentsResponse(sessionId, query, diagnostics = []) {
21323
21881
  return {
21324
21882
  sessionId,
21325
21883
  query,
@@ -21335,7 +21893,7 @@ function normalizeEntryEvidenceRefs(entry) {
21335
21893
  const derivedRetrieverMix = Array.from(new Set(rawRefs.map((ref) => ref.method)));
21336
21894
  return rawRefs.map((ref) => {
21337
21895
  if (ref.excerpt === undefined && ref.content === undefined) {
21338
- throw new Error("emit_autorag_results: every evidenceRef must include excerpt or content");
21896
+ throw new Error("results: every evidenceRef must include excerpt or content");
21339
21897
  }
21340
21898
  return normalizeSessionEvidenceRef({
21341
21899
  method: ref.method,
@@ -21356,19 +21914,11 @@ function normalizeEntryEvidenceRefs(entry) {
21356
21914
  });
21357
21915
  });
21358
21916
  }
21359
- function recordStructuredResultsSession(sessionId, query, details, sessions, memory, componentDiagnostics = [], options = {}) {
21360
- assertResultsMappingOneToOne("emit_autorag_results", details.results, details.mapping);
21361
- const registry = new Map;
21917
+ function recordStructuredResultsSession(sessionId, query, details, memory, componentDiagnostics = [], options = {}) {
21918
+ assertResultsMappingOneToOne("results", details.results, details.mapping);
21362
21919
  const memoryResults = [];
21363
21920
  for (const entry of details.mapping) {
21364
21921
  const evidenceRefs = normalizeEntryEvidenceRefs(entry);
21365
- registry.set(entry.number, {
21366
- index: entry.number,
21367
- content: entry.content,
21368
- source: entry.source,
21369
- method: entry.method,
21370
- evidenceRefs
21371
- });
21372
21922
  const emittedResult = details.results.find((result) => result.number === entry.number);
21373
21923
  memoryResults.push({
21374
21924
  number: entry.number,
@@ -21377,23 +21927,15 @@ function recordStructuredResultsSession(sessionId, query, details, sessions, mem
21377
21927
  content: entry.content,
21378
21928
  method: entry.method,
21379
21929
  source: entry.source,
21380
- ...emittedResult !== undefined ? { confidence: confidenceFrom(emittedResult.confidence) } : {},
21930
+ ...emittedResult?.confidence !== undefined ? { confidence: confidenceFrom(emittedResult.confidence) } : {},
21381
21931
  evidenceRefs
21382
21932
  });
21383
21933
  }
21384
- sessions.set(sessionId, { query, registry });
21385
21934
  if (!options.isolateMemory) {
21386
21935
  memory.recordCuratedResultsSession({ sessionId, query, results: memoryResults });
21387
21936
  memory.save();
21388
21937
  }
21389
- const results = details.results.map((result) => ({
21390
- number: result.number,
21391
- title: result.title,
21392
- summary: result.summary,
21393
- evidence: result.evidence.map((evidence) => evidence.lineNumber !== undefined ? { excerpt: evidence.excerpt, lineNumber: evidence.lineNumber } : { excerpt: evidence.excerpt }),
21394
- confidence: confidenceFrom(result.confidence),
21395
- source: registry.get(result.number)?.source || undefined
21396
- }));
21938
+ const results = toSearchResults(details, new Map(details.mapping.map((entry) => [entry.number, entry.source || undefined])));
21397
21939
  const citations = reconcileCitations(details.answer, results);
21398
21940
  const answer = citations.answer;
21399
21941
  const diagnostics = [...citations.diagnostics];
@@ -21423,7 +21965,7 @@ var init_search_documents = __esm(() => {
21423
21965
  });
21424
21966
 
21425
21967
  // src/agent/search-all-tool.ts
21426
- import { Type as Type14 } from "typebox";
21968
+ import { Type as Type12 } from "typebox";
21427
21969
  function createSearchAllDocumentsTool(provider, ledger = new EvidenceLedger) {
21428
21970
  return {
21429
21971
  name: SEARCH_ALL_DOCUMENTS_TOOL_NAME,
@@ -21478,17 +22020,17 @@ var SEARCH_ALL_DOCUMENTS_TOOL_NAME = "search_all_documents", searchAllSchema;
21478
22020
  var init_search_all_tool = __esm(() => {
21479
22021
  init_evidence_ledger();
21480
22022
  init_search_documents();
21481
- searchAllSchema = Type14.Object({
21482
- query: Type14.String({ description: "Query to search across all configured retrieval methods." }),
21483
- topK: Type14.Optional(Type14.Integer({
22023
+ searchAllSchema = Type12.Object({
22024
+ query: Type12.String({ description: "Query to search across all configured retrieval methods." }),
22025
+ topK: Type12.Optional(Type12.Integer({
21484
22026
  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."
21485
22027
  })),
21486
- scope: Type14.Optional(Type14.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
22028
+ scope: Type12.Optional(Type12.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
21487
22029
  });
21488
22030
  });
21489
22031
 
21490
22032
  // src/agent/search-minsync-tool.ts
21491
- import { Type as Type15 } from "typebox";
22033
+ import { Type as Type13 } from "typebox";
21492
22034
  function createSearchMinSyncDocumentsTool(getMethod, resolveScope = (scope) => scope, ledger = new EvidenceLedger) {
21493
22035
  return {
21494
22036
  name: SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
@@ -21538,17 +22080,17 @@ var SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME = "semantic_search_local_docs", searchMin
21538
22080
  var init_search_minsync_tool = __esm(() => {
21539
22081
  init_evidence_ledger();
21540
22082
  init_search_documents();
21541
- searchMinSyncSchema = Type15.Object({
21542
- query: Type15.String({
22083
+ searchMinSyncSchema = Type13.Object({
22084
+ query: Type13.String({
21543
22085
  description: "Semantic query to search parsed document mirrors with MinSync vector retrieval."
21544
22086
  }),
21545
- topK: Type15.Optional(Type15.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
21546
- scope: Type15.Optional(Type15.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
22087
+ topK: Type13.Optional(Type13.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
22088
+ scope: Type13.Optional(Type13.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
21547
22089
  });
21548
22090
  });
21549
22091
 
21550
22092
  // src/agent/search-single-datasource-tool.ts
21551
- import { Type as Type16 } from "typebox";
22093
+ import { Type as Type14 } from "typebox";
21552
22094
  function createSingleDatasourceSearchTools(provider, specs, ledger = new EvidenceLedger) {
21553
22095
  return specs.map((spec) => createTool(provider, spec, ledger));
21554
22096
  }
@@ -21614,10 +22156,10 @@ var init_search_single_datasource_tool = __esm(() => {
21614
22156
  init_evidence_ledger();
21615
22157
  init_search_documents();
21616
22158
  singleDatasourceToolName = datasourceSearchToolName;
21617
- searchSingleDatasourceSchema = Type16.Object({
21618
- query: Type16.String({ description: "Query to search within this datasource connection." }),
21619
- topK: Type16.Optional(Type16.Integer({ description: "Maximum number of chunks to return. Defaults to 20." })),
21620
- scope: Type16.Optional(Type16.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
22159
+ searchSingleDatasourceSchema = Type14.Object({
22160
+ query: Type14.String({ description: "Query to search within this datasource connection." }),
22161
+ topK: Type14.Optional(Type14.Integer({ description: "Maximum number of chunks to return. Defaults to 20." })),
22162
+ scope: Type14.Optional(Type14.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
21621
22163
  });
21622
22164
  });
21623
22165
 
@@ -21702,7 +22244,7 @@ ${input.skill}
21702
22244
 
21703
22245
  ${input.query}
21704
22246
 
21705
- ` + `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.`;
22247
+ ` + `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.`;
21706
22248
  }
21707
22249
  var SETUP_SKILL_RELATIVE_PATH;
21708
22250
  var init_self_config = __esm(() => {
@@ -21733,7 +22275,6 @@ function buildSystemPrompt(config) {
21733
22275
  toolLine(config, "check_memory", "inspect evidence earlier searches found for similar questions"),
21734
22276
  toolLine(config, "recommend_peer_targets", "recommend local peer personas to ask about a topic without contacting them"),
21735
22277
  toolLine(config, "query_peer_agent", "ask one trusted peer agent over SimpleX"),
21736
- toolLine(config, "emit_autorag_results", "return the final structured answer with evidence ids for each result"),
21737
22278
  ...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`),
21738
22279
  ...config.toolNames.filter((name) => ![
21739
22280
  "bash",
@@ -21749,8 +22290,7 @@ function buildSystemPrompt(config) {
21749
22290
  "jev",
21750
22291
  "check_memory",
21751
22292
  "recommend_peer_targets",
21752
- "query_peer_agent",
21753
- "emit_autorag_results"
22293
+ "query_peer_agent"
21754
22294
  ].includes(name) && !name.startsWith("search_datasource_")).map((name) => `- **${name}**: caller-provided tool`)
21755
22295
  ].filter((line) => line !== undefined);
21756
22296
  const manifests = config.manifests.length === 0 ? "" : `
@@ -21814,12 +22354,12 @@ Your job is to retrieve candidates, read the relevant source material directly,
21814
22354
  ## Workflow
21815
22355
 
21816
22356
  Searches follow a progressive, two-phase loop:
21817
- 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.
22357
+ 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.
21818
22358
  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.
21819
22359
  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.
21820
22360
  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.
21821
22361
  5. **CURATE** — Produce concise numbered knowledge units grounded in source evidence.
21822
- 6. **FINALIZE** — Call \`emit_autorag_results\` exactly once as the final action.
22362
+ 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.
21823
22363
 
21824
22364
  ## Available Tools
21825
22365
 
@@ -21864,17 +22404,17 @@ ${fsearch}
21864
22404
  ${manifests}
21865
22405
  ## Output Format
21866
22406
 
21867
- Call \`emit_autorag_results\` exactly once with:
21868
- - \`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].
21869
- - \`results\`: curated units with number, title, summary, evidence, confidence, and \`refs\`.
21870
- - \`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.
22407
+ 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:
22408
+ - 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.
22409
+ - For a local file you opened yourself with \`bash\`, cite \`[file:<absolute path>]\`.
22410
+ - 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.
22411
+ - A citation whose id no tool returned in this run is dropped, so cite only ids you saw.
21871
22412
 
21872
22413
  ## Answer Guidelines
21873
22414
 
21874
22415
  - **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.
21875
22416
  - **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.
21876
- - **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\`).
21877
- - **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\`.
22417
+ - **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.
21878
22418
  - ${ANSWER_CITATION_RULE}
21879
22419
  - ${ANSWER_IMAGE_EMBED_RULE} ${ANSWER_IMAGE_DELTA_RULE}
21880
22420
  - **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.
@@ -21887,7 +22427,7 @@ Call \`emit_autorag_results\` exactly once with:
21887
22427
  - **Curate, don't dump**: return useful knowledge units, not raw search output.
21888
22428
  - **Address intent**: answer the caller's actual need.
21889
22429
  - **Preserve traceability**: cite evidence by the ids retrieval tools show, so source paths and excerpts are attached for you.
21890
- - **Finalize once**: the structured result tool is the final action.
22430
+ - **Finalize once**: the last reply, with no tool call, is the final answer.
21891
22431
  `;
21892
22432
  }
21893
22433
  var init_system_prompt = __esm(() => {
@@ -23874,7 +24414,7 @@ var init_render = __esm(() => {
23874
24414
  });
23875
24415
 
23876
24416
  // src/agent/web-fetch-tool.ts
23877
- import { Type as Type17 } from "typebox";
24417
+ import { Type as Type15 } from "typebox";
23878
24418
  function truncateHead(output, maxBytes, maxLines) {
23879
24419
  const lines = output.split(`
23880
24420
  `);
@@ -23978,9 +24518,9 @@ var init_web_fetch_tool = __esm(() => {
23978
24518
  init_render();
23979
24519
  init_evidence_ledger();
23980
24520
  FETCH_MAX_OUTPUT_BYTES = 50 * 1024;
23981
- webFetchSchema = Type17.Object({
23982
- url: Type17.String({ description: "The http(s) URL to fetch and read." }),
23983
- raw: Type17.Optional(Type17.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
24521
+ webFetchSchema = Type15.Object({
24522
+ url: Type15.String({ description: "The http(s) URL to fetch and read." }),
24523
+ raw: Type15.Optional(Type15.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
23984
24524
  });
23985
24525
  });
23986
24526
 
@@ -24845,7 +25385,7 @@ function parseResponse(data) {
24845
25385
  } : {}
24846
25386
  };
24847
25387
  }
24848
- var DEFAULT_BASE_URL3 = "https://generativelanguage.googleapis.com", API_VERSION = "v1beta", DEFAULT_MODEL = "gemini-3.8-flash", MAX_RESPONSE_BYTES, MAX_ERROR_BYTES, GeminiProvider;
25388
+ var DEFAULT_BASE_URL4 = "https://generativelanguage.googleapis.com", API_VERSION = "v1beta", DEFAULT_MODEL = "gemini-3.8-flash", MAX_RESPONSE_BYTES, MAX_ERROR_BYTES, GeminiProvider;
24849
25389
  var init_gemini = __esm(() => {
24850
25390
  init_model_auth();
24851
25391
  init_query();
@@ -24867,7 +25407,7 @@ var init_gemini = __esm(() => {
24867
25407
  const model = envCredential("GEMINI_SEARCH_MODEL") ?? (credential.source === "injected" ? credential.modelId : undefined) ?? DEFAULT_MODEL;
24868
25408
  const parsed = params.parsedQuery ?? parseSearchQuery(params.query);
24869
25409
  const query = parsed.hasDirectives ? formatQuery(parsed, GOOGLE_QUERY_SYNTAX) : params.query;
24870
- const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL3).replace(/\/+$/, "");
25410
+ const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/+$/, "");
24871
25411
  const fetchImpl = params.fetch ?? fetch;
24872
25412
  const response = await fetchImpl(`${baseUrl}/${API_VERSION}/models/${model}:generateContent`, {
24873
25413
  method: "POST",
@@ -25012,7 +25552,7 @@ function parseResponse2(response) {
25012
25552
  ...response.id !== undefined ? { requestId: response.id } : {}
25013
25553
  };
25014
25554
  }
25015
- var DEFAULT_BASE_URL4 = "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;
25555
+ var DEFAULT_BASE_URL5 = "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;
25016
25556
  var init_anthropic = __esm(() => {
25017
25557
  init_model_auth();
25018
25558
  init_query();
@@ -25043,7 +25583,7 @@ var init_anthropic = __esm(() => {
25043
25583
  const model = envCredential("ANTHROPIC_SEARCH_MODEL") ?? (credential.source === "injected" ? credential.modelId : undefined) ?? DEFAULT_MODEL2;
25044
25584
  const parsed = params.parsedQuery ?? parseSearchQuery(params.query);
25045
25585
  const plan = planQuery(params.query, parsed);
25046
- const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/+$/, "");
25586
+ const baseUrl = (credential.baseUrl ?? DEFAULT_BASE_URL5).replace(/\/+$/, "");
25047
25587
  const fetchImpl = params.fetch ?? fetch;
25048
25588
  const response = await fetchImpl(`${baseUrl}/v1/messages?beta=true`, {
25049
25589
  method: "POST",
@@ -25055,7 +25595,7 @@ var init_anthropic = __esm(() => {
25055
25595
  },
25056
25596
  body: JSON.stringify({
25057
25597
  model,
25058
- max_tokens: params.maxOutputTokens ?? DEFAULT_MAX_TOKENS,
25598
+ max_tokens: params.maxOutputTokens ?? DEFAULT_MAX_TOKENS2,
25059
25599
  ...params.systemPrompt ? { system: params.systemPrompt } : {},
25060
25600
  messages: [{ role: "user", content: plan.query }],
25061
25601
  tools: [
@@ -27138,7 +27678,7 @@ async function searchPublicWeb(params, deadlines = {}) {
27138
27678
  }
27139
27679
  var PUBLIC_ENGINE_IDS, DEFAULT_NUM_RESULTS8 = 15, MAX_NUM_RESULTS8 = 30, SOFT_DEADLINE_MS = 5000, HARD_DEADLINE_MS = 30000, PublicWebProvider;
27140
27680
  var init_public = __esm(() => {
27141
- init_provider();
27681
+ init_provider2();
27142
27682
  init_types4();
27143
27683
  init_utils();
27144
27684
  PUBLIC_ENGINE_IDS = [
@@ -27212,7 +27752,7 @@ function resolveProviderCandidates(routing = {}) {
27212
27752
  return candidates;
27213
27753
  }
27214
27754
  var PROVIDER_META, instanceCache;
27215
- var init_provider = __esm(() => {
27755
+ var init_provider2 = __esm(() => {
27216
27756
  init_types4();
27217
27757
  init_types4();
27218
27758
  PROVIDER_META = {
@@ -27398,15 +27938,15 @@ async function executeWebSearch(params, options = {}) {
27398
27938
  }
27399
27939
  var TOTAL_TIMEOUT_MULTIPLIER = 2;
27400
27940
  var init_search = __esm(() => {
27401
- init_provider();
27941
+ init_provider2();
27402
27942
  init_query();
27403
27943
  init_types4();
27404
- init_provider();
27944
+ init_provider2();
27405
27945
  init_types4();
27406
27946
  });
27407
27947
 
27408
27948
  // src/agent/web-search-tool.ts
27409
- import { Type as Type18 } from "typebox";
27949
+ import { Type as Type16 } from "typebox";
27410
27950
  function createWebSearchTool(options = {}, ledger = new EvidenceLedger) {
27411
27951
  return {
27412
27952
  name: WEB_SEARCH_TOOL_NAME,
@@ -27482,15 +28022,15 @@ var WEB_SEARCH_TOOL_NAME = "web_search", webSearchSchema;
27482
28022
  var init_web_search_tool = __esm(() => {
27483
28023
  init_search();
27484
28024
  init_evidence_ledger();
27485
- webSearchSchema = Type18.Object({
27486
- query: Type18.String({
28025
+ webSearchSchema = Type16.Object({
28026
+ query: Type16.String({
27487
28027
  description: 'Search query. Supports Google-style directives: site:/-site:, after:/before: (YYYY-MM-DD), inurl:, intitle:, filetype:, "exact phrase", -term, OR.'
27488
28028
  }),
27489
- recency: Type18.Optional(Type18.Union([Type18.Literal("day"), Type18.Literal("week"), Type18.Literal("month"), Type18.Literal("year")], {
28029
+ recency: Type16.Optional(Type16.Union([Type16.Literal("day"), Type16.Literal("week"), Type16.Literal("month"), Type16.Literal("year")], {
27490
28030
  description: "Optional recency window for results (pure time filter)."
27491
28031
  })),
27492
- limit: Type18.Optional(Type18.Integer({ description: "Maximum number of results to return." })),
27493
- num_search_results: Type18.Optional(Type18.Integer({ description: "Alias for limit (result count hint)." }))
28032
+ limit: Type16.Optional(Type16.Integer({ description: "Maximum number of results to return." })),
28033
+ num_search_results: Type16.Optional(Type16.Integer({ description: "Alias for limit (result count hint)." }))
27494
28034
  });
27495
28035
  });
27496
28036
 
@@ -27537,10 +28077,7 @@ class AutoRAGAgent {
27537
28077
  runLogger;
27538
28078
  lastQuery;
27539
28079
  lastSessionId;
27540
- sessions = new Map;
27541
28080
  activeRun = false;
27542
- resultCapture;
27543
- interactiveFastAnswerCallback;
27544
28081
  modelNativeSearchAuth;
27545
28082
  retrievalTrace = [];
27546
28083
  evidenceLedger = new EvidenceLedger;
@@ -27702,10 +28239,6 @@ class AutoRAGAgent {
27702
28239
  const searchMinSyncTool = createSearchMinSyncDocumentsTool(() => this.remoteFilteredRetrievalMethod(this.minSyncMethod), (scope) => this.resolveRetrievalScope(scope), this.evidenceLedger);
27703
28240
  const searchAllTool = createSearchAllDocumentsTool(this, this.evidenceLedger);
27704
28241
  const loadDatasourceSkillTool = createLoadDatasourceSkillTool(this);
27705
- const emitResultsTool = createEmitResultsTool((details) => this.resultCapture?.(details), {
27706
- ledger: this.evidenceLedger,
27707
- allowLocalFiles: !this.remoteSession
27708
- });
27709
28242
  const scanDuplicateDocumentsTool = this.dupeyOptions === false ? undefined : createScanDuplicateDocumentsTool(this);
27710
28243
  this.jevJudge = options.jev === undefined || options.jev === false || this.remoteSession ? undefined : createJevJudge(options.jev);
27711
28244
  this.jevExtension = this.jevJudge === undefined ? undefined : createJevExtension(this.jevJudge);
@@ -27740,8 +28273,6 @@ class AutoRAGAgent {
27740
28273
  "check_memory",
27741
28274
  ...singleDatasourceTools.map((tool) => tool.name),
27742
28275
  LOAD_DATASOURCE_SKILL_TOOL_NAME,
27743
- EMIT_AUTORAG_RESULTS_TOOL_NAME,
27744
- EMIT_FAST_ANSWER_TOOL_NAME,
27745
28276
  SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
27746
28277
  SEARCH_ALL_DOCUMENTS_TOOL_NAME,
27747
28278
  JIKJI_FIND_TOOL_NAME,
@@ -27772,7 +28303,6 @@ class AutoRAGAgent {
27772
28303
  loadDatasourceSkillTool,
27773
28304
  ...webSearchTool !== undefined ? [webSearchTool] : [],
27774
28305
  ...webFetchTool !== undefined ? [webFetchTool] : [],
27775
- emitResultsTool,
27776
28306
  ...scanDuplicateDocumentsTool !== undefined ? [scanDuplicateDocumentsTool] : [],
27777
28307
  ...jikjiFindTool !== undefined ? [jikjiFindTool] : [],
27778
28308
  ...everythingSearchTool !== undefined ? [everythingSearchTool] : [],
@@ -27919,12 +28449,11 @@ ${context.text}
27919
28449
  source: "memory"
27920
28450
  };
27921
28451
  }
27922
- const registry = this.sessions.get(sessionId)?.registry;
27923
28452
  const resultByNumber = new Map(details.results.map((result) => [result.number, result]));
27924
28453
  const units = [];
27925
28454
  for (const entry of details.mapping) {
27926
28455
  const result = resultByNumber.get(entry.number);
27927
- const refs = registry?.get(entry.number)?.evidenceRefs ?? [];
28456
+ const refs = normalizeEntryEvidenceRefs(entry);
27928
28457
  if (result === undefined || refs.length === 0)
27929
28458
  continue;
27930
28459
  for (const ref of refs) {
@@ -28005,7 +28534,7 @@ ${context.text}
28005
28534
  providerApiKeys: { [local.provider]: local.apiKey }
28006
28535
  };
28007
28536
  }
28008
- async createSearchSession(resolved, systemPrompt, extraTools = []) {
28537
+ async createSearchSession(resolved, systemPrompt) {
28009
28538
  if (this.boundPiRuntime !== undefined) {
28010
28539
  const session = this.boundPiRuntime.session;
28011
28540
  return {
@@ -28025,10 +28554,7 @@ ${context.text}
28025
28554
  apiKey: resolved.apiKey,
28026
28555
  providerApiKeys: resolved.providerApiKeys,
28027
28556
  getSystemPrompt: () => systemPrompt,
28028
- customTools: [
28029
- ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
28030
- ...extraTools
28031
- ],
28557
+ customTools: this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
28032
28558
  remoteSession: this.remoteSession,
28033
28559
  contextTransform: (messages) => this.withMemoryContext(messages),
28034
28560
  ...this.jevExtension !== undefined ? { extensionFactories: [this.jevExtension], extensionToolNames: [JEV_TOOL_NAME] } : {}
@@ -28109,19 +28635,12 @@ ${context.text}
28109
28635
  modelId: this.boundPiRuntime?.session.model?.id ?? resolved?.model.id
28110
28636
  })),
28111
28637
  contextTransform: (messages) => this.withMemoryContext(messages),
28112
- customTools: [
28113
- ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
28114
- createEmitFastAnswerTool((details) => this.interactiveFastAnswerCallback?.(details), {
28115
- ledger: this.evidenceLedger
28116
- })
28117
- ],
28638
+ customTools: this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
28118
28639
  onQuery: (query, pi) => this.runInteractivePiQuery(query, pi),
28119
- inactiveToolNames: [EMIT_FAST_ANSWER_TOOL_NAME],
28120
28640
  ...this.jevExtension !== undefined ? { extensionFactories: [this.jevExtension], extensionToolNames: [JEV_TOOL_NAME] } : {},
28121
28641
  ...this.updateNotice === undefined ? {} : { updateNotice: this.updateNotice }
28122
28642
  });
28123
28643
  this.boundPiRuntime = runtime.runtime;
28124
- runtime.runtime.session.setActiveToolsByName(runtime.runtime.session.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
28125
28644
  const dispose = runtime.dispose;
28126
28645
  return {
28127
28646
  ...runtime,
@@ -28132,17 +28651,14 @@ ${context.text}
28132
28651
  }
28133
28652
  };
28134
28653
  }
28654
+ deriveAnswer(text) {
28655
+ const derived = deriveResultsFromAnswer(text, this.evidenceLedger, { allowLocalFiles: !this.remoteSession });
28656
+ this.routingDiagnostics.push(...derived.diagnostics);
28657
+ return derived.details;
28658
+ }
28135
28659
  async runInteractivePiQuery(query, pi) {
28136
28660
  pi.setSessionName(query.slice(0, 80));
28137
- for await (const event of this.searchDocumentsStream(query)) {
28138
- const text = event.type === "progress" ? event.text : event.response.answer;
28139
- pi.sendMessage({
28140
- customType: `autorag.${event.type}`,
28141
- content: [{ type: "text", text }],
28142
- display: true,
28143
- details: event
28144
- }, { triggerTurn: false });
28145
- }
28661
+ for await (const _event of this.searchDocumentsStream(query)) {}
28146
28662
  }
28147
28663
  abort() {
28148
28664
  this.activeSession?.abort();
@@ -28173,11 +28689,6 @@ ${context.text}
28173
28689
  this.refreshing = false;
28174
28690
  }
28175
28691
  }
28176
- getResultRegistry(sessionId) {
28177
- const sid = sessionId ?? this.lastSessionId;
28178
- const session = sid ? this.sessions.get(sid) : undefined;
28179
- return session?.registry ?? new Map;
28180
- }
28181
28692
  async searchDocuments(query, options = {}) {
28182
28693
  if (this.activeRun) {
28183
28694
  throw new Error("AutoRAG agent is busy; await the in-flight searchDocuments() call before starting another");
@@ -28189,7 +28700,7 @@ ${context.text}
28189
28700
  if (trimmedQuery.length === 0) {
28190
28701
  this.lastQuery = trimmedQuery;
28191
28702
  this.lastSessionId = sessionId;
28192
- return createEmptySearchDocumentsResponse(sessionId, trimmedQuery, this.sessions, this.startupDiagnostics);
28703
+ return createEmptySearchDocumentsResponse(sessionId, trimmedQuery, this.startupDiagnostics);
28193
28704
  }
28194
28705
  options = this.normalizeRetrievalOptions(options);
28195
28706
  if (this.remoteSession && options.observedSources !== undefined)
@@ -28225,11 +28736,7 @@ ${context.text}
28225
28736
  publishPreliminary(details);
28226
28737
  };
28227
28738
  let session;
28228
- this.interactiveFastAnswerCallback = emitPreliminary;
28229
28739
  let unsubscribers = [];
28230
- this.resultCapture = (details) => {
28231
- captured = details;
28232
- };
28233
28740
  let searchStarted = false;
28234
28741
  try {
28235
28742
  const resolved = await this.resolveSessionModel();
@@ -28247,7 +28754,7 @@ ${context.text}
28247
28754
  model: resolved.model.id
28248
28755
  });
28249
28756
  searchStarted = true;
28250
- session = await this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })), [createEmitFastAnswerTool(emitPreliminary, { ledger: this.evidenceLedger })]);
28757
+ session = await this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })));
28251
28758
  this.activeSession = session;
28252
28759
  unsubscribers = this.configureSearchSession(session);
28253
28760
  let timeout;
@@ -28256,45 +28763,36 @@ ${context.text}
28256
28763
  await Promise.race([
28257
28764
  (async () => {
28258
28765
  const plan = await this.planQuery(trimmedQuery, resolved, planAbort.signal);
28259
- const sessionAgent = session.piSession;
28260
28766
  const activeSession = session;
28261
- const activateFastPhase = () => {
28262
- if (sessionAgent !== undefined) {
28263
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.fastThinkingLevel));
28264
- sessionAgent.setActiveToolsByName([
28265
- ...sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME),
28266
- EMIT_FAST_ANSWER_TOOL_NAME
28267
- ]);
28268
- } else {
28269
- activeSession.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.fastThinkingLevel);
28270
- activeSession.agent.state.tools = [
28271
- ...this.tools,
28272
- { name: EMIT_FAST_ANSWER_TOOL_NAME }
28273
- ];
28274
- }
28767
+ const sessionAgent = activeSession.piSession;
28768
+ const transcript = () => sessionAgent?.messages ?? activeSession.agent.state.messages;
28769
+ const setThinking = (level) => {
28770
+ const clamped = clampThinkingLevel(resolved.model, level);
28771
+ if (sessionAgent !== undefined)
28772
+ sessionAgent.setThinkingLevel(clamped);
28773
+ else
28774
+ activeSession.agent.state.thinkingLevel = clamped;
28275
28775
  };
28276
28776
  if (plan.route === "config" && plan.selfConfigSkill !== undefined && this.selfConfig !== undefined) {
28277
28777
  selfConfigRun = true;
28278
28778
  mkdirSync25(this.workspaceProjectRoot, { recursive: true });
28279
28779
  const previousTools = sessionAgent?.getActiveToolNames();
28280
- if (sessionAgent !== undefined) {
28281
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.finalThinkingLevel));
28282
- sessionAgent.setActiveToolsByName([...PI_BUILTIN_TOOL_NAMES, EMIT_AUTORAG_RESULTS_TOOL_NAME]);
28283
- } else {
28284
- activeSession.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
28285
- activeSession.agent.state.tools = this.tools.filter((tool) => tool.name === EMIT_AUTORAG_RESULTS_TOOL_NAME);
28286
- }
28780
+ setThinking(this.finalThinkingLevel);
28781
+ if (sessionAgent !== undefined)
28782
+ sessionAgent.setActiveToolsByName([...PI_BUILTIN_TOOL_NAMES]);
28783
+ else
28784
+ activeSession.agent.state.tools = [];
28287
28785
  const configBefore = snapshotConfigFile(this.selfConfig.configPath);
28288
28786
  try {
28289
- await session.prompt(buildSelfConfigPrompt({
28787
+ await activeSession.prompt(buildSelfConfigPrompt({
28290
28788
  query: trimmedQuery,
28291
28789
  configPath: this.selfConfig.configPath,
28292
28790
  agentDir: this.piAgentDir ?? getAgentDir3(),
28293
28791
  skill: plan.selfConfigSkill
28294
28792
  }));
28295
- if (captured === undefined && !planAbort.signal.aborted && lastModelRequestError(session.piSession?.messages ?? session.agent.state.messages) === undefined) {
28296
- await session.prompt(buildFinalEmitReminder());
28297
- }
28793
+ const report = finalAnswerText(transcript());
28794
+ if (report !== undefined)
28795
+ captured = this.deriveAnswer(report);
28298
28796
  const rolledBack = await rollbackIfBroken(this.selfConfig, configBefore);
28299
28797
  if (rolledBack !== undefined) {
28300
28798
  this.routingDiagnostics.push({
@@ -28303,11 +28801,10 @@ ${context.text}
28303
28801
  message: `The edited config did not validate, so the previous config was restored. ${rolledBack}`,
28304
28802
  source: "self-config"
28305
28803
  });
28306
- const emitted = captured;
28307
- if (emitted !== undefined) {
28804
+ if (captured !== undefined) {
28308
28805
  captured = {
28309
- ...emitted,
28310
- answer: `${emitted.answer}
28806
+ ...captured,
28807
+ answer: `${captured.answer}
28311
28808
 
28312
28809
  Warning: the edited config did not validate, so the previous config was restored (nothing was changed). Problem: ${rolledBack}`
28313
28810
  };
@@ -28321,49 +28818,35 @@ Warning: the edited config did not validate, so the previous config was restored
28321
28818
  return;
28322
28819
  }
28323
28820
  if (plan.route === "direct") {
28324
- activateFastPhase();
28325
- await session.prompt(this.buildDirectAnswerPrompt(trimmedQuery));
28326
- const answer = fastCaptured?.answer ?? lastAssistantText(session.piSession?.messages ?? session.agent.state.messages);
28821
+ setThinking(this.fastThinkingLevel);
28822
+ await activeSession.prompt(this.buildDirectAnswerPrompt(trimmedQuery));
28823
+ const answer = finalAnswerText(transcript());
28327
28824
  if (answer !== undefined)
28328
- captured = { answer, results: [], mapping: [], warnings: [] };
28825
+ captured = this.deriveAnswer(answer);
28329
28826
  return;
28330
28827
  }
28331
28828
  const baseline = await this.prefetchInitialRetrievalContext(trimmedQuery, plan.queries, options, plan.datasources);
28332
- activateFastPhase();
28333
- await session.prompt(this.buildFastAnswerPrompt(trimmedQuery, options, baseline));
28334
- let preliminary = fastCaptured;
28335
- if (preliminary === undefined) {
28336
- const text = lastAssistantText(session.piSession?.messages ?? session.agent.state.messages);
28337
- if (text !== undefined)
28338
- preliminary = { answer: text, results: [], sources: [], evidenceRefs: [] };
28339
- }
28340
- if (preliminary !== undefined)
28341
- emitPreliminary(preliminary);
28342
- if (captured !== undefined)
28343
- return;
28829
+ setThinking(this.fastThinkingLevel);
28830
+ await activeSession.prompt(this.buildFastAnswerPrompt(trimmedQuery, options, baseline));
28831
+ const fastText = finalAnswerText(transcript());
28832
+ const preliminary = fastText === undefined ? undefined : this.deriveAnswer(fastText);
28344
28833
  if (preliminary !== undefined) {
28834
+ emitPreliminary(preliminary);
28345
28835
  const followUp = await this.shouldFollowUp(trimmedQuery, preliminary);
28346
28836
  if (planAbort.signal.aborted)
28347
28837
  return;
28348
28838
  if (!followUp) {
28349
- captured = fastAnswerAsFinal(preliminary);
28839
+ captured = preliminary;
28350
28840
  return;
28351
28841
  }
28352
- }
28353
- if (preliminary !== undefined)
28354
28842
  publishPreliminary(preliminary);
28355
- if (sessionAgent !== undefined) {
28356
- sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.finalThinkingLevel));
28357
- sessionAgent.setActiveToolsByName(sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
28358
- } else {
28359
- session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
28360
- session.agent.state.tools = [...this.tools];
28361
28843
  }
28844
+ setThinking(this.finalThinkingLevel);
28362
28845
  const fastAnswerDelivered = preliminary !== undefined && this.preliminaryCallback !== undefined;
28363
- await session.prompt(this.buildRefinementPrompt(trimmedQuery, options, preliminary, fastAnswerDelivered));
28364
- if (captured === undefined && !planAbort.signal.aborted && this.searchToolCallCount < this.maxSearchToolCalls && lastModelRequestError(session.piSession?.messages ?? session.agent.state.messages) === undefined) {
28365
- await session.prompt(buildFinalEmitReminder());
28366
- }
28846
+ await activeSession.prompt(this.buildRefinementPrompt(trimmedQuery, options, fastText, fastAnswerDelivered));
28847
+ const finalText = finalAnswerText(transcript());
28848
+ if (finalText !== undefined)
28849
+ captured = this.deriveAnswer(finalText);
28367
28850
  })(),
28368
28851
  new Promise((resolve, reject) => {
28369
28852
  timeout = setTimeout(() => {
@@ -28383,7 +28866,7 @@ Warning: the edited config did not validate, so the previous config was restored
28383
28866
  clearTimeout(timeout);
28384
28867
  }
28385
28868
  if (captured === undefined && timedOutAfterFastAnswer && fastCaptured !== undefined) {
28386
- const response = recordStructuredResultsSession(sessionId, trimmedQuery, fastAnswerAsFinal(fastCaptured), this.sessions, this.memory, [
28869
+ const response = recordStructuredResultsSession(sessionId, trimmedQuery, fastCaptured, this.memory, [
28387
28870
  ...this.collectComponentDiagnostics(),
28388
28871
  {
28389
28872
  code: "search-timeout",
@@ -28417,15 +28900,15 @@ Warning: the edited config did not validate, so the previous config was restored
28417
28900
  sessionId,
28418
28901
  query: trimmedQuery,
28419
28902
  results: [],
28420
- answer: buildMissingFinalEmitAnswer(trimmedQuery, reason, this.retrievalTrace, modelError),
28903
+ answer: buildMissingFinalAnswer(trimmedQuery, reason, this.retrievalTrace, modelError),
28421
28904
  searched: this.retrievalTrace.reduce((total, entry) => total + entry.resultCount, 0),
28422
28905
  warnings: [],
28423
28906
  diagnostics: [
28424
28907
  ...this.collectComponentDiagnostics(),
28425
28908
  {
28426
- code: "missing-final-emit",
28909
+ code: "no-final-answer",
28427
28910
  severity: "warning",
28428
- message: "The agent ended its run without calling emit_autorag_results; returning a degraded response that carries the run's retrieval trace."
28911
+ message: "The agent ended its run without a final answer message; returning a degraded response that carries the run's retrieval trace."
28429
28912
  },
28430
28913
  ...modelError === undefined ? [] : [
28431
28914
  {
@@ -28471,7 +28954,7 @@ Warning: the edited config did not validate, so the previous config was restored
28471
28954
  source: "agent"
28472
28955
  });
28473
28956
  }
28474
- const recorded = recordStructuredResultsSession(sessionId, trimmedQuery, captured, this.sessions, this.memory, componentDiagnostics, { isolateMemory: this.remoteSession || selfConfigRun });
28957
+ const recorded = recordStructuredResultsSession(sessionId, trimmedQuery, captured, this.memory, componentDiagnostics, { isolateMemory: this.remoteSession || selfConfigRun });
28475
28958
  const memoryDiagnostic = selfConfigRun ? undefined : await this.recordJudgedEvidence(sessionId, trimmedQuery, captured);
28476
28959
  const response = memoryDiagnostic === undefined ? recorded : { ...recorded, diagnostics: [...recorded.diagnostics ?? [], memoryDiagnostic] };
28477
28960
  this.runLogger.write({
@@ -28512,36 +28995,25 @@ Warning: the edited config did not validate, so the previous config was restored
28512
28995
  });
28513
28996
  }
28514
28997
  this.activeSession = undefined;
28515
- this.resultCapture = undefined;
28516
28998
  this.activeRetrievalOptions = undefined;
28517
28999
  this.preliminaryCallback = undefined;
28518
- if (this.interactiveFastAnswerCallback === emitPreliminary)
28519
- this.interactiveFastAnswerCallback = undefined;
28520
29000
  this.activeRun = false;
28521
29001
  this.memoryContextCache = undefined;
28522
29002
  }
28523
29003
  }
28524
29004
  async* searchDocumentsStream(query, options = {}) {
28525
29005
  const queue = [];
28526
- let progressBuffer = "";
28527
29006
  let wake;
28528
29007
  let settled = false;
28529
29008
  const unsubscribe = this.subscribe((event) => {
28530
- if (event.type !== "message_update" || event.assistantMessageEvent.type !== "text_delta")
29009
+ if (event.type !== "message_end" || event.message.role !== "assistant")
28531
29010
  return;
28532
- const text = event.assistantMessageEvent.delta;
28533
- if (text.trim().length === 0)
29011
+ if (event.message.stopReason !== "toolUse")
28534
29012
  return;
28535
- progressBuffer += text;
28536
- if (!/[.!?。!?]\s*$/u.test(progressBuffer))
29013
+ const text = event.message.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
29014
+ if (text === "")
28537
29015
  return;
28538
- queue.push({
28539
- type: "progress",
28540
- sessionId: this.lastSessionId ?? "",
28541
- query: query.trim(),
28542
- text: progressBuffer
28543
- });
28544
- progressBuffer = "";
29016
+ queue.push({ type: "progress", sessionId: this.lastSessionId ?? "", query: query.trim(), text });
28545
29017
  wake?.();
28546
29018
  wake = undefined;
28547
29019
  });
@@ -28557,15 +29029,6 @@ Warning: the edited config did not validate, so the previous config was restored
28557
29029
  wake = undefined;
28558
29030
  };
28559
29031
  const run = this.searchDocuments(query, options).then((response) => {
28560
- if (progressBuffer.trim() !== "") {
28561
- queue.push({
28562
- type: "progress",
28563
- sessionId: this.lastSessionId ?? "",
28564
- query: query.trim(),
28565
- text: progressBuffer
28566
- });
28567
- progressBuffer = "";
28568
- }
28569
29032
  queue.push({ type: "complete", response });
28570
29033
  }).catch((error) => {
28571
29034
  settled = true;
@@ -28956,7 +29419,7 @@ ${result.content.replace(/\s+/gu, " ")}`).join(`
28956
29419
  }
28957
29420
  }
28958
29421
  buildFastAnswerPrompt(query, options, baseline) {
28959
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} knowledge units.` : "";
29422
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
28960
29423
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
28961
29424
  return `Answer this original query immediately: ${query}${limit}${scope}
28962
29425
 
@@ -28968,21 +29431,18 @@ ${baseline}
28968
29431
  ` + `Formatting and content rules for the answer:
28969
29432
  ` + `- 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.
28970
29433
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
28971
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
28972
29434
  ` + `- ${ANSWER_CITATION_RULE}
28973
29435
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
28974
29436
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack" or "checked Drive but found nothing").
28975
29437
  ` + `- When evidence conflicts, treat the freshest (most recent) information as the correct source of truth.
28976
29438
  ` + `- 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.
28977
29439
 
28978
- ` + `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.`;
29440
+ ` + `Write the answer as your reply, then stop.`;
28979
29441
  }
28980
29442
  buildDirectAnswerPrompt(query) {
28981
29443
  return `Answer this query directly from your own general knowledge: ${query}
28982
29444
 
28983
- ` + `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.
28984
-
28985
- ` + `Call emit_fast_answer exactly once with the answer and an empty results list, then stop.`;
29445
+ ` + `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.`;
28986
29446
  }
28987
29447
  discoveryHint(sentence) {
28988
29448
  const names = this.tools.map((tool) => tool.name).filter((name) => name === JIKJI_FIND_TOOL_NAME || name === EVERYTHING_SEARCH_TOOL_NAME);
@@ -28996,22 +29456,20 @@ ${baseline}
28996
29456
  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. `;
28997
29457
  }
28998
29458
  buildRefinementPrompt(query, options, fastAnswer, fastAnswerDelivered) {
28999
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} curated results.` : "";
29459
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
29000
29460
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
29001
29461
  const firstAnswer = formatFirstAnswerContext(fastAnswer, fastAnswerDelivered);
29002
- const answerRules = fastAnswerDelivered ? `Formatting and content rules for the final \`answer\` (DELTA ONLY):
29003
- ` + `- 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.
29462
+ const answerRules = fastAnswerDelivered ? `Formatting and content rules for your final answer (DELTA ONLY):
29463
+ ` + `- 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.
29004
29464
  ` + `- NEVER restate or re-list first-answer facts that remain correct, and never repeat its bullet list.
29005
29465
  ` + `- Mark each item clearly as a correction or as a new finding.
29006
29466
  ` + `- 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.
29007
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
29008
- ` + `- ${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.
29467
+ ` + `- ${ANSWER_CITATION_RULE} A correction or new finding that relies on evidence the first answer cited must cite that evidence's id again.
29009
29468
  ` + `- ${ANSWER_IMAGE_EMBED_RULE} ${ANSWER_IMAGE_DELTA_RULE}
29010
29469
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
29011
29470
  ` + `- 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):
29012
29471
  ` + `- 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.
29013
29472
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
29014
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
29015
29473
  ` + `- ${ANSWER_CITATION_RULE}
29016
29474
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
29017
29475
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
@@ -29020,35 +29478,34 @@ ${baseline}
29020
29478
 
29021
29479
  ` + `${firstAnswer}
29022
29480
 
29023
- ` + `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.
29481
+ ` + `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()}
29024
29482
 
29025
29483
  ` + `${answerRules}
29026
29484
 
29027
- ` + `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.`;
29485
+ ` + `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.`;
29028
29486
  }
29029
29487
  buildSearchPrompt(query, options, initialRetrievalContext) {
29030
- const limit = typeof options.topK === "number" ? ` Return at most ${options.topK} curated results.` : "";
29488
+ const limit = typeof options.topK === "number" ? ` Cite at most ${options.topK} sources.` : "";
29031
29489
  const scope = options.scope ? ` Restrict search to virtual path scope ${options.scope}.` : "";
29032
29490
  return `Find and curate information for this original query: ${query}${limit}${scope}
29033
29491
 
29034
- ` + `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.
29492
+ ` + `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.
29035
29493
 
29036
29494
  ` + `Baseline retrieval context:
29037
29495
  ${initialRetrievalContext ?? "Pending; continue only with a brief progress statement."}
29038
29496
 
29039
- ` + `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.
29497
+ ` + `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.
29040
29498
 
29041
29499
  ` + `Formatting and content rules for the answer:
29042
29500
  ` + `- 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.
29043
29501
  ` + `- Answer the question directly. Do not include specific file paths, datasource descriptions, or retrieval mechanics in the answer text.
29044
- ` + `- Cite evidence with bracketed numbers only (e.g. [1], [2]); do not quote raw chunks or mention source paths directly in the answer.
29045
29502
  ` + `- ${ANSWER_CITATION_RULE}
29046
29503
  ` + `- ${ANSWER_IMAGE_EMBED_RULE}
29047
29504
  ` + `- Do not report per-source negative findings (e.g. "no information found in Slack").
29048
29505
  ` + `- When evidence conflicts, treat the freshest (most recent) information as the correct source of truth.
29049
29506
  ` + `- If information is incomplete or uncertain, acknowledge it briefly without lengthy explanations. If there are partial clues or leads, mention them concisely.
29050
29507
 
29051
- ` + `${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.`;
29508
+ ` + `${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.`;
29052
29509
  }
29053
29510
  async refresh(force = false, opts) {
29054
29511
  const methods = opts?.methods;
@@ -29680,57 +30137,21 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
29680
30137
  function formatRerankedBaseline(results, evidenceIds) {
29681
30138
  const lines = results.map((result, index) => `[${evidenceIds[index]}] ${result.source}
29682
30139
  ${result.content.replace(/\s+/gu, " ")}`);
29683
- return `Reranked initial candidates (ordered by relevance to the query; cite evidence by its [eN] id in refs):
30140
+ return `Reranked initial candidates (ordered by relevance to the query; cite evidence by its [eN] id):
29684
30141
  ${lines.join(`
29685
30142
  `)}`;
29686
30143
  }
29687
- function fastAnswerAsFinal(fastAnswer) {
29688
- const refsByNumber = new Map(fastAnswer.evidenceRefs.map((entry) => [entry.number, entry.refs]));
29689
- return {
29690
- answer: fastAnswer.answer,
29691
- results: fastAnswer.results.map((result) => ({
29692
- number: result.number,
29693
- title: result.title,
29694
- summary: result.summary,
29695
- evidence: result.evidence,
29696
- confidence: result.confidence ?? 0.5
29697
- })),
29698
- mapping: fastAnswer.results.map((result) => {
29699
- const refs = refsByNumber.get(result.number) ?? [];
29700
- const primary = refs[0];
29701
- return {
29702
- number: result.number,
29703
- source: primary?.source ?? "",
29704
- method: primary?.method ?? EMIT_FAST_ANSWER_TOOL_NAME,
29705
- content: primary?.content ?? (result.evidence.map((evidence) => evidence.excerpt).join(`
29706
- `) || result.summary),
29707
- evidenceRefs: refs
29708
- };
29709
- }),
29710
- warnings: []
29711
- };
29712
- }
29713
30144
  function formatFirstAnswerContext(fastAnswer, delivered) {
29714
30145
  if (fastAnswer === undefined) {
29715
30146
  return "(the fast phase produced no answer — write the complete answer)";
29716
30147
  }
29717
- 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:";
29718
- const units = fastAnswer.results.length === 0 ? "" : `
29719
-
29720
- Numbered units of that first answer (its own numbering — NOT citation numbers for your final answer; cite only the results you emit):
29721
- ${fastAnswer.results.map((result) => `[${result.number}] ${result.title} — ${result.summary}`).join(`
29722
- `)}`;
29723
- const sources = fastAnswer.sources.length === 0 ? "" : `
29724
-
29725
- Sources of that first answer:
29726
- ${fastAnswer.sources.map((entry) => `[${entry.number}] -> ${entry.source}`).join(`
29727
- `)}`;
30148
+ 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:";
29728
30149
  return `${header}
29729
- ${fastAnswer.answer}${units}${sources}`;
30150
+ ${fastAnswer}`;
29730
30151
  }
29731
- function buildMissingFinalEmitAnswer(query, reason, trace, modelError) {
30152
+ function buildMissingFinalAnswer(query, reason, trace, modelError) {
29732
30153
  const lines = [
29733
- `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.`,
30154
+ `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.`,
29734
30155
  ...modelError === undefined ? [] : [`The model request failed: ${modelError}`],
29735
30156
  ...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}"`],
29736
30157
  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.",
@@ -29751,8 +30172,17 @@ function lastModelRequestError(messages) {
29751
30172
  }
29752
30173
  return;
29753
30174
  }
29754
- function buildFinalEmitReminder() {
29755
- 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.`;
30175
+ function finalAnswerText(messages) {
30176
+ for (let index = messages.length - 1;index >= 0; index--) {
30177
+ const message = messages[index];
30178
+ if (message.role !== "assistant")
30179
+ continue;
30180
+ if (message.stopReason !== "stop")
30181
+ return;
30182
+ const text = message.content.filter((block) => block.type === "text").map((block) => block.text).join("").trim();
30183
+ return text === "" ? undefined : text;
30184
+ }
30185
+ return;
29756
30186
  }
29757
30187
  function lastAssistantText(messages) {
29758
30188
  for (let index = messages.length - 1;index >= 0; index--) {
@@ -29901,7 +30331,7 @@ var init_agent = __esm(() => {
29901
30331
  init_context();
29902
30332
  init_memory();
29903
30333
  init_similar_queries();
29904
- init_errors3();
30334
+ init_errors4();
29905
30335
  init_minsync();
29906
30336
  init_paths();
29907
30337
  init_sync();
@@ -29914,13 +30344,12 @@ var init_agent = __esm(() => {
29914
30344
  init_rerank();
29915
30345
  init_scope();
29916
30346
  init_model_auth();
30347
+ init_answer_citations();
29917
30348
  init_datasource_skill();
29918
30349
  init_dupey_tool();
29919
- init_emit_results_tool();
29920
30350
  init_everything_search_tool();
29921
30351
  init_evidence_judgment();
29922
30352
  init_evidence_ledger();
29923
- init_fast_answer_tool();
29924
30353
  init_fsearch_search_tool();
29925
30354
  init_jev_extension();
29926
30355
  init_jikji_find_tool();
@@ -30009,7 +30438,7 @@ var ALL_METHOD_NAMES;
30009
30438
  var init_refresh = __esm(() => {
30010
30439
  init_agent();
30011
30440
  init_embedding_runtime();
30012
- init_config2();
30441
+ init_config3();
30013
30442
  ALL_METHOD_NAMES = ["all", "minsync", "parsed", "datasources", "jikji", "everything", "fsearch"];
30014
30443
  });
30015
30444
 
@@ -30028,7 +30457,7 @@ async function runStatus(ctx) {
30028
30457
  }
30029
30458
  var init_status = __esm(() => {
30030
30459
  init_agent();
30031
- init_config2();
30460
+ init_config3();
30032
30461
  });
30033
30462
 
30034
30463
  // src/cli/commands/search.ts
@@ -30177,7 +30606,7 @@ var HEALTH_HINT_MESSAGE = "Run autorag health to diagnose model/provider setup."
30177
30606
  var init_search2 = __esm(() => {
30178
30607
  init_agent();
30179
30608
  init_embedding_runtime();
30180
- init_config2();
30609
+ init_config3();
30181
30610
  AUTH_PATTERNS = [
30182
30611
  "api key",
30183
30612
  "apikey",
@@ -30275,7 +30704,7 @@ async function runEvidence(ctx) {
30275
30704
  }
30276
30705
  var init_evidence = __esm(() => {
30277
30706
  init_memory();
30278
- init_config2();
30707
+ init_config3();
30279
30708
  });
30280
30709
 
30281
30710
  // src/cli/commands/memory.ts
@@ -30299,7 +30728,7 @@ async function runMemory(ctx) {
30299
30728
  var USAGE = "Usage: autorag memory inspect";
30300
30729
  var init_memory2 = __esm(() => {
30301
30730
  init_memory();
30302
- init_config2();
30731
+ init_config3();
30303
30732
  });
30304
30733
 
30305
30734
  // src/cli/commands/index.ts
@@ -30411,7 +30840,7 @@ var init_commands = __esm(() => {
30411
30840
  init_refresh_progress();
30412
30841
  init_paths5();
30413
30842
  init_paths();
30414
- init_config2();
30843
+ init_config3();
30415
30844
  init_refresh();
30416
30845
  ALL_RESET_TARGETS = [PARSED_MIRROR_SUBDIR, MINSYNC_SUBDIR];
30417
30846
  ALL_RESET_TARGET_NAMES = ["parsed", "minsync"];
@@ -30479,7 +30908,7 @@ async function runWatch(ctx) {
30479
30908
  }
30480
30909
  var init_watch = __esm(() => {
30481
30910
  init_agent();
30482
- init_config2();
30911
+ init_config3();
30483
30912
  });
30484
30913
 
30485
30914
  // src/cli/commands/health.ts
@@ -30679,7 +31108,7 @@ async function runHealth(ctx, deps = {}) {
30679
31108
  }
30680
31109
  var DEFAULT_TIMEOUT_MS10 = 1e4;
30681
31110
  var init_health = __esm(() => {
30682
- init_config2();
31111
+ init_config3();
30683
31112
  });
30684
31113
 
30685
31114
  // src/cli/commands/duplicates.ts
@@ -30736,7 +31165,7 @@ function exactGroupsFromScan(scan) {
30736
31165
  }
30737
31166
  var init_duplicates = __esm(() => {
30738
31167
  init_dupey();
30739
- init_config2();
31168
+ init_config3();
30740
31169
  });
30741
31170
 
30742
31171
  // src/cli/update-check.ts
@@ -30881,7 +31310,7 @@ var THINKING_LEVELS2;
30881
31310
  var init_tui = __esm(() => {
30882
31311
  init_agent();
30883
31312
  init_pi_session();
30884
- init_config2();
31313
+ init_config3();
30885
31314
  init_update_check();
30886
31315
  init_version();
30887
31316
  THINKING_LEVELS2 = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
@@ -31069,7 +31498,7 @@ var init_serve = __esm(() => {
31069
31498
  init_policy();
31070
31499
  init_simplex_server();
31071
31500
  init_simplex_transport();
31072
- init_config2();
31501
+ init_config3();
31073
31502
  });
31074
31503
 
31075
31504
  // src/cli/commands/p2p.ts
@@ -31285,7 +31714,7 @@ function readLocalFlags(flags) {
31285
31714
  var init_p2p = __esm(() => {
31286
31715
  init_approval_store();
31287
31716
  init_simplex_server();
31288
- init_config2();
31717
+ init_config3();
31289
31718
  });
31290
31719
 
31291
31720
  // src/cli/commands/p2p-policy.ts
@@ -31447,6 +31876,7 @@ async function listModelCatalog(options) {
31447
31876
  modelsPath: join40(agentDir, "models.json"),
31448
31877
  allowModelNetwork: false
31449
31878
  });
31879
+ await registerAutoRAGProvider(runtime);
31450
31880
  const key = (provider, id) => `${provider}/${id}`;
31451
31881
  let availableKeys = new Set;
31452
31882
  try {
@@ -31526,7 +31956,8 @@ async function runModels(ctx, deps = {}) {
31526
31956
  }
31527
31957
  }
31528
31958
  var UsageError;
31529
- var init_models = __esm(() => {
31959
+ var init_models2 = __esm(() => {
31960
+ init_provider();
31530
31961
  init_embedding_runtime();
31531
31962
  UsageError = class UsageError extends Error {
31532
31963
  };
@@ -31606,7 +32037,6 @@ class AutoRAGLite {
31606
32037
  agent;
31607
32038
  retrievalEngine;
31608
32039
  memory;
31609
- sessions = new Map;
31610
32040
  constructor(config) {
31611
32041
  this.config = config;
31612
32042
  const agentOptions = buildAgentOptions(config);
@@ -31661,14 +32091,11 @@ class AutoRAGLite {
31661
32091
  return this.retrievalEngine.retrieveByMethod(query, options);
31662
32092
  }
31663
32093
  recordStructuredResultsSession(sessionId, query, details) {
31664
- return recordStructuredResultsSession(sessionId, query, details, this.sessions, this.memory);
32094
+ return recordStructuredResultsSession(sessionId, query, details, this.memory);
31665
32095
  }
31666
32096
  recordReport(query, details) {
31667
32097
  return this.recordStructuredResultsSession(randomUUID10(), query, details);
31668
32098
  }
31669
- getResultRegistry(sessionId) {
31670
- return this.sessions.get(sessionId)?.registry ?? new Map;
31671
- }
31672
32099
  getMemorySchema() {
31673
32100
  return structuredClone(this.memory.getSchema());
31674
32101
  }
@@ -31686,9 +32113,9 @@ function createAutoRAGLite(options = {}) {
31686
32113
  var init_core = __esm(() => {
31687
32114
  init_agent();
31688
32115
  init_search_documents();
31689
- init_config2();
32116
+ init_config3();
31690
32117
  init_memory();
31691
- init_config2();
32118
+ init_config3();
31692
32119
  });
31693
32120
 
31694
32121
  // src/cli/commands/lite-refresh.ts
@@ -31708,7 +32135,7 @@ async function runLiteRefresh(ctx) {
31708
32135
  }
31709
32136
  var init_lite_refresh = __esm(() => {
31710
32137
  init_core();
31711
- init_config2();
32138
+ init_config3();
31712
32139
  init_refresh();
31713
32140
  });
31714
32141
 
@@ -31950,6 +32377,60 @@ var init_lite_retrieve = __esm(() => {
31950
32377
  init_parser();
31951
32378
  });
31952
32379
 
32380
+ // src/agent/results.ts
32381
+ import { Type as Type17 } from "typebox";
32382
+ var evidenceRefSchema, answerSchema, warningsSchema, curatedResultFields, reportSchema;
32383
+ var init_results = __esm(() => {
32384
+ evidenceRefSchema = Type17.Object({
32385
+ method: Type17.String({ description: "Retrieval method namespace for this evidence chunk" }),
32386
+ source: Type17.String({ description: "Internal opaque source identifier for this evidence chunk" }),
32387
+ excerpt: Type17.Optional(Type17.String({ description: "Evidence excerpt used for stable ID normalization" })),
32388
+ content: Type17.Optional(Type17.String({ description: "Evidence content used for stable ID normalization" })),
32389
+ retrievalResultId: Type17.Optional(Type17.String({ description: "Backend retrieval ID when path-opaque and stable" })),
32390
+ chunkIndex: Type17.Optional(Type17.Integer({ description: "Chunk index, if available" })),
32391
+ lineNumber: Type17.Optional(Type17.Integer({ description: "Line number, if available" })),
32392
+ stableEvidenceId: Type17.Optional(Type17.String({ description: "Stable evidence ID, if already normalized" })),
32393
+ retrieverMix: Type17.Optional(Type17.Array(Type17.String({ maxLength: 64 }), {
32394
+ description: "Retrievers that contributed to this result",
32395
+ maxItems: 8
32396
+ })),
32397
+ parserType: Type17.Optional(Type17.String({ description: "Parser that produced this evidence", maxLength: 120 })),
32398
+ documentType: Type17.Optional(Type17.String({ description: "Document type, if known", maxLength: 120 })),
32399
+ documentArea: Type17.Optional(Type17.String({ description: "Document collection area, if known", maxLength: 120 })),
32400
+ evidenceType: Type17.Optional(Type17.String({ description: "Evidence type, if known", maxLength: 120 })),
32401
+ evidenceLocation: Type17.Optional(Type17.String({ description: "Human-readable evidence location", maxLength: 120 })),
32402
+ confidence: Type17.Optional(Type17.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
32403
+ });
32404
+ answerSchema = Type17.String({
32405
+ 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}`
32406
+ });
32407
+ warningsSchema = Type17.Optional(Type17.Array(Type17.String(), { description: "Optional warnings about this result set" }));
32408
+ curatedResultFields = {
32409
+ number: Type17.Integer({ description: "1-based result number" }),
32410
+ title: Type17.String({ description: "Short name of the curated knowledge unit" }),
32411
+ summary: Type17.String({ description: "Key insight: purpose, details, and line range" }),
32412
+ evidence: Type17.Array(Type17.Object({
32413
+ excerpt: Type17.String({ description: "Supporting excerpt" }),
32414
+ lineNumber: Type17.Optional(Type17.Integer({ description: "Line number of the excerpt, if known" }))
32415
+ })),
32416
+ confidence: Type17.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
32417
+ };
32418
+ reportSchema = Type17.Object({
32419
+ answer: answerSchema,
32420
+ results: Type17.Array(Type17.Object(curatedResultFields), { description: "Numbered curated knowledge units." }),
32421
+ mapping: Type17.Array(Type17.Object({
32422
+ number: Type17.Integer({ description: "Matches the result number this entry maps" }),
32423
+ source: Type17.String({ description: "Source identifier — a real file path or a datasource id" }),
32424
+ method: Type17.String({ description: "Retrieval method or tool that produced the source" }),
32425
+ content: Type17.String({ description: "Raw content snippet of the evidence behind this result" }),
32426
+ evidenceRefs: Type17.Optional(Type17.Array(evidenceRefSchema, {
32427
+ description: "Hidden evidence chunk references supporting this curated result"
32428
+ }))
32429
+ }), { description: "Internal number -> source/method mapping. One entry per result number." }),
32430
+ warnings: warningsSchema
32431
+ });
32432
+ });
32433
+
31953
32434
  // src/cli/commands/report.ts
31954
32435
  import { readFileSync as readFileSync28 } from "node:fs";
31955
32436
  import { Value as Value3 } from "typebox/value";
@@ -32045,9 +32526,9 @@ async function runReport(ctx) {
32045
32526
  }
32046
32527
  var MAX_REPORTED_SCHEMA_ERRORS = 8;
32047
32528
  var init_report = __esm(() => {
32048
- init_emit_results_tool();
32529
+ init_results();
32049
32530
  init_core();
32050
- init_config2();
32531
+ init_config3();
32051
32532
  });
32052
32533
 
32053
32534
  // src/cli/commands/lite.ts
@@ -32321,8 +32802,9 @@ var COMMAND_USAGE = {
32321
32802
  " /resume, /new, /tree Resume, start, or branch sessions",
32322
32803
  " /compact, /settings Compact context, edit settings",
32323
32804
  "",
32324
- "AutoRAG streams progress, preliminary answers, and final results into the",
32325
- "same session and adds its retrieval tools.",
32805
+ "AutoRAG adds its retrieval tools and runs the two-phase search in the same",
32806
+ "session: the model's progress notes, first answer, and final answer are",
32807
+ "ordinary assistant messages in it.",
32326
32808
  "",
32327
32809
  "Flags:",
32328
32810
  " --fast-thinking <lvl> Thinking level for the fast first answer",
@@ -32675,7 +33157,7 @@ async function dispatch(command, ctx) {
32675
33157
  return dispatchLite(ctx);
32676
33158
  }
32677
33159
  case "models": {
32678
- await Promise.resolve().then(() => init_models());
33160
+ await Promise.resolve().then(() => init_models2());
32679
33161
  return runModels(ctx);
32680
33162
  }
32681
33163
  case "gateway": {