@autorag/librarian 2.13.3 → 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/NOTICE +3 -0
- package/README.md +0 -1
- package/dist/agent/context-token-guard.d.ts +11 -6
- package/dist/agent/token-count.d.ts +4 -0
- package/dist/cli/index.js +230 -631
- package/dist/core.js +146 -546
- package/dist/datasource/connector-skill.d.ts +1 -1
- package/dist/datasource/connector.d.ts +1 -1
- package/dist/datasource/index.d.ts +0 -1
- package/dist/index.js +148 -551
- package/dist/mcp/index.js +148 -548
- package/dist/profiles.js +231 -631
- package/package.json +2 -1
- package/skills/autorag-doctor/SKILL.md +1 -2
- package/skills/autorag-lite-setup/SKILL.md +1 -1
- package/skills/autorag-setup/SKILL.md +3 -4
- package/dist/datasource/skills/spotlight/connector.d.ts +0 -53
- package/dist/datasource/skills/spotlight/index.d.ts +0 -2
- package/dist/datasource/skills/spotlight/skill.d.ts +0 -33
package/dist/mcp/index.js
CHANGED
|
@@ -24335,413 +24335,6 @@ var init_slack = __esm(() => {
|
|
|
24335
24335
|
};
|
|
24336
24336
|
});
|
|
24337
24337
|
|
|
24338
|
-
// src/datasource/skills/spotlight/connector.ts
|
|
24339
|
-
import { spawn as spawn19 } from "node:child_process";
|
|
24340
|
-
import { createHash as createHash19 } from "node:crypto";
|
|
24341
|
-
import { readFile as fsReadFile, stat as stat5 } from "node:fs/promises";
|
|
24342
|
-
import { basename as basename11, extname as extname7 } from "node:path";
|
|
24343
|
-
|
|
24344
|
-
class SpotlightConnector {
|
|
24345
|
-
options;
|
|
24346
|
-
run;
|
|
24347
|
-
readFile;
|
|
24348
|
-
platform;
|
|
24349
|
-
constructor(options = {}) {
|
|
24350
|
-
this.options = options;
|
|
24351
|
-
this.run = options.run ?? spawnRunner;
|
|
24352
|
-
this.readFile = options.readFile ?? ((path) => fsReadFile(path, "utf8"));
|
|
24353
|
-
this.platform = options.platform ?? process.platform;
|
|
24354
|
-
}
|
|
24355
|
-
async probe() {
|
|
24356
|
-
const queries = (this.options.queries ?? []).map((query) => query.trim()).filter((query) => query.length > 0);
|
|
24357
|
-
const failure = await this.readinessFailure(queries);
|
|
24358
|
-
return failure ?? { ok: true, documents: [] };
|
|
24359
|
-
}
|
|
24360
|
-
async search(query, limit = DEFAULT_MAX_DOCUMENTS4, acceptDocument) {
|
|
24361
|
-
const trimmed = query.trim();
|
|
24362
|
-
if (trimmed.length === 0 || limit <= 0)
|
|
24363
|
-
return { ok: true, documents: [] };
|
|
24364
|
-
const queries = (this.options.queries ?? []).map((query) => query.trim()).filter((query) => query.length > 0);
|
|
24365
|
-
const failure = await this.readinessFailure(queries);
|
|
24366
|
-
if (failure !== undefined)
|
|
24367
|
-
return failure;
|
|
24368
|
-
const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
|
|
24369
|
-
const maxPerQuery = this.options.maxResultsPerQuery ?? DEFAULT_MAX_RESULTS_PER_QUERY;
|
|
24370
|
-
const maxDocuments = Math.min(this.options.maxDocuments ?? DEFAULT_MAX_DOCUMENTS4, limit);
|
|
24371
|
-
const seen = new Set;
|
|
24372
|
-
const paths = [];
|
|
24373
|
-
const textQuery = trimmed.split(/\s+/u).map((term) => `"${term.replace(/\\/gu, "\\\\").replace(/"/gu, "\\\"")}"`).join(" AND ");
|
|
24374
|
-
let mdfindMissing = false;
|
|
24375
|
-
let failedQueries = 0;
|
|
24376
|
-
const failures = [];
|
|
24377
|
-
for (const filter of queries) {
|
|
24378
|
-
const query = `(${filter}) AND (${textQuery})`;
|
|
24379
|
-
const args = this.options.onlyIn !== undefined ? ["-onlyin", this.options.onlyIn, query] : [query];
|
|
24380
|
-
const result = await this.run("mdfind", args, timeoutMs);
|
|
24381
|
-
if (!result.ok) {
|
|
24382
|
-
if (result.error === "ENOENT") {
|
|
24383
|
-
mdfindMissing = true;
|
|
24384
|
-
break;
|
|
24385
|
-
}
|
|
24386
|
-
failedQueries += 1;
|
|
24387
|
-
failures.push(result);
|
|
24388
|
-
continue;
|
|
24389
|
-
}
|
|
24390
|
-
let kept = 0;
|
|
24391
|
-
for (const line of result.stdout.split(`
|
|
24392
|
-
`)) {
|
|
24393
|
-
const path = line.trim();
|
|
24394
|
-
if (path.length === 0 || seen.has(path))
|
|
24395
|
-
continue;
|
|
24396
|
-
if (kept >= maxPerQuery)
|
|
24397
|
-
break;
|
|
24398
|
-
seen.add(path);
|
|
24399
|
-
paths.push(path);
|
|
24400
|
-
kept += 1;
|
|
24401
|
-
}
|
|
24402
|
-
}
|
|
24403
|
-
if (mdfindMissing) {
|
|
24404
|
-
return { ok: false, reason: "unavailable", message: "mdfind binary not found; Spotlight requires macOS" };
|
|
24405
|
-
}
|
|
24406
|
-
if (failedQueries === queries.length) {
|
|
24407
|
-
return {
|
|
24408
|
-
ok: false,
|
|
24409
|
-
reason: "unavailable",
|
|
24410
|
-
message: "every configured mdfind query failed",
|
|
24411
|
-
stderr: failures[0]?.stderr,
|
|
24412
|
-
stdout: failures[0]?.stdout,
|
|
24413
|
-
code: failures[0]?.code
|
|
24414
|
-
};
|
|
24415
|
-
}
|
|
24416
|
-
const documents = [];
|
|
24417
|
-
let permissionDenied = 0;
|
|
24418
|
-
let readFailures = 0;
|
|
24419
|
-
const maxBytes = this.options.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE2;
|
|
24420
|
-
const maxContentChars = this.options.maxContentChars ?? MAX_CONTENT_CHARS4;
|
|
24421
|
-
for (const path of paths) {
|
|
24422
|
-
if (documents.length >= maxDocuments)
|
|
24423
|
-
break;
|
|
24424
|
-
const docId = createHash19("sha256").update(path).digest("hex").slice(0, 16);
|
|
24425
|
-
if (acceptDocument !== undefined && !acceptDocument(docId))
|
|
24426
|
-
continue;
|
|
24427
|
-
try {
|
|
24428
|
-
const info = await stat5(path);
|
|
24429
|
-
if (!info.isFile() || info.size > maxBytes)
|
|
24430
|
-
continue;
|
|
24431
|
-
const text = await this.readFile(path);
|
|
24432
|
-
const content = text.trim().slice(0, maxContentChars);
|
|
24433
|
-
if (content.length === 0)
|
|
24434
|
-
continue;
|
|
24435
|
-
documents.push({
|
|
24436
|
-
docId,
|
|
24437
|
-
hierarchy: ["files"],
|
|
24438
|
-
title: basename11(path),
|
|
24439
|
-
content,
|
|
24440
|
-
publishedAt: info.mtimeMs,
|
|
24441
|
-
metadata: { path, extension: extname7(path).toLowerCase() }
|
|
24442
|
-
});
|
|
24443
|
-
} catch (error) {
|
|
24444
|
-
const code = error.code;
|
|
24445
|
-
if (code === "EPERM" || code === "EACCES")
|
|
24446
|
-
permissionDenied += 1;
|
|
24447
|
-
else
|
|
24448
|
-
readFailures += 1;
|
|
24449
|
-
}
|
|
24450
|
-
}
|
|
24451
|
-
if (documents.length === 0 && permissionDenied > 0) {
|
|
24452
|
-
return {
|
|
24453
|
-
ok: false,
|
|
24454
|
-
reason: "permission",
|
|
24455
|
-
message: `macOS denied access to all Spotlight hits; ${FDA_GUIDANCE}`
|
|
24456
|
-
};
|
|
24457
|
-
}
|
|
24458
|
-
if (documents.length === 0 && failedQueries > 0) {
|
|
24459
|
-
return {
|
|
24460
|
-
ok: false,
|
|
24461
|
-
reason: "unavailable",
|
|
24462
|
-
message: "some mdfind queries failed and no readable hits remained",
|
|
24463
|
-
stderr: failures[0]?.stderr,
|
|
24464
|
-
stdout: failures[0]?.stdout,
|
|
24465
|
-
code: failures[0]?.code
|
|
24466
|
-
};
|
|
24467
|
-
}
|
|
24468
|
-
const warnings = [];
|
|
24469
|
-
if (failedQueries > 0)
|
|
24470
|
-
warnings.push(`${failedQueries} mdfind quer(y/ies) failed`);
|
|
24471
|
-
if (permissionDenied > 0) {
|
|
24472
|
-
warnings.push(`${permissionDenied} Spotlight hit(s) were denied by macOS privacy protections; ${FDA_GUIDANCE}`);
|
|
24473
|
-
}
|
|
24474
|
-
if (readFailures > 0)
|
|
24475
|
-
warnings.push(`${readFailures} Spotlight hit(s) failed to read`);
|
|
24476
|
-
return { ok: true, documents, ...warnings.length > 0 ? { warnings } : {} };
|
|
24477
|
-
}
|
|
24478
|
-
async readinessFailure(queries) {
|
|
24479
|
-
if (this.platform !== "darwin") {
|
|
24480
|
-
return { ok: false, reason: "unavailable", message: "spotlight datasource is supported on macOS only" };
|
|
24481
|
-
}
|
|
24482
|
-
if (queries.length === 0) {
|
|
24483
|
-
return { ok: false, reason: "not-configured", message: "no spotlight queries configured" };
|
|
24484
|
-
}
|
|
24485
|
-
const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
|
|
24486
|
-
const status = await this.run("mdutil", ["-s", "/"], timeoutMs);
|
|
24487
|
-
if (status.ok && /indexing disabled/iu.test(status.stdout)) {
|
|
24488
|
-
return {
|
|
24489
|
-
ok: false,
|
|
24490
|
-
reason: "unavailable",
|
|
24491
|
-
message: "Spotlight indexing is disabled; enable it with `sudo mdutil -i on /`"
|
|
24492
|
-
};
|
|
24493
|
-
}
|
|
24494
|
-
return;
|
|
24495
|
-
}
|
|
24496
|
-
}
|
|
24497
|
-
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) => {
|
|
24498
|
-
const child = spawn19(command, [...args], { stdio: ["ignore", "pipe", "pipe"] });
|
|
24499
|
-
let stdout = "";
|
|
24500
|
-
let stderr = "";
|
|
24501
|
-
let settled = false;
|
|
24502
|
-
const finish = (result) => {
|
|
24503
|
-
if (settled)
|
|
24504
|
-
return;
|
|
24505
|
-
settled = true;
|
|
24506
|
-
clearTimeout(timer);
|
|
24507
|
-
resolve(result);
|
|
24508
|
-
};
|
|
24509
|
-
const timer = setTimeout(() => {
|
|
24510
|
-
child.kill("SIGKILL");
|
|
24511
|
-
finish({ ok: false, stdout, stderr: "process timed out", code: null });
|
|
24512
|
-
}, timeoutMs);
|
|
24513
|
-
child.stdout.setEncoding("utf8");
|
|
24514
|
-
child.stderr.setEncoding("utf8");
|
|
24515
|
-
child.stdout.on("data", (chunk) => {
|
|
24516
|
-
if (stdout.length < MAX_BUFFER_BYTES)
|
|
24517
|
-
stdout += chunk;
|
|
24518
|
-
});
|
|
24519
|
-
child.stderr.on("data", (chunk) => {
|
|
24520
|
-
if (stderr.length < MAX_BUFFER_BYTES)
|
|
24521
|
-
stderr += chunk;
|
|
24522
|
-
});
|
|
24523
|
-
child.on("error", (error) => {
|
|
24524
|
-
finish({ ok: false, stdout, stderr: error.message, code: null, error: error.code });
|
|
24525
|
-
});
|
|
24526
|
-
child.on("close", (code) => {
|
|
24527
|
-
finish({ ok: code === 0, stdout, stderr, code });
|
|
24528
|
-
});
|
|
24529
|
-
});
|
|
24530
|
-
var init_connector5 = __esm(() => {
|
|
24531
|
-
DEFAULT_MAX_BYTES_PER_FILE2 = 256 * 1024;
|
|
24532
|
-
MAX_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
24533
|
-
});
|
|
24534
|
-
|
|
24535
|
-
// src/datasource/skills/spotlight/skill.ts
|
|
24536
|
-
class SpotlightSkill {
|
|
24537
|
-
connector;
|
|
24538
|
-
skillName;
|
|
24539
|
-
instanceId;
|
|
24540
|
-
instances;
|
|
24541
|
-
tags;
|
|
24542
|
-
lastIndexedAt;
|
|
24543
|
-
lastError;
|
|
24544
|
-
constructor(options = {}) {
|
|
24545
|
-
this.skillName = options.skillName ?? "spotlight";
|
|
24546
|
-
this.instanceId = options.instanceId ?? "default";
|
|
24547
|
-
this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
|
|
24548
|
-
this.tags = options.tags ?? DEFAULT_TAGS4;
|
|
24549
|
-
this.connector = options.connector ?? new SpotlightConnector(options.connectorOptions ?? {});
|
|
24550
|
-
}
|
|
24551
|
-
describe() {
|
|
24552
|
-
return {
|
|
24553
|
-
name: this.skillName,
|
|
24554
|
-
id: this.skillName,
|
|
24555
|
-
type: "spotlight-search",
|
|
24556
|
-
description: "Live macOS Spotlight search via the built-in mdfind CLI",
|
|
24557
|
-
capabilities: ["files", "macos-only", "local-search", "live-search", "scoped", "external-cli"],
|
|
24558
|
-
tags: this.tags,
|
|
24559
|
-
status: "active",
|
|
24560
|
-
requiresExternalCli: true,
|
|
24561
|
-
datasourceId: this.skillName,
|
|
24562
|
-
instanceId: this.instanceId,
|
|
24563
|
-
instances: this.instances
|
|
24564
|
-
};
|
|
24565
|
-
}
|
|
24566
|
-
polling() {
|
|
24567
|
-
return {
|
|
24568
|
-
mode: "none",
|
|
24569
|
-
...this.lastIndexedAt !== undefined ? { lastIndexedAt: this.lastIndexedAt } : {},
|
|
24570
|
-
...this.lastError !== undefined ? { lastError: this.lastError } : {}
|
|
24571
|
-
};
|
|
24572
|
-
}
|
|
24573
|
-
async index() {
|
|
24574
|
-
try {
|
|
24575
|
-
const result = await this.connector.probe();
|
|
24576
|
-
if (!result.ok) {
|
|
24577
|
-
const code = connectorFailureToDiagnosticCode(result.reason);
|
|
24578
|
-
const message = boundDiagnosticText(result.message ?? result.reason);
|
|
24579
|
-
this.lastError = message;
|
|
24580
|
-
return this.fail(code, message);
|
|
24581
|
-
}
|
|
24582
|
-
this.lastError = undefined;
|
|
24583
|
-
this.lastIndexedAt = Date.now();
|
|
24584
|
-
return {
|
|
24585
|
-
ok: true,
|
|
24586
|
-
instanceId: this.instanceId,
|
|
24587
|
-
skill: this.skillName,
|
|
24588
|
-
chunkCount: 0,
|
|
24589
|
-
indexedAt: this.lastIndexedAt,
|
|
24590
|
-
diagnostics: [this.note(LIVE_NOTE, "datasource-empty", "info")]
|
|
24591
|
-
};
|
|
24592
|
-
} catch (error) {
|
|
24593
|
-
const message = boundDiagnosticText(error instanceof Error ? error.message : "spotlight probe failed");
|
|
24594
|
-
this.lastError = message;
|
|
24595
|
-
return this.fail("datasource-unavailable", message);
|
|
24596
|
-
}
|
|
24597
|
-
}
|
|
24598
|
-
retrievalMethods() {
|
|
24599
|
-
return [new SpotlightLiveMethod(this)];
|
|
24600
|
-
}
|
|
24601
|
-
describeSources() {
|
|
24602
|
-
return this.instances.map((instanceId) => ({
|
|
24603
|
-
source: datasourceSourcePath(this.skillName, instanceId),
|
|
24604
|
-
datasourceId: this.skillName,
|
|
24605
|
-
skill: this.skillName,
|
|
24606
|
-
instanceId,
|
|
24607
|
-
contentType: "document",
|
|
24608
|
-
metadata: { datasourceId: this.skillName, instanceId, tags: this.tags }
|
|
24609
|
-
}));
|
|
24610
|
-
}
|
|
24611
|
-
skillManifest() {
|
|
24612
|
-
const scopes = this.instances.map((instanceId) => `- \`${datasourceSourcePath(this.skillName, instanceId)}\``).join(`
|
|
24613
|
-
`);
|
|
24614
|
-
return {
|
|
24615
|
-
name: `datasource-${this.skillName}`,
|
|
24616
|
-
description: "Search the current macOS Spotlight index directly. AutoRAG keeps no file snapshot.",
|
|
24617
|
-
content: [
|
|
24618
|
-
"# macOS Spotlight (live mdfind search)",
|
|
24619
|
-
"",
|
|
24620
|
-
"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.",
|
|
24621
|
-
"",
|
|
24622
|
-
"## Platform requirements",
|
|
24623
|
-
"- macOS only: this datasource is unavailable on any other platform.",
|
|
24624
|
-
"- Spotlight indexing must be enabled (`sudo mdutil -i on /`; check with `mdutil -s /`).",
|
|
24625
|
-
"- 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.",
|
|
24626
|
-
"",
|
|
24627
|
-
"## How to search",
|
|
24628
|
-
`Call the dedicated \`${datasourceSearchToolName(this.skillName)}\` tool with a query and optional narrowing scope. Available scopes:`,
|
|
24629
|
-
scopes,
|
|
24630
|
-
"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`.",
|
|
24631
|
-
"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.",
|
|
24632
|
-
"",
|
|
24633
|
-
"## Native CLI",
|
|
24634
|
-
"- `mdfind <query>` searches Spotlight; `mdfind -onlyin <dir> <query>` scopes to a directory; `mdfind -name <text>` matches file names.",
|
|
24635
|
-
"- `mdls <file>` shows Spotlight metadata for one file.",
|
|
24636
|
-
"- `mdutil -s /` checks index status; `sudo mdutil -i on /` enables indexing."
|
|
24637
|
-
].join(`
|
|
24638
|
-
`)
|
|
24639
|
-
};
|
|
24640
|
-
}
|
|
24641
|
-
async search(query, options) {
|
|
24642
|
-
const trimmed = query.trim();
|
|
24643
|
-
if (trimmed.length === 0)
|
|
24644
|
-
return [];
|
|
24645
|
-
const scope = options.scope?.trim() ? normalizeVirtualPath2(options.scope) : undefined;
|
|
24646
|
-
if (scope !== undefined) {
|
|
24647
|
-
const chunksRoot = normalizeVirtualPath2(`/${this.skillName}/${this.instanceId}/chunks`);
|
|
24648
|
-
const scopeProbe = datasourceSourcePath(this.skillName, this.instanceId, "__scope_probe__");
|
|
24649
|
-
if (!matchesDatasourceScope(chunksRoot, scope) && !matchesDatasourceScope(scopeProbe, scope) && !scope.startsWith(`${chunksRoot}/`)) {
|
|
24650
|
-
return [];
|
|
24651
|
-
}
|
|
24652
|
-
}
|
|
24653
|
-
const topK = options.topK ?? DEFAULT_TOP_K9;
|
|
24654
|
-
const result = await this.connector.search(trimmed, topK, (docId) => matchesDatasourceScope(datasourceSourcePath(this.skillName, this.instanceId, docId), scope));
|
|
24655
|
-
if (!result.ok) {
|
|
24656
|
-
throw datasourceCliError(this.skillName, "search", {
|
|
24657
|
-
reason: result.reason,
|
|
24658
|
-
stderr: result.stderr ?? result.message,
|
|
24659
|
-
stdout: result.stdout,
|
|
24660
|
-
code: result.code
|
|
24661
|
-
});
|
|
24662
|
-
}
|
|
24663
|
-
const hits = [];
|
|
24664
|
-
for (const [index, document] of result.documents.entries()) {
|
|
24665
|
-
const source = datasourceSourcePath(this.skillName, this.instanceId, document.docId);
|
|
24666
|
-
if (!matchesDatasourceScope(source, options.scope))
|
|
24667
|
-
continue;
|
|
24668
|
-
hits.push({
|
|
24669
|
-
id: `${this.skillName}:${this.instanceId}:${document.docId}`,
|
|
24670
|
-
content: document.content,
|
|
24671
|
-
source,
|
|
24672
|
-
score: 1 / (index + 1),
|
|
24673
|
-
metadata: {
|
|
24674
|
-
...document.metadata,
|
|
24675
|
-
method: `${this.skillName}-live`,
|
|
24676
|
-
datasourceId: this.skillName,
|
|
24677
|
-
instanceId: this.instanceId,
|
|
24678
|
-
chunkId: document.docId,
|
|
24679
|
-
...document.title !== undefined ? { title: document.title } : {},
|
|
24680
|
-
...document.hierarchy !== undefined && document.hierarchy.length > 0 ? { hierarchy: document.hierarchy.join("/") } : {},
|
|
24681
|
-
...document.publishedAt !== undefined ? { publishedAt: document.publishedAt } : {},
|
|
24682
|
-
...result.warnings !== undefined && result.warnings.length > 0 ? { warnings: result.warnings } : {}
|
|
24683
|
-
}
|
|
24684
|
-
});
|
|
24685
|
-
if (hits.length >= topK)
|
|
24686
|
-
break;
|
|
24687
|
-
}
|
|
24688
|
-
return hits;
|
|
24689
|
-
}
|
|
24690
|
-
fail(code, message) {
|
|
24691
|
-
return {
|
|
24692
|
-
ok: false,
|
|
24693
|
-
instanceId: this.instanceId,
|
|
24694
|
-
skill: this.skillName,
|
|
24695
|
-
indexedAt: Date.now(),
|
|
24696
|
-
diagnostics: [
|
|
24697
|
-
this.note(message, code, code === "datasource-unavailable" || code === "datasource-empty" ? "warning" : "error")
|
|
24698
|
-
],
|
|
24699
|
-
error: message,
|
|
24700
|
-
code,
|
|
24701
|
-
message
|
|
24702
|
-
};
|
|
24703
|
-
}
|
|
24704
|
-
note(message, code, severity) {
|
|
24705
|
-
return { code, severity, message, instanceId: this.instanceId, source: this.skillName };
|
|
24706
|
-
}
|
|
24707
|
-
}
|
|
24708
|
-
|
|
24709
|
-
class SpotlightLiveMethod {
|
|
24710
|
-
skill;
|
|
24711
|
-
constructor(skill) {
|
|
24712
|
-
this.skill = skill;
|
|
24713
|
-
}
|
|
24714
|
-
describe() {
|
|
24715
|
-
const descriptor = this.skill.describe();
|
|
24716
|
-
return {
|
|
24717
|
-
name: `${descriptor.datasourceId ?? "spotlight"}-live`,
|
|
24718
|
-
type: "remote",
|
|
24719
|
-
description: "Live macOS Spotlight search via mdfind",
|
|
24720
|
-
status: "active",
|
|
24721
|
-
capabilities: ["live-search", "scoped", "external-cli", "path-opaque-sources"],
|
|
24722
|
-
datasourceId: descriptor.datasourceId,
|
|
24723
|
-
tags: descriptor.tags
|
|
24724
|
-
};
|
|
24725
|
-
}
|
|
24726
|
-
retrieve(query, options) {
|
|
24727
|
-
return this.skill.search(query, options);
|
|
24728
|
-
}
|
|
24729
|
-
}
|
|
24730
|
-
var DEFAULT_TAGS4, DEFAULT_TOP_K9 = 20, LIVE_NOTE = "live-search datasource: macOS owns the Spotlight index; AutoRAG stores no snapshot";
|
|
24731
|
-
var init_skill12 = __esm(() => {
|
|
24732
|
-
init_connector();
|
|
24733
|
-
init_errors4();
|
|
24734
|
-
init_scope2();
|
|
24735
|
-
init_connector5();
|
|
24736
|
-
DEFAULT_TAGS4 = ["spotlight", "files"];
|
|
24737
|
-
});
|
|
24738
|
-
|
|
24739
|
-
// src/datasource/skills/spotlight/index.ts
|
|
24740
|
-
var init_spotlight = __esm(() => {
|
|
24741
|
-
init_connector5();
|
|
24742
|
-
init_skill12();
|
|
24743
|
-
});
|
|
24744
|
-
|
|
24745
24338
|
// src/datasource/skills/telecrawl/index.ts
|
|
24746
24339
|
function globalArgs3(options) {
|
|
24747
24340
|
return [
|
|
@@ -25146,7 +24739,6 @@ var init_factory = __esm(() => {
|
|
|
25146
24739
|
init_obsidian();
|
|
25147
24740
|
init_rss();
|
|
25148
24741
|
init_slack();
|
|
25149
|
-
init_spotlight();
|
|
25150
24742
|
init_telecrawl();
|
|
25151
24743
|
init_wacrawl();
|
|
25152
24744
|
BUILDERS = {
|
|
@@ -25283,12 +24875,6 @@ var init_factory = __esm(() => {
|
|
|
25283
24875
|
...common(config, workspaceRoot),
|
|
25284
24876
|
skillName: registrationName,
|
|
25285
24877
|
connectorOptions: config.connector
|
|
25286
|
-
}),
|
|
25287
|
-
spotlight: (config, _workspaceRoot, registrationName) => new SpotlightSkill({
|
|
25288
|
-
...config.instanceId !== undefined ? { instanceId: config.instanceId } : {},
|
|
25289
|
-
...config.tags !== undefined ? { tags: config.tags } : {},
|
|
25290
|
-
skillName: registrationName,
|
|
25291
|
-
connectorOptions: config.connector
|
|
25292
24878
|
})
|
|
25293
24879
|
};
|
|
25294
24880
|
PLATFORM_ONLY_SKILLS = { kakao: "darwin" };
|
|
@@ -25298,7 +24884,7 @@ var init_factory = __esm(() => {
|
|
|
25298
24884
|
// src/cli/config.ts
|
|
25299
24885
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
25300
24886
|
import { existsSync as existsSync27, mkdirSync as mkdirSync22, readFileSync as readFileSync24, unlinkSync as unlinkSync3, writeFileSync as writeFileSync15 } from "node:fs";
|
|
25301
|
-
import { basename as
|
|
24887
|
+
import { basename as basename11, dirname as dirname23, isAbsolute as isAbsolute11, join as join42, resolve as resolve15 } from "node:path";
|
|
25302
24888
|
import { findEnvKeys, getEnvApiKey } from "@earendil-works/pi-ai/compat";
|
|
25303
24889
|
import { getAgentDir as getAgentDir2, ModelRuntime, SettingsManager } from "@earendil-works/pi-coding-agent";
|
|
25304
24890
|
function resolveConfigPath(input) {
|
|
@@ -25372,7 +24958,7 @@ function acquireConfigWriteLock(configPath) {
|
|
|
25372
24958
|
});
|
|
25373
24959
|
}
|
|
25374
24960
|
function replaceFileAtomically(path, contents, assertCommitAllowed) {
|
|
25375
|
-
const temporaryPath = join42(dirname23(path), `.${
|
|
24961
|
+
const temporaryPath = join42(dirname23(path), `.${basename11(path)}.${process.pid}.${randomUUID6()}.tmp`);
|
|
25376
24962
|
try {
|
|
25377
24963
|
writeFileSync15(temporaryPath, contents, { encoding: "utf8", flag: "wx", flush: true, mode: 384 });
|
|
25378
24964
|
assertCommitAllowed?.();
|
|
@@ -26883,6 +26469,42 @@ function loopGuardPrompt(rule) {
|
|
|
26883
26469
|
`);
|
|
26884
26470
|
}
|
|
26885
26471
|
|
|
26472
|
+
// src/agent/token-count.ts
|
|
26473
|
+
import { createHash as createHash19 } from "node:crypto";
|
|
26474
|
+
import { countTokens } from "gpt-tokenizer/encoding/o200k_base";
|
|
26475
|
+
function estimateTextTokens(text) {
|
|
26476
|
+
return Math.max(Math.ceil(text.length / 4), countText(text));
|
|
26477
|
+
}
|
|
26478
|
+
function tokensBeyondCharGuess(parts) {
|
|
26479
|
+
let excess = 0;
|
|
26480
|
+
for (const part of parts)
|
|
26481
|
+
excess += Math.max(0, countText(part) - Math.ceil(part.length / 4));
|
|
26482
|
+
return excess;
|
|
26483
|
+
}
|
|
26484
|
+
function countText(text) {
|
|
26485
|
+
if (text.length === 0)
|
|
26486
|
+
return 0;
|
|
26487
|
+
if (text.length < CACHE_MIN_CHARS)
|
|
26488
|
+
return countTokens(text, PLAIN_TEXT);
|
|
26489
|
+
const key = `${text.length}:${createHash19("sha1").update(text).digest("base64")}`;
|
|
26490
|
+
const hit = cache.get(key);
|
|
26491
|
+
if (hit !== undefined) {
|
|
26492
|
+
cache.delete(key);
|
|
26493
|
+
cache.set(key, hit);
|
|
26494
|
+
return hit;
|
|
26495
|
+
}
|
|
26496
|
+
const count = countTokens(text, PLAIN_TEXT);
|
|
26497
|
+
cache.set(key, count);
|
|
26498
|
+
if (cache.size > CACHE_ENTRIES)
|
|
26499
|
+
cache.delete(cache.keys().next().value);
|
|
26500
|
+
return count;
|
|
26501
|
+
}
|
|
26502
|
+
var PLAIN_TEXT, CACHE_MIN_CHARS = 2000, CACHE_ENTRIES = 64, cache;
|
|
26503
|
+
var init_token_count = __esm(() => {
|
|
26504
|
+
PLAIN_TEXT = { disallowedSpecial: new Set };
|
|
26505
|
+
cache = new Map;
|
|
26506
|
+
});
|
|
26507
|
+
|
|
26886
26508
|
// src/agent/context-token-guard.ts
|
|
26887
26509
|
import { calculateContextTokens, estimateTokens } from "@earendil-works/pi-coding-agent";
|
|
26888
26510
|
function createContextTokenGuardedTransform(model, base, fixedOverheadTokens = () => 0) {
|
|
@@ -26933,50 +26555,40 @@ function guardWithinBudget(model, messages, useReportedUsage = true, fixedOverhe
|
|
|
26933
26555
|
}
|
|
26934
26556
|
let guarded = messages;
|
|
26935
26557
|
if (candidates.length > 0) {
|
|
26936
|
-
const
|
|
26937
|
-
const maximumOmitted = candidates.reduce((total, section) => total + section.blocks.length, 0);
|
|
26558
|
+
const entries = candidates.flatMap((section, sectionIndex) => section.blocks.map((block, blockIndex) => ({ block, sectionIndex, blockIndex })));
|
|
26938
26559
|
const omissionMarker = (count) => `
|
|
26939
26560
|
|
|
26940
26561
|
${GUARD_MARKER} Retrieval candidates omitted: ${count}.
|
|
26941
26562
|
`;
|
|
26942
|
-
|
|
26943
|
-
|
|
26944
|
-
|
|
26945
|
-
|
|
26946
|
-
for (const
|
|
26947
|
-
|
|
26948
|
-
|
|
26949
|
-
if (tokens <= remaining) {
|
|
26950
|
-
kept[sectionIndex]?.push(block);
|
|
26951
|
-
remaining -= tokens;
|
|
26952
|
-
continue;
|
|
26953
|
-
}
|
|
26954
|
-
omitted += section.blocks.length - (kept[sectionIndex]?.length ?? 0);
|
|
26955
|
-
for (const later of candidates.slice(sectionIndex + 1))
|
|
26956
|
-
omitted += later.blocks.length;
|
|
26957
|
-
firstOmitted = sectionIndex;
|
|
26958
|
-
break;
|
|
26959
|
-
}
|
|
26960
|
-
if (firstOmitted !== -1)
|
|
26563
|
+
const markerTokens = candidates.length * Math.ceil(omissionMarker(entries.length).length / 4);
|
|
26564
|
+
let remaining = Math.max(0, budget - estimateContextMessageTokens(base, false) - markerTokens);
|
|
26565
|
+
entries.sort((a, b) => a.block.rank - b.block.rank || a.sectionIndex - b.sectionIndex || a.blockIndex - b.blockIndex);
|
|
26566
|
+
const kept = new Set;
|
|
26567
|
+
for (const { block } of entries) {
|
|
26568
|
+
const tokens = Math.max(1, estimateTextTokens(block.text));
|
|
26569
|
+
if (tokens > remaining)
|
|
26961
26570
|
break;
|
|
26571
|
+
remaining -= tokens;
|
|
26572
|
+
kept.add(block);
|
|
26962
26573
|
}
|
|
26963
|
-
if (
|
|
26964
|
-
const
|
|
26965
|
-
for (const [sectionIndex, messageIndex] of candidateIndexes.entries())
|
|
26966
|
-
candidateByMessage.set(messageIndex, sectionIndex);
|
|
26574
|
+
if (kept.size < entries.length) {
|
|
26575
|
+
const sectionByMessage = new Map(candidateIndexes.map((messageIndex, i) => [messageIndex, candidates[i]]));
|
|
26967
26576
|
guarded = base.map((message, index) => {
|
|
26968
|
-
const
|
|
26969
|
-
if (
|
|
26577
|
+
const section = sectionByMessage.get(index);
|
|
26578
|
+
if (section === undefined)
|
|
26970
26579
|
return message;
|
|
26971
|
-
const
|
|
26972
|
-
const
|
|
26973
|
-
|
|
26580
|
+
const keptBlocks = section.blocks.filter((block) => kept.has(block));
|
|
26581
|
+
const omitted = section.blocks.length - keptBlocks.length;
|
|
26582
|
+
if (omitted === 0)
|
|
26583
|
+
return messages[index] ?? message;
|
|
26584
|
+
const marker = omissionMarker(omitted);
|
|
26585
|
+
return replaceTextContent(message, `${section.prefix}${keptBlocks.map((block) => block.text).join("")}${marker}${section.suffix}`);
|
|
26974
26586
|
});
|
|
26975
26587
|
}
|
|
26976
26588
|
}
|
|
26977
|
-
if (estimateContextMessageTokens(guarded, false) <= budget
|
|
26589
|
+
if (guarded !== messages && estimateContextMessageTokens(guarded, false) <= budget)
|
|
26978
26590
|
return guarded;
|
|
26979
|
-
return
|
|
26591
|
+
return fitNewestToolResult(guarded, budget);
|
|
26980
26592
|
}
|
|
26981
26593
|
function estimateContextMessageTokens(messages, useReportedUsage = false) {
|
|
26982
26594
|
if (useReportedUsage) {
|
|
@@ -26987,82 +26599,37 @@ function estimateContextMessageTokens(messages, useReportedUsage = false) {
|
|
|
26987
26599
|
}
|
|
26988
26600
|
return messages.reduce((total, message) => total + estimateMessageTokens(message), 0);
|
|
26989
26601
|
}
|
|
26990
|
-
function
|
|
26991
|
-
const
|
|
26992
|
-
const
|
|
26993
|
-
|
|
26994
|
-
|
|
26995
|
-
const
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
26999
|
-
|
|
27000
|
-
trimmed[index] = fitMessageToTokens(message, Math.max(floorTokens, inputBudget - others));
|
|
27001
|
-
};
|
|
27002
|
-
for (const [index, message] of trimmed.entries()) {
|
|
27003
|
-
if (index === lastIndex || index === queryIndex || message.role === "system")
|
|
27004
|
-
continue;
|
|
27005
|
-
const replacement = replaceMessageWithMarker(message);
|
|
27006
|
-
if (replacement === message || estimateMessageTokens(replacement) >= estimateMessageTokens(message))
|
|
27007
|
-
continue;
|
|
27008
|
-
trimmed[index] = replacement;
|
|
27009
|
-
if (fits())
|
|
27010
|
-
return trimmed;
|
|
27011
|
-
}
|
|
27012
|
-
if (lastIndex !== queryIndex && trimmed[lastIndex]?.role !== "system") {
|
|
27013
|
-
fitInto(lastIndex, 0);
|
|
27014
|
-
if (fits())
|
|
27015
|
-
return trimmed;
|
|
27016
|
-
}
|
|
27017
|
-
for (const [index, message] of trimmed.entries()) {
|
|
27018
|
-
if (message.role !== "system")
|
|
27019
|
-
continue;
|
|
27020
|
-
fitInto(index, 0);
|
|
27021
|
-
if (fits())
|
|
27022
|
-
return trimmed;
|
|
27023
|
-
}
|
|
27024
|
-
if (queryIndex >= 0)
|
|
27025
|
-
fitInto(queryIndex, MIN_QUERY_TOKENS);
|
|
27026
|
-
return trimmed;
|
|
26602
|
+
function fitNewestToolResult(messages, inputBudget) {
|
|
26603
|
+
const lastIndex = messages.length - 1;
|
|
26604
|
+
const last = messages[lastIndex];
|
|
26605
|
+
if (last?.role !== "toolResult")
|
|
26606
|
+
return messages;
|
|
26607
|
+
const others = messages.reduce((total, message, index) => index === lastIndex ? total : total + estimateMessageTokens(message), 0);
|
|
26608
|
+
if (others >= inputBudget)
|
|
26609
|
+
return messages;
|
|
26610
|
+
const fitted = fitMessageToTokens(last, inputBudget - others);
|
|
26611
|
+
return fitted === last ? messages : [...messages.slice(0, lastIndex), fitted];
|
|
27027
26612
|
}
|
|
27028
26613
|
function fitMessageToTokens(message, maxTokens) {
|
|
27029
26614
|
const original = textContent(message);
|
|
27030
26615
|
if (original === undefined)
|
|
27031
|
-
return
|
|
26616
|
+
return message;
|
|
27032
26617
|
const marker = `
|
|
27033
26618
|
|
|
27034
26619
|
${GUARD_MARKER}
|
|
27035
26620
|
`;
|
|
27036
|
-
|
|
27037
|
-
|
|
27038
|
-
let
|
|
27039
|
-
|
|
27040
|
-
const
|
|
27041
|
-
const
|
|
27042
|
-
if (
|
|
27043
|
-
|
|
27044
|
-
|
|
27045
|
-
|
|
27046
|
-
high = middle - 1;
|
|
27047
|
-
}
|
|
26621
|
+
const overhead = estimateMessageTokens(replaceTextContent(message, ""));
|
|
26622
|
+
const density = Math.max(0, estimateMessageTokens(message) - overhead) / Math.max(1, original.length);
|
|
26623
|
+
let chars = density > 0 ? Math.floor((maxTokens - overhead) / density) : original.length;
|
|
26624
|
+
for (let attempt = 0;attempt < MAX_FIT_ATTEMPTS && chars > 0; attempt++) {
|
|
26625
|
+
const candidate = replaceTextContent(message, excerpt(original, chars, marker));
|
|
26626
|
+
const tokens = estimateMessageTokens(candidate);
|
|
26627
|
+
if (tokens <= maxTokens)
|
|
26628
|
+
return candidate;
|
|
26629
|
+
const scaled = Math.floor(chars * Math.max(0, maxTokens - overhead) / Math.max(1, tokens - overhead) * 0.98);
|
|
26630
|
+
chars = Math.min(chars - 1, scaled);
|
|
27048
26631
|
}
|
|
27049
|
-
return
|
|
27050
|
-
}
|
|
27051
|
-
function stripNonTextContent(message) {
|
|
27052
|
-
if (message.role !== "user" || typeof message.content === "string")
|
|
27053
|
-
return replaceMessageWithMarker(message);
|
|
27054
|
-
const marker = `
|
|
27055
|
-
|
|
27056
|
-
${GUARD_MARKER}
|
|
27057
|
-
`;
|
|
27058
|
-
let replacedImage = false;
|
|
27059
|
-
const content = message.content.map((block) => {
|
|
27060
|
-
if (block.type === "text")
|
|
27061
|
-
return block;
|
|
27062
|
-
replacedImage = true;
|
|
27063
|
-
return { type: "text", text: marker };
|
|
27064
|
-
});
|
|
27065
|
-
return replacedImage ? { ...message, content } : message;
|
|
26632
|
+
return replaceTextContent(message, marker);
|
|
27066
26633
|
}
|
|
27067
26634
|
function excerpt(text, maxChars, marker) {
|
|
27068
26635
|
if (text.length <= maxChars)
|
|
@@ -27072,32 +26639,54 @@ function excerpt(text, maxChars, marker) {
|
|
|
27072
26639
|
const tail = Math.max(0, available - head);
|
|
27073
26640
|
return `${text.slice(0, head)}${marker}${tail > 0 ? text.slice(-tail) : ""}`;
|
|
27074
26641
|
}
|
|
27075
|
-
function replaceMessageWithMarker(message) {
|
|
27076
|
-
return replaceTextContent(message, `
|
|
27077
|
-
|
|
27078
|
-
${GUARD_MARKER}
|
|
27079
|
-
`);
|
|
27080
|
-
}
|
|
27081
26642
|
function estimateMessageTokens(message) {
|
|
27082
26643
|
if (message.role === "system")
|
|
27083
26644
|
return estimateSystemMessageTokens(message);
|
|
27084
|
-
const estimate = estimateTokens(message);
|
|
26645
|
+
const estimate = estimateTokens(message) + tokensBeyondCharGuess(messageTextParts(message));
|
|
27085
26646
|
return message.role === "toolResult" ? estimate + Math.ceil(message.toolName.length / 4) : estimate;
|
|
27086
26647
|
}
|
|
27087
26648
|
function estimateSystemMessageTokens(message) {
|
|
27088
|
-
|
|
27089
|
-
|
|
26649
|
+
const parts = [];
|
|
26650
|
+
let chars = 0;
|
|
26651
|
+
if (typeof message.content === "string")
|
|
26652
|
+
parts.push(message.content);
|
|
26653
|
+
else {
|
|
27090
26654
|
for (const block of message.content) {
|
|
27091
26655
|
if (block.type === "text")
|
|
27092
|
-
|
|
26656
|
+
parts.push(block.text);
|
|
27093
26657
|
else if (block.type === "image")
|
|
27094
26658
|
chars += 4800;
|
|
27095
26659
|
}
|
|
27096
26660
|
}
|
|
27097
|
-
|
|
27098
|
-
|
|
27099
|
-
|
|
27100
|
-
return Math.ceil(chars / 4);
|
|
26661
|
+
parts.push(JSON.stringify(message.sections ?? {}), JSON.stringify(message.toolsAdded ?? []), JSON.stringify(message.toolsRemoved ?? []));
|
|
26662
|
+
for (const part of parts)
|
|
26663
|
+
chars += part.length;
|
|
26664
|
+
return Math.ceil(chars / 4) + tokensBeyondCharGuess(parts);
|
|
26665
|
+
}
|
|
26666
|
+
function messageTextParts(message) {
|
|
26667
|
+
switch (message.role) {
|
|
26668
|
+
case "user":
|
|
26669
|
+
case "custom":
|
|
26670
|
+
case "toolResult":
|
|
26671
|
+
return typeof message.content === "string" ? [message.content] : message.content.flatMap((block) => block.type === "text" ? [block.text] : []);
|
|
26672
|
+
case "assistant":
|
|
26673
|
+
return message.content.flatMap((block) => {
|
|
26674
|
+
if (block.type === "text")
|
|
26675
|
+
return [block.text];
|
|
26676
|
+
if (block.type === "thinking")
|
|
26677
|
+
return [block.thinking];
|
|
26678
|
+
if (block.type === "toolCall")
|
|
26679
|
+
return [`${block.name}${JSON.stringify(block.arguments)}`];
|
|
26680
|
+
return [];
|
|
26681
|
+
});
|
|
26682
|
+
case "bashExecution":
|
|
26683
|
+
return [message.command, message.output];
|
|
26684
|
+
case "branchSummary":
|
|
26685
|
+
case "compactionSummary":
|
|
26686
|
+
return [message.summary];
|
|
26687
|
+
default:
|
|
26688
|
+
return [];
|
|
26689
|
+
}
|
|
27101
26690
|
}
|
|
27102
26691
|
function findLastAssistantUsage(messages) {
|
|
27103
26692
|
for (let index = messages.length - 1;index >= 0; index--) {
|
|
@@ -27171,7 +26760,7 @@ function parseCandidateSection(message, text) {
|
|
|
27171
26760
|
const sectionEnd = findBaselineSectionEnd(text, sectionStart);
|
|
27172
26761
|
if (!/^\[e?\d+\] /mu.test(text.slice(sectionStart, sectionEnd)))
|
|
27173
26762
|
return;
|
|
27174
|
-
return splitCandidates(text, sectionStart, sectionEnd);
|
|
26763
|
+
return splitCandidates(text, sectionStart, sectionEnd, { lists: true });
|
|
27175
26764
|
}
|
|
27176
26765
|
if (message.role !== "toolResult")
|
|
27177
26766
|
return;
|
|
@@ -27182,7 +26771,9 @@ function parseCandidateSection(message, text) {
|
|
|
27182
26771
|
const directiveStart = text.indexOf(`
|
|
27183
26772
|
|
|
27184
26773
|
directive:`);
|
|
27185
|
-
return splitCandidates(text, 0, directiveStart >= 0 ? directiveStart : text.length,
|
|
26774
|
+
return splitCandidates(text, 0, directiveStart >= 0 ? directiveStart : text.length, {
|
|
26775
|
+
pattern: /^- [^\n]*(?:\n|$)/gmu
|
|
26776
|
+
});
|
|
27186
26777
|
}
|
|
27187
26778
|
const diagnosticsStart = text.indexOf(`
|
|
27188
26779
|
|
|
@@ -27204,17 +26795,23 @@ Formatting and content rules`
|
|
|
27204
26795
|
const positions = endMarkers.map((marker) => text.indexOf(marker, startIndex)).filter((index) => index >= 0);
|
|
27205
26796
|
return positions.length > 0 ? Math.min(...positions) : text.length;
|
|
27206
26797
|
}
|
|
27207
|
-
function splitCandidates(text, sectionStart, sectionEnd,
|
|
26798
|
+
function splitCandidates(text, sectionStart, sectionEnd, options = {}) {
|
|
27208
26799
|
const region = text.slice(sectionStart, sectionEnd);
|
|
27209
|
-
const matches = [...region.matchAll(pattern)];
|
|
26800
|
+
const matches = [...region.matchAll(options.pattern ?? /^\[e?\d+\] [^\n]*(?:\n|$)/gmu)];
|
|
27210
26801
|
const firstStart = matches[0]?.index;
|
|
27211
26802
|
if (firstStart === undefined)
|
|
27212
26803
|
return;
|
|
27213
26804
|
const blocks = [];
|
|
26805
|
+
let rank = 0;
|
|
26806
|
+
let heading = "";
|
|
27214
26807
|
for (const [index, match] of matches.entries()) {
|
|
27215
26808
|
const start = match.index ?? 0;
|
|
27216
26809
|
const end = index + 1 < matches.length ? matches[index + 1]?.index ?? region.length : region.length;
|
|
27217
|
-
|
|
26810
|
+
const raw = region.slice(start, end);
|
|
26811
|
+
const tail = options.lists === true ? LIST_HEADING_TAIL.exec(raw) : null;
|
|
26812
|
+
blocks.push({ text: heading + (tail === null ? raw : raw.slice(0, tail.index)), rank });
|
|
26813
|
+
rank = tail === null ? rank + 1 : 0;
|
|
26814
|
+
heading = tail === null ? "" : tail[0];
|
|
27218
26815
|
}
|
|
27219
26816
|
return {
|
|
27220
26817
|
prefix: text.slice(0, sectionStart) + region.slice(0, firstStart),
|
|
@@ -27222,9 +26819,10 @@ function splitCandidates(text, sectionStart, sectionEnd, pattern = /^\[e?\d+\] [
|
|
|
27222
26819
|
blocks
|
|
27223
26820
|
};
|
|
27224
26821
|
}
|
|
27225
|
-
var CONTEXT_HEADROOM = 1.2, MAX_OUTPUT_TOKENS = 32000,
|
|
26822
|
+
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;
|
|
27226
26823
|
var init_context_token_guard = __esm(() => {
|
|
27227
26824
|
init_context_overflow();
|
|
26825
|
+
init_token_count();
|
|
27228
26826
|
RETRIEVAL_TOOL_NAMES = {
|
|
27229
26827
|
jikji_find: true,
|
|
27230
26828
|
search_all_documents: true,
|
|
@@ -27233,6 +26831,7 @@ var init_context_token_guard = __esm(() => {
|
|
|
27233
26831
|
everything_search: true,
|
|
27234
26832
|
fsearch_search: true
|
|
27235
26833
|
};
|
|
26834
|
+
LIST_HEADING_TAIL = /\n[^\n]*initial candidates[^\n]*:\n$/u;
|
|
27236
26835
|
});
|
|
27237
26836
|
|
|
27238
26837
|
// src/agent/current-date.ts
|
|
@@ -27678,7 +27277,7 @@ function guardContext(pi, contextTransform) {
|
|
|
27678
27277
|
pi.on("context", async (event, ctx) => {
|
|
27679
27278
|
const activeTools = new Set(pi.getActiveTools());
|
|
27680
27279
|
const toolDeclarations = pi.getAllTools().filter((tool) => activeTools.has(tool.name)).map(({ name, description, parameters }) => ({ name, description, parameters }));
|
|
27681
|
-
const fixedOverheadTokens =
|
|
27280
|
+
const fixedOverheadTokens = estimateTextTokens(ctx.getSystemPrompt()) + estimateTextTokens(JSON.stringify(toolDeclarations));
|
|
27682
27281
|
return {
|
|
27683
27282
|
messages: await createContextTokenGuardedTransform(ctx.model, contextTransform, () => fixedOverheadTokens)(event.messages)
|
|
27684
27283
|
};
|
|
@@ -27912,6 +27511,7 @@ var init_pi_session = __esm(() => {
|
|
|
27912
27511
|
init_intent_tracing();
|
|
27913
27512
|
init_mcp_client();
|
|
27914
27513
|
init_request_limits();
|
|
27514
|
+
init_token_count();
|
|
27915
27515
|
init_welcome_header();
|
|
27916
27516
|
PI_BUILTIN_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls"];
|
|
27917
27517
|
});
|
|
@@ -29100,7 +28700,7 @@ var init_automation_tool = __esm(() => {
|
|
|
29100
28700
|
});
|
|
29101
28701
|
|
|
29102
28702
|
// src/agent/citation-links.ts
|
|
29103
|
-
import { basename as
|
|
28703
|
+
import { basename as basename12, isAbsolute as isAbsolute12 } from "node:path";
|
|
29104
28704
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
29105
28705
|
function openableTarget(source) {
|
|
29106
28706
|
if (/^https?:\/\//iu.test(source)) {
|
|
@@ -29118,7 +28718,7 @@ function linkCitations(markdown, sourceOf, isFile) {
|
|
|
29118
28718
|
for (const marker of answerMarkers(markdown, isFile)) {
|
|
29119
28719
|
if (marker.kind === "number")
|
|
29120
28720
|
continue;
|
|
29121
|
-
const labels = marker.kind === "file" ? [{ label:
|
|
28721
|
+
const labels = marker.kind === "file" ? [{ label: basename12(marker.path), source: marker.path }] : marker.ids.map((id) => ({ label: id, source: sourceOf(id) }));
|
|
29122
28722
|
let linked = false;
|
|
29123
28723
|
const parts = labels.map(({ label, source }) => {
|
|
29124
28724
|
const target = source === undefined ? undefined : openableTarget(source);
|
|
@@ -30357,7 +29957,7 @@ class DazziJevBackend {
|
|
|
30357
29957
|
this.apiKey = apiKey;
|
|
30358
29958
|
this.baseUrl = options.baseUrl ?? resolveBaseUrl(env);
|
|
30359
29959
|
this.defaultModel = options.defaultModel ?? DAZZI_DEFAULT_JEV_MODEL;
|
|
30360
|
-
this.timeoutMs = options.timeoutMs ??
|
|
29960
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS11;
|
|
30361
29961
|
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
30362
29962
|
this.fetchImpl = options.fetchImpl;
|
|
30363
29963
|
}
|
|
@@ -30544,7 +30144,7 @@ async function extractErrorMessage(response) {
|
|
|
30544
30144
|
function sleep6(ms) {
|
|
30545
30145
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
30546
30146
|
}
|
|
30547
|
-
var JEV_PATH, DAZZI_DEFAULT_JEV_MODEL = "jev-1.13",
|
|
30147
|
+
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;
|
|
30548
30148
|
var init_jev_backend = __esm(() => {
|
|
30549
30149
|
init_config();
|
|
30550
30150
|
init_credential();
|
|
@@ -32028,7 +31628,7 @@ var init_page_loader = __esm(() => {
|
|
|
32028
31628
|
});
|
|
32029
31629
|
|
|
32030
31630
|
// src/web/fetch/url-target.ts
|
|
32031
|
-
import { extname as
|
|
31631
|
+
import { extname as extname7 } from "node:path";
|
|
32032
31632
|
function repairCollapsedScheme(value) {
|
|
32033
31633
|
const m = value.match(/^(https?):\/(?!\/)/i);
|
|
32034
31634
|
return m ? `${m[1]}://${value.slice(m[0].length)}` : value;
|
|
@@ -32047,7 +31647,7 @@ function getFilenameExtensionHint(filename) {
|
|
|
32047
31647
|
const lower = filename.toLowerCase();
|
|
32048
31648
|
if (lower.endsWith(".tar.gz"))
|
|
32049
31649
|
return ".tar.gz";
|
|
32050
|
-
return
|
|
31650
|
+
return extname7(filename).toLowerCase();
|
|
32051
31651
|
}
|
|
32052
31652
|
function getExtensionHint(url, contentDisposition) {
|
|
32053
31653
|
if (contentDisposition) {
|
|
@@ -32224,7 +31824,7 @@ var init_convert2 = __esm(() => {
|
|
|
32224
31824
|
});
|
|
32225
31825
|
|
|
32226
31826
|
// src/web/fetch/feeds.ts
|
|
32227
|
-
import { extname as
|
|
31827
|
+
import { extname as extname8 } from "node:path";
|
|
32228
31828
|
import { XMLParser as XMLParser3 } from "fast-xml-parser";
|
|
32229
31829
|
function getHtmlAttribute(tag, attribute) {
|
|
32230
31830
|
const pattern = new RegExp(`\\b${attribute}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'=<>]+))`, "i");
|
|
@@ -32287,7 +31887,7 @@ function extractDocumentLinks(html, baseUrl) {
|
|
|
32287
31887
|
const href = getHtmlAttribute(tag, "href");
|
|
32288
31888
|
if (!href)
|
|
32289
31889
|
continue;
|
|
32290
|
-
const ext =
|
|
31890
|
+
const ext = extname8(href).toLowerCase();
|
|
32291
31891
|
if (!CONVERTIBLE_EXTENSIONS2.has(ext))
|
|
32292
31892
|
continue;
|
|
32293
31893
|
const resolved = href.startsWith("http") ? href : new URL(href, baseUrl).href;
|
|
@@ -33955,7 +33555,7 @@ var init_web_search_tool = __esm(() => {
|
|
|
33955
33555
|
// src/agent/agent.ts
|
|
33956
33556
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
33957
33557
|
import { existsSync as existsSync34, watch as fsWatch, mkdirSync as mkdirSync25, realpathSync as realpathSync7, statSync as statSync9, writeFileSync as writeFileSync18 } from "node:fs";
|
|
33958
|
-
import { basename as
|
|
33558
|
+
import { basename as basename13, dirname as dirname26, join as join52, resolve as resolve18 } from "node:path";
|
|
33959
33559
|
import { clampThinkingLevel } from "@earendil-works/pi-ai/compat";
|
|
33960
33560
|
import { getAgentDir as getAgentDir5, keyText } from "@earendil-works/pi-coding-agent";
|
|
33961
33561
|
function positiveLimit(value, fallback, path) {
|
|
@@ -36878,7 +36478,7 @@ function toMinSyncReasonDiagnostic(reason) {
|
|
|
36878
36478
|
function pinExcludedPath(path) {
|
|
36879
36479
|
const resolvedPath = resolve18(path);
|
|
36880
36480
|
try {
|
|
36881
|
-
return join52(realpathSync7(dirname26(resolvedPath)),
|
|
36481
|
+
return join52(realpathSync7(dirname26(resolvedPath)), basename13(resolvedPath));
|
|
36882
36482
|
} catch {
|
|
36883
36483
|
return resolvedPath;
|
|
36884
36484
|
}
|
|
@@ -37765,7 +37365,7 @@ import { z as z4 } from "zod";
|
|
|
37765
37365
|
// src/filesystem/name-search.ts
|
|
37766
37366
|
import { realpathSync as realpathSync8 } from "node:fs";
|
|
37767
37367
|
import { lstat, readdir as readdir3 } from "node:fs/promises";
|
|
37768
|
-
import { basename as
|
|
37368
|
+
import { basename as basename14, dirname as dirname27, isAbsolute as isAbsolute13, join as join53, relative as relative8, resolve as resolve19, sep as sep10 } from "node:path";
|
|
37769
37369
|
var SKIP_DIR_NAMES2 = {
|
|
37770
37370
|
".git": true,
|
|
37771
37371
|
".autorag": true,
|
|
@@ -37799,7 +37399,7 @@ function isContained(childReal, parentReal) {
|
|
|
37799
37399
|
function pinExcludedPath2(path) {
|
|
37800
37400
|
const resolvedPath = resolve19(path);
|
|
37801
37401
|
try {
|
|
37802
|
-
return join53(realpathSync8(dirname27(resolvedPath)),
|
|
37402
|
+
return join53(realpathSync8(dirname27(resolvedPath)), basename14(resolvedPath));
|
|
37803
37403
|
} catch {
|
|
37804
37404
|
return resolvedPath;
|
|
37805
37405
|
}
|