@autorag/librarian 2.13.2 → 2.13.4

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/core.js CHANGED
@@ -15098,6 +15098,51 @@ var init_permission_gate = __esm(() => {
15098
15098
  };
15099
15099
  });
15100
15100
 
15101
+ // src/cloud/context-overflow.ts
15102
+ import {
15103
+ createAssistantMessageEventStream,
15104
+ isContextOverflow
15105
+ } from "@earendil-works/pi-ai";
15106
+ import { getApiProvider } from "@earendil-works/pi-ai/compat";
15107
+ function recordRequestEstimate(model, estimatedTokens) {
15108
+ lastEstimates.set(modelKey(model), estimatedTokens);
15109
+ }
15110
+ function noteContextOverflow(model) {
15111
+ const key = modelKey(model);
15112
+ const failed = lastEstimates.get(key);
15113
+ if (failed === undefined)
15114
+ return;
15115
+ ceilings.set(key, Math.min(Math.floor(failed / 2), ceilings.get(key) ?? Number.POSITIVE_INFINITY));
15116
+ }
15117
+ function contextOverflowCeiling(model) {
15118
+ return ceilings.get(modelKey(model));
15119
+ }
15120
+ function streamDazziSimple(model, context, options) {
15121
+ const api = getApiProvider(model.api);
15122
+ if (api === undefined)
15123
+ throw new Error(`No API provider registered for api: ${model.api}`);
15124
+ const inner = api.streamSimple(model, context, options);
15125
+ const stream = createAssistantMessageEventStream();
15126
+ (async () => {
15127
+ try {
15128
+ for await (const event of inner) {
15129
+ if (event.type === "error" && event.error.stopReason === "error" && isContextOverflow(event.error)) {
15130
+ noteContextOverflow(model);
15131
+ }
15132
+ stream.push(event);
15133
+ }
15134
+ } finally {
15135
+ stream.end();
15136
+ }
15137
+ })();
15138
+ return stream;
15139
+ }
15140
+ var lastEstimates, ceilings, modelKey = (model) => `${model.provider}/${model.id}`;
15141
+ var init_context_overflow = __esm(() => {
15142
+ lastEstimates = new Map;
15143
+ ceilings = new Map;
15144
+ });
15145
+
15101
15146
  // src/cloud/authorize.ts
