@autorag/librarian 2.6.3 → 2.7.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.
package/dist/cli/index.js CHANGED
@@ -10488,8 +10488,9 @@ function createReranker(config) {
10488
10488
  if (config === false || config === undefined)
10489
10489
  return;
10490
10490
  const provider = config.provider ?? DEFAULT_RERANK_PROVIDER;
10491
- if (provider !== DEFAULT_RERANK_PROVIDER)
10492
- return;
10491
+ if (!SUPPORTED_RERANK_PROVIDERS.includes(provider)) {
10492
+ throw new Error(`Unsupported rerank provider "${provider}"; supported providers: ${SUPPORTED_RERANK_PROVIDERS.join(", ")}`);
10493
+ }
10493
10494
  return new OpenRouterReranker(config);
10494
10495
  }
10495
10496
 
@@ -10518,8 +10519,8 @@ class OpenRouterReranker {
10518
10519
  sdkOptions.timeoutMs = options.timeoutMs;
10519
10520
  const sdk = new OpenRouter(sdkOptions);
10520
10521
  this.client = {
10521
- rerank: async (request) => {
10522
- const response = await sdk.rerank.rerank(request);
10522
+ rerank: async (request, requestOptions) => {
10523
+ const response = await sdk.rerank.rerank(request, requestOptions);
10523
10524
  if (typeof response === "string")
10524
10525
  throw new Error(response);
10525
10526
  return response;
@@ -10548,7 +10549,7 @@ class OpenRouterReranker {
10548
10549
  };
10549
10550
  if (options.topN !== undefined)
10550
10551
  requestBody.topN = options.topN;
10551
- const response = await this.client.rerank({ requestBody });
10552
+ const response = await this.client.rerank({ requestBody }, { signal: options.signal });
10552
10553
  const ordered = Array.isArray(response?.results) ? response.results : [];
10553
10554
  const seen = new Set;
10554
10555
  const reranked = [];
@@ -10578,8 +10579,10 @@ class OpenRouterReranker {
10578
10579
  return reranked;
10579
10580
  }
10580
10581
  }
10581
- var DEFAULT_RERANK_MODEL = "voyageai/rerank-3-lite", DEFAULT_RERANK_PROVIDER = "openrouter", DEFAULT_RERANK_API_KEY_ENV = "OPENROUTER_API_KEY";
10582
- var init_rerank = () => {};
10582
+ var DEFAULT_RERANK_MODEL = "voyageai/rerank-3-lite", DEFAULT_RERANK_PROVIDER = "openrouter", DEFAULT_RERANK_API_KEY_ENV = "OPENROUTER_API_KEY", SUPPORTED_RERANK_PROVIDERS;
10583
+ var init_rerank = __esm(() => {
10584
+ SUPPORTED_RERANK_PROVIDERS = [DEFAULT_RERANK_PROVIDER];
10585
+ });
10583
10586
 
10584
10587
  // src/web/search/types.ts
10585
10588
  function isSearchProviderId(value) {
@@ -10679,7 +10682,8 @@ var init_types4 = __esm(() => {
10679
10682
  import { randomUUID as randomUUID3 } from "node:crypto";
10680
10683
  import { existsSync as existsSync9, mkdirSync as mkdirSync10, readFileSync as readFileSync10, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "node:fs";
10681
10684
  import { basename as basename7, dirname as dirname10, isAbsolute as isAbsolute4, join as join13, resolve as resolve6 } from "node:path";
10682
- import { findEnvKeys, getEnvApiKey, getModel, getProviders } from "@earendil-works/pi-ai/compat";
10685
+ import { findEnvKeys, getEnvApiKey } from "@earendil-works/pi-ai/compat";
10686
+ import { getAgentDir, ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
10683
10687
  function resolveConfigPath(input) {
10684
10688
  const flags = input.flags;
10685
10689
  const env = input.env ?? process.env;
@@ -11402,6 +11406,9 @@ function normalizeRerankConfig(raw, path) {
11402
11406
  }
11403
11407
  out.provider = record.provider.trim();
11404
11408
  }
11409
+ if (!SUPPORTED_RERANK_PROVIDERS.includes(out.provider ?? "")) {
11410
+ throw new ConfigError(`${path}.provider must be one of: ${SUPPORTED_RERANK_PROVIDERS.join(", ")}`);
11411
+ }
11405
11412
  if (record.model !== undefined) {
11406
11413
  if (typeof record.model !== "string" || record.model.trim() === "") {
11407
11414
  throw new ConfigError(`${path}.model must be a non-empty string`);
@@ -11533,12 +11540,7 @@ function buildModelFromConfiguredEndpoint(reference) {
11533
11540
  maxTokens: reference.maxTokens ?? 16384
11534
11541
  };
11535
11542
  }
11536
- function resolveCatalogModel(reference) {
11537
- if (!getProviders().includes(reference.provider))
11538
- return;
11539
- const catalog = getModel(reference.provider, reference.id);
11540
- if (catalog === undefined)
11541
- return;
11543
+ function mergeCatalogModel(catalog, reference) {
11542
11544
  return {
11543
11545
  ...catalog,
11544
11546
  ...reference.name !== undefined ? { name: reference.name } : {},
@@ -11550,109 +11552,120 @@ function resolveCatalogModel(reference) {
11550
11552
  ...reference.maxTokens !== undefined ? { maxTokens: reference.maxTokens } : {}
11551
11553
  };
11552
11554
  }
11553
- function resolveRegisteredModel(reference) {
11554
- const catalog = resolveCatalogModel(reference);
11555
+ function resolveRuntimeCatalogModel(runtime, reference) {
11556
+ const catalog = runtime.getModel(reference.provider, reference.id);
11557
+ if (catalog === undefined)
11558
+ return;
11559
+ return mergeCatalogModel(catalog, reference);
11560
+ }
11561
+ function resolveRegisteredModel(runtime, reference) {
11562
+ const catalog = resolveRuntimeCatalogModel(runtime, reference);
11555
11563
  if (catalog !== undefined)
11556
11564
  return catalog;
11557
11565
  if (isConfiguredEndpoint(reference))
11558
11566
  return buildModelFromConfiguredEndpoint(reference);
11559
11567
  throw new ConfigError(`Unknown configured model: ${reference.provider}/${reference.id}. ${UNKNOWN_MODEL_HINT}`);
11560
11568
  }
11561
- function resolveBuiltInModel(reference) {
11569
+ function resolveBuiltInModel(runtime, reference) {
11562
11570
  if (reference === undefined)
11563
11571
  return;
11564
- const catalog = resolveCatalogModel(reference);
11572
+ const catalog = resolveRuntimeCatalogModel(runtime, reference);
11565
11573
  if (catalog !== undefined)
11566
11574
  return catalog;
11567
11575
  if (isConfiguredEndpoint(reference))
11568
11576
  return buildModelFromConfiguredEndpoint(reference);
11569
- if (getProviders().includes(reference.provider)) {
11577
+ if (runtime.getProvider(reference.provider) !== undefined) {
11570
11578
  throw new ConfigError(`Unknown configured model: ${reference.provider}/${reference.id}. ${UNKNOWN_MODEL_HINT}`);
11571
11579
  }
11572
11580
  return;
11573
11581
  }
11574
- function resolveModel(config) {
11582
+ function resolveAgentDir(options) {
11583
+ return options.agentDir ?? getAgentDir();
11584
+ }
11585
+ function getModelRuntime(agentDir) {
11586
+ const cached = modelRuntimeCache.get(agentDir);
11587
+ if (cached !== undefined)
11588
+ return cached;
11589
+ const created = ModelRuntime.create({
11590
+ authPath: join13(agentDir, "auth.json"),
11591
+ modelsPath: join13(agentDir, "models.json"),
11592
+ allowModelNetwork: false
11593
+ });
11594
+ modelRuntimeCache.set(agentDir, created);
11595
+ created.catch(() => {
11596
+ modelRuntimeCache.delete(agentDir);
11597
+ });
11598
+ return created;
11599
+ }
11600
+ async function resolveModel(config, options = {}) {
11575
11601
  if (!config.model) {
11576
11602
  throw new ConfigError('No model configured. Provide --model-provider and --model-id on the command line, or set the "model" key (with provider and id) in the config file.');
11577
11603
  }
11578
- return resolveRegisteredModel(config.model);
11604
+ const runtime = options.runtime ?? await getModelRuntime(resolveAgentDir(options));
11605
+ return resolveRegisteredModel(runtime, config.model);
11579
11606
  }
11580
- function resolveAgentModelCore(config, localOptions = {}) {
11581
- const modelRef = config.model;
11582
- const registered = resolveBuiltInModel(modelRef);
11583
- const needsLocal = modelRef === undefined || registered === undefined;
11584
- const localModelOptions = { ...localOptions, modelId: modelRef?.id };
11585
- const local = needsLocal ? loadLocalAutoRAGModel(localModelOptions) : undefined;
11586
- const model = registered ?? (modelRef === undefined || modelRef.provider === local?.provider ? local?.model : resolveRegisteredModel(modelRef));
11587
- const configuredEndpoint = isConfiguredEndpoint(modelRef);
11588
- const usesConfiguredEndpoint = configuredEndpoint;
11589
- const env = localOptions.env ?? process.env;
11590
- const fromLocal = registered === undefined && (modelRef === undefined || modelRef.provider === local?.provider);
11591
- const catalog = registered !== undefined && !configuredEndpoint;
11592
- if (local === undefined && !usesConfiguredEndpoint) {
11593
- return {
11594
- model,
11595
- modelRef,
11596
- fromLocal,
11597
- configuredEndpoint,
11598
- catalog,
11599
- local,
11600
- usesConfiguredEndpoint,
11601
- env
11602
- };
11603
- }
11604
- const providerApiKeys = {};
11605
- if (local !== undefined)
11606
- providerApiKeys[local.provider] = local.apiKey;
11607
- for (const ref of [modelRef]) {
11608
- if (!isConfiguredEndpoint(ref))
11609
- continue;
11610
- const envName = configuredApiKeyEnv(ref);
11611
- const value = env[envName];
11612
- if (typeof value === "string" && value.length > 0) {
11613
- providerApiKeys[ref.provider] = value;
11614
- }
11615
- }
11616
- const apiKey = local !== undefined && (modelRef === undefined || modelRef.provider === local.provider) ? local.apiKey : providerApiKeys[model.provider] !== undefined && usesConfiguredEndpoint ? providerApiKeys[model.provider] : undefined;
11607
+ function localFallbackOptions(options, modelId) {
11617
11608
  return {
11618
- model,
11619
- ...apiKey !== undefined ? { apiKey } : {},
11620
- ...Object.keys(providerApiKeys).length > 0 ? { providerApiKeys } : {},
11621
- modelRef,
11622
- fromLocal,
11623
- configuredEndpoint,
11624
- catalog,
11625
- local,
11626
- usesConfiguredEndpoint,
11627
- env
11609
+ ...options.configPath !== undefined ? { configPath: options.configPath } : {},
11610
+ ...options.env !== undefined ? { env: options.env } : {},
11611
+ ...modelId !== undefined ? { modelId } : {}
11628
11612
  };
11629
11613
  }
11630
- function resolveAgentModel(config, localOptions = {}) {
11631
- const core = resolveAgentModelCore(config, localOptions);
11614
+ function localRuntimeAuth(local) {
11632
11615
  return {
11633
- model: core.model,
11634
- ...core.apiKey !== undefined ? { apiKey: core.apiKey } : {},
11635
- ...core.providerApiKeys !== undefined ? { providerApiKeys: core.providerApiKeys } : {}
11616
+ apiKey: local.apiKey,
11617
+ providerApiKeys: { [local.provider]: local.apiKey },
11618
+ present: true,
11619
+ source: "local_runtime"
11636
11620
  };
11637
11621
  }
11638
- function providerApiKeyEnvName(provider) {
11639
- return `${provider.replace(/[^A-Za-z0-9_]/g, "_").toUpperCase()}_API_KEY`;
11640
- }
11641
- function resolveRoleAuth(model, fromLocal, local, providerApiKeys, configuredEndpoint, apiKeyEnv, env) {
11642
- if (fromLocal && local !== undefined && model.provider === local.provider) {
11643
- return { present: true, source: "local_runtime" };
11622
+ async function resolvePiDefaultModel(runtime, options) {
11623
+ let provider;
11624
+ let id;
11625
+ try {
11626
+ const settings = SettingsManager.create(options.cwd ?? process.cwd(), resolveAgentDir(options));
11627
+ provider = settings.getDefaultProvider();
11628
+ id = settings.getDefaultModel();
11629
+ } catch {
11630
+ return;
11644
11631
  }
11645
- if (configuredEndpoint) {
11646
- const envName = apiKeyEnv ?? providerApiKeyEnvName(model.provider);
11647
- if (providerApiKeys?.[model.provider] !== undefined) {
11648
- return { present: true, source: "env", envName };
11649
- }
11650
- const fromEnv = env[envName] ?? process.env[envName];
11651
- if (typeof fromEnv === "string" && fromEnv.length > 0) {
11652
- return { present: true, source: "env", envName };
11653
- }
11654
- return { present: false, source: "none", envName };
11632
+ if (provider === undefined || id === undefined)
11633
+ return;
11634
+ const model = runtime.getModel(provider, id);
11635
+ if (model === undefined)
11636
+ return;
11637
+ try {
11638
+ if (await runtime.checkAuth(provider) === undefined)
11639
+ return;
11640
+ } catch {
11641
+ return;
11655
11642
  }
11643
+ return model;
11644
+ }
11645
+ function resolveConfiguredEndpointAuth(reference, model, env) {
11646
+ const envName = configuredApiKeyEnv(reference);
11647
+ const value = env[envName];
11648
+ const providerApiKeys = typeof value === "string" && value.length > 0 ? { [model.provider]: value } : undefined;
11649
+ const fromProcessEnv = process.env[envName];
11650
+ const present = providerApiKeys !== undefined || typeof fromProcessEnv === "string" && fromProcessEnv.length > 0;
11651
+ return {
11652
+ ...providerApiKeys !== undefined ? { apiKey: providerApiKeys[model.provider], providerApiKeys } : {},
11653
+ present,
11654
+ source: present ? "env" : "none",
11655
+ envName
11656
+ };
11657
+ }
11658
+ async function resolveCatalogAuth(runtime, model, env) {
11659
+ try {
11660
+ const result = await runtime.getAuth(model);
11661
+ if (result !== undefined) {
11662
+ const apiKey = result.auth.apiKey;
11663
+ if (typeof apiKey === "string" && apiKey.length > 0) {
11664
+ return { apiKey, providerApiKeys: { [model.provider]: apiKey }, present: true, source: "pi_auth" };
11665
+ }
11666
+ return { present: true, source: "pi_auth" };
11667
+ }
11668
+ } catch {}
11656
11669
  const envKeys = findEnvKeys(model.provider);
11657
11670
  if (envKeys !== undefined && envKeys.length > 0) {
11658
11671
  for (const key of envKeys) {
@@ -11667,21 +11680,102 @@ function resolveRoleAuth(model, fromLocal, local, providerApiKeys, configuredEnd
11667
11680
  }
11668
11681
  return { present: false, source: "none", envName: envKeys[0] };
11669
11682
  }
11670
- const catalogKey = getEnvApiKey(model.provider);
11671
- if (catalogKey !== undefined) {
11683
+ if (getEnvApiKey(model.provider) !== undefined) {
11672
11684
  return { present: true, source: "catalog" };
11673
11685
  }
11674
11686
  return { present: false, source: "none", envName: providerApiKeyEnvName(model.provider) };
11675
11687
  }
11688
+ async function resolveAgentModelCore(config, options = {}) {
11689
+ const env = options.env ?? process.env;
11690
+ const runtime = options.runtime ?? await getModelRuntime(resolveAgentDir(options));
11691
+ const modelRef = config.model;
11692
+ if (modelRef !== undefined && isConfiguredEndpoint(modelRef)) {
11693
+ const catalogModel = resolveRuntimeCatalogModel(runtime, modelRef);
11694
+ const model = catalogModel ?? buildModelFromConfiguredEndpoint(modelRef);
11695
+ return {
11696
+ model,
11697
+ modelRef,
11698
+ fromLocal: false,
11699
+ configuredEndpoint: true,
11700
+ catalog: catalogModel !== undefined,
11701
+ local: undefined,
11702
+ env,
11703
+ auth: resolveConfiguredEndpointAuth(modelRef, model, env)
11704
+ };
11705
+ }
11706
+ const registered = resolveBuiltInModel(runtime, modelRef);
11707
+ if (registered !== undefined) {
11708
+ return {
11709
+ model: registered,
11710
+ modelRef,
11711
+ fromLocal: false,
11712
+ configuredEndpoint: false,
11713
+ catalog: true,
11714
+ local: undefined,
11715
+ env,
11716
+ auth: await resolveCatalogAuth(runtime, registered, env)
11717
+ };
11718
+ }
11719
+ if (modelRef === undefined) {
11720
+ const piDefault = await resolvePiDefaultModel(runtime, options);
11721
+ if (piDefault !== undefined) {
11722
+ return {
11723
+ model: piDefault,
11724
+ modelRef,
11725
+ fromLocal: false,
11726
+ configuredEndpoint: false,
11727
+ catalog: true,
11728
+ local: undefined,
11729
+ env,
11730
+ auth: await resolveCatalogAuth(runtime, piDefault, env)
11731
+ };
11732
+ }
11733
+ const local = loadLocalAutoRAGModel(localFallbackOptions(options, undefined));
11734
+ return {
11735
+ model: local.model,
11736
+ modelRef,
11737
+ fromLocal: true,
11738
+ configuredEndpoint: false,
11739
+ catalog: false,
11740
+ local,
11741
+ env,
11742
+ auth: localRuntimeAuth(local)
11743
+ };
11744
+ }
11745
+ const local = loadLocalAutoRAGModel(localFallbackOptions(options, modelRef.id));
11746
+ const fromLocal = modelRef.provider === local.provider;
11747
+ const model = fromLocal ? local.model : resolveRegisteredModel(runtime, modelRef);
11748
+ return {
11749
+ model,
11750
+ modelRef,
11751
+ fromLocal,
11752
+ configuredEndpoint: false,
11753
+ catalog: !fromLocal,
11754
+ local: fromLocal ? local : undefined,
11755
+ env,
11756
+ auth: fromLocal ? localRuntimeAuth(local) : await resolveCatalogAuth(runtime, model, env)
11757
+ };
11758
+ }
11759
+ async function resolveAgentModel(config, options = {}) {
11760
+ const core = await resolveAgentModelCore(config, options);
11761
+ return {
11762
+ model: core.model,
11763
+ ...core.auth.apiKey !== undefined ? { apiKey: core.auth.apiKey } : {},
11764
+ ...core.auth.providerApiKeys !== undefined ? { providerApiKeys: core.auth.providerApiKeys } : {}
11765
+ };
11766
+ }
11767
+ function providerApiKeyEnvName(provider) {
11768
+ return `${provider.replace(/[^A-Za-z0-9_]/g, "_").toUpperCase()}_API_KEY`;
11769
+ }
11676
11770
  function resolveRoleSource(ref, fromLocal, configuredEndpoint, catalog) {
11677
- if (ref === undefined)
11678
- return "local_runtime";
11679
11771
  if (configuredEndpoint)
11680
11772
  return "config";
11681
11773
  if (fromLocal)
11682
11774
  return "mixed";
11683
11775
  if (catalog)
11684
11776
  return "catalog";
11777
+ if (ref === undefined)
11778
+ return "local_runtime";
11685
11779
  return "config";
11686
11780
  }
11687
11781
  function buildResolvedRole(model, auth, resolutionSource) {
@@ -11698,14 +11792,18 @@ function buildResolvedRole(model, auth, resolutionSource) {
11698
11792
  resolutionSource
11699
11793
  };
11700
11794
  }
11701
- function resolveAgentModelDetailed(config, localOptions = {}) {
11702
- const core = resolveAgentModelCore(config, localOptions);
11703
- const auth = resolveRoleAuth(core.model, core.fromLocal, core.local, core.providerApiKeys, core.configuredEndpoint, core.modelRef !== undefined ? configuredApiKeyEnv(core.modelRef) : undefined, core.env);
11795
+ async function resolveAgentModelDetailed(config, options = {}) {
11796
+ const core = await resolveAgentModelCore(config, options);
11797
+ const auth = {
11798
+ present: core.auth.present,
11799
+ source: core.auth.source,
11800
+ ...core.auth.envName !== undefined ? { envName: core.auth.envName } : {}
11801
+ };
11704
11802
  const source = resolveRoleSource(core.modelRef, core.fromLocal, core.configuredEndpoint, core.catalog);
11705
11803
  return {
11706
11804
  model: core.model,
11707
- ...core.apiKey !== undefined ? { apiKey: core.apiKey } : {},
11708
- ...core.providerApiKeys !== undefined ? { providerApiKeys: core.providerApiKeys } : {},
11805
+ ...core.auth.apiKey !== undefined ? { apiKey: core.auth.apiKey } : {},
11806
+ ...core.auth.providerApiKeys !== undefined ? { providerApiKeys: core.auth.providerApiKeys } : {},
11709
11807
  role: buildResolvedRole(core.model, auth, source)
11710
11808
  };
11711
11809
  }
@@ -11786,7 +11884,7 @@ function writeDefaultConfig(path, partial, opts = {}) {
11786
11884
  lock.release();
11787
11885
  }
11788
11886
  }
11789
- 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, 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, 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.";
11887
+ 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, 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, 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;
11790
11888
  var init_config2 = __esm(() => {
11791
11889
  init_local_model();
11792
11890
  init_home();
@@ -11864,6 +11962,7 @@ var init_config2 = __esm(() => {
11864
11962
  sectionLimit: true
11865
11963
  };
11866
11964
  RERANK_ALLOWLIST = new Set(["enabled", "provider", "model", "apiKeyEnv", "baseUrl", "topN", "timeoutMs"]);
11965
+ modelRuntimeCache = new Map;
11867
11966
  });
11868
11967
 
11869
11968
  // src/cli/commands/init.ts
@@ -17571,392 +17670,9 @@ var init_model_auth = __esm(() => {
17571
17670
  };
17572
17671
  });
17573
17672
 
17574
- // src/filesystem/cloud-placeholder.ts
17575
- import { execFile as execFile3 } from "node:child_process";
17576
- import { lstat } from "node:fs/promises";
17577
- import { dirname as dirname18, relative as relative6, sep as sep7 } from "node:path";
17578
- import { promisify as promisify2 } from "node:util";
17579
- function pathLooksLikeCloudRoot(target) {
17580
- const normalized = target.replaceAll("\\", "/");
17581
- return MAC_CLOUD_PATH_MARKERS.some((marker) => normalized.includes(marker)) || WINDOWS_CLOUD_PATH_MARKERS.some((marker) => normalized.toLowerCase().includes(marker.toLowerCase()));
17582
- }
17583
- async function classifyFilesystemRoot(target) {
17584
- if (pathLooksLikeCloudRoot(target)) {
17585
- return { kind: "file-provider", reason: "path-marker", provider: cloudProviderFromPath(target) };
17586
- }
17587
- if (process.platform === "darwin")
17588
- return classifyDarwinRoot(target);
17589
- if (process.platform === "win32")
17590
- return classifyWindowsRoot(target);
17591
- return { kind: "local", reason: "local" };
17592
- }
17593
- async function isDatalessPlaceholder(target) {
17594
- if (process.platform === "darwin") {
17595
- try {
17596
- const { stdout } = await execFileAsync("/usr/bin/stat", ["-f", "%f", target], { timeout: 2000 });
17597
- const flags = Number.parseInt(stdout.trim(), 16);
17598
- return Number.isFinite(flags) && (flags & UF_DATALESS) !== 0;
17599
- } catch {
17600
- return false;
17601
- }
17602
- }
17603
- if (process.platform === "win32") {
17604
- const attributes = await windowsFileAttributes(target);
17605
- return attributes !== undefined && (attributes & WINDOWS_FILE_ATTRIBUTE_OFFLINE) !== 0 && (attributes & (WINDOWS_FILE_ATTRIBUTE_RECALL_ON_OPEN | WINDOWS_FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS)) !== 0;
17606
- }
17607
- return false;
17608
- }
17609
- async function classifyDarwinRoot(target) {
17610
- let cursor = target;
17611
- for (let depth = 0;depth < 8; depth += 1) {
17612
- const provider = await readFileProviderDomain(cursor);
17613
- if (provider !== undefined)
17614
- return { kind: "file-provider", reason: "file-provider-xattr", provider };
17615
- const parent = dirname18(cursor);
17616
- if (parent === cursor)
17617
- break;
17618
- cursor = parent;
17619
- }
17620
- return { kind: "local", reason: "local" };
17621
- }
17622
- async function classifyWindowsRoot(target) {
17623
- const attributes = await windowsFileAttributes(target);
17624
- if (attributes !== undefined && (attributes & WINDOWS_FILE_ATTRIBUTE_OFFLINE) !== 0 && (attributes & (WINDOWS_FILE_ATTRIBUTE_RECALL_ON_OPEN | WINDOWS_FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS)) !== 0) {
17625
- return { kind: "file-provider", reason: "placeholder-attribute", provider: "windows-cloud-files" };
17626
- }
17627
- if (await windowsCloudVolume(target)) {
17628
- return { kind: "file-provider", reason: "cloud-volume", provider: "windows-cloud-volume" };
17629
- }
17630
- return { kind: "local", reason: "local" };
17631
- }
17632
- async function windowsFileAttributes(target) {
17633
- try {
17634
- const script = `(Get-Item -LiteralPath ${quotePowerShell(target)} -Force).Attributes.value__`;
17635
- const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
17636
- timeout: 2000
17637
- });
17638
- const value = Number.parseInt(stdout.trim(), 10);
17639
- return Number.isFinite(value) ? value : undefined;
17640
- } catch {
17641
- return;
17642
- }
17643
- }
17644
- async function windowsCloudVolume(target) {
17645
- try {
17646
- const root = /^[A-Za-z]:/.test(target) ? `${target.slice(0, 2)}\\` : target;
17647
- const script = `Get-Volume -DriveLetter '${root[0]}' -ErrorAction SilentlyContinue | ` + "Select-Object -Property FileSystem,FileSystemLabel | ConvertTo-Json -Compress";
17648
- const { stdout } = await execFileAsync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
17649
- timeout: 2000
17650
- });
17651
- return /drivefs|google drive|onedrive|cloud/i.test(stdout);
17652
- } catch {
17653
- return false;
17654
- }
17655
- }
17656
- async function readFileProviderDomain(target) {
17657
- try {
17658
- await lstat(target);
17659
- const { stdout } = await execFileAsync("/usr/bin/xattr", ["-p", FILE_PROVIDER_XATTR, target], {
17660
- timeout: 2000
17661
- });
17662
- const value = stdout.trim();
17663
- return value.length > 0 ? value : undefined;
17664
- } catch {
17665
- return;
17666
- }
17667
- }
17668
- function cloudProviderFromPath(target) {
17669
- const lower = target.toLowerCase();
17670
- if (lower.includes("googledrive") || lower.includes("google drive") || lower.includes("drivefs"))
17671
- return "google-drive";
17672
- if (lower.includes("onedrive"))
17673
- return "onedrive";
17674
- if (lower.includes("mobile documents") || lower.includes("clouddocs"))
17675
- return "icloud";
17676
- return "file-provider";
17677
- }
17678
- function quotePowerShell(value) {
17679
- return `'${value.replaceAll("'", "''")}'`;
17680
- }
17681
- var execFileAsync, UF_DATALESS = 32768, FILE_PROVIDER_XATTR = "com.apple.file-provider-domain-id", WINDOWS_FILE_ATTRIBUTE_OFFLINE = 4096, WINDOWS_FILE_ATTRIBUTE_RECALL_ON_OPEN = 262144, WINDOWS_FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 4194304, MAC_CLOUD_PATH_MARKERS, WINDOWS_CLOUD_PATH_MARKERS;
17682
- var init_cloud_placeholder = __esm(() => {
17683
- execFileAsync = promisify2(execFile3);
17684
- MAC_CLOUD_PATH_MARKERS = ["/Library/CloudStorage/", "/Library/Mobile Documents/"];
17685
- WINDOWS_CLOUD_PATH_MARKERS = [
17686
- "\\OneDrive",
17687
- "/OneDrive",
17688
- "\\Google Drive",
17689
- "/Google Drive",
17690
- "\\GoogleDriveFS",
17691
- "/GoogleDriveFS",
17692
- "\\My Drive",
17693
- "/My Drive",
17694
- "\\Shared drives",
17695
- "/Shared drives"
17696
- ];
17697
- });
17698
-
17699
- // src/agent/bash-tool.ts
17700
- import { spawn as spawn18 } from "node:child_process";
17701
- import { Type as Type2 } from "typebox";
17702
- function runCommand(command, cwd, timeoutMs, maxOutputBytes, signal) {
17703
- return new Promise((resolve) => {
17704
- if (signal?.aborted) {
17705
- resolve({
17706
- output: "",
17707
- exitCode: undefined,
17708
- aborted: true,
17709
- terminationFailed: false,
17710
- timedOut: false,
17711
- truncated: false
17712
- });
17713
- return;
17714
- }
17715
- const shell = process.platform === "win32" ? "bash.exe" : "/bin/bash";
17716
- const child = spawn18(shell, ["-c", command], {
17717
- cwd,
17718
- detached: process.platform !== "win32",
17719
- windowsHide: true
17720
- });
17721
- const chunks = [];
17722
- let total = 0;
17723
- let truncated = false;
17724
- let timedOut = false;
17725
- let aborted = false;
17726
- let settled = false;
17727
- let killGraceTimer;
17728
- let terminationRequested = false;
17729
- let terminationStarted = false;
17730
- let terminationSettled = false;
17731
- let terminationFailed = false;
17732
- let pendingExitCode;
17733
- const collect = (data) => {
17734
- if (total >= maxOutputBytes) {
17735
- truncated = true;
17736
- return;
17737
- }
17738
- const remaining = maxOutputBytes - total;
17739
- if (data.length > remaining) {
17740
- chunks.push(data.subarray(0, remaining));
17741
- total = maxOutputBytes;
17742
- truncated = true;
17743
- } else {
17744
- chunks.push(data);
17745
- total += data.length;
17746
- }
17747
- };
17748
- child.stdout?.on("data", collect);
17749
- child.stderr?.on("data", collect);
17750
- const finish = (exitCode) => {
17751
- if (settled)
17752
- return;
17753
- if (terminationRequested && !terminationSettled) {
17754
- pendingExitCode = exitCode;
17755
- return;
17756
- }
17757
- settled = true;
17758
- clearTimeout(timer);
17759
- if (killGraceTimer !== undefined)
17760
- clearTimeout(killGraceTimer);
17761
- signal?.removeEventListener("abort", onAbort);
17762
- resolve({
17763
- output: Buffer.concat(chunks).toString("utf8"),
17764
- exitCode,
17765
- aborted,
17766
- terminationFailed,
17767
- timedOut,
17768
- truncated
17769
- });
17770
- };
17771
- const killDirectChild = () => {
17772
- try {
17773
- return child.kill("SIGKILL");
17774
- } catch {
17775
- return false;
17776
- }
17777
- };
17778
- const killProcessTree = async () => {
17779
- if (child.pid === undefined)
17780
- return true;
17781
- if (process.platform === "win32") {
17782
- return await new Promise((resolve) => {
17783
- const killer = spawn18("taskkill", ["/pid", String(child.pid), "/t", "/f"], { stdio: "ignore" });
17784
- let completed = false;
17785
- const graceTimer = setTimeout(() => {
17786
- if (completed)
17787
- return;
17788
- completed = true;
17789
- killer.kill();
17790
- resolve(killDirectChild());
17791
- }, KILL_EXIT_GRACE_MS);
17792
- const finishKill = (success) => {
17793
- if (completed)
17794
- return;
17795
- completed = true;
17796
- clearTimeout(graceTimer);
17797
- if (!success)
17798
- killDirectChild();
17799
- resolve(success);
17800
- };
17801
- killer.on("error", () => finishKill(false));
17802
- killer.on("close", (code) => finishKill(code === 0));
17803
- });
17804
- }
17805
- try {
17806
- process.kill(-child.pid, "SIGKILL");
17807
- return true;
17808
- } catch {
17809
- killDirectChild();
17810
- return false;
17811
- }
17812
- };
17813
- const releaseAfterKill = async () => {
17814
- if (terminationStarted)
17815
- return;
17816
- terminationStarted = true;
17817
- const killed = await killProcessTree();
17818
- terminationSettled = true;
17819
- terminationFailed = !killed;
17820
- child.stdout?.destroy();
17821
- child.stderr?.destroy();
17822
- killGraceTimer = setTimeout(() => finish(undefined), KILL_EXIT_GRACE_MS);
17823
- if (pendingExitCode !== undefined)
17824
- finish(pendingExitCode);
17825
- };
17826
- const timer = setTimeout(() => {
17827
- timedOut = true;
17828
- terminationRequested = true;
17829
- releaseAfterKill();
17830
- }, timeoutMs);
17831
- const onAbort = () => {
17832
- aborted = true;
17833
- terminationRequested = true;
17834
- releaseAfterKill();
17835
- };
17836
- if (signal) {
17837
- if (signal.aborted)
17838
- onAbort();
17839
- else
17840
- signal.addEventListener("abort", onAbort, { once: true });
17841
- }
17842
- child.on("error", () => finish(undefined));
17843
- child.on("close", (code) => finish(code === null ? undefined : code));
17844
- });
17845
- }
17846
- function createBashTool(options) {
17847
- const defaultTimeout = options.timeoutMs ?? DEFAULT_TIMEOUT_MS10;
17848
- const maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
17849
- return {
17850
- name: BASH_TOOL_NAME,
17851
- label: "Bash",
17852
- description: "Run a shell command to explore and read the document collection (ls, find, grep, cat, head, sed, rg). Returns combined stdout/stderr.",
17853
- parameters: bashSchema,
17854
- async execute(_toolCallId, params, signal) {
17855
- const command = String(params.command ?? "").trim();
17856
- if (command.length === 0) {
17857
- return {
17858
- content: [{ type: "text", text: "Command was empty; nothing was run." }],
17859
- details: {
17860
- method: "bash",
17861
- command: "",
17862
- aborted: false,
17863
- exitCode: undefined,
17864
- terminationFailed: false,
17865
- timedOut: false,
17866
- truncated: false
17867
- }
17868
- };
17869
- }
17870
- const cwd = typeof params.cwd === "string" && params.cwd.length > 0 ? params.cwd : options.cwd;
17871
- if (CLOUD_CONTENT_COMMAND.test(command)) {
17872
- const classification = await classifyFilesystemRoot(cwd);
17873
- if (classification.kind === "file-provider") {
17874
- return {
17875
- content: [
17876
- {
17877
- type: "text",
17878
- text: "AUTORAG_CLOUD_PLACEHOLDER_BLOCKED: content access under a cloud placeholder root was refused to prevent remote hydration. " + "Use the configured cloud-drive datasource or a materialized local file."
17879
- }
17880
- ],
17881
- details: {
17882
- method: "bash",
17883
- command,
17884
- aborted: false,
17885
- exitCode: undefined,
17886
- terminationFailed: false,
17887
- timedOut: false,
17888
- truncated: false
17889
- }
17890
- };
17891
- }
17892
- if (await isDatalessPlaceholder(cwd)) {
17893
- return {
17894
- content: [
17895
- {
17896
- type: "text",
17897
- text: "AUTORAG_CLOUD_PLACEHOLDER_BLOCKED: the working path is a data-less cloud placeholder. " + "Use the configured cloud-drive datasource or materialize the file first."
17898
- }
17899
- ],
17900
- details: {
17901
- method: "bash",
17902
- command,
17903
- aborted: false,
17904
- exitCode: undefined,
17905
- terminationFailed: false,
17906
- timedOut: false,
17907
- truncated: false
17908
- }
17909
- };
17910
- }
17911
- }
17912
- const timeoutMs = typeof params.timeoutMs === "number" && params.timeoutMs > 0 ? params.timeoutMs : defaultTimeout;
17913
- const run = await runCommand(command, cwd, timeoutMs, maxOutputBytes, signal);
17914
- const parts = [];
17915
- parts.push(run.output.length > 0 ? run.output : run.aborted ? "(command aborted)" : "(no output)");
17916
- if (run.timedOut)
17917
- parts.push(`
17918
- (command timed out after ${timeoutMs}ms and was killed)`);
17919
- if (run.truncated)
17920
- parts.push(`
17921
- (output truncated at ${maxOutputBytes} bytes)`);
17922
- if (run.exitCode !== undefined && run.exitCode !== 0 && !run.timedOut) {
17923
- parts.push(`
17924
- (exit code ${run.exitCode})`);
17925
- }
17926
- if (run.terminationFailed)
17927
- parts.push(`
17928
- (process termination failed)`);
17929
- return {
17930
- content: [{ type: "text", text: parts.join("") }],
17931
- details: {
17932
- method: "bash",
17933
- command,
17934
- aborted: run.aborted,
17935
- exitCode: run.exitCode,
17936
- terminationFailed: run.terminationFailed,
17937
- timedOut: run.timedOut,
17938
- truncated: run.truncated
17939
- }
17940
- };
17941
- }
17942
- };
17943
- }
17944
- var BASH_TOOL_NAME = "bash", DEFAULT_TIMEOUT_MS10 = 120000, DEFAULT_MAX_OUTPUT_BYTES = 131072, KILL_EXIT_GRACE_MS = 5000, bashSchema, CLOUD_CONTENT_COMMAND;
17945
- var init_bash_tool = __esm(() => {
17946
- init_cloud_placeholder();
17947
- bashSchema = Type2.Object({
17948
- command: Type2.String({
17949
- description: "Shell command to run (bash -c). Use standard tools like ls, find, grep, cat, head, sed, rg."
17950
- }),
17951
- cwd: Type2.Optional(Type2.String({ description: "Working directory for the command. Defaults to the configured workspace root." })),
17952
- timeoutMs: Type2.Optional(Type2.Integer({ description: "Optional timeout in milliseconds for this command." }))
17953
- });
17954
- CLOUD_CONTENT_COMMAND = /\b(?:rg|ripgrep|grep|egrep|fgrep|cat|less|more|head|tail|sed|awk)\b/i;
17955
- });
17956
-
17957
17673
  // src/agent/datasource-skill.ts
17958
17674
  import { formatSkillsForSystemPrompt } from "@earendil-works/pi-agent-core";
17959
- import { Type as Type3 } from "typebox";
17675
+ import { Type as Type2 } from "typebox";
17960
17676
  function datasourceSkillLocation(name) {
17961
17677
  return `datasource://${name}`;
17962
17678
  }
@@ -18002,15 +17718,15 @@ function createLoadDatasourceSkillTool(provider) {
18002
17718
  }
18003
17719
  var LOAD_DATASOURCE_SKILL_TOOL_NAME = "load_datasource_skill", loadDatasourceSkillSchema;
18004
17720
  var init_datasource_skill = __esm(() => {
18005
- loadDatasourceSkillSchema = Type3.Object({
18006
- name: Type3.String({
17721
+ loadDatasourceSkillSchema = Type2.Object({
17722
+ name: Type2.String({
18007
17723
  description: "Datasource skill name from the available skills list to load full instructions for."
18008
17724
  })
18009
17725
  });
18010
17726
  });
18011
17727
 
18012
17728
  // src/agent/dupey-tool.ts
18013
- import { Type as Type4 } from "typebox";
17729
+ import { Type as Type3 } from "typebox";
18014
17730
  function createScanDuplicateDocumentsTool(provider) {
18015
17731
  return {
18016
17732
  name: SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME,
@@ -18129,11 +17845,11 @@ function formatScore(value) {
18129
17845
  }
18130
17846
  var SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME = "scan_duplicate_documents", MAX_RENDERED_FAMILIES = 200, MAX_RENDERED_MEMBERS = 50, scanDuplicateDocumentsSchema;
18131
17847
  var init_dupey_tool = __esm(() => {
18132
- scanDuplicateDocumentsSchema = Type4.Object({});
17848
+ scanDuplicateDocumentsSchema = Type3.Object({});
18133
17849
  });
18134
17850
 
18135
17851
  // src/agent/emit-results-tool.ts
18136
- import { Type as Type5 } from "typebox";
17852
+ import { Type as Type4 } from "typebox";
18137
17853
  function createEmitResultsTool(capture) {
18138
17854
  return {
18139
17855
  name: EMIT_AUTORAG_RESULTS_TOOL_NAME,
@@ -18186,55 +17902,55 @@ function createEmitResultsTool(capture) {
18186
17902
  }
18187
17903
  var EMIT_AUTORAG_RESULTS_TOOL_NAME = "emit_autorag_results", evidenceRefSchema, emitResultsSchema;
18188
17904
  var init_emit_results_tool = __esm(() => {
18189
- evidenceRefSchema = Type5.Object({
18190
- method: Type5.String({ description: "Retrieval method namespace for this evidence chunk" }),
18191
- source: Type5.String({ description: "Internal opaque source identifier for this evidence chunk" }),
18192
- excerpt: Type5.Optional(Type5.String({ description: "Evidence excerpt used for stable ID normalization" })),
18193
- content: Type5.Optional(Type5.String({ description: "Evidence content used for stable ID normalization" })),
18194
- retrievalResultId: Type5.Optional(Type5.String({ description: "Backend retrieval ID when path-opaque and stable" })),
18195
- chunkIndex: Type5.Optional(Type5.Integer({ description: "Chunk index, if available" })),
18196
- lineNumber: Type5.Optional(Type5.Integer({ description: "Line number, if available" })),
18197
- stableEvidenceId: Type5.Optional(Type5.String({ description: "Stable evidence ID, if already normalized" })),
18198
- retrieverMix: Type5.Optional(Type5.Array(Type5.String({ maxLength: 64 }), {
17905
+ evidenceRefSchema = Type4.Object({
17906
+ method: Type4.String({ description: "Retrieval method namespace for this evidence chunk" }),
17907
+ source: Type4.String({ description: "Internal opaque source identifier for this evidence chunk" }),
17908
+ excerpt: Type4.Optional(Type4.String({ description: "Evidence excerpt used for stable ID normalization" })),
17909
+ content: Type4.Optional(Type4.String({ description: "Evidence content used for stable ID normalization" })),
17910
+ retrievalResultId: Type4.Optional(Type4.String({ description: "Backend retrieval ID when path-opaque and stable" })),
17911
+ chunkIndex: Type4.Optional(Type4.Integer({ description: "Chunk index, if available" })),
17912
+ lineNumber: Type4.Optional(Type4.Integer({ description: "Line number, if available" })),
17913
+ stableEvidenceId: Type4.Optional(Type4.String({ description: "Stable evidence ID, if already normalized" })),
17914
+ retrieverMix: Type4.Optional(Type4.Array(Type4.String({ maxLength: 64 }), {
18199
17915
  description: "Retrievers that contributed to this result",
18200
17916
  maxItems: 8
18201
17917
  })),
18202
- parserType: Type5.Optional(Type5.String({ description: "Parser that produced this evidence", maxLength: 120 })),
18203
- documentType: Type5.Optional(Type5.String({ description: "Document type, if known", maxLength: 120 })),
18204
- documentArea: Type5.Optional(Type5.String({ description: "Document collection area, if known", maxLength: 120 })),
18205
- evidenceType: Type5.Optional(Type5.String({ description: "Evidence type, if known", maxLength: 120 })),
18206
- evidenceLocation: Type5.Optional(Type5.String({ description: "Human-readable evidence location", maxLength: 120 })),
18207
- confidence: Type5.Optional(Type5.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
17918
+ parserType: Type4.Optional(Type4.String({ description: "Parser that produced this evidence", maxLength: 120 })),
17919
+ documentType: Type4.Optional(Type4.String({ description: "Document type, if known", maxLength: 120 })),
17920
+ documentArea: Type4.Optional(Type4.String({ description: "Document collection area, if known", maxLength: 120 })),
17921
+ evidenceType: Type4.Optional(Type4.String({ description: "Evidence type, if known", maxLength: 120 })),
17922
+ evidenceLocation: Type4.Optional(Type4.String({ description: "Human-readable evidence location", maxLength: 120 })),
17923
+ confidence: Type4.Optional(Type4.Number({ description: "Evidence confidence, 0..1", minimum: 0, maximum: 1 }))
18208
17924
  });
18209
- emitResultsSchema = Type5.Object({
18210
- answer: Type5.String({
17925
+ emitResultsSchema = Type4.Object({
17926
+ answer: Type4.String({
18211
17927
  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."
18212
17928
  }),
18213
- results: Type5.Array(Type5.Object({
18214
- number: Type5.Integer({ description: "1-based result number" }),
18215
- title: Type5.String({ description: "Short name of the curated knowledge unit" }),
18216
- summary: Type5.String({ description: "Key insight: purpose, details, and line range" }),
18217
- evidence: Type5.Array(Type5.Object({
18218
- excerpt: Type5.String({ description: "Supporting excerpt" }),
18219
- lineNumber: Type5.Optional(Type5.Integer({ description: "Line number of the excerpt, if known" }))
17929
+ results: Type4.Array(Type4.Object({
17930
+ number: Type4.Integer({ description: "1-based result number" }),
17931
+ title: Type4.String({ description: "Short name of the curated knowledge unit" }),
17932
+ summary: Type4.String({ description: "Key insight: purpose, details, and line range" }),
17933
+ evidence: Type4.Array(Type4.Object({
17934
+ excerpt: Type4.String({ description: "Supporting excerpt" }),
17935
+ lineNumber: Type4.Optional(Type4.Integer({ description: "Line number of the excerpt, if known" }))
18220
17936
  })),
18221
- confidence: Type5.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
17937
+ confidence: Type4.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 })
18222
17938
  }), { description: "Numbered curated knowledge units." }),
18223
- mapping: Type5.Array(Type5.Object({
18224
- number: Type5.Integer({ description: "Matches the result number this entry maps" }),
18225
- source: Type5.String({ description: "Source identifier — a real file path or a datasource id" }),
18226
- method: Type5.String({ description: "Retrieval method or tool that produced the source" }),
18227
- content: Type5.String({ description: "Raw content snippet for feedback tracking" }),
18228
- evidenceRefs: Type5.Optional(Type5.Array(evidenceRefSchema, {
17939
+ mapping: Type4.Array(Type4.Object({
17940
+ number: Type4.Integer({ description: "Matches the result number this entry maps" }),
17941
+ source: Type4.String({ description: "Source identifier — a real file path or a datasource id" }),
17942
+ method: Type4.String({ description: "Retrieval method or tool that produced the source" }),
17943
+ content: Type4.String({ description: "Raw content snippet for feedback tracking" }),
17944
+ evidenceRefs: Type4.Optional(Type4.Array(evidenceRefSchema, {
18229
17945
  description: "Hidden evidence chunk references supporting this curated result"
18230
17946
  }))
18231
17947
  }), { description: "Internal number -> source/method mapping for feedback. One entry per result number." }),
18232
- warnings: Type5.Optional(Type5.Array(Type5.String(), { description: "Optional warnings about this result set" }))
17948
+ warnings: Type4.Optional(Type4.Array(Type4.String(), { description: "Optional warnings about this result set" }))
18233
17949
  });
18234
17950
  });
18235
17951
 
18236
17952
  // src/agent/everything-search-tool.ts
18237
- import { Type as Type6 } from "typebox";
17953
+ import { Type as Type5 } from "typebox";
18238
17954
  function createEverythingSearchTool(provider) {
18239
17955
  return {
18240
17956
  name: EVERYTHING_SEARCH_TOOL_NAME,
@@ -18286,28 +18002,28 @@ ${lines.join(`
18286
18002
  }
18287
18003
  var EVERYTHING_SEARCH_TOOL_NAME = "everything_search", MAX_RESULTS_CAP2 = 1000, DEFAULT_MAX_RESULTS3 = 100, everythingSearchSchema;
18288
18004
  var init_everything_search_tool = __esm(() => {
18289
- everythingSearchSchema = Type6.Object({
18290
- query: Type6.String({
18005
+ everythingSearchSchema = Type5.Object({
18006
+ query: Type5.String({
18291
18007
  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.'
18292
18008
  }),
18293
- regex: Type6.Optional(Type6.Boolean({ description: "Treat query as a regular expression." })),
18294
- matchCase: Type6.Optional(Type6.Boolean()),
18295
- matchPath: Type6.Optional(Type6.Boolean({ description: "Match against the full path instead of the name." })),
18296
- wholeWord: Type6.Optional(Type6.Boolean()),
18297
- kind: Type6.Optional(Type6.Union([Type6.Literal("files"), Type6.Literal("folders")])),
18298
- path: Type6.Optional(Type6.String({ description: "Absolute folder to search within." })),
18299
- sort: Type6.Optional(Type6.Union([
18300
- Type6.Literal("name-ascending"),
18301
- Type6.Literal("name-descending"),
18302
- Type6.Literal("path-ascending"),
18303
- Type6.Literal("path-descending"),
18304
- Type6.Literal("size-ascending"),
18305
- Type6.Literal("size-descending"),
18306
- Type6.Literal("date-modified-ascending"),
18307
- Type6.Literal("date-modified-descending")
18009
+ regex: Type5.Optional(Type5.Boolean({ description: "Treat query as a regular expression." })),
18010
+ matchCase: Type5.Optional(Type5.Boolean()),
18011
+ matchPath: Type5.Optional(Type5.Boolean({ description: "Match against the full path instead of the name." })),
18012
+ wholeWord: Type5.Optional(Type5.Boolean()),
18013
+ kind: Type5.Optional(Type5.Union([Type5.Literal("files"), Type5.Literal("folders")])),
18014
+ path: Type5.Optional(Type5.String({ description: "Absolute folder to search within." })),
18015
+ sort: Type5.Optional(Type5.Union([
18016
+ Type5.Literal("name-ascending"),
18017
+ Type5.Literal("name-descending"),
18018
+ Type5.Literal("path-ascending"),
18019
+ Type5.Literal("path-descending"),
18020
+ Type5.Literal("size-ascending"),
18021
+ Type5.Literal("size-descending"),
18022
+ Type5.Literal("date-modified-ascending"),
18023
+ Type5.Literal("date-modified-descending")
18308
18024
  ])),
18309
- offset: Type6.Optional(Type6.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18310
- maxResults: Type6.Optional(Type6.Integer({
18025
+ offset: Type5.Optional(Type5.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18026
+ maxResults: Type5.Optional(Type5.Integer({
18311
18027
  minimum: 1,
18312
18028
  description: `Maximum results (default ${DEFAULT_MAX_RESULTS3}, cap ${MAX_RESULTS_CAP2}).`
18313
18029
  }))
@@ -18315,7 +18031,7 @@ var init_everything_search_tool = __esm(() => {
18315
18031
  });
18316
18032
 
18317
18033
  // src/agent/fast-answer-tool.ts
18318
- import { Type as Type7 } from "typebox";
18034
+ import { Type as Type6 } from "typebox";
18319
18035
  function createEmitFastAnswerTool(capture) {
18320
18036
  return {
18321
18037
  name: EMIT_FAST_ANSWER_TOOL_NAME,
@@ -18349,29 +18065,29 @@ function createEmitFastAnswerTool(capture) {
18349
18065
  }
18350
18066
  var EMIT_FAST_ANSWER_TOOL_NAME = "emit_fast_answer", fastAnswerSchema;
18351
18067
  var init_fast_answer_tool = __esm(() => {
18352
- fastAnswerSchema = Type7.Object({
18353
- answer: Type7.String({
18068
+ fastAnswerSchema = Type6.Object({
18069
+ answer: Type6.String({
18354
18070
  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."
18355
18071
  }),
18356
- results: Type7.Array(Type7.Object({
18357
- number: Type7.Integer({ description: "1-based result number" }),
18358
- title: Type7.String({ description: "Short name of the knowledge unit" }),
18359
- summary: Type7.String({ description: "Key insight backing the first answer" }),
18360
- evidence: Type7.Optional(Type7.Array(Type7.Object({
18361
- excerpt: Type7.String({ description: "Supporting excerpt" }),
18362
- lineNumber: Type7.Optional(Type7.Integer({ description: "Line number of the excerpt, if known" }))
18072
+ results: Type6.Array(Type6.Object({
18073
+ number: Type6.Integer({ description: "1-based result number" }),
18074
+ title: Type6.String({ description: "Short name of the knowledge unit" }),
18075
+ summary: Type6.String({ description: "Key insight backing the first answer" }),
18076
+ evidence: Type6.Optional(Type6.Array(Type6.Object({
18077
+ excerpt: Type6.String({ description: "Supporting excerpt" }),
18078
+ lineNumber: Type6.Optional(Type6.Integer({ description: "Line number of the excerpt, if known" }))
18363
18079
  }))),
18364
- confidence: Type7.Optional(Type7.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 }))
18080
+ confidence: Type6.Optional(Type6.Number({ description: "Confidence in this result, 0..1", minimum: 0, maximum: 1 }))
18365
18081
  }), { description: "Numbered knowledge units backing the first answer." }),
18366
- sources: Type7.Optional(Type7.Array(Type7.Object({
18367
- number: Type7.Integer({ description: "Matches the result number this source belongs to" }),
18368
- source: Type7.String({ description: "Source identifier — a real file path or a datasource id" })
18082
+ sources: Type6.Optional(Type6.Array(Type6.Object({
18083
+ number: Type6.Integer({ description: "Matches the result number this source belongs to" }),
18084
+ source: Type6.String({ description: "Source identifier — a real file path or a datasource id" })
18369
18085
  }), { description: "Optional number -> source mapping for the first answer." }))
18370
18086
  });
18371
18087
  });
18372
18088
 
18373
18089
  // src/agent/fsearch-search-tool.ts
18374
- import { Type as Type8 } from "typebox";
18090
+ import { Type as Type7 } from "typebox";
18375
18091
  function createFSearchSearchTool(provider) {
18376
18092
  return {
18377
18093
  name: FSEARCH_SEARCH_TOOL_NAME,
@@ -18427,27 +18143,27 @@ ${lines.join(`
18427
18143
  }
18428
18144
  var FSEARCH_SEARCH_TOOL_NAME = "fsearch_search", MAX_RESULTS_CAP3 = 1000, DEFAULT_MAX_RESULTS4 = 100, fsearchSearchSchema;
18429
18145
  var init_fsearch_search_tool = __esm(() => {
18430
- fsearchSearchSchema = Type8.Object({
18431
- query: Type8.String({
18146
+ fsearchSearchSchema = Type7.Object({
18147
+ query: Type7.String({
18432
18148
  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.'
18433
18149
  }),
18434
- regex: Type8.Optional(Type8.Boolean({ description: "Treat query as a regular expression." })),
18435
- matchCase: Type8.Optional(Type8.Boolean()),
18436
- matchPath: Type8.Optional(Type8.Boolean({ description: "Match against the full path instead of the name." })),
18437
- kind: Type8.Optional(Type8.Union([Type8.Literal("files"), Type8.Literal("folders")])),
18438
- path: Type8.Optional(Type8.String({ description: "Absolute folder to search within." })),
18439
- sort: Type8.Optional(Type8.Union([
18440
- Type8.Literal("name-ascending"),
18441
- Type8.Literal("name-descending"),
18442
- Type8.Literal("path-ascending"),
18443
- Type8.Literal("path-descending"),
18444
- Type8.Literal("size-ascending"),
18445
- Type8.Literal("size-descending"),
18446
- Type8.Literal("date-modified-ascending"),
18447
- Type8.Literal("date-modified-descending")
18150
+ regex: Type7.Optional(Type7.Boolean({ description: "Treat query as a regular expression." })),
18151
+ matchCase: Type7.Optional(Type7.Boolean()),
18152
+ matchPath: Type7.Optional(Type7.Boolean({ description: "Match against the full path instead of the name." })),
18153
+ kind: Type7.Optional(Type7.Union([Type7.Literal("files"), Type7.Literal("folders")])),
18154
+ path: Type7.Optional(Type7.String({ description: "Absolute folder to search within." })),
18155
+ sort: Type7.Optional(Type7.Union([
18156
+ Type7.Literal("name-ascending"),
18157
+ Type7.Literal("name-descending"),
18158
+ Type7.Literal("path-ascending"),
18159
+ Type7.Literal("path-descending"),
18160
+ Type7.Literal("size-ascending"),
18161
+ Type7.Literal("size-descending"),
18162
+ Type7.Literal("date-modified-ascending"),
18163
+ Type7.Literal("date-modified-descending")
18448
18164
  ])),
18449
- offset: Type8.Optional(Type8.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18450
- maxResults: Type8.Optional(Type8.Integer({
18165
+ offset: Type7.Optional(Type7.Integer({ minimum: 0, description: "Skip this many results (pagination)." })),
18166
+ maxResults: Type7.Optional(Type7.Integer({
18451
18167
  minimum: 1,
18452
18168
  description: `Maximum results (default ${DEFAULT_MAX_RESULTS4}, cap ${MAX_RESULTS_CAP3}).`
18453
18169
  }))
@@ -18455,7 +18171,7 @@ var init_fsearch_search_tool = __esm(() => {
18455
18171
  });
18456
18172
 
18457
18173
  // src/agent/jikji-find-tool.ts
18458
- import { Type as Type9 } from "typebox";
18174
+ import { Type as Type8 } from "typebox";
18459
18175
  function createJikjiFindTool(provider) {
18460
18176
  return {
18461
18177
  name: JIKJI_FIND_TOOL_NAME,
@@ -18576,10 +18292,10 @@ function formatDirective(policy) {
18576
18292
  }
18577
18293
  var JIKJI_FIND_TOOL_NAME = "jikji_find", jikjiFindSchema;
18578
18294
  var init_jikji_find_tool = __esm(() => {
18579
- jikjiFindSchema = Type9.Object({
18580
- query: Type9.String({ description: "Query for Jikji local file discovery." }),
18581
- topK: Type9.Optional(Type9.Integer({ description: "Maximum number of answer paths / candidates to return." })),
18582
- first: Type9.Optional(Type9.Boolean({ description: "Return only the first/best answer." }))
18295
+ jikjiFindSchema = Type8.Object({
18296
+ query: Type8.String({ description: "Query for Jikji local file discovery." }),
18297
+ topK: Type8.Optional(Type8.Integer({ description: "Maximum number of answer paths / candidates to return." })),
18298
+ first: Type8.Optional(Type8.Boolean({ description: "Return only the first/best answer." }))
18583
18299
  });
18584
18300
  });
18585
18301
 
@@ -18594,7 +18310,7 @@ import {
18594
18310
  watch,
18595
18311
  writeFileSync as writeFileSync17
18596
18312
  } from "node:fs";
18597
- import { dirname as dirname19, join as join29 } from "node:path";
18313
+ import { dirname as dirname18, join as join29 } from "node:path";
18598
18314
  function requestsDir(workspacePath) {
18599
18315
  return join29(workspacePath, P2P_DIR, "requests");
18600
18316
  }
@@ -18611,7 +18327,7 @@ function isRecord17(value) {
18611
18327
  return typeof value === "object" && value !== null && !Array.isArray(value);
18612
18328
  }
18613
18329
  function atomicWrite(path, value) {
18614
- mkdirSync19(dirname19(path), { recursive: true });
18330
+ mkdirSync19(dirname18(path), { recursive: true });
18615
18331
  const tempPath = `${path}.${process.pid}.tmp`;
18616
18332
  writeFileSync17(tempPath, `${JSON.stringify(value, null, 2)}
18617
18333
  `, { mode: 384 });
@@ -19017,7 +18733,7 @@ var init_egress_gate = __esm(() => {
19017
18733
 
19018
18734
  // src/p2p/policy.ts
19019
18735
  import { existsSync as existsSync25, mkdirSync as mkdirSync20, readFileSync as readFileSync20, writeFileSync as writeFileSync18 } from "node:fs";
19020
- import { basename as basename13, dirname as dirname20, join as join30, resolve as resolve14 } from "node:path";
18736
+ import { basename as basename13, dirname as dirname19, join as join30, resolve as resolve14 } from "node:path";
19021
18737
  import { parse as parseToml } from "smol-toml";
19022
18738
  function isRecord18(value) {
19023
18739
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -19355,7 +19071,7 @@ class PolicyStore {
19355
19071
  }
19356
19072
  persistSeenSources() {
19357
19073
  try {
19358
- mkdirSync20(dirname20(this.seenSourcesPath), { recursive: true });
19074
+ mkdirSync20(dirname19(this.seenSourcesPath), { recursive: true });
19359
19075
  writeFileSync18(this.seenSourcesPath, `${JSON.stringify({
19360
19076
  sources: [...this.seenSources].sort(),
19361
19077
  pending: [...this.pendingSources].sort()
@@ -19501,57 +19217,57 @@ var init_policy = __esm(() => {
19501
19217
  });
19502
19218
 
19503
19219
  // src/p2p/wire.ts
19504
- import { Type as Type10 } from "typebox";
19220
+ import { Type as Type9 } from "typebox";
19505
19221
  var PeerRefusalCodeSchema, PeerDiagnosticSchema, PeerFileEntrySchema, PeerResultEntrySchema, PeerQueryRequestSchema, PeerQueryResponseSchema;
19506
19222
  var init_wire = __esm(() => {
19507
- PeerRefusalCodeSchema = Type10.Union([
19508
- Type10.Literal("auth-error"),
19509
- Type10.Literal("replay-rejected"),
19510
- Type10.Literal("rate-limited"),
19511
- Type10.Literal("injection-detected"),
19512
- Type10.Literal("policy-denied"),
19513
- Type10.Literal("queue-full"),
19514
- Type10.Literal("internal-error")
19223
+ PeerRefusalCodeSchema = Type9.Union([
19224
+ Type9.Literal("auth-error"),
19225
+ Type9.Literal("replay-rejected"),
19226
+ Type9.Literal("rate-limited"),
19227
+ Type9.Literal("injection-detected"),
19228
+ Type9.Literal("policy-denied"),
19229
+ Type9.Literal("queue-full"),
19230
+ Type9.Literal("internal-error")
19515
19231
  ]);
19516
- PeerDiagnosticSchema = Type10.Object({
19517
- code: Type10.String({ minLength: 1, description: "Diagnostic or refusal code" }),
19518
- message: Type10.String({ description: "Human-readable diagnostic message" })
19232
+ PeerDiagnosticSchema = Type9.Object({
19233
+ code: Type9.String({ minLength: 1, description: "Diagnostic or refusal code" }),
19234
+ message: Type9.String({ description: "Human-readable diagnostic message" })
19519
19235
  });
19520
- PeerFileEntrySchema = Type10.Object({
19521
- source: Type10.String({
19236
+ PeerFileEntrySchema = Type9.Object({
19237
+ source: Type9.String({
19522
19238
  description: "Canonical retrieval source identifier"
19523
19239
  }),
19524
- contentBase64: Type10.String({ description: "Base64-encoded file content" }),
19525
- redacted: Type10.Boolean({ description: "Whether the content was PII-redacted" })
19240
+ contentBase64: Type9.String({ description: "Base64-encoded file content" }),
19241
+ redacted: Type9.Boolean({ description: "Whether the content was PII-redacted" })
19526
19242
  });
19527
- PeerResultEntrySchema = Type10.Object({
19528
- number: Type10.Integer({ minimum: 1, description: "1-based result number" }),
19529
- title: Type10.String({ minLength: 1, description: "Short title of the result" }),
19530
- summary: Type10.String({ description: "Key insight summary" }),
19531
- source: Type10.String({
19243
+ PeerResultEntrySchema = Type9.Object({
19244
+ number: Type9.Integer({ minimum: 1, description: "1-based result number" }),
19245
+ title: Type9.String({ minLength: 1, description: "Short title of the result" }),
19246
+ summary: Type9.String({ description: "Key insight summary" }),
19247
+ source: Type9.String({
19532
19248
  description: "Canonical retrieval source identifier"
19533
19249
  }),
19534
- excerpt: Type10.String({ description: "Supporting excerpt" })
19250
+ excerpt: Type9.String({ description: "Supporting excerpt" })
19535
19251
  });
19536
- PeerQueryRequestSchema = Type10.Object({
19537
- v: Type10.Literal(1, { description: "Protocol version" }),
19538
- query: Type10.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
19539
- topK: Type10.Optional(Type10.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
19540
- scope: Type10.Optional(Type10.String({ description: "Optional search scope hint" }))
19252
+ PeerQueryRequestSchema = Type9.Object({
19253
+ v: Type9.Literal(1, { description: "Protocol version" }),
19254
+ query: Type9.String({ minLength: 1, maxLength: 4096, description: "Search query (max 4096 chars)" }),
19255
+ topK: Type9.Optional(Type9.Integer({ minimum: 1, maximum: 20, description: "Max results to return (max 20)" })),
19256
+ scope: Type9.Optional(Type9.String({ description: "Optional search scope hint" }))
19541
19257
  });
19542
- PeerQueryResponseSchema = Type10.Object({
19543
- v: Type10.Literal(1, { description: "Protocol version" }),
19544
- status: Type10.Union([Type10.Literal("ok"), Type10.Literal("rejected")], {
19258
+ PeerQueryResponseSchema = Type9.Object({
19259
+ v: Type9.Literal(1, { description: "Protocol version" }),
19260
+ status: Type9.Union([Type9.Literal("ok"), Type9.Literal("rejected")], {
19545
19261
  description: "Response status"
19546
19262
  }),
19547
- answer: Type10.String({ description: "Curated answer text" }),
19548
- results: Type10.Array(PeerResultEntrySchema, {
19263
+ answer: Type9.String({ description: "Curated answer text" }),
19264
+ results: Type9.Array(PeerResultEntrySchema, {
19549
19265
  description: "Curated result entries with opaque source ids"
19550
19266
  }),
19551
- files: Type10.Array(PeerFileEntrySchema, {
19267
+ files: Type9.Array(PeerFileEntrySchema, {
19552
19268
  description: "Attached original files with opaque source ids"
19553
19269
  }),
19554
- diagnostics: Type10.Array(PeerDiagnosticSchema, {
19270
+ diagnostics: Type9.Array(PeerDiagnosticSchema, {
19555
19271
  description: "Diagnostic messages (degraded-mode, rejection reasons, etc.)"
19556
19272
  })
19557
19273
  });
@@ -19560,7 +19276,7 @@ var init_wire = __esm(() => {
19560
19276
  // src/p2p/simplex-query-store.ts
19561
19277
  import { randomUUID as randomUUID7 } from "node:crypto";
19562
19278
  import { existsSync as existsSync26, mkdirSync as mkdirSync21, readdirSync as readdirSync5, readFileSync as readFileSync21, renameSync as renameSync10, unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "node:fs";
19563
- import { dirname as dirname21, join as join31 } from "node:path";
19279
+ import { dirname as dirname20, join as join31 } from "node:path";
19564
19280
  import { Value } from "typebox/value";
19565
19281
  function statePath(workspacePath, directory, id) {
19566
19282
  return join31(workspacePath, QUERY_DIR, directory, `${id}.json`);
@@ -19569,7 +19285,7 @@ function isRecord19(value) {
19569
19285
  return typeof value === "object" && value !== null && !Array.isArray(value);
19570
19286
  }
19571
19287
  function atomicWrite2(path, value) {
19572
- mkdirSync21(dirname21(path), { recursive: true });
19288
+ mkdirSync21(dirname20(path), { recursive: true });
19573
19289
  const tempPath = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
19574
19290
  writeFileSync19(tempPath, `${JSON.stringify(value, null, 2)}
19575
19291
  `, { mode: 384 });
@@ -19798,7 +19514,7 @@ var init_simplex_query_store = __esm(() => {
19798
19514
  // src/p2p/simplex-server.ts
19799
19515
  import { existsSync as existsSync27, mkdirSync as mkdirSync22, readFileSync as readFileSync22, writeFileSync as writeFileSync20 } from "node:fs";
19800
19516
  import { join as join32 } from "node:path";
19801
- import { Type as Type11 } from "typebox";
19517
+ import { Type as Type10 } from "typebox";
19802
19518
  import { Value as Value2 } from "typebox/value";
19803
19519
  function targetTokens(value) {
19804
19520
  return new Set((value.toLocaleLowerCase().match(TARGET_TOKEN_PATTERN) ?? []).filter((token) => token.length > 1));
@@ -20112,11 +19828,11 @@ var init_simplex_server = __esm(() => {
20112
19828
  shareBytes: false,
20113
19829
  redact: true
20114
19830
  };
20115
- SimplexWireEnvelopeSchema = Type11.Object({
20116
- v: Type11.Literal(1, { description: "Envelope version" }),
20117
- kind: Type11.Union([Type11.Literal("query"), Type11.Literal("response")], { description: "Payload kind" }),
20118
- id: Type11.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
20119
- payload: Type11.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
19831
+ SimplexWireEnvelopeSchema = Type10.Object({
19832
+ v: Type10.Literal(1, { description: "Envelope version" }),
19833
+ kind: Type10.Union([Type10.Literal("query"), Type10.Literal("response")], { description: "Payload kind" }),
19834
+ id: Type10.String({ minLength: 1, maxLength: 128, description: "Correlation id" }),
19835
+ payload: Type10.Unknown({ description: "PeerQueryRequest or PeerQueryResponse" })
20120
19836
  });
20121
19837
  TARGET_TOKEN_PATTERN = /[\p{L}\p{N}]+/gu;
20122
19838
  PEERS_DIR = join32(".autorag", "p2p");
@@ -20129,7 +19845,7 @@ var init_simplex_server = __esm(() => {
20129
19845
  });
20130
19846
 
20131
19847
  // src/agent/peer-target-tool.ts
20132
- import { Type as Type12 } from "typebox";
19848
+ import { Type as Type11 } from "typebox";
20133
19849
  function createRecommendPeerTargetsTool(workspacePath) {
20134
19850
  return {
20135
19851
  name: RECOMMEND_PEER_TARGETS_TOOL_NAME,
@@ -20158,17 +19874,216 @@ function createRecommendPeerTargetsTool(workspacePath) {
20158
19874
  };
20159
19875
  }
20160
19876
  };
20161
- }
20162
- var RECOMMEND_PEER_TARGETS_TOOL_NAME = "recommend_peer_targets", recommendPeerTargetsSchema;
20163
- var init_peer_target_tool = __esm(() => {
20164
- init_simplex_server();
20165
- recommendPeerTargetsSchema = Type12.Object({
20166
- query: Type12.String({ description: "Question or topic to match against local peer personas." })
19877
+ }
19878
+ var RECOMMEND_PEER_TARGETS_TOOL_NAME = "recommend_peer_targets", recommendPeerTargetsSchema;
19879
+ var init_peer_target_tool = __esm(() => {
19880
+ init_simplex_server();
19881
+ recommendPeerTargetsSchema = Type11.Object({
19882
+ query: Type11.String({ description: "Question or topic to match against local peer personas." })
19883
+ });
19884
+ });
19885
+
19886
+ // src/agent/pi-session.ts
19887
+ import { join as join33 } from "node:path";
19888
+ import { streamSimple as compatStreamSimple } from "@earendil-works/pi-ai/compat";
19889
+ import {
19890
+ createAgentSession,
19891
+ createAgentSessionFromServices,
19892
+ createAgentSessionRuntime,
19893
+ createAgentSessionServices,
19894
+ DefaultResourceLoader,
19895
+ getAgentDir as getAgentDir2,
19896
+ ModelRuntime as ModelRuntime2,
19897
+ SessionManager,
19898
+ SettingsManager as SettingsManager2
19899
+ } from "@earendil-works/pi-coding-agent";
19900
+ function toToolDefinition(tool) {
19901
+ return {
19902
+ name: tool.name,
19903
+ label: tool.label,
19904
+ description: tool.description,
19905
+ parameters: tool.parameters,
19906
+ ...tool.prepareArguments === undefined ? {} : { prepareArguments: tool.prepareArguments },
19907
+ execute: async (toolCallId, params, signal, onUpdate) => {
19908
+ return tool.execute(toolCallId, params, signal, onUpdate);
19909
+ }
19910
+ };
19911
+ }
19912
+ function modelConfig(model, configuredApiKey) {
19913
+ return {
19914
+ name: model.name,
19915
+ baseUrl: model.baseUrl,
19916
+ api: model.api,
19917
+ ...configuredApiKey === undefined ? {} : { apiKey: configuredApiKey },
19918
+ authHeader: false,
19919
+ streamSimple: (requestModel, context, options) => compatStreamSimple(requestModel, context, {
19920
+ ...options,
19921
+ ...configuredApiKey === EMBEDDED_AUTH_MARKER ? { apiKey: undefined } : {}
19922
+ }),
19923
+ models: [
19924
+ {
19925
+ id: model.id,
19926
+ name: model.name,
19927
+ reasoning: model.reasoning,
19928
+ input: [...model.input],
19929
+ cost: model.cost,
19930
+ contextWindow: model.contextWindow,
19931
+ maxTokens: model.maxTokens,
19932
+ ...model.thinkingLevelMap === undefined ? {} : { thinkingLevelMap: model.thinkingLevelMap }
19933
+ }
19934
+ ]
19935
+ };
19936
+ }
19937
+ async function configureModelRuntime(modelRuntime, model, apiKey, providerApiKeys) {
19938
+ if (model !== undefined) {
19939
+ const configuredKey = apiKey ?? providerApiKeys?.[model.provider];
19940
+ if (modelRuntime.getModel(model.provider, model.id) === undefined) {
19941
+ modelRuntime.registerProvider(model.provider, modelConfig(model, configuredKey ?? EMBEDDED_AUTH_MARKER));
19942
+ }
19943
+ }
19944
+ const keys = new Map;
19945
+ if (model !== undefined && apiKey !== undefined)
19946
+ keys.set(model.provider, apiKey);
19947
+ for (const [provider, key] of Object.entries(providerApiKeys ?? {}))
19948
+ keys.set(provider, key);
19949
+ for (const [provider, key] of keys)
19950
+ await modelRuntime.setRuntimeApiKey(provider, key);
19951
+ }
19952
+ function createAutoRAGExtension(getSystemPrompt, contextTransform) {
19953
+ return (pi) => {
19954
+ pi.on("before_agent_start", () => ({ systemPrompt: getSystemPrompt() }));
19955
+ if (contextTransform !== undefined) {
19956
+ pi.on("context", async (event) => ({ messages: await contextTransform(event.messages) }));
19957
+ }
19958
+ };
19959
+ }
19960
+ function createAutoRAGInteractiveExtension(getSystemPrompt, contextTransform, onQuery) {
19961
+ return (pi) => {
19962
+ pi.on("before_agent_start", () => ({ systemPrompt: getSystemPrompt() }));
19963
+ if (contextTransform !== undefined) {
19964
+ pi.on("context", async (event) => ({ messages: await contextTransform(event.messages) }));
19965
+ }
19966
+ pi.on("input", async (event) => {
19967
+ const query = event.text.trim();
19968
+ if (event.source !== "interactive" || query.length === 0 || query.startsWith("/"))
19969
+ return;
19970
+ try {
19971
+ await onQuery(query, pi);
19972
+ } catch (error) {
19973
+ pi.sendMessage({
19974
+ customType: "autorag.error",
19975
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
19976
+ display: true
19977
+ });
19978
+ }
19979
+ return { action: "handled" };
19980
+ });
19981
+ };
19982
+ }
19983
+ async function createAutoRAGPiSession(options) {
19984
+ const agentDir = options.agentDir ?? getAgentDir2();
19985
+ const settingsManager = SettingsManager2.create(options.cwd, agentDir);
19986
+ if (settingsManager.getDefaultTools() === undefined) {
19987
+ settingsManager.applyOverrides({ defaultTools: [...PI_BUILTIN_TOOL_NAMES] });
19988
+ }
19989
+ const modelRuntime = await ModelRuntime2.create({
19990
+ authPath: join33(agentDir, "auth.json"),
19991
+ modelsPath: join33(agentDir, "models.json")
19992
+ });
19993
+ await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
19994
+ const customTools = [...options.customTools];
19995
+ const resourceLoader = new DefaultResourceLoader({
19996
+ cwd: options.cwd,
19997
+ agentDir,
19998
+ settingsManager,
19999
+ extensionFactories: [createAutoRAGExtension(options.getSystemPrompt, options.contextTransform)],
20000
+ systemPromptOverride: () => options.getSystemPrompt(),
20001
+ appendSystemPromptOverride: () => []
20002
+ });
20003
+ await resourceLoader.reload();
20004
+ const sessionManager = options.sessionPath ? SessionManager.open(options.sessionPath, options.sessionDir, options.cwd) : options.persistSession ? SessionManager.create(options.cwd, options.sessionDir) : SessionManager.inMemory(options.cwd);
20005
+ const customToolNames = customTools.map((tool) => tool.name);
20006
+ const customToolDefinitions = customTools.map(toToolDefinition);
20007
+ const { session } = await createAgentSession({
20008
+ cwd: options.cwd,
20009
+ agentDir,
20010
+ modelRuntime,
20011
+ settingsManager,
20012
+ resourceLoader,
20013
+ sessionManager,
20014
+ model: options.model,
20015
+ customTools: customToolDefinitions,
20016
+ tools: [...PI_BUILTIN_TOOL_NAMES, ...customToolNames],
20017
+ excludeTools: options.remoteSession ? ["edit", "write", "powershell"] : undefined,
20018
+ thinkingLevel: "off"
20019
+ });
20020
+ const initialToolNames = [...new Set([...session.getActiveToolNames(), ...customToolNames])];
20021
+ session.setActiveToolsByName(initialToolNames);
20022
+ return {
20023
+ session,
20024
+ baseToolNames: initialToolNames,
20025
+ sessionFile: session.sessionFile
20026
+ };
20027
+ }
20028
+ async function createAutoRAGPiInteractiveRuntime(options) {
20029
+ const agentDir = options.agentDir ?? getAgentDir2();
20030
+ const settingsManager = SettingsManager2.create(options.cwd, agentDir);
20031
+ if (settingsManager.getDefaultTools() === undefined) {
20032
+ settingsManager.applyOverrides({ defaultTools: [...PI_BUILTIN_TOOL_NAMES] });
20033
+ }
20034
+ const modelRuntime = await ModelRuntime2.create({
20035
+ authPath: join33(agentDir, "auth.json"),
20036
+ modelsPath: join33(agentDir, "models.json")
20037
+ });
20038
+ await configureModelRuntime(modelRuntime, options.model, options.apiKey, options.providerApiKeys);
20039
+ const sessionManager = options.sessionPath ? SessionManager.open(options.sessionPath, options.sessionDir, options.cwd) : SessionManager.create(options.cwd, options.sessionDir);
20040
+ const createRuntime = async ({
20041
+ cwd,
20042
+ agentDir: runtimeAgentDir,
20043
+ sessionManager: runtimeSessionManager,
20044
+ sessionStartEvent
20045
+ }) => {
20046
+ const services = await createAgentSessionServices({
20047
+ cwd,
20048
+ agentDir: runtimeAgentDir,
20049
+ modelRuntime,
20050
+ settingsManager,
20051
+ resourceLoaderOptions: {
20052
+ extensionFactories: [
20053
+ createAutoRAGInteractiveExtension(options.getSystemPrompt, options.contextTransform, options.onQuery)
20054
+ ],
20055
+ systemPrompt: options.getSystemPrompt(),
20056
+ appendSystemPrompt: []
20057
+ }
20058
+ });
20059
+ const result = await createAgentSessionFromServices({
20060
+ services,
20061
+ sessionManager: runtimeSessionManager,
20062
+ sessionStartEvent,
20063
+ customTools: options.customTools.map(toToolDefinition),
20064
+ tools: [...PI_BUILTIN_TOOL_NAMES, ...options.customTools.map((tool) => tool.name)],
20065
+ excludeTools: options.remoteSession ? ["edit", "write", "powershell"] : undefined
20066
+ });
20067
+ if (options.inactiveToolNames !== undefined && options.inactiveToolNames.length > 0) {
20068
+ const inactive = new Set(options.inactiveToolNames);
20069
+ result.session.setActiveToolsByName(result.session.getActiveToolNames().filter((name) => !inactive.has(name)));
20070
+ }
20071
+ return { ...result, services, diagnostics: services.diagnostics };
20072
+ };
20073
+ const runtime = await createAgentSessionRuntime(createRuntime, {
20074
+ cwd: options.cwd,
20075
+ agentDir,
20076
+ sessionManager
20167
20077
  });
20078
+ return { runtime, dispose: () => runtime.dispose() };
20079
+ }
20080
+ var PI_BUILTIN_TOOL_NAMES, EMBEDDED_AUTH_MARKER = "<autorag-embedded-model>";
20081
+ var init_pi_session = __esm(() => {
20082
+ PI_BUILTIN_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
20168
20083
  });
20169
20084
 
20170
20085
  // src/agent/query-peer-tool.ts
20171
- import { Type as Type13 } from "typebox";
20086
+ import { Type as Type12 } from "typebox";
20172
20087
  function failure4(alias, message) {
20173
20088
  const details = { method: "query_peer_agent", ok: false, alias, message };
20174
20089
  return { content: [{ type: "text", text: message }], details };
@@ -20273,18 +20188,18 @@ var QUERY_PEER_AGENT_TOOL_NAME = "query_peer_agent", queryPeerAgentSchema;
20273
20188
  var init_query_peer_tool = __esm(() => {
20274
20189
  init_simplex_query_store();
20275
20190
  init_simplex_server();
20276
- queryPeerAgentSchema = Type13.Object({
20277
- alias: Type13.String({ minLength: 1 }),
20278
- query: Type13.String({ minLength: 1, maxLength: 4096 }),
20279
- topK: Type13.Optional(Type13.Integer({ minimum: 1, maximum: 20 })),
20280
- scope: Type13.Optional(Type13.String())
20191
+ queryPeerAgentSchema = Type12.Object({
20192
+ alias: Type12.String({ minLength: 1 }),
20193
+ query: Type12.String({ minLength: 1, maxLength: 4096 }),
20194
+ topK: Type12.Optional(Type12.Integer({ minimum: 1, maximum: 20 })),
20195
+ scope: Type12.Optional(Type12.String())
20281
20196
  });
20282
20197
  });
20283
20198
 
20284
20199
  // src/agent/refresh-progress.ts
20285
20200
  import { randomUUID as randomUUID8 } from "node:crypto";
20286
20201
  import { mkdirSync as mkdirSync23, readFileSync as readFileSync23, renameSync as renameSync11, rmSync as rmSync7, writeFileSync as writeFileSync21 } from "node:fs";
20287
- import { dirname as dirname22 } from "node:path";
20202
+ import { dirname as dirname21 } from "node:path";
20288
20203
  function readRefreshProgress(root) {
20289
20204
  try {
20290
20205
  const parsed = JSON.parse(readFileSync23(refreshProgressPath(root), "utf8"));
@@ -20298,7 +20213,7 @@ function readRefreshProgress(root) {
20298
20213
  }
20299
20214
  function writeRefreshProgress(root, progress) {
20300
20215
  const path = refreshProgressPath(root);
20301
- mkdirSync23(dirname22(path), { recursive: true });
20216
+ mkdirSync23(dirname21(path), { recursive: true });
20302
20217
  const temporaryPath = `${path}.${randomUUID8()}.tmp`;
20303
20218
  try {
20304
20219
  writeFileSync21(temporaryPath, `${JSON.stringify(progress, null, 2)}
@@ -20521,7 +20436,7 @@ var init_search_documents = __esm(() => {
20521
20436
  });
20522
20437
 
20523
20438
  // src/agent/search-all-tool.ts
20524
- import { Type as Type14 } from "typebox";
20439
+ import { Type as Type13 } from "typebox";
20525
20440
  function createSearchAllDocumentsTool(provider) {
20526
20441
  return {
20527
20442
  name: SEARCH_ALL_DOCUMENTS_TOOL_NAME,
@@ -20574,17 +20489,17 @@ ${rows.join(`
20574
20489
  var SEARCH_ALL_DOCUMENTS_TOOL_NAME = "search_all_documents", searchAllSchema;
20575
20490
  var init_search_all_tool = __esm(() => {
20576
20491
  init_search_documents();
20577
- searchAllSchema = Type14.Object({
20578
- query: Type14.String({ description: "Query to search across all configured retrieval methods." }),
20579
- topK: Type14.Optional(Type14.Integer({
20492
+ searchAllSchema = Type13.Object({
20493
+ query: Type13.String({ description: "Query to search across all configured retrieval methods." }),
20494
+ topK: Type13.Optional(Type13.Integer({
20580
20495
  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."
20581
20496
  })),
20582
- scope: Type14.Optional(Type14.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
20497
+ scope: Type13.Optional(Type13.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
20583
20498
  });
20584
20499
  });
20585
20500
 
20586
20501
  // src/agent/search-minsync-tool.ts
20587
- import { Type as Type15 } from "typebox";
20502
+ import { Type as Type14 } from "typebox";
20588
20503
  function createSearchMinSyncDocumentsTool(getMethod, resolveScope = (scope) => scope) {
20589
20504
  return {
20590
20505
  name: SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
@@ -20655,17 +20570,17 @@ ${rows.join(`
20655
20570
  var SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME = "semantic_search_local_docs", searchMinSyncSchema;
20656
20571
  var init_search_minsync_tool = __esm(() => {
20657
20572
  init_search_documents();
20658
- searchMinSyncSchema = Type15.Object({
20659
- query: Type15.String({
20573
+ searchMinSyncSchema = Type14.Object({
20574
+ query: Type14.String({
20660
20575
  description: "Semantic query to search parsed document mirrors with MinSync vector retrieval."
20661
20576
  }),
20662
- topK: Type15.Optional(Type15.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
20663
- scope: Type15.Optional(Type15.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
20577
+ topK: Type14.Optional(Type14.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
20578
+ scope: Type14.Optional(Type14.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
20664
20579
  });
20665
20580
  });
20666
20581
 
20667
20582
  // src/agent/search-single-datasource-tool.ts
20668
- import { Type as Type16 } from "typebox";
20583
+ import { Type as Type15 } from "typebox";
20669
20584
  function createSingleDatasourceSearchTools(provider, specs) {
20670
20585
  return specs.map((spec) => createTool(provider, spec));
20671
20586
  }
@@ -20729,10 +20644,10 @@ var singleDatasourceToolName, searchSingleDatasourceSchema;
20729
20644
  var init_search_single_datasource_tool = __esm(() => {
20730
20645
  init_search_documents();
20731
20646
  singleDatasourceToolName = datasourceSearchToolName;
20732
- searchSingleDatasourceSchema = Type16.Object({
20733
- query: Type16.String({ description: "Query to search within this datasource connection." }),
20734
- topK: Type16.Optional(Type16.Integer({ description: "Maximum number of chunks to return. Defaults to 50." })),
20735
- scope: Type16.Optional(Type16.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
20647
+ searchSingleDatasourceSchema = Type15.Object({
20648
+ query: Type15.String({ description: "Query to search within this datasource connection." }),
20649
+ topK: Type15.Optional(Type15.Integer({ description: "Maximum number of chunks to return. Defaults to 50." })),
20650
+ scope: Type15.Optional(Type15.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
20736
20651
  });
20737
20652
  });
20738
20653
 
@@ -21245,7 +21160,7 @@ var init_url_target = __esm(() => {
21245
21160
  // src/web/fetch/convert.ts
21246
21161
  import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile3 } from "node:fs/promises";
21247
21162
  import { tmpdir as tmpdir2 } from "node:os";
21248
- import { join as join33 } from "node:path";
21163
+ import { join as join34 } from "node:path";
21249
21164
  function combineSignals3(signal, timeoutMs) {
21250
21165
  if (!signal)
21251
21166
  return AbortSignal.timeout(timeoutMs);
@@ -21321,8 +21236,8 @@ async function convertBinaryPayload(buffer, extension, _finalUrl, signal) {
21321
21236
  if (!parser) {
21322
21237
  return { content: "", ok: false, error: `No parser registered for ${ext}` };
21323
21238
  }
21324
- const tempDir = await mkdtemp2(join33(tmpdir2(), "autorag-fetch-"));
21325
- const tempPath = join33(tempDir, `payload${ext}`);
21239
+ const tempDir = await mkdtemp2(join34(tmpdir2(), "autorag-fetch-"));
21240
+ const tempPath = join34(tempDir, `payload${ext}`);
21326
21241
  try {
21327
21242
  await writeFile3(tempPath, buffer);
21328
21243
  const input = {
@@ -22881,7 +22796,7 @@ var init_render = __esm(() => {
22881
22796
  });
22882
22797
 
22883
22798
  // src/agent/web-fetch-tool.ts
22884
- import { Type as Type17 } from "typebox";
22799
+ import { Type as Type16 } from "typebox";
22885
22800
  function truncateHead(output, maxBytes, maxLines) {
22886
22801
  const lines = output.split(`
22887
22802
  `);
@@ -22978,9 +22893,9 @@ var WEB_FETCH_TOOL_NAME = "web_fetch", FETCH_DEFAULT_MAX_LINES = 300, FETCH_MAX_
22978
22893
  var init_web_fetch_tool = __esm(() => {
22979
22894
  init_render();
22980
22895
  FETCH_MAX_OUTPUT_BYTES = 50 * 1024;
22981
- webFetchSchema = Type17.Object({
22982
- url: Type17.String({ description: "The http(s) URL to fetch and read." }),
22983
- raw: Type17.Optional(Type17.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
22896
+ webFetchSchema = Type16.Object({
22897
+ url: Type16.String({ description: "The http(s) URL to fetch and read." }),
22898
+ raw: Type16.Optional(Type16.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
22984
22899
  });
22985
22900
  });
22986
22901
 
@@ -26406,7 +26321,7 @@ var init_search = __esm(() => {
26406
26321
  });
26407
26322
 
26408
26323
  // src/agent/web-search-tool.ts
26409
- import { Type as Type18 } from "typebox";
26324
+ import { Type as Type17 } from "typebox";
26410
26325
  function createWebSearchTool(options = {}) {
26411
26326
  return {
26412
26327
  name: WEB_SEARCH_TOOL_NAME,
@@ -26476,24 +26391,23 @@ function createWebSearchTool(options = {}) {
26476
26391
  var WEB_SEARCH_TOOL_NAME = "web_search", webSearchSchema;
26477
26392
  var init_web_search_tool = __esm(() => {
26478
26393
  init_search();
26479
- webSearchSchema = Type18.Object({
26480
- query: Type18.String({
26394
+ webSearchSchema = Type17.Object({
26395
+ query: Type17.String({
26481
26396
  description: 'Search query. Supports Google-style directives: site:/-site:, after:/before: (YYYY-MM-DD), inurl:, intitle:, filetype:, "exact phrase", -term, OR.'
26482
26397
  }),
26483
- recency: Type18.Optional(Type18.Union([Type18.Literal("day"), Type18.Literal("week"), Type18.Literal("month"), Type18.Literal("year")], {
26398
+ recency: Type17.Optional(Type17.Union([Type17.Literal("day"), Type17.Literal("week"), Type17.Literal("month"), Type17.Literal("year")], {
26484
26399
  description: "Optional recency window for results (pure time filter)."
26485
26400
  })),
26486
- limit: Type18.Optional(Type18.Integer({ description: "Maximum number of results to return." })),
26487
- num_search_results: Type18.Optional(Type18.Integer({ description: "Alias for limit (result count hint)." }))
26401
+ limit: Type17.Optional(Type17.Integer({ description: "Maximum number of results to return." })),
26402
+ num_search_results: Type17.Optional(Type17.Integer({ description: "Alias for limit (result count hint)." }))
26488
26403
  });
26489
26404
  });
26490
26405
 
26491
26406
  // src/agent/agent.ts
26492
26407
  import { randomUUID as randomUUID9 } from "node:crypto";
26493
26408
  import { existsSync as existsSync29, watch as fsWatch, mkdirSync as mkdirSync24, realpathSync as realpathSync5, statSync, writeFileSync as writeFileSync22 } from "node:fs";
26494
- import { basename as basename14, dirname as dirname23, join as join34, resolve as resolve15 } from "node:path";
26495
- import { Agent } from "@earendil-works/pi-agent-core";
26496
- import { clampThinkingLevel, streamSimple } from "@earendil-works/pi-ai/compat";
26409
+ import { basename as basename14, dirname as dirname22, join as join35, resolve as resolve15 } from "node:path";
26410
+ import { clampThinkingLevel } from "@earendil-works/pi-ai/compat";
26497
26411
  function hasSearchEvidence(toolName, details, isError) {
26498
26412
  if (isError || details === null || typeof details !== "object")
26499
26413
  return false;
@@ -26510,9 +26424,6 @@ function hasSearchEvidence(toolName, details, isError) {
26510
26424
  }
26511
26425
  return Array.isArray(outcome.sources) && outcome.sources.some((source) => typeof source === "string" && source.trim().length > 0) || Array.isArray(outcome.results) && outcome.results.some((result) => result !== null && typeof result === "object" && typeof result.source === "string" && result.source.trim().length > 0);
26512
26426
  }
26513
- function keepLlmMessages(messages) {
26514
- return messages.filter((message) => message.role === "system" || message.role === "user" || message.role === "assistant" || message.role === "toolResult");
26515
- }
26516
26427
  function positiveLimit(value, fallback, path) {
26517
26428
  if (value === undefined)
26518
26429
  return fallback;
@@ -26553,6 +26464,7 @@ class AutoRAGAgent {
26553
26464
  sessions = new Map;
26554
26465
  activeRun = false;
26555
26466
  resultCapture;
26467
+ interactiveFastAnswerCallback;
26556
26468
  modelNativeSearchAuth;
26557
26469
  retrievalTrace = [];
26558
26470
  preliminaryCallback;
@@ -26601,6 +26513,10 @@ class AutoRAGAgent {
26601
26513
  droppedCallerToolNames;
26602
26514
  searchTimeoutMs;
26603
26515
  maxSearchToolCalls;
26516
+ piAgentDir;
26517
+ piSessionDir;
26518
+ persistPiSessions;
26519
+ boundPiRuntime;
26604
26520
  remoteSession;
26605
26521
  activeRetrievalOptions;
26606
26522
  searchToolCallCount = 0;
@@ -26622,6 +26538,9 @@ class AutoRAGAgent {
26622
26538
  this.finalThinkingLevel = thinking === false ? undefined : thinking?.final ?? "high";
26623
26539
  this.apiKey = options.apiKey;
26624
26540
  this.providerApiKeys = options.providerApiKeys;
26541
+ this.piAgentDir = options.piAgentDir;
26542
+ this.piSessionDir = options.piSessionDir;
26543
+ this.persistPiSessions = options.persistPiSessions ?? true;
26625
26544
  const manifests = manifestDir ? loadManifests(manifestDir) : [];
26626
26545
  this.datasourceSkills = options.datasourceSkills ?? [];
26627
26546
  this.datasourceVirtualScopePrefixes = this.datasourceSkills.map((skill) => normalizeVirtualPath2(`/${skill.describe().name}`));
@@ -26682,10 +26601,10 @@ class AutoRAGAgent {
26682
26601
  if (fsearchClient.isSupported())
26683
26602
  this.fsearchClient = fsearchClient;
26684
26603
  }
26685
- const memPath = memoryPath ?? join34(resolveAutoRAGHome(), "memory.json");
26604
+ const memPath = memoryPath ?? join35(resolveAutoRAGHome(), "memory.json");
26686
26605
  this.memory = new RetrievalMemory({ storagePath: memPath });
26687
26606
  this.memory.load();
26688
- this.runLogger = new AutoRAGRunLogger(join34(dirname23(memPath), "logs", "runs.jsonl"));
26607
+ this.runLogger = new AutoRAGRunLogger(join35(dirname22(memPath), "logs", "runs.jsonl"));
26689
26608
  const checkMemoryTool = createCheckMemoryTool(this.memory);
26690
26609
  const singleDatasourceTools = createSingleDatasourceSearchTools(this, this.singleDatasourceToolSpecs());
26691
26610
  this.searchToolNames = new Set([...SEARCH_TOOLS, ...singleDatasourceTools.map((tool) => tool.name)]);
@@ -26694,16 +26613,13 @@ class AutoRAGAgent {
26694
26613
  const loadDatasourceSkillTool = createLoadDatasourceSkillTool(this);
26695
26614
  const emitResultsTool = createEmitResultsTool((details) => this.resultCapture?.(details));
26696
26615
  const scanDuplicateDocumentsTool = this.dupeyOptions === false ? undefined : createScanDuplicateDocumentsTool(this);
26697
- const bashTool = createBashTool({
26698
- cwd: this.workspaceProjectRoot
26699
- });
26700
26616
  const peerTargetTool = this.remoteSession ? undefined : createRecommendPeerTargetsTool(this.workspaceProjectRoot);
26701
26617
  const peerQuery = options.peerQuery;
26702
26618
  const queryPeerTool = this.remoteSession || peerQuery === undefined || peerQuery === false ? undefined : createQueryPeerAgentTool({
26703
26619
  workspacePath: this.workspaceProjectRoot,
26704
26620
  onResponse: peerQuery?.onResponse,
26705
26621
  openTransport: peerQuery?.openTransport ?? (() => openPeerQueryTransport({
26706
- dbPrefix: peerQuery?.simplexDbPrefix ?? join34(this.workspaceProjectRoot, ".autorag", "p2p", "simplex"),
26622
+ dbPrefix: peerQuery?.simplexDbPrefix ?? join35(this.workspaceProjectRoot, ".autorag", "p2p", "simplex"),
26707
26623
  displayName: `autorag-${basename14(this.workspaceProjectRoot) || "node"}`
26708
26624
  })),
26709
26625
  autoStart: true,
@@ -26717,7 +26633,7 @@ class AutoRAGAgent {
26717
26633
  const webSearchTool = webToolsEnabled ? createWebSearchTool({ ...webSearchOption ?? {}, modelAuth: () => this.modelNativeSearchAuth }) : undefined;
26718
26634
  const webFetchTool = webToolsEnabled && webSearchOption?.fetch !== false ? createWebFetchTool(webSearchOption?.fetch ?? {}) : undefined;
26719
26635
  const reservedNames = new Set([
26720
- BASH_TOOL_NAME,
26636
+ ...PI_BUILTIN_TOOL_NAMES,
26721
26637
  "check_memory",
26722
26638
  ...singleDatasourceTools.map((tool) => tool.name),
26723
26639
  LOAD_DATASOURCE_SKILL_TOOL_NAME,
@@ -26744,7 +26660,6 @@ class AutoRAGAgent {
26744
26660
  });
26745
26661
  this.droppedCallerToolNames = [...new Set(droppedCallerToolNames)];
26746
26662
  const orderedTools = [
26747
- ...bashTool !== undefined ? [bashTool] : [],
26748
26663
  ...callerTools,
26749
26664
  checkMemoryTool,
26750
26665
  searchMinSyncTool,
@@ -26769,7 +26684,7 @@ class AutoRAGAgent {
26769
26684
  return true;
26770
26685
  });
26771
26686
  this.tools = tools;
26772
- const toolNames = tools.map((tool) => tool.name);
26687
+ const toolNames = [...PI_BUILTIN_TOOL_NAMES, ...tools.map((tool) => tool.name)];
26773
26688
  this.baseSystemPromptConfig = {
26774
26689
  toolNames,
26775
26690
  modelId: options.model?.id,
@@ -26780,28 +26695,14 @@ class AutoRAGAgent {
26780
26695
  retrievedContentGuard: false
26781
26696
  };
26782
26697
  const systemPrompt = buildSystemPrompt(this.currentSystemPromptConfig());
26783
- this.innerAgent = new Agent({
26784
- initialState: {
26698
+ this.innerAgent = {
26699
+ state: {
26785
26700
  systemPrompt,
26786
- model: options.model,
26787
- tools
26701
+ tools: [...PI_BUILTIN_TOOL_NAMES.map((name) => ({ name })), ...tools],
26702
+ messages: []
26788
26703
  },
26789
- streamFn: streamSimple,
26790
- convertToLlm: keepLlmMessages,
26791
- transformContext: async (messages) => this.withMemoryContext(messages),
26792
- afterToolCall: async (context) => {
26793
- const toolName = context.toolCall.name;
26794
- if (!this.lastQuery || !this.searchToolNames.has(toolName))
26795
- return;
26796
- if (!hasSearchEvidence(toolName, context.result.details, context.isError))
26797
- return;
26798
- const details = context.result.details;
26799
- const method = details?.method ?? toolName;
26800
- this.memory.recordWeakSignal(this.lastQuery, method, "followup");
26801
- this.memory.save();
26802
- return;
26803
- }
26804
- });
26704
+ transformContext: (messages) => this.withMemoryContext(messages)
26705
+ };
26805
26706
  if (options.autoRefresh) {
26806
26707
  this.startAutoRefresh(options.autoRefresh.intervalMs, { immediate: options.autoRefresh.immediate });
26807
26708
  }
@@ -26842,7 +26743,16 @@ ${summary}
26842
26743
  ...messages
26843
26744
  ];
26844
26745
  }
26845
- resolveSessionModel() {
26746
+ async resolveSessionModel() {
26747
+ const boundModel = this.boundPiRuntime?.session.model;
26748
+ if (boundModel !== undefined) {
26749
+ const auth = await this.boundPiRuntime?.session.modelRuntime.getAuth(boundModel);
26750
+ const apiKey = auth?.auth.apiKey;
26751
+ return {
26752
+ model: boundModel,
26753
+ ...apiKey !== undefined ? { apiKey, providerApiKeys: { [boundModel.provider]: apiKey } } : {}
26754
+ };
26755
+ }
26846
26756
  if (this.configuredModel !== undefined) {
26847
26757
  return {
26848
26758
  model: this.configuredModel,
@@ -26857,19 +26767,40 @@ ${summary}
26857
26767
  providerApiKeys: { [local.provider]: local.apiKey }
26858
26768
  };
26859
26769
  }
26860
- createSearchSession(resolved, systemPrompt) {
26861
- const agent = new Agent({
26862
- initialState: { systemPrompt, model: resolved.model, tools: [...this.tools] },
26863
- streamFn: streamSimple,
26864
- getApiKey: (provider) => resolved.providerApiKeys?.[provider] ?? (provider === resolved.model.provider ? resolved.apiKey : undefined),
26865
- convertToLlm: keepLlmMessages,
26866
- transformContext: async (messages) => this.withMemoryContext(messages)
26770
+ async createSearchSession(resolved, systemPrompt, extraTools = []) {
26771
+ if (this.boundPiRuntime !== undefined) {
26772
+ const session = this.boundPiRuntime.session;
26773
+ return {
26774
+ agent: session.agent,
26775
+ piSession: session,
26776
+ prompt: async (prompt) => session.prompt(prompt, { source: "extension" }),
26777
+ abort: async () => session.abort(),
26778
+ dispose: () => {}
26779
+ };
26780
+ }
26781
+ const piSession = await createAutoRAGPiSession({
26782
+ cwd: this.workspaceProjectRoot,
26783
+ agentDir: this.piAgentDir,
26784
+ sessionDir: this.piSessionDir,
26785
+ persistSession: this.persistPiSessions,
26786
+ model: resolved.model,
26787
+ apiKey: resolved.apiKey,
26788
+ providerApiKeys: resolved.providerApiKeys,
26789
+ getSystemPrompt: () => systemPrompt,
26790
+ customTools: [
26791
+ ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
26792
+ ...extraTools
26793
+ ],
26794
+ remoteSession: this.remoteSession,
26795
+ contextTransform: (messages) => this.withMemoryContext(messages)
26867
26796
  });
26797
+ const agent = piSession.session.agent;
26868
26798
  return {
26869
26799
  agent,
26870
- prompt: async (prompt) => agent.prompt(prompt),
26871
- abort: async () => agent.abort(),
26872
- dispose: () => {}
26800
+ piSession: piSession.session,
26801
+ prompt: async (prompt) => piSession.session.prompt(prompt, { source: "extension" }),
26802
+ abort: async () => piSession.session.abort(),
26803
+ dispose: () => piSession.session.dispose()
26873
26804
  };
26874
26805
  }
26875
26806
  configureSearchSession(session) {
@@ -26920,6 +26851,55 @@ ${summary}
26920
26851
  this.listeners.delete(listener);
26921
26852
  };
26922
26853
  }
26854
+ async createPiInteractiveRuntime() {
26855
+ const resolved = this.configuredModel === undefined ? undefined : await this.resolveSessionModel();
26856
+ const runtime = await createAutoRAGPiInteractiveRuntime({
26857
+ cwd: this.workspaceProjectRoot,
26858
+ agentDir: this.piAgentDir,
26859
+ sessionDir: this.piSessionDir,
26860
+ persistSession: this.persistPiSessions,
26861
+ ...resolved === undefined ? {} : {
26862
+ model: resolved.model,
26863
+ ...resolved.apiKey !== undefined ? { apiKey: resolved.apiKey } : {},
26864
+ ...resolved.providerApiKeys !== undefined ? { providerApiKeys: resolved.providerApiKeys } : {}
26865
+ },
26866
+ getSystemPrompt: () => buildSystemPrompt(this.currentSystemPromptConfig({
26867
+ modelId: this.boundPiRuntime?.session.model?.id ?? resolved?.model.id
26868
+ })),
26869
+ contextTransform: (messages) => this.withMemoryContext(messages),
26870
+ customTools: [
26871
+ ...this.tools.filter((tool) => !PI_BUILTIN_TOOL_NAMES.includes(tool.name)),
26872
+ ...this.fastThinkingLevel === undefined ? [] : [createEmitFastAnswerTool((details) => this.interactiveFastAnswerCallback?.(details))]
26873
+ ],
26874
+ onQuery: (query, pi) => this.runInteractivePiQuery(query, pi),
26875
+ inactiveToolNames: this.fastThinkingLevel === undefined ? [] : [EMIT_FAST_ANSWER_TOOL_NAME]
26876
+ });
26877
+ this.boundPiRuntime = runtime.runtime;
26878
+ if (this.fastThinkingLevel !== undefined) {
26879
+ runtime.runtime.session.setActiveToolsByName(runtime.runtime.session.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
26880
+ }
26881
+ const dispose = runtime.dispose;
26882
+ return {
26883
+ ...runtime,
26884
+ dispose: async () => {
26885
+ if (this.boundPiRuntime === runtime.runtime)
26886
+ this.boundPiRuntime = undefined;
26887
+ await dispose();
26888
+ }
26889
+ };
26890
+ }
26891
+ async runInteractivePiQuery(query, pi) {
26892
+ pi.setSessionName(query.slice(0, 80));
26893
+ for await (const event of this.searchDocumentsStream(query)) {
26894
+ const text = event.type === "progress" ? event.text : event.response.answer;
26895
+ pi.sendMessage({
26896
+ customType: `autorag.${event.type}`,
26897
+ content: [{ type: "text", text }],
26898
+ display: true,
26899
+ details: event
26900
+ });
26901
+ }
26902
+ }
26923
26903
  abort() {
26924
26904
  this.activeSession?.abort();
26925
26905
  }
@@ -27002,14 +26982,21 @@ ${summary}
27002
26982
  this.scheduleMinSyncPrepare();
27003
26983
  let captured;
27004
26984
  let fastCaptured;
26985
+ const emitPreliminary = (details) => {
26986
+ if (fastCaptured !== undefined)
26987
+ return;
26988
+ fastCaptured = details;
26989
+ this.preliminaryCallback?.(createPreliminarySearchDocumentsResponse(sessionId, trimmedQuery, details, this.collectComponentDiagnostics()));
26990
+ };
27005
26991
  let session;
26992
+ this.interactiveFastAnswerCallback = emitPreliminary;
27006
26993
  let unsubscribers = [];
27007
26994
  this.resultCapture = (details) => {
27008
26995
  captured = details;
27009
26996
  };
27010
26997
  let searchStarted = false;
27011
26998
  try {
27012
- const resolved = this.resolveSessionModel();
26999
+ const resolved = await this.resolveSessionModel();
27013
27000
  this.modelNativeSearchAuth = modelNativeAuthFromAgentModel({
27014
27001
  provider: resolved.model.provider,
27015
27002
  ...resolved.apiKey !== undefined ? { apiKey: resolved.apiKey } : {},
@@ -27024,7 +27011,7 @@ ${summary}
27024
27011
  model: resolved.model.id
27025
27012
  });
27026
27013
  searchStarted = true;
27027
- session = this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })));
27014
+ session = await this.createSearchSession(resolved, buildSystemPrompt(this.currentSystemPromptConfig({ modelId: resolved.model.id })), this.fastThinkingLevel === undefined ? [] : [createEmitFastAnswerTool(emitPreliminary)]);
27028
27015
  this.activeSession = session;
27029
27016
  unsubscribers = this.configureSearchSession(session);
27030
27017
  let timeout;
@@ -27042,28 +27029,35 @@ ${initialRetrievalContext}`);
27042
27029
  }
27043
27030
  return;
27044
27031
  }
27045
- const emitPreliminary = (details) => {
27046
- if (fastCaptured !== undefined)
27047
- return;
27048
- fastCaptured = details;
27049
- this.preliminaryCallback?.(createPreliminarySearchDocumentsResponse(sessionId, trimmedQuery, details, this.collectComponentDiagnostics()));
27050
- };
27051
- const fastTool = createEmitFastAnswerTool(emitPreliminary);
27052
27032
  const baseline = await retrievalPromise;
27053
- session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.fastThinkingLevel);
27054
- session.agent.state.tools = [...this.tools, fastTool];
27033
+ const sessionAgent = session.piSession;
27034
+ if (sessionAgent !== undefined) {
27035
+ sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.fastThinkingLevel));
27036
+ sessionAgent.setActiveToolsByName([
27037
+ ...sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME),
27038
+ EMIT_FAST_ANSWER_TOOL_NAME
27039
+ ]);
27040
+ } else {
27041
+ session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.fastThinkingLevel);
27042
+ session.agent.state.tools = [...this.tools, { name: EMIT_FAST_ANSWER_TOOL_NAME }];
27043
+ }
27055
27044
  await session.prompt(this.buildFastAnswerPrompt(trimmedQuery, options, baseline));
27056
27045
  let preliminary = fastCaptured;
27057
27046
  if (preliminary === undefined) {
27058
- const text = lastAssistantText(session.agent.state.messages);
27047
+ const text = lastAssistantText(session.piSession?.messages ?? session.agent.state.messages);
27059
27048
  if (text !== undefined)
27060
27049
  preliminary = { answer: text, results: [], sources: [] };
27061
27050
  }
27062
27051
  if (preliminary !== undefined)
27063
27052
  emitPreliminary(preliminary);
27064
27053
  if (captured === undefined && this.finalThinkingLevel !== undefined) {
27065
- session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
27066
- session.agent.state.tools = [...this.tools];
27054
+ if (sessionAgent !== undefined) {
27055
+ sessionAgent.setThinkingLevel(clampThinkingLevel(resolved.model, this.finalThinkingLevel));
27056
+ sessionAgent.setActiveToolsByName(sessionAgent.getActiveToolNames().filter((name) => name !== EMIT_FAST_ANSWER_TOOL_NAME));
27057
+ } else {
27058
+ session.agent.state.thinkingLevel = clampThinkingLevel(resolved.model, this.finalThinkingLevel);
27059
+ session.agent.state.tools = [...this.tools];
27060
+ }
27067
27061
  const fastAnswerDelivered = preliminary !== undefined && this.preliminaryCallback !== undefined;
27068
27062
  await session.prompt(this.buildRefinementPrompt(trimmedQuery, options, preliminary, fastAnswerDelivered));
27069
27063
  }
@@ -27192,6 +27186,8 @@ ${initialRetrievalContext}`);
27192
27186
  this.resultCapture = undefined;
27193
27187
  this.activeRetrievalOptions = undefined;
27194
27188
  this.preliminaryCallback = undefined;
27189
+ if (this.interactiveFastAnswerCallback === emitPreliminary)
27190
+ this.interactiveFastAnswerCallback = undefined;
27195
27191
  this.activeRun = false;
27196
27192
  }
27197
27193
  }
@@ -27588,7 +27584,7 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
27588
27584
  lastError: undefined
27589
27585
  };
27590
27586
  if (needsParsed) {
27591
- mkdirSync24(dirname23(refreshReadinessPath(this.workspaceProjectRoot)), { recursive: true });
27587
+ mkdirSync24(dirname22(refreshReadinessPath(this.workspaceProjectRoot)), { recursive: true });
27592
27588
  writeFileSync22(refreshReadinessPath(this.workspaceProjectRoot), `{"version":1,"completed":true,"parsed":true}
27593
27589
  `);
27594
27590
  }
@@ -27800,7 +27796,7 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
27800
27796
  written: 0,
27801
27797
  deleted: 0,
27802
27798
  skipped: 0,
27803
- indexPath: join34(this.workspaceProjectRoot, PARSED_MIRROR_SUBDIR),
27799
+ indexPath: join35(this.workspaceProjectRoot, PARSED_MIRROR_SUBDIR),
27804
27800
  diagnostics
27805
27801
  };
27806
27802
  }
@@ -28346,7 +28342,7 @@ function toMinSyncReasonDiagnostic(reason) {
28346
28342
  function pinExcludedPath(path) {
28347
28343
  const resolvedPath = resolve15(path);
28348
28344
  try {
28349
- return join34(realpathSync5(dirname23(resolvedPath)), basename14(resolvedPath));
28345
+ return join35(realpathSync5(dirname22(resolvedPath)), basename14(resolvedPath));
28350
28346
  } catch {
28351
28347
  return resolvedPath;
28352
28348
  }
@@ -28407,7 +28403,6 @@ var init_agent = __esm(() => {
28407
28403
  init_rerank();
28408
28404
  init_scope();
28409
28405
  init_model_auth();
28410
- init_bash_tool();
28411
28406
  init_datasource_skill();
28412
28407
  init_dupey_tool();
28413
28408
  init_emit_results_tool();
@@ -28417,6 +28412,7 @@ var init_agent = __esm(() => {
28417
28412
  init_jikji_find_tool();
28418
28413
  init_local_model();
28419
28414
  init_peer_target_tool();
28415
+ init_pi_session();
28420
28416
  init_query_peer_tool();
28421
28417
  init_refresh_progress();
28422
28418
  init_search_all_tool();
@@ -28626,7 +28622,7 @@ async function runSearch(ctx, deps = {}) {
28626
28622
  } else {
28627
28623
  let resolvedModel;
28628
28624
  try {
28629
- resolvedModel = (deps.modelResolver ?? resolveAgentModel)(config);
28625
+ resolvedModel = await (deps.modelResolver ?? resolveAgentModel)(config);
28630
28626
  } catch (error) {
28631
28627
  const hint = classifySearchHealthHint(error);
28632
28628
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug, hint }));
@@ -28855,7 +28851,7 @@ var init_memory2 = __esm(() => {
28855
28851
 
28856
28852
  // src/cli/commands/index.ts
28857
28853
  import { existsSync as existsSync30, lstatSync as lstatSync3, rmSync as rmSync8 } from "node:fs";
28858
- import { join as join35, resolve as resolve16, sep as sep8 } from "node:path";
28854
+ import { join as join36, resolve as resolve16, sep as sep7 } from "node:path";
28859
28855
  async function runIndex(ctx) {
28860
28856
  const sub = ctx.positionals[0];
28861
28857
  if (sub !== "reset" && sub !== "rebuild") {
@@ -28889,7 +28885,7 @@ async function runIndex(ctx) {
28889
28885
  }
28890
28886
  if (!ctx.flags.yes) {
28891
28887
  if (ctx.promptYesNo) {
28892
- const ok = await ctx.promptYesNo(`Reset the ${targetNames.join(", ")} indexes under ${join35(config.workspacePath, ".autorag")}?`);
28888
+ const ok = await ctx.promptYesNo(`Reset the ${targetNames.join(", ")} indexes under ${join36(config.workspacePath, ".autorag")}?`);
28893
28889
  if (!ok) {
28894
28890
  ctx.stderr(renderError(new Error("Reset declined."), { json: ctx.json }));
28895
28891
  return 2;
@@ -28953,7 +28949,7 @@ function resolveResetScope(methods) {
28953
28949
  };
28954
28950
  }
28955
28951
  function isWithin(target, base) {
28956
- const prefix = base.endsWith(sep8) ? base : `${base}${sep8}`;
28952
+ const prefix = base.endsWith(sep7) ? base : `${base}${sep7}`;
28957
28953
  return target === base || target.startsWith(prefix);
28958
28954
  }
28959
28955
  var ALL_RESET_TARGETS, ALL_RESET_TARGET_NAMES;
@@ -29045,7 +29041,7 @@ function sanitizeMessage(raw) {
29045
29041
  function parseTimeoutMs(flags) {
29046
29042
  const raw = flags["timeout-ms"];
29047
29043
  if (raw === undefined || raw === true)
29048
- return DEFAULT_TIMEOUT_MS11;
29044
+ return DEFAULT_TIMEOUT_MS10;
29049
29045
  const text = typeof raw === "string" ? raw.trim() : "";
29050
29046
  if (!/^\d+$/.test(text) || Number(text) <= 0) {
29051
29047
  return `--timeout-ms must be a positive integer (got "${text}")`;
@@ -29159,7 +29155,7 @@ async function runHealth(ctx, deps = {}) {
29159
29155
  }
29160
29156
  let resolved;
29161
29157
  try {
29162
- const detailed = (deps.modelResolver ?? resolveAgentModelDetailed)(config);
29158
+ const detailed = await (deps.modelResolver ?? resolveAgentModelDetailed)(config);
29163
29159
  resolved = detailed;
29164
29160
  } catch (error) {
29165
29161
  const report = {
@@ -29228,7 +29224,7 @@ async function runHealth(ctx, deps = {}) {
29228
29224
  ctx.stdout(renderHealth(report, { json: ctx.json, debug: ctx.debug }));
29229
29225
  return exitCode(probe.category);
29230
29226
  }
29231
- var DEFAULT_TIMEOUT_MS11 = 1e4;
29227
+ var DEFAULT_TIMEOUT_MS10 = 1e4;
29232
29228
  var init_health = __esm(() => {
29233
29229
  init_config2();
29234
29230
  });
@@ -29290,289 +29286,8 @@ var init_duplicates = __esm(() => {
29290
29286
  init_config2();
29291
29287
  });
29292
29288
 
29293
- // src/cli/tui-commands.ts
29294
- function parseSlashCommand(input) {
29295
- const trimmed = input.trim();
29296
- if (!trimmed.startsWith("/"))
29297
- return;
29298
- const [rawName, ...args] = trimmed.slice(1).split(/\s+/u);
29299
- if (!rawName)
29300
- return { kind: "incomplete" };
29301
- if (rawName === "quit")
29302
- return { kind: "quit" };
29303
- if (rawName === "resume") {
29304
- const sessionId = args.join(" ").trim();
29305
- return { kind: "resume", sessionId: sessionId || undefined };
29306
- }
29307
- return { kind: "unknown", name: rawName };
29308
- }
29309
- function createTuiSlashCommands(store) {
29310
- return [
29311
- { name: "quit", description: "Exit the AutoRAG TUI" },
29312
- {
29313
- name: "resume",
29314
- description: "List or restore a previous TUI session",
29315
- argumentHint: "[number|session-id]",
29316
- getArgumentCompletions: (prefix) => {
29317
- const normalized = prefix.trim().toLowerCase();
29318
- return store.list().filter((session) => normalized.length === 0 || session.id.toLowerCase().includes(normalized) || session.query.toLowerCase().includes(normalized)).map((session) => ({
29319
- value: session.id,
29320
- label: session.id,
29321
- description: session.query
29322
- }));
29323
- }
29324
- }
29325
- ];
29326
- }
29327
- function renderSlashHelp() {
29328
- return "commands: /quit, /resume [session-id]";
29329
- }
29330
-
29331
- // src/cli/tui-session-store.ts
29332
- import { existsSync as existsSync31, mkdirSync as mkdirSync25, readFileSync as readFileSync24, renameSync as renameSync12, writeFileSync as writeFileSync23 } from "node:fs";
29333
- import { dirname as dirname24 } from "node:path";
29334
- function createFileTuiSessionStore(path) {
29335
- const readSessions = () => {
29336
- if (!existsSync31(path))
29337
- return [];
29338
- try {
29339
- const parsed = JSON.parse(readFileSync24(path, "utf8"));
29340
- if (!Array.isArray(parsed))
29341
- return [];
29342
- return parsed.filter(isTuiSessionRecord).sort((a, b) => b.updatedAt - a.updatedAt);
29343
- } catch {
29344
- return [];
29345
- }
29346
- };
29347
- return {
29348
- list: readSessions,
29349
- get: (id) => readSessions().find((session) => session.id === id),
29350
- save: (session) => {
29351
- const sessions = readSessions().filter((item) => item.id !== session.id);
29352
- sessions.unshift(session);
29353
- const dir = dirname24(path);
29354
- mkdirSync25(dir, { recursive: true });
29355
- const tmpPath = `${path}.${process.pid}.tmp`;
29356
- writeFileSync23(tmpPath, `${JSON.stringify(sessions.slice(0, MAX_SESSIONS), null, 2)}
29357
- `, "utf8");
29358
- renameSync12(tmpPath, path);
29359
- }
29360
- };
29361
- }
29362
- function createMergedTuiSessionStore(...stores) {
29363
- return {
29364
- list: () => {
29365
- const sessions = new Map;
29366
- for (const store of stores) {
29367
- for (const session of store.list()) {
29368
- const current = sessions.get(session.id);
29369
- if (current === undefined || session.updatedAt > current.updatedAt) {
29370
- sessions.set(session.id, session);
29371
- }
29372
- }
29373
- }
29374
- return [...sessions.values()].sort((a, b) => b.updatedAt - a.updatedAt);
29375
- },
29376
- get: (id) => {
29377
- const matches = stores.flatMap((store) => store.list()).filter((session) => session.id === id).sort((a, b) => b.updatedAt - a.updatedAt);
29378
- return matches[0];
29379
- },
29380
- save: (session) => {
29381
- for (const store of stores)
29382
- store.save(session);
29383
- }
29384
- };
29385
- }
29386
- function renderTuiSessionList(sessions) {
29387
- if (sessions.length === 0)
29388
- return "resume: no saved sessions";
29389
- return [
29390
- "resume sessions:",
29391
- ...sessions.map((session, index) => ` ${index + 1}. ${session.query} [${session.id}]`),
29392
- "enter the session number to restore it"
29393
- ].join(`
29394
- `);
29395
- }
29396
- function renderRestoredTuiSession(session) {
29397
- return [`resumed: ${session.id}`, `> ${session.query}`, session.answer, "--- restored trace ---", session.trace].filter((line) => line.length > 0).join(`
29398
- `);
29399
- }
29400
- function isTuiSessionRecord(value) {
29401
- if (typeof value !== "object" || value === null)
29402
- return false;
29403
- const record = value;
29404
- return typeof record.id === "string" && typeof record.query === "string" && typeof record.answer === "string" && typeof record.trace === "string" && typeof record.updatedAt === "number";
29405
- }
29406
- var MAX_SESSIONS = 100;
29407
- var init_tui_session_store = () => {};
29408
-
29409
29289
  // src/cli/commands/tui.ts
29410
- import { join as join36 } from "node:path";
29411
- import {
29412
- CombinedAutocompleteProvider,
29413
- Editor,
29414
- ProcessTerminal,
29415
- Text,
29416
- TuiMainScreen
29417
- } from "@earendil-works/pi-tui";
29418
- function createTuiPresenter() {
29419
- const output = [];
29420
- let thinkingIndex;
29421
- let answer = "";
29422
- let active = false;
29423
- let paused = false;
29424
- let suppressEvents = false;
29425
- const lifecycleRows = new Map;
29426
- let statusText = "ready";
29427
- const append = (line) => {
29428
- output.push(line);
29429
- };
29430
- const appendDelta = (prefix, delta, index) => {
29431
- if (index === "answer") {
29432
- answer = `${answer.length === 0 ? prefix : answer}${delta}`;
29433
- return;
29434
- }
29435
- const currentIndex = thinkingIndex;
29436
- if (currentIndex === undefined) {
29437
- append(dimGray(`${prefix}${delta}`));
29438
- thinkingIndex = output.length - 1;
29439
- return;
29440
- }
29441
- output[currentIndex] = dimGray(`${stripAnsi(output[currentIndex])}${delta}`);
29442
- };
29443
- const updateLifecycle = (key, started, completed) => {
29444
- const index = lifecycleRows.get(key);
29445
- if (index === undefined) {
29446
- lifecycleRows.set(key, output.length);
29447
- append(started);
29448
- return;
29449
- }
29450
- output[index] = completed;
29451
- };
29452
- return {
29453
- working: () => active,
29454
- status: () => statusText,
29455
- reset: () => {
29456
- output.length = 0;
29457
- thinkingIndex = undefined;
29458
- answer = "";
29459
- active = false;
29460
- paused = false;
29461
- suppressEvents = false;
29462
- lifecycleRows.clear();
29463
- statusText = "ready";
29464
- },
29465
- setWorking: (value) => {
29466
- active = value;
29467
- statusText = value ? "working..." : "completed.";
29468
- },
29469
- beginRun: () => {
29470
- active = true;
29471
- statusText = "working...";
29472
- paused = false;
29473
- suppressEvents = false;
29474
- },
29475
- interrupt: () => {
29476
- active = false;
29477
- statusText = "stopped.";
29478
- paused = true;
29479
- suppressEvents = true;
29480
- },
29481
- handle(event) {
29482
- if (suppressEvents)
29483
- return;
29484
- switch (event.type) {
29485
- case "agent_start":
29486
- active = true;
29487
- statusText = "working...";
29488
- paused = false;
29489
- return;
29490
- case "agent_end":
29491
- active = false;
29492
- statusText = "completed.";
29493
- return;
29494
- case "turn_start":
29495
- return;
29496
- case "turn_end":
29497
- return;
29498
- case "message_start":
29499
- return;
29500
- case "message_end":
29501
- return;
29502
- case "message_update": {
29503
- const streamEvent = event.assistantMessageEvent;
29504
- if (streamEvent.type === "thinking_start") {
29505
- thinkingIndex = undefined;
29506
- } else if (streamEvent.type === "thinking_delta") {
29507
- appendDelta("thinking: ", streamEvent.delta, "thinking");
29508
- } else if (streamEvent.type === "thinking_end" && thinkingIndex !== undefined) {
29509
- output[thinkingIndex] = dimGray("thinking: (collapsed)");
29510
- thinkingIndex = undefined;
29511
- } else if (streamEvent.type === "text_start") {
29512
- answer = "";
29513
- } else if (streamEvent.type === "text_delta") {
29514
- appendDelta("assistant: ", streamEvent.delta, "answer");
29515
- }
29516
- return;
29517
- }
29518
- case "tool_execution_start":
29519
- updateLifecycle(`tool:${event.toolCallId}`, `${event.toolName}: searching`, `✓ ${event.toolName}: done`);
29520
- return;
29521
- case "tool_execution_update":
29522
- updateLifecycle(`tool:${event.toolCallId}`, `${event.toolName}: searching`, `${event.toolName}: searching`);
29523
- return;
29524
- case "tool_execution_end":
29525
- updateLifecycle(`tool:${event.toolCallId}`, `${event.toolName}: searching`, `${event.isError ? "✗" : "✓"} ${event.toolName}: ${event.isError ? "error" : "done"}`);
29526
- return;
29527
- }
29528
- },
29529
- lines: () => (paused ? ["paused"] : []).concat(output, answer.length > 0 ? [answer] : [])
29530
- };
29531
- }
29532
- function dimGray(text) {
29533
- return `${ANSI_DIM_GRAY}${text}${ANSI_RESET}`;
29534
- }
29535
- function renderProgressEvent(event) {
29536
- return event.type === "progress" && event.text.trim() !== "" ? event.text : undefined;
29537
- }
29538
- async function consumeSearchStream(agent, query, handlers) {
29539
- for await (const event of agent.searchDocumentsStream(query)) {
29540
- if (handlers.isInterrupted?.())
29541
- return;
29542
- switch (event.type) {
29543
- case "progress": {
29544
- const progress = renderProgressEvent(event);
29545
- if (progress !== undefined)
29546
- handlers.onProgress(progress);
29547
- break;
29548
- }
29549
- case "preliminary":
29550
- handlers.onPreliminary?.(event.response);
29551
- break;
29552
- case "complete":
29553
- handlers.onComplete(event.response);
29554
- break;
29555
- }
29556
- }
29557
- }
29558
- function stripAnsi(text) {
29559
- return text.replace(/\u001b\[[0-9;]*m/g, "");
29560
- }
29561
- function createAgent(ctx, deps) {
29562
- const thinking = parseThinkingFlags(ctx.flags);
29563
- if (deps.agentFactory)
29564
- return deps.agentFactory(thinking === undefined ? undefined : { thinking });
29565
- const config = resolveConfig({ flags: ctx.flags, cwd: ctx.cwd });
29566
- const resolvedModel = (deps.modelResolver ?? resolveAgentModel)(config);
29567
- const options = {
29568
- ...buildAgentOptions(config),
29569
- model: resolvedModel.model,
29570
- ...resolvedModel.apiKey !== undefined ? { apiKey: resolvedModel.apiKey } : {},
29571
- ...resolvedModel.providerApiKeys !== undefined ? { providerApiKeys: resolvedModel.providerApiKeys } : {},
29572
- ...thinking !== undefined ? { thinking } : {}
29573
- };
29574
- return new AutoRAGAgent(options);
29575
- }
29290
+ import { InteractiveMode } from "@earendil-works/pi-coding-agent";
29576
29291
  function parseThinkingFlags(flags) {
29577
29292
  if (flags["single-phase"] === true)
29578
29293
  return false;
@@ -29589,366 +29304,50 @@ function parseThinkingFlags(flags) {
29589
29304
  return;
29590
29305
  return { ...fast !== undefined ? { fast } : {}, ...final !== undefined ? { final } : {} };
29591
29306
  }
29592
- function createRealTui() {
29593
- return new TuiMainScreen(new ProcessTerminal);
29594
- }
29595
- function sessionForSelection(store, input) {
29596
- const sessions = store.list();
29597
- const index = Number.parseInt(input, 10);
29598
- if (Number.isInteger(index) && index > 0)
29599
- return sessions[index - 1];
29600
- return store.get(input);
29601
- }
29602
- function renderTuiSessionView(session, input) {
29603
- const content = session === undefined ? `resume: session not found: ${input}` : renderRestoredTuiSession(session);
29604
- return `${TUI_TITLE}
29605
-
29606
- ${content}`;
29607
- }
29608
- function defaultSessionStore(ctx) {
29307
+ async function createTuiAgent(ctx) {
29609
29308
  const config = resolveConfig({ flags: ctx.flags, cwd: ctx.cwd });
29610
- const workspace = createFileTuiSessionStore(join36(config.workspacePath, ".autorag", "tui-sessions.json"));
29611
- const global = createFileTuiSessionStore(join36(resolveAutoRAGHome(), "tui-sessions.json"));
29612
- return createMergedTuiSessionStore(workspace, global);
29613
- }
29614
- function runRealTui(ctx, agent, store) {
29615
- const tui = createRealTui();
29616
- let transcriptHistory = TUI_TITLE;
29617
- const transcript = new Text(transcriptHistory);
29618
- const presenter = createTuiPresenter();
29619
- let finalAnswer = "";
29620
- const renderTranscript = () => {
29621
- const trace = presenter.lines();
29622
- const sections = [
29623
- transcriptHistory,
29624
- trace.length > 0 ? `--- live trace ---
29625
- ${trace.join(`
29626
- `)}` : "",
29627
- finalAnswer
29628
- ];
29629
- transcript.setText(sections.filter((section) => section.length > 0).join(`
29630
-
29631
- `));
29632
- };
29633
- const status = new Text(presenter.status());
29634
- const renderStatus = () => {
29635
- status.setText(presenter.status());
29636
- };
29637
- const editor = new Editor(tui, {
29638
- borderColor: (value) => value,
29639
- selectList: {
29640
- selectedPrefix: (value) => value,
29641
- selectedText: (value) => value,
29642
- description: (value) => value,
29643
- scrollInfo: (value) => value,
29644
- noMatch: (value) => value
29645
- }
29646
- });
29647
- editor.setAutocompleteProvider(new CombinedAutocompleteProvider(createTuiSlashCommands(store), ctx.cwd));
29648
- let settled = false;
29649
- let queryRunning = false;
29650
- let interrupted = false;
29651
- let resumeSelection = false;
29652
- let completedResponse;
29653
- let completedAnswer = "";
29654
- return new Promise((resolve) => {
29655
- const finish = () => {
29656
- if (settled)
29657
- return;
29658
- settled = true;
29659
- unsubscribe?.();
29660
- tui.stop();
29661
- stopRuntime().catch(() => {
29662
- return;
29663
- }).finally(() => resolve(0));
29664
- };
29665
- const unsubscribe = agent.subscribe?.((event) => {
29666
- presenter.handle(event);
29667
- renderStatus();
29668
- renderTranscript();
29669
- tui.requestRender();
29670
- });
29671
- const handleInput = (data) => {
29672
- if (data === "\x03") {
29673
- if (queryRunning) {
29674
- interrupted = true;
29675
- presenter.interrupt();
29676
- agent.abort?.();
29677
- transcriptHistory = `${transcriptHistory}
29678
- interrupted`;
29679
- } else {
29680
- presenter.interrupt();
29681
- transcriptHistory = `${transcriptHistory}
29682
- paused`;
29683
- }
29684
- renderStatus();
29685
- renderTranscript();
29686
- tui.requestRender();
29687
- return;
29688
- }
29689
- if (data === "\x04")
29690
- finish();
29691
- };
29692
- editor.onSubmit = (raw) => {
29693
- const query = raw.trim();
29694
- editor.setText("");
29695
- if (query.length === 0)
29696
- return;
29697
- if (resumeSelection && !query.startsWith("/")) {
29698
- resumeSelection = false;
29699
- const session = sessionForSelection(store, query);
29700
- presenter.reset();
29701
- finalAnswer = "";
29702
- transcriptHistory = renderTuiSessionView(session, query);
29703
- renderTranscript();
29704
- tui.requestRender();
29705
- return;
29706
- }
29707
- resumeSelection = false;
29708
- const command = parseSlashCommand(query);
29709
- if (command !== undefined) {
29710
- if (command.kind === "quit") {
29711
- finish();
29712
- return;
29713
- }
29714
- if (command.kind === "incomplete" || command.kind === "unknown") {
29715
- transcriptHistory = `${transcriptHistory}
29716
-
29717
- ${command.kind === "unknown" ? `unknown command: /${command.name}` : renderSlashHelp()}`;
29718
- renderTranscript();
29719
- tui.requestRender();
29720
- return;
29721
- }
29722
- if (command.sessionId === undefined) {
29723
- presenter.reset();
29724
- finalAnswer = "";
29725
- resumeSelection = store.list().length > 0;
29726
- transcriptHistory = `${TUI_TITLE}
29727
-
29728
- ${renderTuiSessionList(store.list())}`;
29729
- } else {
29730
- const session = sessionForSelection(store, command.sessionId);
29731
- presenter.reset();
29732
- finalAnswer = "";
29733
- transcriptHistory = renderTuiSessionView(session, command.sessionId);
29734
- }
29735
- renderTranscript();
29736
- tui.requestRender();
29737
- return;
29738
- }
29739
- queryRunning = true;
29740
- interrupted = false;
29741
- presenter.beginRun();
29742
- editor.disableSubmit = true;
29743
- presenter.setWorking(true);
29744
- renderStatus();
29745
- finalAnswer = "";
29746
- transcriptHistory = `${transcriptHistory}
29747
-
29748
- > ${query}`;
29749
- renderTranscript();
29750
- tui.requestRender();
29751
- consumeSearchStream(agent, query, {
29752
- onProgress: (progress) => {
29753
- transcriptHistory = `${transcriptHistory}
29754
-
29755
- ${progress}`;
29756
- renderTranscript();
29757
- tui.requestRender();
29758
- },
29759
- onPreliminary: (response) => {
29760
- transcriptHistory = `${transcriptHistory}
29761
-
29762
- ${renderPreliminary(response, {
29763
- json: false,
29764
- debug: ctx.debug
29765
- })}`;
29766
- renderTranscript();
29767
- tui.requestRender();
29768
- },
29769
- onComplete: (response) => {
29770
- const answer = renderSearch(response, { json: false, debug: ctx.debug });
29771
- completedResponse = response;
29772
- completedAnswer = answer;
29773
- finalAnswer = answer;
29774
- renderTranscript();
29775
- tui.requestRender();
29776
- },
29777
- isInterrupted: () => interrupted
29778
- }).catch((error) => {
29779
- if (interrupted)
29780
- return;
29781
- transcriptHistory = `${transcriptHistory}
29782
-
29783
- ${renderError(error, {
29784
- json: false,
29785
- debug: ctx.debug
29786
- })}`;
29787
- renderTranscript();
29788
- }).finally(() => {
29789
- queryRunning = false;
29790
- presenter.setWorking(false);
29791
- renderStatus();
29792
- if (completedResponse !== undefined) {
29793
- store.save({
29794
- id: completedResponse.sessionId,
29795
- query,
29796
- answer: completedAnswer,
29797
- trace: presenter.lines().join(`
29798
- `),
29799
- updatedAt: Date.now()
29800
- });
29801
- completedResponse = undefined;
29802
- }
29803
- renderTranscript();
29804
- editor.disableSubmit = false;
29805
- tui.requestRender();
29806
- });
29807
- };
29808
- tui.addChild(transcript);
29809
- tui.addChild(status);
29810
- tui.addChild(editor);
29811
- tui.setFocus(editor);
29812
- tui.addInputListener((data) => {
29813
- handleInput(data);
29814
- return { consume: data === "\x03" || data === "\x04" };
29815
- });
29816
- tui.start();
29817
- });
29309
+ const options = { ...buildAgentOptions(config) };
29310
+ const thinking = parseThinkingFlags(ctx.flags);
29311
+ if (thinking !== undefined)
29312
+ options.thinking = thinking;
29313
+ if (config.model !== undefined) {
29314
+ const resolved = await resolveAgentModel(config);
29315
+ options.model = resolved.model;
29316
+ if (resolved.apiKey !== undefined)
29317
+ options.apiKey = resolved.apiKey;
29318
+ if (resolved.providerApiKeys !== undefined)
29319
+ options.providerApiKeys = resolved.providerApiKeys;
29320
+ }
29321
+ return new AutoRAGAgent(options);
29818
29322
  }
29819
- async function runTui(ctx, deps = {}) {
29323
+ async function runTui(ctx) {
29820
29324
  try {
29821
- const agent = createAgent(ctx, deps);
29822
- const store = deps.sessionStore ?? defaultSessionStore(ctx);
29823
- if (!deps.tuiFactory)
29824
- return runRealTui(ctx, agent, store);
29825
- const tui = deps.tuiFactory(ctx);
29826
- const presenter = createTuiPresenter();
29827
- let queryRunning = false;
29828
- let interrupted = false;
29829
- let resumeSelection = false;
29830
- let completedResponse;
29831
- let completedAnswer = "";
29832
- const unsubscribe = agent.subscribe?.((event) => {
29833
- presenter.handle(event);
29834
- tui.rendered.push(presenter.lines().join(`
29835
- `));
29836
- tui.onEvent?.(event);
29837
- });
29838
- tui.onSubmit = async (raw) => {
29839
- const query = raw.trim();
29840
- if (query.length === 0)
29841
- return;
29842
- if (resumeSelection && !query.startsWith("/")) {
29843
- resumeSelection = false;
29844
- const session = sessionForSelection(store, query);
29845
- presenter.reset();
29846
- tui.rendered.length = 0;
29847
- tui.rendered.push(session === undefined ? `resume: session not found: ${query}` : renderRestoredTuiSession(session));
29848
- return;
29849
- }
29850
- resumeSelection = false;
29851
- const command = parseSlashCommand(query);
29852
- if (command !== undefined) {
29853
- if (command.kind === "quit") {
29854
- tui.onExit?.();
29855
- return;
29856
- }
29857
- if (command.kind === "incomplete") {
29858
- tui.rendered.push(renderSlashHelp());
29859
- } else if (command.kind === "unknown") {
29860
- tui.rendered.push(`unknown command: /${command.name}`);
29861
- } else if (command.sessionId === undefined) {
29862
- presenter.reset();
29863
- tui.rendered.length = 0;
29864
- resumeSelection = store.list().length > 0;
29865
- tui.rendered.push(renderTuiSessionList(store.list()));
29866
- } else {
29867
- const session = sessionForSelection(store, command.sessionId);
29868
- presenter.reset();
29869
- tui.rendered.length = 0;
29870
- tui.rendered.push(session === undefined ? `resume: session not found: ${command.sessionId}` : renderRestoredTuiSession(session));
29871
- }
29872
- return;
29873
- }
29874
- queryRunning = true;
29875
- interrupted = false;
29876
- presenter.beginRun();
29877
- try {
29878
- await consumeSearchStream(agent, query, {
29879
- onProgress: (progress) => {
29880
- tui.rendered.push(progress);
29881
- },
29882
- onPreliminary: (response) => {
29883
- tui.rendered.push(renderPreliminary(response, { json: false, debug: ctx.debug }));
29884
- },
29885
- onComplete: (response) => {
29886
- const answer = renderSearch(response, { json: false, debug: ctx.debug });
29887
- tui.rendered.push(answer);
29888
- completedResponse = response;
29889
- completedAnswer = answer;
29890
- },
29891
- isInterrupted: () => interrupted
29892
- });
29893
- } catch (error) {
29894
- if (!interrupted) {
29895
- tui.rendered.push(renderError(error, { json: false, debug: ctx.debug }));
29896
- }
29897
- } finally {
29898
- queryRunning = false;
29899
- presenter.setWorking(false);
29900
- if (completedResponse !== undefined) {
29901
- store.save({
29902
- id: completedResponse.sessionId,
29903
- query,
29904
- answer: completedAnswer,
29905
- trace: presenter.lines().join(`
29906
- `),
29907
- updatedAt: Date.now()
29908
- });
29909
- completedResponse = undefined;
29910
- }
29911
- }
29912
- };
29913
- tui.onInput = (data) => {
29914
- if (data === "\x03") {
29915
- if (queryRunning) {
29916
- interrupted = true;
29917
- presenter.interrupt();
29918
- agent.abort?.();
29919
- tui.rendered.push("interrupted");
29920
- } else {
29921
- presenter.interrupt();
29922
- tui.rendered.push("paused");
29923
- }
29325
+ const agent = await createTuiAgent(ctx);
29326
+ const hosted = await agent.createPiInteractiveRuntime();
29327
+ try {
29328
+ const interactive = new InteractiveMode(hosted.runtime, { verbose: ctx.debug });
29329
+ await interactive.init();
29330
+ await interactive.run();
29331
+ return 0;
29332
+ } finally {
29333
+ await hosted.dispose().catch(() => {
29924
29334
  return;
29925
- }
29926
- if (data === "\x04")
29927
- tui.onExit?.();
29928
- };
29929
- tui.onExit = () => {
29930
- unsubscribe?.();
29931
- tui.stopped = true;
29932
- };
29933
- tui.started = true;
29934
- return 0;
29335
+ });
29336
+ }
29935
29337
  } catch (error) {
29936
29338
  ctx.stderr(renderError(error, { json: ctx.json, debug: ctx.debug }));
29937
29339
  return 1;
29938
29340
  }
29939
29341
  }
29940
- var ANSI_RESET = "\x1B[0m", ANSI_DIM_GRAY = "\x1B[90m\x1B[2m", THINKING_LEVELS2, TUI_TITLE = "AutoRAG librarian - Ctrl+C or Ctrl+D to exit";
29342
+ var THINKING_LEVELS2;
29941
29343
  var init_tui = __esm(() => {
29942
29344
  init_agent();
29943
- init_home();
29944
- init_embedding_runtime();
29945
29345
  init_config2();
29946
- init_tui_session_store();
29947
29346
  THINKING_LEVELS2 = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
29948
29347
  });
29949
29348
 
29950
29349
  // src/cli/commands/serve.ts
29951
- import { existsSync as existsSync32 } from "node:fs";
29350
+ import { existsSync as existsSync31 } from "node:fs";
29952
29351
  import { completeSimple as completeSimple2 } from "@earendil-works/pi-ai/compat";
29953
29352
  function classifierText(message) {
29954
29353
  return message.content.filter((part) => part.type === "text").map((part) => part.text).join("");
@@ -29966,7 +29365,7 @@ function createInjectionClassifierModel(resolved) {
29966
29365
  async function runServe(ctx, deps = {}) {
29967
29366
  const flags = ctx.flags;
29968
29367
  const resolved = resolveConfigPath({ flags, cwd: ctx.cwd });
29969
- if (!existsSync32(resolved.configPath)) {
29368
+ if (!existsSync31(resolved.configPath)) {
29970
29369
  ctx.stderr(renderError(new ConfigError(`Config file not found: ${resolved.configPath}. Run autorag init first.`), {
29971
29370
  json: ctx.json
29972
29371
  }));
@@ -29997,7 +29396,7 @@ async function runServe(ctx, deps = {}) {
29997
29396
  const injectionClassifier = p2p.injectionClassifier !== false;
29998
29397
  let resolvedModel;
29999
29398
  try {
30000
- resolvedModel = (deps.modelResolver ?? resolveAgentModel)(config);
29399
+ resolvedModel = await (deps.modelResolver ?? resolveAgentModel)(config);
30001
29400
  } catch (error) {
30002
29401
  if (!injectionClassifier) {
30003
29402
  resolvedModel = undefined;
@@ -30349,8 +29748,8 @@ var init_p2p = __esm(() => {
30349
29748
  });
30350
29749
 
30351
29750
  // src/cli/commands/p2p-policy.ts
30352
- import { existsSync as existsSync33, mkdirSync as mkdirSync26, readFileSync as readFileSync25, writeFileSync as writeFileSync24 } from "node:fs";
30353
- import { dirname as dirname25, join as join37 } from "node:path";
29751
+ import { existsSync as existsSync32, mkdirSync as mkdirSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync23 } from "node:fs";
29752
+ import { dirname as dirname23, join as join37 } from "node:path";
30354
29753
  import { parse as parseToml2, stringify as stringifyToml } from "smol-toml";
30355
29754
  function workspacePolicyPath(cwd) {
30356
29755
  return join37(cwd, ".autorag", "p2p", "policy.toml");
@@ -30380,9 +29779,9 @@ function normalizeEntry(value, key) {
30380
29779
  throw new Error(`Invalid policy entry for ${key}: ${JSON.stringify(value)}`);
30381
29780
  }
30382
29781
  function readPolicyToml(policyPath) {
30383
- if (!existsSync33(policyPath))
29782
+ if (!existsSync32(policyPath))
30384
29783
  return {};
30385
- const parsed = parseToml2(readFileSync25(policyPath, "utf8"));
29784
+ const parsed = parseToml2(readFileSync24(policyPath, "utf8"));
30386
29785
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
30387
29786
  return {};
30388
29787
  let raw;
@@ -30403,22 +29802,22 @@ function readPolicyToml(policyPath) {
30403
29802
  return entries;
30404
29803
  }
30405
29804
  function writePolicyToml(policyPath, entries) {
30406
- mkdirSync26(dirname25(policyPath), { recursive: true });
29805
+ mkdirSync25(dirname23(policyPath), { recursive: true });
30407
29806
  if (Object.keys(entries).length === 0) {
30408
- writeFileSync24(policyPath, "", { mode: 384 });
29807
+ writeFileSync23(policyPath, "", { mode: 384 });
30409
29808
  return;
30410
29809
  }
30411
29810
  const data = { policy: entries };
30412
29811
  const toml = stringifyToml(data);
30413
- writeFileSync24(policyPath, toml, { mode: 384 });
29812
+ writeFileSync23(policyPath, toml, { mode: 384 });
30414
29813
  }
30415
29814
  function getGlobalPolicy() {
30416
29815
  const home = resolveAutoRAGHome();
30417
29816
  const configPath = join37(home, "config.json");
30418
- if (!existsSync33(configPath))
29817
+ if (!existsSync32(configPath))
30419
29818
  return {};
30420
29819
  try {
30421
- const raw = readFileSync25(configPath, "utf8");
29820
+ const raw = readFileSync24(configPath, "utf8");
30422
29821
  const parsed = JSON.parse(raw);
30423
29822
  if (parsed.p2p && typeof parsed.p2p === "object" && !Array.isArray(parsed.p2p)) {
30424
29823
  const p2p = parsed.p2p;
@@ -30498,16 +29897,69 @@ var init_p2p_policy = __esm(() => {
30498
29897
  });
30499
29898
 
30500
29899
  // src/cli/commands/models.ts
29900
+ import { join as join38 } from "node:path";
29901
+ import { getAgentDir as getAgentDir3, ModelRuntime as ModelRuntime3 } from "@earendil-works/pi-coding-agent";
29902
+ async function listModelCatalog(options) {
29903
+ const agentDir = options.agentDir ?? getAgentDir3();
29904
+ const runtime = await ModelRuntime3.create({
29905
+ authPath: join38(agentDir, "auth.json"),
29906
+ modelsPath: join38(agentDir, "models.json"),
29907
+ allowModelNetwork: false
29908
+ });
29909
+ const key = (provider, id) => `${provider}/${id}`;
29910
+ let availableKeys = new Set;
29911
+ try {
29912
+ availableKeys = new Set((await runtime.getAvailable(options.provider)).map((model) => key(model.provider, model.id)));
29913
+ } catch {}
29914
+ const models = [...runtime.getModels(options.provider)].filter((model) => options.available !== true || availableKeys.has(key(model.provider, model.id)));
29915
+ return models.map((model) => ({
29916
+ provider: model.provider,
29917
+ id: model.id,
29918
+ name: model.name,
29919
+ api: model.api,
29920
+ available: availableKeys.has(key(model.provider, model.id))
29921
+ })).sort((a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id));
29922
+ }
30501
29923
  function profile(ctx) {
30502
29924
  const value = ctx.flags.profile;
30503
29925
  return typeof value === "string" ? value : undefined;
30504
29926
  }
29927
+ function flagString2(flags, name) {
29928
+ const value = flags[name];
29929
+ return typeof value === "string" && value.length > 0 ? value : undefined;
29930
+ }
30505
29931
  function output(ctx, result, action) {
30506
29932
  ctx.stdout(ctx.json || ctx.flags.format === "json" ? JSON.stringify({ ok: true, action, ...result ?? {} }, null, 2) : `models: ${action}`);
30507
29933
  }
29934
+ async function runList(ctx, deps) {
29935
+ const provider = flagString2(ctx.flags, "provider");
29936
+ const available = ctx.flags.available === true;
29937
+ const models = await (deps.listModels ?? listModelCatalog)({
29938
+ ...provider !== undefined ? { provider } : {},
29939
+ ...available ? { available: true } : {}
29940
+ });
29941
+ if (ctx.json || ctx.flags.format === "json") {
29942
+ ctx.stdout(JSON.stringify({
29943
+ ok: true,
29944
+ action: "list",
29945
+ ...provider !== undefined ? { provider } : {},
29946
+ count: models.length,
29947
+ models
29948
+ }, null, 2));
29949
+ return 0;
29950
+ }
29951
+ ctx.stdout(`models: ${models.length} model(s)`);
29952
+ for (const model of models) {
29953
+ ctx.stdout(`${model.provider}/${model.id} ${model.name}${model.available ? " (auth)" : ""}`);
29954
+ }
29955
+ return 0;
29956
+ }
30508
29957
  async function runModels(ctx, deps = {}) {
30509
29958
  const sub = ctx.positionals[0];
30510
29959
  try {
29960
+ if (sub === "list" || sub === "ls") {
29961
+ return await runList(ctx, deps);
29962
+ }
30511
29963
  if (sub === "prefetch") {
30512
29964
  const result = await (deps.prefetchModel ?? prefetchModel)(profile(ctx));
30513
29965
  output(ctx, result, "prefetch");
@@ -30526,7 +29978,7 @@ async function runModels(ctx, deps = {}) {
30526
29978
  output(ctx, result, "verify");
30527
29979
  return 0;
30528
29980
  }
30529
- throw new UsageError("Usage: autorag models prefetch|import <path>|verify [--profile <id>]");
29981
+ throw new UsageError("Usage: autorag models list [--provider <id>] [--available] | prefetch | import <path> | verify [--profile <id>]");
30530
29982
  } catch (error) {
30531
29983
  ctx.stderr(renderError(error, { json: ctx.json || ctx.flags.format === "json", debug: ctx.debug }));
30532
29984
  return error instanceof UsageError ? 2 : 1;
@@ -30688,7 +30140,7 @@ var init_mirror = __esm(() => {
30688
30140
  });
30689
30141
 
30690
30142
  // src/cli/commands/lite-retrieve.ts
30691
- import { existsSync as existsSync34, readFileSync as readFileSync26 } from "node:fs";
30143
+ import { existsSync as existsSync33, readFileSync as readFileSync25 } from "node:fs";
30692
30144
  function parseIntOptional2(value) {
30693
30145
  if (typeof value !== "string" || value.trim() === "")
30694
30146
  return;
@@ -30791,10 +30243,10 @@ function renderLiteRetrieveHuman(envelope, debug) {
30791
30243
  }
30792
30244
  function hasCompletedParsedRefresh(workspacePath) {
30793
30245
  const markerPath = refreshReadinessPath(workspacePath);
30794
- if (!existsSync34(markerPath))
30246
+ if (!existsSync33(markerPath))
30795
30247
  return false;
30796
30248
  try {
30797
- const marker = JSON.parse(readFileSync26(markerPath, "utf8"));
30249
+ const marker = JSON.parse(readFileSync25(markerPath, "utf8"));
30798
30250
  return typeof marker === "object" && marker !== null && "version" in marker && marker.version === 1 && "completed" in marker && marker.completed === true && "parsed" in marker && marker.parsed === true;
30799
30251
  } catch {
30800
30252
  return false;
@@ -30941,12 +30393,12 @@ var init_lite_retrieve = __esm(() => {
30941
30393
  });
30942
30394
 
30943
30395
  // src/cli/commands/report.ts
30944
- import { readFileSync as readFileSync27 } from "node:fs";
30396
+ import { readFileSync as readFileSync26 } from "node:fs";
30945
30397
  import { Value as Value3 } from "typebox/value";
30946
30398
  function readReportInput(input) {
30947
30399
  if (typeof input === "string" && input.length > 0)
30948
- return readFileSync27(input, "utf8");
30949
- return readFileSync27(0, "utf8");
30400
+ return readFileSync26(input, "utf8");
30401
+ return readFileSync26(0, "utf8");
30950
30402
  }
30951
30403
  function describeSchemaErrors(value) {
30952
30404
  const errors = Value3.Errors(emitResultsSchema, value);
@@ -31123,7 +30575,7 @@ var init_lite = __esm(() => {
31123
30575
 
31124
30576
  // src/cli/index.ts
31125
30577
  init_embedding_runtime();
31126
- import { readFileSync as readFileSync28, realpathSync as realpathSync6 } from "node:fs";
30578
+ import { readFileSync as readFileSync27, realpathSync as realpathSync6 } from "node:fs";
31127
30579
  import { createInterface } from "node:readline";
31128
30580
  import { fileURLToPath as fileURLToPath2 } from "node:url";
31129
30581
 
@@ -31303,6 +30755,19 @@ var COMMAND_USAGE = {
31303
30755
  "",
31304
30756
  "Usage: autorag tui [flags]",
31305
30757
  "",
30758
+ "Runs Pi's interactive mode over the AutoRAG librarian. Pi owns the",
30759
+ "terminal UI, provider login, model selection, session persistence,",
30760
+ "resume/fork/compaction, settings, and extensions, so its native commands",
30761
+ "are available in-session:",
30762
+ " /login, /logout Provider credentials and OAuth",
30763
+ " /model Pick the model (required before the first search",
30764
+ " when no model is configured)",
30765
+ " /resume, /new, /tree Resume, start, or branch sessions",
30766
+ " /compact, /settings Compact context, edit settings",
30767
+ "",
30768
+ "AutoRAG streams progress, preliminary answers, and final results into the",
30769
+ "same session and adds its retrieval tools.",
30770
+ "",
31306
30771
  "Flags:",
31307
30772
  " --fast-thinking <lvl> Thinking level for the fast first answer",
31308
30773
  " --final-thinking <lvl> Thinking level for the verified answer",
@@ -31347,18 +30812,23 @@ var COMMAND_USAGE = {
31347
30812
  "Peers connect via the SimpleX addresses printed by `autorag serve`."
31348
30813
  ]),
31349
30814
  models: usage([
31350
- "autorag models - manage the verified embedding model cache",
30815
+ "autorag models - list configured chat models and manage the embedding cache",
31351
30816
  "",
31352
- "Usage: autorag models <prefetch|import|verify> [flags]",
30817
+ "Usage: autorag models <list|prefetch|import|verify> [flags]",
31353
30818
  "",
31354
30819
  "Subcommands:",
31355
- " prefetch Download and verify the configured profile",
31356
- " import <path> Import an already-downloaded model file",
31357
- " verify Verify the cached model's hash",
30820
+ " list List chat models from the pi runtime (built-in catalog plus",
30821
+ " models.json/custom/extension providers) with provider auth status;",
30822
+ " never prints credential values",
30823
+ " prefetch Download and verify the configured embedding profile",
30824
+ " import <path> Import an already-downloaded embedding model file",
30825
+ " verify Verify the cached embedding model's hash",
31358
30826
  "",
31359
30827
  "Flags:",
31360
- " --profile <id> Embedding profile (default qwen3-embedding-0.6b)",
31361
- " --format json Emit machine-readable JSON"
30828
+ " --provider <id> Restrict `list` to one provider",
30829
+ " --available With `list`, show only providers with configured credentials",
30830
+ " --profile <id> Embedding profile (default qwen3-embedding-0.6b)",
30831
+ " --format json Emit machine-readable JSON"
31362
30832
  ]),
31363
30833
  gateway: usage([
31364
30834
  "autorag gateway - inspect or stop the on-demand embedding gateway",
@@ -31393,7 +30863,8 @@ var BOOLEAN_FLAGS = new Set([
31393
30863
  "full",
31394
30864
  "single-phase",
31395
30865
  "strict",
31396
- "refresh"
30866
+ "refresh",
30867
+ "available"
31397
30868
  ]);
31398
30869
  var VALUE_FLAGS = new Set([
31399
30870
  "config",
@@ -31436,6 +30907,7 @@ var VALUE_FLAGS = new Set([
31436
30907
  "input",
31437
30908
  "profile",
31438
30909
  "format",
30910
+ "provider",
31439
30911
  "fast-thinking",
31440
30912
  "final-thinking"
31441
30913
  ]);
@@ -31496,6 +30968,7 @@ Commands:
31496
30968
  p2p policy list Show effective merged sharing policy (virtual-path keys)
31497
30969
  p2p policy set Set a sharing rule: <source-glob> <private|never|always|peers> [--peer fp...]
31498
30970
  p2p policy unset Remove a sharing rule by key
30971
+ models list List chat models from the pi runtime (--provider ID --available)
31499
30972
  models prefetch|import|verify
31500
30973
  Manage verified embedding model cache (--profile ID)
31501
30974
  gateway status|stop Inspect or stop the on-demand embedding gateway (--format json)
@@ -31527,7 +31000,7 @@ Run: autorag <command> --help for command-specific usage.
31527
31000
  `;
31528
31001
  function readPackageVersion() {
31529
31002
  try {
31530
- const manifest = JSON.parse(readFileSync28(new URL("../../package.json", import.meta.url), "utf8"));
31003
+ const manifest = JSON.parse(readFileSync27(new URL("../../package.json", import.meta.url), "utf8"));
31531
31004
  return typeof manifest.version === "string" && manifest.version.length > 0 ? manifest.version : "0.0.0";
31532
31005
  } catch {
31533
31006
  return "0.0.0";