15102
15147
  function buildAuthorizeUrl(params) {
15103
15148
  const url = new URL(`${normalizeBaseUrl(params.baseUrl)}${AUTHORIZE_PATH}`);
@@ -15453,6 +15498,7 @@ function createDazziProviderConfig(env = process.env) {
15453
15498
  name: PROVIDER_NAME,
15454
15499
  baseUrl: endpoints.apiBaseUrl,
15455
15500
  api: "openai-responses",
15501
+ streamSimple: streamDazziSimple,
15456
15502
  oauth: {
15457
15503
  name: PROVIDER_NAME,
15458
15504
  login: (callbacks) => loginDazzi(callbacks, { baseUrl }),
@@ -15468,6 +15514,7 @@ async function registerDazziProvider(runtime, env = process.env) {
15468
15514
  }
15469
15515
  var init_provider2 = __esm(() => {
15470
15516
  init_config();
15517
+ init_context_overflow();
15471
15518
  init_models();
15472
15519
  init_oauth_login();
15473
15520
  });
@@ -24287,413 +24334,6 @@ var init_slack = __esm(() => {
24287
24334
  };
24288
24335
  });
24289
24336
 
24290
- // src/datasource/skills/spotlight/connector.ts
24291
- import { spawn as spawn19 } from "node:child_process";
24292
- import { createHash as createHash19 } from "node:crypto";
24293
- import { readFile as fsReadFile, stat as stat5 } from "node:fs/promises";
24294
- import { basename as basename11, extname as extname7 } from "node:path";
24295
-
24296
- class SpotlightConnector {
24297
- options;
24298
- run;
24299
- readFile;
24300
- platform;
24301
- constructor(options = {}) {
24302
- this.options = options;
24303
- this.run = options.run ?? spawnRunner;
24304
- this.readFile = options.readFile ?? ((path) => fsReadFile(path, "utf8"));
24305
- this.platform = options.platform ?? process.platform;
24306
- }
24307
- async probe() {
24308
- const queries = (this.options.queries ?? []).map((query) => query.trim()).filter((query) => query.length > 0);
24309
- const failure = await this.readinessFailure(queries);
24310
- return failure ?? { ok: true, documents: [] };
24311
- }
24312
- async search(query, limit = DEFAULT_MAX_DOCUMENTS4, acceptDocument) {
24313
- const trimmed = query.trim();
24314
- if (trimmed.length === 0 || limit <= 0)
24315
- return { ok: true, documents: [] };
24316
- const queries = (this.options.queries ?? []).map((query) => query.trim()).filter((query) => query.length > 0);
24317
- const failure = await this.readinessFailure(queries);
24318
- if (failure !== undefined)
24319
- return failure;
24320
- const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
24321
- const maxPerQuery = this.options.maxResultsPerQuery ?? DEFAULT_MAX_RESULTS_PER_QUERY;
24322
- const maxDocuments = Math.min(this.options.maxDocuments ?? DEFAULT_MAX_DOCUMENTS4, limit);
24323
- const seen = new Set;
24324
- const paths = [];
24325
- const textQuery = trimmed.split(/\s+/u).map((term) => `"${term.replace(/\\/gu, "\\\\").replace(/"/gu, "\\\"")}"`).join(" AND ");
24326
- let mdfindMissing = false;
24327
- let failedQueries = 0;
24328
- const failures = [];
24329
- for (const filter of queries) {
24330
- const query = `(${filter}) AND (${textQuery})`;
24331
- const args = this.options.onlyIn !== undefined ? ["-onlyin", this.options.onlyIn, query] : [query];
24332
- const result = await this.run("mdfind", args, timeoutMs);
24333
- if (!result.ok) {
24334
- if (result.error === "ENOENT") {
24335
- mdfindMissing = true;
24336
- break;
24337
- }
24338
- failedQueries += 1;
24339
- failures.push(result);
24340
- continue;
24341
- }
24342
- let kept = 0;
24343
- for (const line of result.stdout.split(`
24344
- `)) {
24345
- const path = line.trim();
24346
- if (path.length === 0 || seen.has(path))
24347
- continue;
24348
- if (kept >= maxPerQuery)
24349
- break;
24350
- seen.add(path);
24351
- paths.push(path);
24352
- kept += 1;
24353
- }
24354
- }
24355
- if (mdfindMissing) {
24356
- return { ok: false, reason: "unavailable", message: "mdfind binary not found; Spotlight requires macOS" };
24357
- }
24358
- if (failedQueries === queries.length) {
24359
- return {
24360
- ok: false,
24361
- reason: "unavailable",
24362
- message: "every configured mdfind query failed",
24363
- stderr: failures[0]?.stderr,
24364
- stdout: failures[0]?.stdout,
24365
- code: failures[0]?.code
24366
- };
24367
- }
24368
- const documents = [];
24369
- let permissionDenied = 0;
24370
- let readFailures = 0;
24371
- const maxBytes = this.options.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE2;
24372
- const maxContentChars = this.options.maxContentChars ?? MAX_CONTENT_CHARS4;
24373
- for (const path of paths) {
24374
- if (documents.length >= maxDocuments)
24375
- break;
24376
- const docId = createHash19("sha256").update(path).digest("hex").slice(0, 16);
24377
- if (acceptDocument !== undefined && !acceptDocument(docId))
24378
- continue;
24379
- try {
24380
- const info = await stat5(path);
24381
- if (!info.isFile() || info.size > maxBytes)
24382
- continue;
24383
- const text = await this.readFile(path);
24384
- const content = text.trim().slice(0, maxContentChars);
24385
- if (content.length === 0)
24386
- continue;
24387
- documents.push({
24388
- docId,
24389
- hierarchy: ["files"],
24390
- title: basename11(path),
24391
- content,
24392
- publishedAt: info.mtimeMs,
24393
- metadata: { path, extension: extname7(path).toLowerCase() }
24394
- });
24395
- } catch (error) {
24396
- const code = error.code;
24397
- if (code === "EPERM" || code === "EACCES")
24398
- permissionDenied += 1;
24399
- else
24400
- readFailures += 1;
24401
- }
24402
- }
24403
- if (documents.length === 0 && permissionDenied > 0) {
24404
- return {
24405
- ok: false,
24406
- reason: "permission",
24407
- message: `macOS denied access to all Spotlight hits; ${FDA_GUIDANCE}`
24408
- };
24409
- }
24410
- if (documents.length === 0 && failedQueries > 0) {
24411
- return {
24412
- ok: false,
24413
- reason: "unavailable",
24414
- message: "some mdfind queries failed and no readable hits remained",
24415
- stderr: failures[0]?.stderr,
24416
- stdout: failures[0]?.stdout,
24417
- code: failures[0]?.code
24418
- };
24419
- }
24420
- const warnings = [];
24421
- if (failedQueries > 0)
24422
- warnings.push(`${failedQueries} mdfind quer(y/ies) failed`);
24423
- if (permissionDenied > 0) {
24424
- warnings.push(`${permissionDenied} Spotlight hit(s) were denied by macOS privacy protections; ${FDA_GUIDANCE}`);
24425
- }
24426
- if (readFailures > 0)
24427
- warnings.push(`${readFailures} Spotlight hit(s) failed to read`);
24428
- return { ok: true, documents, ...warnings.length > 0 ? { warnings } : {} };
24429
- }
24430
- async readinessFailure(queries) {
24431
- if (this.platform !== "darwin") {
24432
- return { ok: false, reason: "unavailable", message: "spotlight datasource is supported on macOS only" };
24433
- }
24434
- if (queries.length === 0) {
24435
- return { ok: false, reason: "not-configured", message: "no spotlight queries configured" };
24436
- }
24437
- const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
24438
- const status = await this.run("mdutil", ["-s", "/"], timeoutMs);
24439
- if (status.ok && /indexing disabled/iu.test(status.stdout)) {
24440
- return {
24441
- ok: false,
24442
- reason: "unavailable",
24443
- message: "Spotlight indexing is disabled; enable it with `sudo mdutil -i on /`"
24444
- };
24445
- }
24446
- return;
24447
- }
24448
- }
24449
- var DEFAULT_MAX_RESULTS_PER_QUERY = 100, DEFAULT_MAX_DOCUMENTS4 = 300, DEFAULT_MAX_BYTES_PER_FILE2, DEFAULT_TIMEOUT_MS11 = 15000, MAX_CONTENT_CHARS4 = 1e5, MAX_BUFFER_BYTES, FDA_GUIDANCE = "grant Full Disk Access to the terminal or app running AutoRAG (System Settings -> Privacy & Security -> Full Disk Access), then restart it", spawnRunner = (command, args, timeoutMs) => new Promise((resolve) => {
24450
- const child = spawn19(command, [...args], { stdio: ["ignore", "pipe", "pipe"] });
24451
- let stdout = "";
24452
- let stderr = "";
24453
- let settled = false;
24454
- const finish = (result) => {
24455
- if (settled)
24456
- return;
24457
- settled = true;
24458
- clearTimeout(timer);
24459
- resolve(result);
24460
- };
24461
- const timer = setTimeout(() => {
24462
- child.kill("SIGKILL");
24463
- finish({ ok: false, stdout, stderr: "process timed out", code: null });
24464
- }, timeoutMs);
24465
- child.stdout.setEncoding("utf8");
24466
- child.stderr.setEncoding("utf8");
24467
- child.stdout.on("data", (chunk) => {
24468
- if (stdout.length < MAX_BUFFER_BYTES)
24469
- stdout += chunk;
24470
- });
24471
- child.stderr.on("data", (chunk) => {
24472
- if (stderr.length < MAX_BUFFER_BYTES)
24473
- stderr += chunk;
24474
- });
24475
- child.on("error", (error) => {
24476
- finish({ ok: false, stdout, stderr: error.message, code: null, error: error.code });
24477
- });
24478
- child.on("close", (code) => {
24479
- finish({ ok: code === 0, stdout, stderr, code });
24480
- });
24481
- });
24482
- var init_connector5 = __esm(() => {
24483
- DEFAULT_MAX_BYTES_PER_FILE2 = 256 * 1024;
24484
- MAX_BUFFER_BYTES = 4 * 1024 * 1024;
24485
- });
24486
-
24487
- // src/datasource/skills/spotlight/skill.ts
24488
- class SpotlightSkill {
24489
- connector;
24490
- skillName;
24491
- instanceId;
24492
- instances;
24493
- tags;
24494
- lastIndexedAt;
24495
- lastError;
24496
- constructor(options = {}) {
24497
- this.skillName = options.skillName ?? "spotlight";
24498
- this.instanceId = options.instanceId ?? "default";
24499
- this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
24500
- this.tags = options.tags ?? DEFAULT_TAGS4;
24501
- this.connector = options.connector ?? new SpotlightConnector(options.connectorOptions ?? {});
24502
- }
24503
- describe() {
24504
- return {
24505
- name: this.skillName,
24506
- id: this.skillName,
24507
- type: "spotlight-search",
24508
- description: "Live macOS Spotlight search via the built-in mdfind CLI",
24509
- capabilities: ["files", "macos-only", "local-search", "live-search", "scoped", "external-cli"],
24510
- tags: this.tags,
24511
- status: "active",
24512
- requiresExternalCli: true,
24513
- datasourceId: this.skillName,
24514
- instanceId: this.instanceId,
24515
- instances: this.instances
24516
- };
24517
- }
24518
- polling() {
24519
- return {
24520
- mode: "none",
24521
- ...this.lastIndexedAt !== undefined ? { lastIndexedAt: this.lastIndexedAt } : {},
24522
- ...this.lastError !== undefined ? { lastError: this.lastError } : {}
24523
- };
24524
- }
24525
- async index() {
24526
- try {
24527
- const result = await this.connector.probe();
24528
- if (!result.ok) {
24529
- const code = connectorFailureToDiagnosticCode(result.reason);
24530
- const message = boundDiagnosticText(result.message ?? result.reason);
24531
- this.lastError = message;
24532
- return this.fail(code, message);
24533
- }
24534
- this.lastError = undefined;
24535
- this.lastIndexedAt = Date.now();
24536
- return {
24537
- ok: true,
24538
- instanceId: this.instanceId,
24539
- skill: this.skillName,
24540
- chunkCount: 0,
24541
- indexedAt: this.lastIndexedAt,
24542
- diagnostics: [this.note(LIVE_NOTE, "datasource-empty", "info")]
24543
- };
24544
- } catch (error) {
24545
- const message = boundDiagnosticText(error instanceof Error ? error.message : "spotlight probe failed");
24546
- this.lastError = message;
24547
- return this.fail("datasource-unavailable", message);
24548
- }
24549
- }
24550
- retrievalMethods() {
24551
- return [new SpotlightLiveMethod(this)];
24552
- }
24553
- describeSources() {
24554
- return this.instances.map((instanceId) => ({
24555
- source: datasourceSourcePath(this.skillName, instanceId),
24556
- datasourceId: this.skillName,
24557
- skill: this.skillName,
24558
- instanceId,
24559
- contentType: "document",
24560
- metadata: { datasourceId: this.skillName, instanceId, tags: this.tags }
24561
- }));
24562
- }
24563
- skillManifest() {
24564
- const scopes = this.instances.map((instanceId) => `- \`${datasourceSourcePath(this.skillName, instanceId)}\``).join(`
24565
- `);
24566
- return {
24567
- name: `datasource-${this.skillName}`,
24568
- description: "Search the current macOS Spotlight index directly. AutoRAG keeps no file snapshot.",
24569
- content: [
24570
- "# macOS Spotlight (live mdfind search)",
24571
- "",
24572
- "Search files indexed by macOS Spotlight via the built-in `mdfind` CLI. macOS owns and refreshes the index; AutoRAG does not copy files into a local snapshot.",
24573
- "",
24574
- "## Platform requirements",
24575
- "- macOS only: this datasource is unavailable on any other platform.",
24576
- "- Spotlight indexing must be enabled (`sudo mdutil -i on /`; check with `mdutil -s /`).",
24577
- "- Full Disk Access may be required to read protected hits. Grant it under System Settings -> Privacy & Security -> Full Disk Access, then restart the host app.",
24578
- "",
24579
- "## How to search",
24580
- `Call the dedicated \`${datasourceSearchToolName(this.skillName)}\` tool with a query and optional narrowing scope. Available scopes:`,
24581
- scopes,
24582
- "Each configured Spotlight filter is AND-ed with the user query. Only the requested hits are read; refresh performs a readiness probe without running `mdfind`.",
24583
- "Result metadata carries the real absolute file path (`path`) so hits are traceable back to disk. If paths must not leave this machine, run AutoRAG with a local LLM.",
24584
- "",
24585
- "## Native CLI",
24586
- "- `mdfind <query>` searches Spotlight; `mdfind -onlyin <dir> <query>` scopes to a directory; `mdfind -name <text>` matches file names.",
24587
- "- `mdls <file>` shows Spotlight metadata for one file.",
24588
- "- `mdutil -s /` checks index status; `sudo mdutil -i on /` enables indexing."
24589
- ].join(`
24590
- `)
24591
- };
24592
- }
24593
- async search(query, options) {
24594
- const trimmed = query.trim();
24595
- if (trimmed.length === 0)
24596
- return [];
24597
- const scope = options.scope?.trim() ? normalizeVirtualPath2(options.scope) : undefined;
24598
- if (scope !== undefined) {
24599
- const chunksRoot = normalizeVirtualPath2(`/${this.skillName}/${this.instanceId}/chunks`);
24600
- const scopeProbe = datasourceSourcePath(this.skillName, this.instanceId, "__scope_probe__");
24601
- if (!matchesDatasourceScope(chunksRoot, scope) && !matchesDatasourceScope(scopeProbe, scope) && !scope.startsWith(`${chunksRoot}/`)) {
24602
- return [];
24603
- }
24604
- }
24605
- const topK = options.topK ?? DEFAULT_TOP_K9;
24606
- const result = await this.connector.search(trimmed, topK, (docId) => matchesDatasourceScope(datasourceSourcePath(this.skillName, this.instanceId, docId), scope));
24607
- if (!result.ok) {
24608
- throw datasourceCliError(this.skillName, "search", {
24609
- reason: result.reason,
24610
- stderr: result.stderr ?? result.message,
24611
- stdout: result.stdout,
24612
- code: result.code
24613
- });
24614
- }
24615
- const hits = [];
24616
- for (const [index, document] of result.documents.entries()) {
24617
- const source = datasourceSourcePath(this.skillName, this.instanceId, document.docId);
24618
- if (!matchesDatasourceScope(source, options.scope))
24619
- continue;
24620
- hits.push({
24621
- id: `${this.skillName}:${this.instanceId}:${document.docId}`,
24622
- content: document.content,
24623
- source,
24624
- score: 1 / (index + 1),
24625
- metadata: {
24626
- ...document.metadata,
24627
- method: `${this.skillName}-live`,
24628
- datasourceId: this.skillName,
24629
- instanceId: this.instanceId,
24630
- chunkId: document.docId,
24631
- ...document.title !== undefined ? { title: document.title } : {},
24632
- ...document.hierarchy !== undefined && document.hierarchy.length > 0 ? { hierarchy: document.hierarchy.join("/") } : {},
24633
- ...document.publishedAt !== undefined ? { publishedAt: document.publishedAt } : {},
24634
- ...result.warnings !== undefined && result.warnings.length > 0 ? { warnings: result.warnings } : {}
24635
- }
24636
- });
24637
- if (hits.length >= topK)
24638
- break;
24639
- }
24640
- return hits;
24641
- }
24642
- fail(code, message) {
24643
- return {
24644
- ok: false,
24645
- instanceId: this.instanceId,
24646
- skill: this.skillName,
24647
- indexedAt: Date.now(),
24648
- diagnostics: [
24649
- this.note(message, code, code === "datasource-unavailable" || code === "datasource-empty" ? "warning" : "error")
24650
- ],
24651
- error: message,
24652
- code,
24653
- message
24654
- };
24655
- }
24656
- note(message, code, severity) {
24657
- return { code, severity, message, instanceId: this.instanceId, source: this.skillName };
24658
- }
24659
- }
24660
-
24661
- class SpotlightLiveMethod {
24662
- skill;
24663
- constructor(skill) {
24664
- this.skill = skill;
24665
- }
24666
- describe() {
24667
- const descriptor = this.skill.describe();
24668
- return {
24669
- name: `${descriptor.datasourceId ?? "spotlight"}-live`,
24670
- type: "remote",
24671
- description: "Live macOS Spotlight search via mdfind",
24672
- status: "active",
24673
- capabilities: ["live-search", "scoped", "external-cli", "path-opaque-sources"],
24674
- datasourceId: descriptor.datasourceId,
24675
- tags: descriptor.tags
24676
- };
24677
- }
24678
- retrieve(query, options) {
24679
- return this.skill.search(query, options);
24680
- }
24681
- }
24682
- var DEFAULT_TAGS4, DEFAULT_TOP_K9 = 20, LIVE_NOTE = "live-search datasource: macOS owns the Spotlight index; AutoRAG stores no snapshot";
24683
- var init_skill12 = __esm(() => {
24684
- init_connector();
24685
- init_errors4();
24686
- init_scope2();
24687
- init_connector5();
24688
- DEFAULT_TAGS4 = ["spotlight", "files"];
24689
- });
24690
-
24691
- // src/datasource/skills/spotlight/index.ts
24692
- var init_spotlight = __esm(() => {
24693
- init_connector5();
24694
- init_skill12();
24695
- });
24696
-
24697
24337
  // src/datasource/skills/telecrawl/index.ts
24698
24338
  function globalArgs3(options) {
24699
24339
  return [
@@ -25098,7 +24738,6 @@ var init_factory = __esm(() => {
25098
24738
  init_obsidian();
25099
24739
  init_rss();
25100
24740
  init_slack();
25101
- init_spotlight();
25102
24741
  init_telecrawl();
25103
24742
  init_wacrawl();
25104
24743
  BUILDERS = {
@@ -25235,12 +24874,6 @@ var init_factory = __esm(() => {
25235
24874
  ...common(config, workspaceRoot),
25236
24875
  skillName: registrationName,
25237
24876
  connectorOptions: config.connector
25238
- }),
25239
- spotlight: (config, _workspaceRoot, registrationName) => new SpotlightSkill({
25240
- ...config.instanceId !== undefined ? { instanceId: config.instanceId } : {},
25241
- ...config.tags !== undefined ? { tags: config.tags } : {},
25242
- skillName: registrationName,
25243
- connectorOptions: config.connector
25244
24877
  })
25245
24878
  };
25246
24879
  PLATFORM_ONLY_SKILLS = { kakao: "darwin" };
@@ -25250,7 +24883,7 @@ var init_factory = __esm(() => {
25250
24883
  // src/cli/config.ts
25251
24884
  import { randomUUID as randomUUID6 } from "node:crypto";
25252
24885
  import { existsSync as existsSync27, mkdirSync as mkdirSync22, readFileSync as readFileSync24, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
25253
- import { basename as basename12, dirname as dirname23, isAbsolute as isAbsolute11, join as join42, resolve as resolve15 } from "node:path";
24886
+ import { basename as basename11, dirname as dirname23, isAbsolute as isAbsolute11, join as join42, resolve as resolve15 } from "node:path";
25254
24887
  import { findEnvKeys, getEnvApiKey } from "@earendil-works/pi-ai/compat";
25255
24888
  import { getAgentDir as getAgentDir2, ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
25256
24889
  function resolveConfigPath(input) {
@@ -25324,7 +24957,7 @@ function acquireConfigWriteLock(configPath) {
25324
24957
  });
25325
24958
  }
25326
24959
  function replaceFileAtomically(path, contents, assertCommitAllowed) {
25327
- const temporaryPath = join42(dirname23(path), `.${basename12(path)}.${process.pid}.${randomUUID6()}.tmp`);
24960
+ const temporaryPath = join42(dirname23(path), `.${basename11(path)}.${process.pid}.${randomUUID6()}.tmp`);
25328
24961
  try {
25329
24962
  writeFileSync15(temporaryPath, contents, { encoding: "utf8", flag: "wx", flush: true, mode: 384 });
25330
24963
  assertCommitAllowed?.();
@@ -26835,6 +26468,42 @@ function loopGuardPrompt(rule) {
26835
26468
  `);
26836
26469
  }
26837
26470
 
26471
+ // src/agent/token-count.ts
26472
+ import { createHash as createHash19 } from "node:crypto";
26473
+ import { countTokens } from "gpt-tokenizer/encoding/o200k_base";
26474
+ function estimateTextTokens(text) {
26475
+ return Math.max(Math.ceil(text.length / 4), countText(text));
26476
+ }
26477
+ function tokensBeyondCharGuess(parts) {
26478
+ let excess = 0;
26479
+ for (const part of parts)
26480
+ excess += Math.max(0, countText(part) - Math.ceil(part.length / 4));
26481
+ return excess;
26482
+ }
26483
+ function countText(text) {
26484
+ if (text.length === 0)
26485
+ return 0;
26486
+ if (text.length < CACHE_MIN_CHARS)
26487
+ return countTokens(text, PLAIN_TEXT);
26488
+ const key = `${text.length}:${createHash19("sha1").update(text).digest("base64")}`;
26489
+ const hit = cache.get(key);
26490
+ if (hit !== undefined) {
26491
+ cache.delete(key);
26492
+ cache.set(key, hit);
26493
+ return hit;
26494
+ }
26495
+ const count = countTokens(text, PLAIN_TEXT);
26496
+ cache.set(key, count);
26497
+ if (cache.size > CACHE_ENTRIES)
26498
+ cache.delete(cache.keys().next().value);
26499
+ return count;
26500
+ }
26501
+ var PLAIN_TEXT, CACHE_MIN_CHARS = 2000, CACHE_ENTRIES = 64, cache;
26502
+ var init_token_count = __esm(() => {
26503
+ PLAIN_TEXT = { disallowedSpecial: new Set };
26504
+ cache = new Map;
26505
+ });
26506
+
26838
26507
  // src/agent/context-token-guard.ts
26839
26508
  import { calculateContextTokens, estimateTokens } from "@earendil-works/pi-coding-agent";
26840
26509
  function createContextTokenGuardedTransform(model, base, fixedOverheadTokens = () => 0) {
@@ -26850,12 +26519,20 @@ function withBoundedOutput(model) {
26850
26519
  return { ...model, maxTokens: MAX_OUTPUT_TOKENS };
26851
26520
  }
26852
26521
  function guardAgentContextMessages(model, messages, useReportedUsage = true, fixedOverheadTokens = 0) {
26522
+ const guarded = guardWithinBudget(model, messages, useReportedUsage, fixedOverheadTokens);
26523
+ if (model !== undefined && guarded.length > 0) {
26524
+ recordRequestEstimate(model, estimateContextMessageTokens(guarded, false) + fixedOverheadTokens);
26525
+ }
26526
+ return guarded;
26527
+ }
26528
+ function guardWithinBudget(model, messages, useReportedUsage = true, fixedOverheadTokens = 0) {
26853
26529
  if (model === undefined || !Number.isFinite(model.contextWindow) || model.contextWindow <= 0 || messages.length === 0) {
26854
26530
  return messages;
26855
26531
  }
26856
26532
  const usableContext = Math.floor(model.contextWindow / CONTEXT_HEADROOM);
26857
26533
  const outputReserve = Math.min(Math.floor(usableContext / 4), MAX_OUTPUT_TOKENS, Number.isFinite(model.maxTokens) ? Math.max(0, model.maxTokens) : 0);
26858
- const inputBudget = Math.max(0, usableContext - outputReserve);
26534
+ const overflowCeiling = contextOverflowCeiling(model);
26535
+ const inputBudget = Math.min(Math.max(0, usableContext - outputReserve), overflowCeiling ?? Number.POSITIVE_INFINITY);
26859
26536
  const budget = Math.max(0, inputBudget - fixedOverheadTokens);
26860
26537
  const reported = useReportedUsage && findLastAssistantUsage(messages) !== undefined;
26861
26538
  if (estimateContextMessageTokens(messages, useReportedUsage) <= (reported ? inputBudget : budget)) {
@@ -26877,50 +26554,40 @@ function guardAgentContextMessages(model, messages, useReportedUsage = true, fix
26877
26554
  }
26878
26555
  let guarded = messages;
26879
26556
  if (candidates.length > 0) {
26880
- const fixedTokens = estimateContextMessageTokens(base, false);
26881
- const maximumOmitted = candidates.reduce((total, section) => total + section.blocks.length, 0);
26557
+ const entries = candidates.flatMap((section, sectionIndex) => section.blocks.map((block, blockIndex) => ({ block, sectionIndex, blockIndex })));
26882
26558
  const omissionMarker = (count) => `
26883
26559
 
26884
26560
  ${GUARD_MARKER} Retrieval candidates omitted: ${count}.
26885
26561
  `;
26886
- let remaining = Math.max(0, budget - fixedTokens - Math.ceil(omissionMarker(maximumOmitted).length / 4));
26887
- const kept = candidates.map(() => []);
26888
- let omitted = 0;
26889
- let firstOmitted = -1;
26890
- for (const [sectionIndex, section] of candidates.entries()) {
26891
- for (const block of section.blocks) {
26892
- const tokens = Math.max(1, Math.ceil(block.length / 4));
26893
- if (tokens <= remaining) {
26894
- kept[sectionIndex]?.push(block);
26895
- remaining -= tokens;
26896
- continue;
26897
- }
26898
- omitted += section.blocks.length - (kept[sectionIndex]?.length ?? 0);
26899
- for (const later of candidates.slice(sectionIndex + 1))
26900
- omitted += later.blocks.length;
26901
- firstOmitted = sectionIndex;
26902
- break;
26903
- }
26904
- if (firstOmitted !== -1)
26562
+ const markerTokens = candidates.length * Math.ceil(omissionMarker(entries.length).length / 4);
26563
+ let remaining = Math.max(0, budget - estimateContextMessageTokens(base, false) - markerTokens);
26564
+ entries.sort((a, b) => a.block.rank - b.block.rank || a.sectionIndex - b.sectionIndex || a.blockIndex - b.blockIndex);
26565
+ const kept = new Set;
26566
+ for (const { block } of entries) {
26567
+ const tokens = Math.max(1, estimateTextTokens(block.text));
26568
+ if (tokens > remaining)
26905
26569
  break;
26570
+ remaining -= tokens;
26571
+ kept.add(block);
26906
26572
  }
26907
- if (omitted > 0) {
26908
- const candidateByMessage = new Map;
26909
- for (const [sectionIndex, messageIndex] of candidateIndexes.entries())
26910
- candidateByMessage.set(messageIndex, sectionIndex);
26573
+ if (kept.size < entries.length) {
26574
+ const sectionByMessage = new Map(candidateIndexes.map((messageIndex, i) => [messageIndex, candidates[i]]));
26911
26575
  guarded = base.map((message, index) => {
26912
- const sectionIndex = candidateByMessage.get(index);
26913
- if (sectionIndex === undefined)
26576
+ const section = sectionByMessage.get(index);
26577
+ if (section === undefined)
26914
26578
  return message;
26915
- const section = candidates[sectionIndex];
26916
- const marker = sectionIndex === firstOmitted ? omissionMarker(omitted) : "";
26917
- return replaceTextContent(message, `${section.prefix}${kept[sectionIndex]?.join("") ?? ""}${marker}${section.suffix}`);
26579
+ const keptBlocks = section.blocks.filter((block) => kept.has(block));
26580
+ const omitted = section.blocks.length - keptBlocks.length;
26581
+ if (omitted === 0)
26582
+ return messages[index] ?? message;
26583
+ const marker = omissionMarker(omitted);
26584
+ return replaceTextContent(message, `${section.prefix}${keptBlocks.map((block) => block.text).join("")}${marker}${section.suffix}`);
26918
26585
  });
26919
26586
  }
26920
26587
  }
26921
- if (estimateContextMessageTokens(guarded, false) <= budget && guarded !== messages)
26588
+ if (guarded !== messages && estimateContextMessageTokens(guarded, false) <= budget)
26922
26589
  return guarded;
26923
- return trimFixedContext(guarded, budget);
26590
+ return fitNewestToolResult(guarded, budget);
26924
26591
  }
26925
26592
  function estimateContextMessageTokens(messages, useReportedUsage = false) {
26926
26593
  if (useReportedUsage) {
@@ -26931,82 +26598,37 @@ function estimateContextMessageTokens(messages, useReportedUsage = false) {
26931
26598
  }
26932
26599
  return messages.reduce((total, message) => total + estimateMessageTokens(message), 0);
26933
26600
  }
26934
- function trimFixedContext(messages, inputBudget) {
26935
- const trimmed = messages.slice();
26936
- const lastIndex = trimmed.length - 1;
26937
- const queryIndex = trimmed.reduce((found, message, index) => message.role === "user" ? index : found, -1);
26938
- const fits = () => estimateContextMessageTokens(trimmed, false) <= inputBudget;
26939
- const fitInto = (index, floorTokens) => {
26940
- const message = trimmed[index];
26941
- if (message === undefined)
26942
- return;
26943
- const others = trimmed.reduce((total, other, i) => i === index ? total : total + estimateMessageTokens(other), 0);
26944
- trimmed[index] = fitMessageToTokens(message, Math.max(floorTokens, inputBudget - others));
26945
- };
26946
- for (const [index, message] of trimmed.entries()) {
26947
- if (index === lastIndex || index === queryIndex || message.role === "system")
26948
- continue;
26949
- const replacement = replaceMessageWithMarker(message);
26950
- if (replacement === message || estimateMessageTokens(replacement) >= estimateMessageTokens(message))
26951
- continue;
26952
- trimmed[index] = replacement;
26953
- if (fits())
26954
- return trimmed;
26955
- }
26956
- if (lastIndex !== queryIndex && trimmed[lastIndex]?.role !== "system") {
26957
- fitInto(lastIndex, 0);
26958
- if (fits())
26959
- return trimmed;
26960
- }
26961
- for (const [index, message] of trimmed.entries()) {
26962
- if (message.role !== "system")
26963
- continue;
26964
- fitInto(index, 0);
26965
- if (fits())
26966
- return trimmed;
26967
- }
26968
- if (queryIndex >= 0)
26969
- fitInto(queryIndex, MIN_QUERY_TOKENS);
26970
- return trimmed;
26601
+ function fitNewestToolResult(messages, inputBudget) {
26602
+ const lastIndex = messages.length - 1;
26603
+ const last = messages[lastIndex];
26604
+ if (last?.role !== "toolResult")
26605
+ return messages;
26606
+ const others = messages.reduce((total, message, index) => index === lastIndex ? total : total + estimateMessageTokens(message), 0);
26607
+ if (others >= inputBudget)
26608
+ return messages;
26609
+ const fitted = fitMessageToTokens(last, inputBudget - others);
26610
+ return fitted === last ? messages : [...messages.slice(0, lastIndex), fitted];
26971
26611
  }
26972
26612
  function fitMessageToTokens(message, maxTokens) {
26973
26613
  const original = textContent(message);
26974
26614
  if (original === undefined)
26975
- return stripNonTextContent(message);
26615
+ return message;
26976
26616
  const marker = `
26977
26617
 
26978
26618
  ${GUARD_MARKER}
26979
26619
  `;
26980
- let low = 0;
26981
- let high = original.length;
26982
- let best = replaceTextContent(message, marker);
26983
- while (low <= high) {
26984
- const middle = Math.floor((low + high) / 2);
26985
- const candidate = replaceTextContent(message, excerpt(original, middle, marker));
26986
- if (estimateMessageTokens(candidate) <= maxTokens) {
26987
- best = candidate;
26988
- low = middle + 1;
26989
- } else {
26990
- high = middle - 1;
26991
- }
26620
+ const overhead = estimateMessageTokens(replaceTextContent(message, ""));
26621
+ const density = Math.max(0, estimateMessageTokens(message) - overhead) / Math.max(1, original.length);
26622
+ let chars = density > 0 ? Math.floor((maxTokens - overhead) / density) : original.length;
26623
+ for (let attempt = 0;attempt < MAX_FIT_ATTEMPTS && chars > 0; attempt++) {
26624
+ const candidate = replaceTextContent(message, excerpt(original, chars, marker));
26625
+ const tokens = estimateMessageTokens(candidate);
26626
+ if (tokens <= maxTokens)
26627
+ return candidate;
26628
+ const scaled = Math.floor(chars * Math.max(0, maxTokens - overhead) / Math.max(1, tokens - overhead) * 0.98);
26629
+ chars = Math.min(chars - 1, scaled);
26992
26630
  }
26993
- return best;
26994
- }
26995
- function stripNonTextContent(message) {
26996
- if (message.role !== "user" || typeof message.content === "string")
26997
- return replaceMessageWithMarker(message);
26998
- const marker = `
26999
-
27000
- ${GUARD_MARKER}
27001
- `;
27002
- let replacedImage = false;
27003
- const content = message.content.map((block) => {
27004
- if (block.type === "text")
27005
- return block;
27006
- replacedImage = true;
27007
- return { type: "text", text: marker };
27008
- });
27009
- return replacedImage ? { ...message, content } : message;
26631
+ return replaceTextContent(message, marker);
27010
26632
  }
27011
26633
  function excerpt(text, maxChars, marker) {
27012
26634
  if (text.length <= maxChars)
@@ -27016,32 +26638,54 @@ function excerpt(text, maxChars, marker) {
27016
26638
  const tail = Math.max(0, available - head);
27017
26639
  return `${text.slice(0, head)}${marker}${tail > 0 ? text.slice(-tail) : ""}`;
27018
26640
  }
27019
- function replaceMessageWithMarker(message) {
27020
- return replaceTextContent(message, `
27021
-
27022
- ${GUARD_MARKER}
27023
- `);
27024
- }
27025
26641
  function estimateMessageTokens(message) {
27026
26642
  if (message.role === "system")
27027
26643
  return estimateSystemMessageTokens(message);
27028
- const estimate = estimateTokens(message);
26644
+ const estimate = estimateTokens(message) + tokensBeyondCharGuess(messageTextParts(message));
27029
26645
  return message.role === "toolResult" ? estimate + Math.ceil(message.toolName.length / 4) : estimate;
27030
26646
  }
27031
26647
  function estimateSystemMessageTokens(message) {
27032
- let chars = typeof message.content === "string" ? message.content.length : 0;
27033
- if (Array.isArray(message.content)) {
26648
+ const parts = [];
26649
+ let chars = 0;
26650
+ if (typeof message.content === "string")
26651
+ parts.push(message.content);
26652
+ else {
27034
26653
  for (const block of message.content) {
27035
26654
  if (block.type === "text")
27036
- chars += block.text.length;
26655
+ parts.push(block.text);
27037
26656
  else if (block.type === "image")
27038
26657
  chars += 4800;
27039
26658
  }
27040
26659
  }
27041
- chars += JSON.stringify(message.sections ?? {}).length;
27042
- chars += JSON.stringify(message.toolsAdded ?? []).length;
27043
- chars += JSON.stringify(message.toolsRemoved ?? []).length;
27044
- return Math.ceil(chars / 4);
26660
+ parts.push(JSON.stringify(message.sections ?? {}), JSON.stringify(message.toolsAdded ?? []), JSON.stringify(message.toolsRemoved ?? []));
26661
+ for (const part of parts)
26662
+ chars += part.length;
26663
+ return Math.ceil(chars / 4) + tokensBeyondCharGuess(parts);
26664
+ }
26665
+ function messageTextParts(message) {
26666
+ switch (message.role) {
26667
+ case "user":
26668
+ case "custom":
26669
+ case "toolResult":
26670
+ return typeof message.content === "string" ? [message.content] : message.content.flatMap((block) => block.type === "text" ? [block.text] : []);
26671
+ case "assistant":
26672
+ return message.content.flatMap((block) => {
26673
+ if (block.type === "text")
26674
+ return [block.text];
26675
+ if (block.type === "thinking")
26676
+ return [block.thinking];
26677
+ if (block.type === "toolCall")
26678
+ return [`${block.name}${JSON.stringify(block.arguments)}`];
26679
+ return [];
26680
+ });
26681
+ case "bashExecution":
26682
+ return [message.command, message.output];
26683
+ case "branchSummary":
26684
+ case "compactionSummary":
26685
+ return [message.summary];
26686
+ default:
26687
+ return [];
26688
+ }
27045
26689
  }
27046
26690
  function findLastAssistantUsage(messages) {
27047
26691
  for (let index = messages.length - 1;index >= 0; index--) {
@@ -27115,7 +26759,7 @@ function parseCandidateSection(message, text) {
27115
26759
  const sectionEnd = findBaselineSectionEnd(text, sectionStart);
27116
26760
  if (!/^\[e?\d+\] /mu.test(text.slice(sectionStart, sectionEnd)))
27117
26761
  return;
27118
- return splitCandidates(text, sectionStart, sectionEnd);
26762
+ return splitCandidates(text, sectionStart, sectionEnd, { lists: true });
27119
26763
  }
27120
26764
  if (message.role !== "toolResult")
27121
26765
  return;
@@ -27126,7 +26770,9 @@ function parseCandidateSection(message, text) {
27126
26770
  const directiveStart = text.indexOf(`
27127
26771
 
27128
26772
  directive:`);
27129
- return splitCandidates(text, 0, directiveStart >= 0 ? directiveStart : text.length, /^- [^\n]*(?:\n|$)/gmu);
26773
+ return splitCandidates(text, 0, directiveStart >= 0 ? directiveStart : text.length, {
26774
+ pattern: /^- [^\n]*(?:\n|$)/gmu
26775
+ });
27130
26776
  }
27131
26777
  const diagnosticsStart = text.indexOf(`
27132
26778
 
@@ -27148,17 +26794,23 @@ Formatting and content rules`
27148
26794
  const positions = endMarkers.map((marker) => text.indexOf(marker, startIndex)).filter((index) => index >= 0);
27149
26795
  return positions.length > 0 ? Math.min(...positions) : text.length;
27150
26796
  }
27151
- function splitCandidates(text, sectionStart, sectionEnd, pattern = /^\[e?\d+\] [^\n]*(?:\n|$)/gmu) {
26797
+ function splitCandidates(text, sectionStart, sectionEnd, options = {}) {
27152
26798
  const region = text.slice(sectionStart, sectionEnd);
27153
- const matches = [...region.matchAll(pattern)];
26799
+ const matches = [...region.matchAll(options.pattern ?? /^\[e?\d+\] [^\n]*(?:\n|$)/gmu)];
27154
26800
  const firstStart = matches[0]?.index;
27155
26801
  if (firstStart === undefined)
27156
26802
  return;
27157
26803
  const blocks = [];
26804
+ let rank = 0;
26805
+ let heading = "";
27158
26806
  for (const [index, match] of matches.entries()) {
27159
26807
  const start = match.index ?? 0;
27160
26808
  const end = index + 1 < matches.length ? matches[index + 1]?.index ?? region.length : region.length;
27161
- blocks.push(region.slice(start, end));
26809
+ const raw = region.slice(start, end);
26810
+ const tail = options.lists === true ? LIST_HEADING_TAIL.exec(raw) : null;
26811
+ blocks.push({ text: heading + (tail === null ? raw : raw.slice(0, tail.index)), rank });
26812
+ rank = tail === null ? rank + 1 : 0;
26813
+ heading = tail === null ? "" : tail[0];
27162
26814
  }
27163
26815
  return {
27164
26816
  prefix: text.slice(0, sectionStart) + region.slice(0, firstStart),
@@ -27166,8 +26818,10 @@ function splitCandidates(text, sectionStart, sectionEnd, pattern = /^\[e?\d+\] [
27166
26818
  blocks
27167
26819
  };
27168
26820
  }
27169
- var CONTEXT_HEADROOM = 1.2, MAX_OUTPUT_TOKENS = 32000, MIN_QUERY_TOKENS = 2000, GUARD_MARKER = "[AutoRAG context guard: omitted context to stay within the model context budget.]", RETRIEVAL_TOOL_PREFIX = "search_datasource_", RETRIEVAL_TOOL_NAMES;
26821
+ var CONTEXT_HEADROOM = 1.2, MAX_OUTPUT_TOKENS = 32000, GUARD_MARKER = "[AutoRAG context guard: omitted context to stay within the model context budget.]", RETRIEVAL_TOOL_PREFIX = "search_datasource_", RETRIEVAL_TOOL_NAMES, MAX_FIT_ATTEMPTS = 6, LIST_HEADING_TAIL;
27170
26822
  var init_context_token_guard = __esm(() => {
26823
+ init_context_overflow();
26824
+ init_token_count();
27171
26825
  RETRIEVAL_TOOL_NAMES = {
27172
26826
  jikji_find: true,
27173
26827
  search_all_documents: true,
@@ -27176,6 +26830,7 @@ var init_context_token_guard = __esm(() => {
27176
26830
  everything_search: true,
27177
26831
  fsearch_search: true
27178
26832
  };
26833
+ LIST_HEADING_TAIL = /\n[^\n]*initial candidates[^\n]*:\n$/u;
27179
26834
  });
27180
26835
 
27181
26836
  // src/agent/current-date.ts
@@ -27621,7 +27276,7 @@ function guardContext(pi, contextTransform) {
27621
27276
  pi.on("context", async (event, ctx) => {
27622
27277
  const activeTools = new Set(pi.getActiveTools());
27623
27278
  const toolDeclarations = pi.getAllTools().filter((tool) => activeTools.has(tool.name)).map(({ name, description, parameters }) => ({ name, description, parameters }));
27624
- const fixedOverheadTokens = Math.ceil((ctx.getSystemPrompt().length + JSON.stringify(toolDeclarations).length) / 4);
27279
+ const fixedOverheadTokens = estimateTextTokens(ctx.getSystemPrompt()) + estimateTextTokens(JSON.stringify(toolDeclarations));
27625
27280
  return {
27626
27281
  messages: await createContextTokenGuardedTransform(ctx.model, contextTransform, () => fixedOverheadTokens)(event.messages)
27627
27282
  };
@@ -27855,6 +27510,7 @@ var init_pi_session = __esm(() => {
27855
27510
  init_intent_tracing();
27856
27511
  init_mcp_client();
27857
27512
  init_request_limits();
27513
+ init_token_count();
27858
27514
  init_welcome_header();
27859
27515
  PI_BUILTIN_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
27860
27516
  });
@@ -29043,7 +28699,7 @@ var init_automation_tool = __esm(() => {
29043
28699
  });
29044
28700
 
29045
28701
  // src/agent/citation-links.ts
29046
- import { basename as basename13, isAbsolute as isAbsolute12 } from "node:path";
28702
+ import { basename as basename12, isAbsolute as isAbsolute12 } from "node:path";
29047
28703
  import { pathToFileURL as pathToFileURL3 } from "node:url";
29048
28704
  function openableTarget(source) {
29049
28705
  if (/^https?:\/\//iu.test(source)) {
@@ -29061,7 +28717,7 @@ function linkCitations(markdown, sourceOf, isFile) {
29061
28717
  for (const marker of answerMarkers(markdown, isFile)) {
29062
28718
  if (marker.kind === "number")
29063
28719
  continue;
29064
- const labels = marker.kind === "file" ? [{ label: basename13(marker.path), source: marker.path }] : marker.ids.map((id) => ({ label: id, source: sourceOf(id) }));
28720
+ const labels = marker.kind === "file" ? [{ label: basename12(marker.path), source: marker.path }] : marker.ids.map((id) => ({ label: id, source: sourceOf(id) }));
29065
28721
  let linked = false;
29066
28722
  const parts = labels.map(({ label, source }) => {
29067
28723
  const target = source === undefined ? undefined : openableTarget(source);
@@ -30300,7 +29956,7 @@ class DazziJevBackend {
30300
29956
  this.apiKey = apiKey;
30301
29957
  this.baseUrl = options.baseUrl ?? resolveBaseUrl(env);
30302
29958
  this.defaultModel = options.defaultModel ?? DAZZI_DEFAULT_JEV_MODEL;
30303
- this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS12;
29959
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
30304
29960
  this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
30305
29961
  this.fetchImpl = options.fetchImpl;
30306
29962
  }
@@ -30487,7 +30143,7 @@ async function extractErrorMessage(response) {
30487
30143
  function sleep6(ms) {
30488
30144
  return new Promise((resolve) => setTimeout(resolve, ms));
30489
30145
  }
30490
- var JEV_PATH, DAZZI_DEFAULT_JEV_MODEL = "jev-1.13", DEFAULT_TIMEOUT_MS12 = 1e4, DEFAULT_MAX_RETRIES = 2, RETRY_BASE_MS = 500, RETRY_MAX_MS = 5000;
30146
+ var JEV_PATH, DAZZI_DEFAULT_JEV_MODEL = "jev-1.13", DEFAULT_TIMEOUT_MS11 = 1e4, DEFAULT_MAX_RETRIES = 2, RETRY_BASE_MS = 500, RETRY_MAX_MS = 5000;
30491
30147
  var init_jev_backend = __esm(() => {
30492
30148
  init_config();
30493
30149
  init_credential();
@@ -31971,7 +31627,7 @@ var init_page_loader = __esm(() => {
31971
31627
  });
31972
31628
 
31973
31629
  // src/web/fetch/url-target.ts
31974
- import { extname as extname8 } from "node:path";
31630
+ import { extname as extname7 } from "node:path";
31975
31631
  function repairCollapsedScheme(value) {
31976
31632
  const m = value.match(/^(https?):\/(?!\/)/i);
31977
31633
  return m ? `${m[1]}://${value.slice(m[0].length)}` : value;
@@ -31990,7 +31646,7 @@ function getFilenameExtensionHint(filename) {
31990
31646
  const lower = filename.toLowerCase();
31991
31647
  if (lower.endsWith(".tar.gz"))
31992
31648
  return ".tar.gz";
31993
- return extname8(filename).toLowerCase();
31649
+ return extname7(filename).toLowerCase();
31994
31650
  }
31995
31651
  function getExtensionHint(url, contentDisposition) {
31996
31652
  if (contentDisposition) {
@@ -32167,7 +31823,7 @@ var init_convert2 = __esm(() => {
32167
31823
  });
32168
31824
 
32169
31825
  // src/web/fetch/feeds.ts
32170
- import { extname as extname9 } from "node:path";
31826
+ import { extname as extname8 } from "node:path";
32171
31827
  import { XMLParser as XMLParser3 } from "fast-xml-parser";
32172
31828
  function getHtmlAttribute(tag, attribute) {
32173
31829
  const pattern = new RegExp(`\\b${attribute}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'=<>]+))`, "i");
@@ -32230,7 +31886,7 @@ function extractDocumentLinks(html, baseUrl) {
32230
31886
  const href = getHtmlAttribute(tag, "href");
32231
31887
  if (!href)
32232
31888
  continue;
32233
- const ext = extname9(href).toLowerCase();
31889
+ const ext = extname8(href).toLowerCase();
32234
31890
  if (!CONVERTIBLE_EXTENSIONS2.has(ext))
32235
31891
  continue;
32236
31892
  const resolved = href.startsWith("http") ? href : new URL(href, baseUrl).href;
@@ -33898,7 +33554,7 @@ var init_web_search_tool = __esm(() => {
33898
33554
  // src/agent/agent.ts
33899
33555
  import { randomUUID as randomUUID7 } from "node:crypto";
33900
33556
  import { existsSync as existsSync34, watch as fsWatch, mkdirSync as mkdirSync25, realpathSync as realpathSync7, statSync as statSync9, writeFileSync as writeFileSync18 } from "node:fs";
33901
- import { basename as basename14, dirname as dirname26, join as join52, resolve as resolve18 } from "node:path";
33557
+ import { basename as basename13, dirname as dirname26, join as join52, resolve as resolve18 } from "node:path";
33902
33558
  import { clampThinkingLevel } from "@earendil-works/pi-ai/compat";
33903
33559
  import { getAgentDir as getAgentDir5, keyText } from "@earendil-works/pi-coding-agent";
33904
33560
  function positiveLimit(value, fallback, path) {
@@ -36821,7 +36477,7 @@ function toMinSyncReasonDiagnostic(reason) {
36821
36477
  function pinExcludedPath(path) {
36822
36478
  const resolvedPath = resolve18(path);
36823
36479
  try {
36824
- return join52(realpathSync7(dirname26(resolvedPath)), basename14(resolvedPath));
36480
+ return join52(realpathSync7(dirname26(resolvedPath)), basename13(resolvedPath));
36825
36481
  } catch {
36826
36482
  return resolvedPath;
36827
36483
  }