@stackfactor/agent-utils 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/langChain.d.ts +8 -0
- package/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +3 -2
- package/dist/cjs/referenceContext.d.ts +62 -15
- package/dist/cjs/referenceContext.d.ts.map +1 -1
- package/dist/cjs/referenceContext.js +134 -34
- package/dist/cjs/serve.d.ts.map +1 -1
- package/dist/cjs/serve.js +7 -0
- package/dist/cjs/stackfactorKnowledge.d.ts +9 -4
- package/dist/cjs/stackfactorKnowledge.d.ts.map +1 -1
- package/dist/cjs/stackfactorKnowledge.js +30 -6
- package/dist/cjs/tavily.d.ts +8 -0
- package/dist/cjs/tavily.d.ts.map +1 -1
- package/dist/cjs/tavily.js +73 -4
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/langChain.d.ts +8 -0
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +3 -2
- package/dist/esm/referenceContext.d.ts +62 -15
- package/dist/esm/referenceContext.d.ts.map +1 -1
- package/dist/esm/referenceContext.js +132 -33
- package/dist/esm/serve.d.ts.map +1 -1
- package/dist/esm/serve.js +7 -0
- package/dist/esm/stackfactorKnowledge.d.ts +9 -4
- package/dist/esm/stackfactorKnowledge.d.ts.map +1 -1
- package/dist/esm/stackfactorKnowledge.js +30 -6
- package/dist/esm/tavily.d.ts +8 -0
- package/dist/esm/tavily.d.ts.map +1 -1
- package/dist/esm/tavily.js +73 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -392,6 +392,7 @@ const result = await langChain.runPromptWithModel(
|
|
|
392
392
|
| `excludeDomains` | — | Exclude these domains from `web_search` |
|
|
393
393
|
| `crawlLimit` | `10` | Maximum pages one `web_crawl` or `web_map` call may return |
|
|
394
394
|
| `format` | `"markdown"` | `"markdown"` preserves table and heading structure at fewer tokens than the prose equivalent |
|
|
395
|
+
| `allowedUrls` | — | The only URLs `web_extract` may read; any other gets an error line in the tool result and is never sent to Tavily |
|
|
395
396
|
|
|
396
397
|
### Context management
|
|
397
398
|
|
|
@@ -416,6 +417,7 @@ A model that cannot tell it received half a regulation will reason over the half
|
|
|
416
417
|
- Works with every supported provider.
|
|
417
418
|
- Credits come from each response's own `usage` block rather than an estimate. They are reported to the platform as `credits` of the model `tavily` (see [Usage](#usage)) and counted on `usageTracker.tokens.tavilyCredits`.
|
|
418
419
|
- URLs are collected on `usageTracker.webSearchSources`, deduplicated across the whole run — Tavily's terms require citing the original sources when its content is shown to end users.
|
|
420
|
+
- Every URL `web_extract` asked Tavily for is on `usageTracker.attemptedUrls`, each once, whether Tavily could read it or not; a URL `allowedUrls` refused was never asked for and is not there. `webSearchSources` holds what Tavily answered, under the address it answered with; `attemptedUrls` is what the run tried to read, so a caller can check a model's claim that it read a page.
|
|
419
421
|
- Per-URL failures are surfaced in the tool result instead of being dropped, so a fetch failure is not mistaken for an absence of content.
|
|
420
422
|
- Tool calls honour the caller's abort signal, so a cancelled run stops paying for in-flight crawls.
|
|
421
423
|
|
|
@@ -436,6 +438,28 @@ const kept = references.filter((r) => !r.url || live.has(r.url));
|
|
|
436
438
|
|
|
437
439
|
---
|
|
438
440
|
|
|
441
|
+
## Reading references (`referenceContext`)
|
|
442
|
+
|
|
443
|
+
An agent reading a skill's (or a microskill's, a question's) references gathers what they point at once, with `referenceContext.gatherReferenceContext({ references, queries, search, token, topK?, maxPassages?, maxPages? })`:
|
|
444
|
+
|
|
445
|
+
- **pages**: WEB and PUBLICATION references with an http(s) url, each `{ id: "r<N>", title, url }`, opened by the model through Tavily `extract`. All of them by default; `maxPages` keeps the first N in reference order.
|
|
446
|
+
- **passages**: the passages of the knowledge base documents STACKFACTOR references cite, searched under the run's token (client-api `knowledgeBaseAgent.search`). A passage names the references citing its chunk (`knowledgeBase.chunkId`); when none does, every reference citing its document. The best-ranked 40 are kept (`maxPassages`).
|
|
447
|
+
|
|
448
|
+
**A cited knowledge base that cannot be read stops the run.** With no token, or when the person may not open a cited knowledge base (401, 403, 404) or its search fails, it throws `KnowledgeAccessError` (exported from the package and from `referenceContext`). A search that fails for any reason other than access is tried once more, 200 ms later, before it counts as failed; a refusal is not asked again.
|
|
449
|
+
|
|
450
|
+
| Field | Value |
|
|
451
|
+
| ----------- | -------------------------------------------------------------------------------------------- |
|
|
452
|
+
| `code` | `403` when every skipped knowledge base refused the person (or there was no token), else `502` |
|
|
453
|
+
| `documents` | The titles of the STACKFACTOR references citing those knowledge bases, each once |
|
|
454
|
+
| `skipped` | The knowledge bases that could not be searched, and why |
|
|
455
|
+
| `message` | `The knowledge base documents this content cites could not be read with your access: "A", "B".` (502: `…could not be read: the knowledge base search failed for "A".`) |
|
|
456
|
+
|
|
457
|
+
The agent answers with `code` and `message`, so the person sees which documents could not be read. An agent that does not catch it answers the same: `serve` and `runOnce` turn an uncaught `KnowledgeAccessError` (known by its `name`, so a second copy of this package counts too) into an error with its own `code` and `message`, not a 500. A search that works and finds nothing is not an error: the run gets no passages and the `none` guidance. Grounding from skill coverage (`stackfactorKnowledge.retrievePassages`) still skips a knowledge base it cannot read.
|
|
458
|
+
|
|
459
|
+
`referenceContext.toolsFor(context)` gives the run its tools: `{ tavily: { tools: ["extract"], allowedUrls } }` when there are pages (their urls), else `{}`. Spread it after `tavily: undefined`, so `web_extract` reads only the referenced pages.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
439
463
|
## Supported Models
|
|
440
464
|
|
|
441
465
|
### Text / Chat
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { callAgent, checkAgent } from "./client.js";
|
|
|
7
7
|
import * as runtimeContext from "./runtimeContext.js";
|
|
8
8
|
import { recordUsage, USAGE_UNITS } from "./usage.js";
|
|
9
9
|
import stackfactorKnowledge from "./stackfactorKnowledge.js";
|
|
10
|
-
import referenceContext from "./referenceContext.js";
|
|
10
|
+
import referenceContext, { KnowledgeAccessError } from "./referenceContext.js";
|
|
11
11
|
import { checkUrlsReachable } from "./tavily.js";
|
|
12
12
|
export { constants };
|
|
13
13
|
export { errorHandling, AppError };
|
|
@@ -24,7 +24,7 @@ export type { AgentExecuteRequest, CallAgentOptions, CheckAgentOptions, AgentHea
|
|
|
24
24
|
export { runtimeContext };
|
|
25
25
|
export { recordUsage, USAGE_UNITS };
|
|
26
26
|
export type { UsageEntry, UsageUnit } from "./usage.js";
|
|
27
|
-
export { stackfactorKnowledge, referenceContext };
|
|
27
|
+
export { stackfactorKnowledge, referenceContext, KnowledgeAccessError };
|
|
28
28
|
export type { GroundingPassage, KnowledgeChunk, KnowledgeSearch, KnowledgeSource, SkippedSource, StackFactorReference, } from "./stackfactorKnowledge.js";
|
|
29
29
|
export type { ReferenceContext, ReferencePage, ReferencePassage, SourceGuidance, StoredReference, } from "./referenceContext.js";
|
|
30
30
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,gBAAgB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,gBAAgB,EAAE,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,CAAC;AAE7D,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAEpC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;AAExE,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,eAAe,EACf,aAAa,EACb,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.referenceContext = exports.stackfactorKnowledge = exports.USAGE_UNITS = exports.recordUsage = exports.runtimeContext = exports.checkAgent = exports.callAgent = exports.EXECUTION_ENV = exports.isRunOnceExecution = exports.runOnce = exports.serve = exports.logger = exports.checkUrlsReachable = exports.langChain = exports.AppError = exports.errorHandling = exports.constants = void 0;
|
|
39
|
+
exports.KnowledgeAccessError = exports.referenceContext = exports.stackfactorKnowledge = exports.USAGE_UNITS = exports.recordUsage = exports.runtimeContext = exports.checkAgent = exports.callAgent = exports.EXECUTION_ENV = exports.isRunOnceExecution = exports.runOnce = exports.serve = exports.logger = exports.checkUrlsReachable = exports.langChain = exports.AppError = exports.errorHandling = exports.constants = void 0;
|
|
40
40
|
const const_js_1 = __importDefault(require("./const.js"));
|
|
41
41
|
exports.constants = const_js_1.default;
|
|
42
42
|
const errorHandling_js_1 = __importStar(require("./errorHandling.js"));
|
|
@@ -61,7 +61,8 @@ Object.defineProperty(exports, "recordUsage", { enumerable: true, get: function
|
|
|
61
61
|
Object.defineProperty(exports, "USAGE_UNITS", { enumerable: true, get: function () { return usage_js_1.USAGE_UNITS; } });
|
|
62
62
|
const stackfactorKnowledge_js_1 = __importDefault(require("./stackfactorKnowledge.js"));
|
|
63
63
|
exports.stackfactorKnowledge = stackfactorKnowledge_js_1.default;
|
|
64
|
-
const referenceContext_js_1 =
|
|
64
|
+
const referenceContext_js_1 = __importStar(require("./referenceContext.js"));
|
|
65
65
|
exports.referenceContext = referenceContext_js_1.default;
|
|
66
|
+
Object.defineProperty(exports, "KnowledgeAccessError", { enumerable: true, get: function () { return referenceContext_js_1.KnowledgeAccessError; } });
|
|
66
67
|
const tavily_js_1 = require("./tavily.js");
|
|
67
68
|
Object.defineProperty(exports, "checkUrlsReachable", { enumerable: true, get: function () { return tavily_js_1.checkUrlsReachable; } });
|
package/dist/cjs/langChain.d.ts
CHANGED
|
@@ -31,6 +31,14 @@ export type UsageTracker = {
|
|
|
31
31
|
url: string;
|
|
32
32
|
title?: string;
|
|
33
33
|
}[];
|
|
34
|
+
/**
|
|
35
|
+
* Every URL `web_extract` asked Tavily for, each once, in the order first
|
|
36
|
+
* asked, whether Tavily could read it or not (a failed URL, a failed call).
|
|
37
|
+
* A URL refused by `allowedUrls` was never asked for and is not here. What
|
|
38
|
+
* Tavily answered is `webSearchSources`, under the address it answered with
|
|
39
|
+
* (after a redirect); this is what the run actually tried to read.
|
|
40
|
+
*/
|
|
41
|
+
attemptedUrls?: string[];
|
|
34
42
|
};
|
|
35
43
|
/**
|
|
36
44
|
* Instantiates and returns the appropriate LangChain chat model based on the model
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AAoGA,KAAK,UAAU,GAAG;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IAKtB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AAoGA,KAAK,UAAU,GAAG;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IAKtB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrD;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA0iBF;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,eAAO,MAAM,WAAW,GACtB,WAAW,MAAM,EACjB,QAAQ,GAAG,EACX,SAAQ,GAAU,KACjB,GAwHF,CAAC;;8CAkb+C,OAAO,UAAU,GAAG,KAAG,OAAO;oCAWxC,GAAG,KAAG,OAAO;0CAgBtC,MAAM,cACN,GAAG,SACR,GAAG,KACT,MAAM;2CA0CqC,GAAG,UAAU,GAAG,KAAG,MAAM;sCA5xC9B,MAAM,KAAG,OAAO;0CAuGZ,GAAG,KAAG,IAAI;wBA8sB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,iBACG,YAAY,GAAG,IAAI,KAChC,GAAG;sBAsCG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,aACvB,MAAM,KACf,OAAO,CAAC,GAAG,CAAC;oCAihBF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDA2sBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDAmTF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CAz6C8B,GAAG,KAAG,MAAM;uCAxyB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,YACP,GAAG,WACJ,GAAG,YACF,QAAQ,GAAG,QAAQ,KAC5B,IAAI;kCA5CI,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,SACV,UAAU,GAAG,IAAI,YACd,GAAG,KACZ,IAAI;+CA0FI,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,YACZ,GAAG,KACZ,IAAI;uCAoBI,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,WACR,MAAM,YACL,GAAG,KACZ,IAAI;mCAyuBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AA48CT,wBAkBE"}
|
package/dist/cjs/langChain.js
CHANGED
|
@@ -1210,8 +1210,9 @@ const parseAgenticJsonResponse = (rawContent, schema) => {
|
|
|
1210
1210
|
*
|
|
1211
1211
|
* Setting `config.tavily` adds the Tavily web tools (`web_search`, `web_extract`, and
|
|
1212
1212
|
* optionally `web_map` / `web_crawl`). They execute in this process, so they require
|
|
1213
|
-
* `config.agentic` to be `true`; the credits spent
|
|
1214
|
-
* on `usageTracker`.
|
|
1213
|
+
* `config.agentic` to be `true`; the credits spent, the URLs returned and the URLs
|
|
1214
|
+
* `web_extract` asked for are recorded on `usageTracker`. `tavily.allowedUrls` keeps
|
|
1215
|
+
* `web_extract` to those URLs.
|
|
1215
1216
|
* @param modelName - The model identifier, e.g. `"gpt-4o"`, `"claude-3-5-sonnet"`,
|
|
1216
1217
|
* `"gemini-1.5-pro"`
|
|
1217
1218
|
* @param config - Configuration object with API keys, `temperature`, optional `agentic`
|
|
@@ -10,7 +10,10 @@ export interface ReferencePage {
|
|
|
10
10
|
}
|
|
11
11
|
/** A passage of a document that references cite. */
|
|
12
12
|
export interface ReferencePassage {
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The short ids of the STACKFACTOR references that cite this passage's chunk
|
|
15
|
+
* (`knowledgeBase.chunkId`); when none does, of every one citing its document.
|
|
16
|
+
*/
|
|
14
17
|
references: string[];
|
|
15
18
|
document: string | null;
|
|
16
19
|
section: string | null;
|
|
@@ -23,21 +26,56 @@ export interface ReferencePassage {
|
|
|
23
26
|
export interface ReferenceContext {
|
|
24
27
|
pages: ReferencePage[];
|
|
25
28
|
passages: ReferencePassage[];
|
|
29
|
+
/**
|
|
30
|
+
* Always empty from `gatherReferenceContext`: a cited knowledge base that
|
|
31
|
+
* cannot be read throws KnowledgeAccessError, which carries the skips.
|
|
32
|
+
*/
|
|
26
33
|
skipped: SkippedSource[];
|
|
27
|
-
/** True when the references cite at least one knowledge base document,
|
|
34
|
+
/** True when the references cite at least one knowledge base document (all of them readable, or it would have thrown). */
|
|
28
35
|
citesKnowledge: boolean;
|
|
29
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The knowledge base documents a run's references cite could not be read: the
|
|
39
|
+
* run has no token, the person may not open a cited knowledge base (401, 403,
|
|
40
|
+
* 404), or its search failed. The agent answers with it — `code` and `message`
|
|
41
|
+
* are what the person sees — and generates nothing.
|
|
42
|
+
*/
|
|
43
|
+
export declare class KnowledgeAccessError extends Error {
|
|
44
|
+
/** 403 when every skipped knowledge base refused the person (or there was no token), else 502. */
|
|
45
|
+
readonly code: 403 | 502;
|
|
46
|
+
/** The knowledge bases that could not be searched, and why; empty when there was no token. */
|
|
47
|
+
readonly skipped: SkippedSource[];
|
|
48
|
+
/** The titles of the STACKFACTOR references citing those knowledge bases, each once. */
|
|
49
|
+
readonly documents: string[];
|
|
50
|
+
/**
|
|
51
|
+
* @param details `skipped` (from the search) and `documents` (titles); the
|
|
52
|
+
* code and the message follow from them
|
|
53
|
+
*/
|
|
54
|
+
constructor(details?: {
|
|
55
|
+
skipped?: SkippedSource[];
|
|
56
|
+
documents?: unknown[];
|
|
57
|
+
});
|
|
58
|
+
}
|
|
30
59
|
/**
|
|
31
60
|
* What a list of references points at: its pages, and the passages of the
|
|
32
61
|
* documents its STACKFACTOR references cite. One search per knowledge base per
|
|
33
|
-
* query (per batch of 500 documents), however many references there are.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
62
|
+
* query (per batch of 500 documents), however many references there are.
|
|
63
|
+
*
|
|
64
|
+
* References that cite a knowledge base the run cannot read stop it: with no
|
|
65
|
+
* token, or when any cited knowledge base is skipped (refused or failed), it
|
|
66
|
+
* throws a KnowledgeAccessError naming the documents. A search that works and
|
|
67
|
+
* finds nothing is not an error. With no knowledge cited, no token is needed.
|
|
68
|
+
*
|
|
69
|
+
* A passage is attributed to the references citing its chunk, else to every
|
|
70
|
+
* reference citing its document. The best-ranked `maxPassages` are kept, and
|
|
71
|
+
* the first `maxPages` pages in reference order.
|
|
36
72
|
* @param options `references` (a skill's, a microskill's…), `queries` to
|
|
37
73
|
* search the cited documents with, `search` (client-api
|
|
38
74
|
* `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
|
|
39
|
-
* search (default 5)
|
|
40
|
-
* @returns `{ pages, passages, skipped, citesKnowledge }`
|
|
75
|
+
* search (default 5), `maxPassages` (default 40), `maxPages` (default: all)
|
|
76
|
+
* @returns `{ pages, passages, skipped, citesKnowledge }`; `skipped` is always
|
|
77
|
+
* empty, since a skip throws
|
|
78
|
+
* @throws KnowledgeAccessError When cited knowledge bases cannot be read
|
|
41
79
|
*/
|
|
42
80
|
export declare const gatherReferenceContext: (options: {
|
|
43
81
|
references: unknown;
|
|
@@ -45,6 +83,8 @@ export declare const gatherReferenceContext: (options: {
|
|
|
45
83
|
search: KnowledgeSearch;
|
|
46
84
|
token: string | null | undefined;
|
|
47
85
|
topK?: number;
|
|
86
|
+
maxPassages?: number;
|
|
87
|
+
maxPages?: number;
|
|
48
88
|
}) => Promise<ReferenceContext>;
|
|
49
89
|
/**
|
|
50
90
|
* The passages as a prompt shows them: who cites each, where it came from, and
|
|
@@ -92,23 +132,26 @@ export interface StoredReference {
|
|
|
92
132
|
}
|
|
93
133
|
/**
|
|
94
134
|
* The tools a run is given. Never `search`, `map` or `crawl`: a run reads what
|
|
95
|
-
* its references point at and discovers nothing. `extract` only,
|
|
96
|
-
* there are pages to open
|
|
135
|
+
* its references point at and discovers nothing. `extract` only, only when
|
|
136
|
+
* there are pages to open, and kept to those pages: any other url the model
|
|
137
|
+
* asks for is refused (`allowedUrls`).
|
|
97
138
|
* @param context From `gatherReferenceContext`
|
|
98
|
-
* @returns `{ tavily: { tools: ["extract"] } }` with pages, else
|
|
99
|
-
* pages it returns `{}`, so a caller spreading it over a config
|
|
100
|
-
* has a `tavily` key keeps that key (and `tavily: true` means
|
|
101
|
-
* extract): callers must not carry a base `tavily` key.
|
|
139
|
+
* @returns `{ tavily: { tools: ["extract"], allowedUrls } }` with pages, else
|
|
140
|
+
* `{}`. With no pages it returns `{}`, so a caller spreading it over a config
|
|
141
|
+
* that already has a `tavily` key keeps that key (and `tavily: true` means
|
|
142
|
+
* search plus extract): callers must not carry a base `tavily` key.
|
|
102
143
|
*/
|
|
103
144
|
export declare const toolsFor: (context: ReferenceContext) => {
|
|
104
145
|
tavily?: {
|
|
105
146
|
tools: string[];
|
|
147
|
+
allowedUrls: string[];
|
|
106
148
|
};
|
|
107
149
|
};
|
|
108
150
|
/**
|
|
109
151
|
* The stage prompt followed by the guidance for each kind of source the run
|
|
110
|
-
* has: pages, then passages; when it has neither
|
|
111
|
-
* guidance adds
|
|
152
|
+
* has: pages, then passages; when it has neither (knowledge cited and readable
|
|
153
|
+
* but no passage found included), the `none` guidance. An empty guidance adds
|
|
154
|
+
* nothing.
|
|
112
155
|
* @param stagePrompt The stage's own prompt
|
|
113
156
|
* @param context From `gatherReferenceContext`
|
|
114
157
|
* @param guidance From `sourceGuidanceFrom`
|
|
@@ -159,6 +202,7 @@ export declare const citedReferences: (ids: unknown, supplied: unknown, origin?:
|
|
|
159
202
|
*/
|
|
160
203
|
export declare const sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
|
|
161
204
|
declare const _default: {
|
|
205
|
+
KnowledgeAccessError: typeof KnowledgeAccessError;
|
|
162
206
|
REFERENCE_PASSAGES_KEY: string;
|
|
163
207
|
citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
|
|
164
208
|
composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
|
|
@@ -168,6 +212,8 @@ declare const _default: {
|
|
|
168
212
|
search: KnowledgeSearch;
|
|
169
213
|
token: string | null | undefined;
|
|
170
214
|
topK?: number;
|
|
215
|
+
maxPassages?: number;
|
|
216
|
+
maxPages?: number;
|
|
171
217
|
}) => Promise<ReferenceContext>;
|
|
172
218
|
referenceForModel: <T extends {
|
|
173
219
|
kind?: string;
|
|
@@ -184,6 +230,7 @@ declare const _default: {
|
|
|
184
230
|
toolsFor: (context: ReferenceContext) => {
|
|
185
231
|
tavily?: {
|
|
186
232
|
tools: string[];
|
|
233
|
+
allowedUrls: string[];
|
|
187
234
|
};
|
|
188
235
|
};
|
|
189
236
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"referenceContext.d.ts","sourceRoot":"","sources":["../../src/referenceContext.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"referenceContext.d.ts","sourceRoot":"","sources":["../../src/referenceContext.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,eAAe,EACf,aAAa,EAId,MAAM,2BAA2B,CAAC;AAQnC,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAEhE,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B;;;OAGG;IACH,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,0HAA0H;IAC1H,cAAc,EAAE,OAAO,CAAC;CACzB;AAID;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;IAClC,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAE7B;;;OAGG;gBACS,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KAAO;CAgB/E;AAsFD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,sBAAsB,GAAU,SAAS;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,gBAAgB,CA2C3B,CAAC;AAwBF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GACrC,SAAS,gBAAgB,KACxB;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAMrF,CAAC;AAEN,qFAAqF;AACrF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iFAAiF;AACjF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7F,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;CACjH;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,GAAI,SAAS,gBAAgB,KAAG;IAAE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAA;CAGlG,CAAC;AAET;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,aAAa,MAAM,EACnB,SAAS,gBAAgB,EACzB,UAAU,cAAc,KACvB,MAMF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,WAAW,CAAC,KAAG,CAY7E,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,YAAY,OAAO,KAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQrF,CAAC;AAmBF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,GAAG,EAAE,SAAQ,MAAuB,KAAG,eAoBnF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAAI,KAAK,OAAO,EAAE,UAAU,OAAO,EAAE,SAAS,MAAM,KAAG,eAAe,EAYjG,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,cAInE,CAAC;;;;2BAvBkC,OAAO,YAAY,OAAO,WAAW,MAAM,KAAG,eAAe,EAAE;6CAzGrF,MAAM,WACV,gBAAgB,YACf,cAAc,KACvB,MAAM;sCA7I6C;QACpD,UAAU,EAAE,OAAO,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,MAAM,EAAE,eAAe,CAAC;QACxB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,KAAG,OAAO,CAAC,gBAAgB,CAAC;wBAqJK,CAAC,SAAS;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,aAAa,CAAC,KAAG,CAAC;0CA3EpE,gBAAgB,KACxB;QAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;qCA+F7C,OAAO,KAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;iCAoF5C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,cAAc;mCAjDtC,GAAG,WAAU,MAAM,KAAoB,eAAe;wBA3FjE,gBAAgB,KAAG;QAAE,MAAM,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAAC,WAAW,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE;;AAkJ5G,wBAYE"}
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.sourceGuidanceFrom = exports.citedReferences = exports.toStoredReference = exports.referencesForModel = exports.referenceForModel = exports.composeSourceInstructions = exports.toolsFor = exports.referencePassagesForPrompt = exports.gatherReferenceContext = exports.REFERENCE_PASSAGES_KEY = void 0;
|
|
6
|
+
exports.sourceGuidanceFrom = exports.citedReferences = exports.toStoredReference = exports.referencesForModel = exports.referenceForModel = exports.composeSourceInstructions = exports.toolsFor = exports.referencePassagesForPrompt = exports.gatherReferenceContext = exports.KnowledgeAccessError = exports.REFERENCE_PASSAGES_KEY = void 0;
|
|
7
7
|
//
|
|
8
8
|
// Reference context — gathering what a list of references points at
|
|
9
9
|
//
|
|
@@ -17,6 +17,12 @@ exports.sourceGuidanceFrom = exports.citedReferences = exports.toStoredReference
|
|
|
17
17
|
// references cite, searched under the run's own token, so a run reads only
|
|
18
18
|
// what the person it acts for may open.
|
|
19
19
|
//
|
|
20
|
+
// A cited knowledge base that cannot be read stops the run (Candin,
|
|
21
|
+
// 2026-10-13): with no token, a refusal or a failed search, the gathering
|
|
22
|
+
// throws a KnowledgeAccessError naming the documents, and the agent answers
|
|
23
|
+
// with it rather than writing as if the content cited nothing. A search that
|
|
24
|
+
// works and finds nothing is not an error.
|
|
25
|
+
//
|
|
20
26
|
// A reference is cited by its short id `r<N>`, N being its index in the
|
|
21
27
|
// supplied list, whatever its kind.
|
|
22
28
|
//
|
|
@@ -24,9 +30,44 @@ const logger_js_1 = __importDefault(require("./logger.js"));
|
|
|
24
30
|
const stackfactorKnowledge_js_1 = require("./stackfactorKnowledge.js");
|
|
25
31
|
/** How many passages one search asks for when the caller does not say. */
|
|
26
32
|
const DEFAULT_REFERENCE_TOP_K = 5;
|
|
33
|
+
/** How many passages a gathering keeps when the caller does not say: the best-ranked. */
|
|
34
|
+
const DEFAULT_MAX_PASSAGES = 40;
|
|
27
35
|
/** The prompt key the passages are handed to the model under. */
|
|
28
36
|
exports.REFERENCE_PASSAGES_KEY = "Knowledge Base Passages";
|
|
29
37
|
const text = (value) => (typeof value === "string" ? value.trim() : "");
|
|
38
|
+
/**
|
|
39
|
+
* The knowledge base documents a run's references cite could not be read: the
|
|
40
|
+
* run has no token, the person may not open a cited knowledge base (401, 403,
|
|
41
|
+
* 404), or its search failed. The agent answers with it — `code` and `message`
|
|
42
|
+
* are what the person sees — and generates nothing.
|
|
43
|
+
*/
|
|
44
|
+
class KnowledgeAccessError extends Error {
|
|
45
|
+
/** 403 when every skipped knowledge base refused the person (or there was no token), else 502. */
|
|
46
|
+
code;
|
|
47
|
+
/** The knowledge bases that could not be searched, and why; empty when there was no token. */
|
|
48
|
+
skipped;
|
|
49
|
+
/** The titles of the STACKFACTOR references citing those knowledge bases, each once. */
|
|
50
|
+
documents;
|
|
51
|
+
/**
|
|
52
|
+
* @param details `skipped` (from the search) and `documents` (titles); the
|
|
53
|
+
* code and the message follow from them
|
|
54
|
+
*/
|
|
55
|
+
constructor(details = {}) {
|
|
56
|
+
const skipped = Array.isArray(details.skipped) ? details.skipped : [];
|
|
57
|
+
const documents = [...new Set((Array.isArray(details.documents) ? details.documents : []).map(text).filter(Boolean))];
|
|
58
|
+
const code = skipped.every((source) => source?.noAccess) ? 403 : 502;
|
|
59
|
+
const titles = documents.map((title) => `"${title}"`).join(", ");
|
|
60
|
+
super(code === 403
|
|
61
|
+
? `The knowledge base documents this content cites could not be read with your access${titles ? `: ${titles}` : ""}.`
|
|
62
|
+
: `The knowledge base documents this content cites could not be read: the knowledge base search failed${titles ? ` for ${titles}` : ""}.`);
|
|
63
|
+
this.name = "KnowledgeAccessError";
|
|
64
|
+
this.code = code;
|
|
65
|
+
this.skipped = skipped;
|
|
66
|
+
this.documents = documents;
|
|
67
|
+
Object.setPrototypeOf(this, KnowledgeAccessError.prototype);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.KnowledgeAccessError = KnowledgeAccessError;
|
|
30
71
|
const id = (value) => typeof value === "string" ? value.trim() : value != null && typeof value === "object" ? String(value) : "";
|
|
31
72
|
const shortId = (index) => `r${index}`;
|
|
32
73
|
/** The document a STACKFACTOR reference cites, or "" when it cites none. */
|
|
@@ -35,6 +76,14 @@ const documentOf = (reference) => {
|
|
|
35
76
|
return (id(reference.knowledgeBase?.documentId) ||
|
|
36
77
|
(target.elementType === stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE ? id(target.elementId) : ""));
|
|
37
78
|
};
|
|
79
|
+
/** The knowledge base a STACKFACTOR reference's document is in, or "" when it cites no document. */
|
|
80
|
+
const knowledgeBaseOf = (reference) => {
|
|
81
|
+
const target = reference.target ?? {};
|
|
82
|
+
return (id(reference.knowledgeBase?.knowledgeBaseId) ||
|
|
83
|
+
(target.elementType === stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE ? id(target.parentId) : ""));
|
|
84
|
+
};
|
|
85
|
+
/** A cap the caller passed (a whole number, 0 or more), else `fallback`. */
|
|
86
|
+
const capOf = (value, fallback) => typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
38
87
|
/** The kinds the platform retired; it reads them as PUBLICATION. */
|
|
39
88
|
const RETIRED_KINDS = new Set(["DOCUMENT", "KNOWLEDGE_BASE", "NOTE"]);
|
|
40
89
|
/** A reference's kind as the platform reads it: missing or retired is PUBLICATION. */
|
|
@@ -60,39 +109,71 @@ const pagesOf = (references) => {
|
|
|
60
109
|
});
|
|
61
110
|
return pages;
|
|
62
111
|
};
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
|
|
112
|
+
/**
|
|
113
|
+
* The short ids of the STACKFACTOR references citing each document, and of
|
|
114
|
+
* those citing each chunk (`knowledgeBase.chunkId`) of a document.
|
|
115
|
+
*/
|
|
116
|
+
const citersOf = (references) => {
|
|
117
|
+
const byDocument = new Map();
|
|
118
|
+
const byChunk = new Map();
|
|
66
119
|
references.forEach((reference, index) => {
|
|
67
120
|
if (reference?.kind !== stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.KIND)
|
|
68
121
|
return;
|
|
69
122
|
const documentId = documentOf(reference);
|
|
70
|
-
if (documentId)
|
|
71
|
-
|
|
123
|
+
if (!documentId)
|
|
124
|
+
return;
|
|
125
|
+
byDocument.set(documentId, [...(byDocument.get(documentId) ?? []), shortId(index)]);
|
|
126
|
+
const chunkId = id(reference.knowledgeBase?.chunkId);
|
|
127
|
+
if (chunkId)
|
|
128
|
+
byChunk.set(chunkId, [...(byChunk.get(chunkId) ?? []), shortId(index)]);
|
|
72
129
|
});
|
|
73
|
-
return
|
|
130
|
+
return { byChunk, byDocument };
|
|
74
131
|
};
|
|
132
|
+
/**
|
|
133
|
+
* The error for cited knowledge bases that could not be read: it names the
|
|
134
|
+
* documents of the STACKFACTOR references citing them.
|
|
135
|
+
*/
|
|
136
|
+
const accessError = (references, unread, skipped) => new KnowledgeAccessError({
|
|
137
|
+
documents: references
|
|
138
|
+
.filter((reference) => reference?.kind === stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.KIND && documentOf(reference) && unread.has(knowledgeBaseOf(reference)))
|
|
139
|
+
.map((reference) => reference.title),
|
|
140
|
+
skipped,
|
|
141
|
+
});
|
|
75
142
|
/**
|
|
76
143
|
* What a list of references points at: its pages, and the passages of the
|
|
77
144
|
* documents its STACKFACTOR references cite. One search per knowledge base per
|
|
78
|
-
* query (per batch of 500 documents), however many references there are.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
145
|
+
* query (per batch of 500 documents), however many references there are.
|
|
146
|
+
*
|
|
147
|
+
* References that cite a knowledge base the run cannot read stop it: with no
|
|
148
|
+
* token, or when any cited knowledge base is skipped (refused or failed), it
|
|
149
|
+
* throws a KnowledgeAccessError naming the documents. A search that works and
|
|
150
|
+
* finds nothing is not an error. With no knowledge cited, no token is needed.
|
|
151
|
+
*
|
|
152
|
+
* A passage is attributed to the references citing its chunk, else to every
|
|
153
|
+
* reference citing its document. The best-ranked `maxPassages` are kept, and
|
|
154
|
+
* the first `maxPages` pages in reference order.
|
|
81
155
|
* @param options `references` (a skill's, a microskill's…), `queries` to
|
|
82
156
|
* search the cited documents with, `search` (client-api
|
|
83
157
|
* `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
|
|
84
|
-
* search (default 5)
|
|
85
|
-
* @returns `{ pages, passages, skipped, citesKnowledge }`
|
|
158
|
+
* search (default 5), `maxPassages` (default 40), `maxPages` (default: all)
|
|
159
|
+
* @returns `{ pages, passages, skipped, citesKnowledge }`; `skipped` is always
|
|
160
|
+
* empty, since a skip throws
|
|
161
|
+
* @throws KnowledgeAccessError When cited knowledge bases cannot be read
|
|
86
162
|
*/
|
|
87
163
|
const gatherReferenceContext = async (options) => {
|
|
88
164
|
const references = Array.isArray(options.references) ? options.references : [];
|
|
89
165
|
const sources = (0, stackfactorKnowledge_js_1.sourcesFromReferences)(references);
|
|
90
166
|
const citesKnowledge = sources.length > 0;
|
|
91
|
-
const pages = pagesOf(references);
|
|
92
|
-
if (!
|
|
93
|
-
logContext(pages.length, 0, []
|
|
167
|
+
const pages = pagesOf(references).slice(0, capOf(options.maxPages, Infinity));
|
|
168
|
+
if (!citesKnowledge) {
|
|
169
|
+
logContext(pages.length, 0, []);
|
|
94
170
|
return { citesKnowledge, pages, passages: [], skipped: [] };
|
|
95
171
|
}
|
|
172
|
+
if (!options.token) {
|
|
173
|
+
const error = accessError(references, new Set(sources.map((source) => source.knowledgeBaseId)), []);
|
|
174
|
+
logContext(pages.length, 0, [], { error, noToken: true });
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
96
177
|
const found = await (0, stackfactorKnowledge_js_1.retrievePassages)({
|
|
97
178
|
queries: options.queries,
|
|
98
179
|
search: options.search,
|
|
@@ -100,31 +181,45 @@ const gatherReferenceContext = async (options) => {
|
|
|
100
181
|
token: options.token,
|
|
101
182
|
topK: options.topK ?? DEFAULT_REFERENCE_TOP_K,
|
|
102
183
|
});
|
|
103
|
-
|
|
184
|
+
if (found.skipped.length > 0) {
|
|
185
|
+
const unread = new Set(found.skipped.map((source) => source.knowledgeBaseId));
|
|
186
|
+
const error = accessError(references, unread, found.skipped);
|
|
187
|
+
logContext(pages.length, 0, found.skipped, { error });
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
const citers = citersOf(references);
|
|
104
191
|
const passages = found.passages
|
|
105
|
-
.filter((passage) => citers.has(passage.documentId))
|
|
192
|
+
.filter((passage) => citers.byDocument.has(passage.documentId))
|
|
193
|
+
.slice(0, capOf(options.maxPassages, DEFAULT_MAX_PASSAGES))
|
|
106
194
|
.map((passage) => ({
|
|
107
195
|
chunkId: passage.chunkId,
|
|
108
196
|
document: passage.documentName,
|
|
109
197
|
documentId: passage.documentId,
|
|
110
198
|
knowledgeBaseId: passage.knowledgeBaseId,
|
|
111
|
-
references: citers.get(passage.documentId),
|
|
199
|
+
references: citers.byChunk.get(passage.chunkId) ?? citers.byDocument.get(passage.documentId),
|
|
112
200
|
section: passage.sectionTitle,
|
|
113
201
|
text: passage.text,
|
|
114
202
|
}));
|
|
115
|
-
logContext(pages.length, passages.length,
|
|
116
|
-
return { citesKnowledge, pages, passages, skipped:
|
|
203
|
+
logContext(pages.length, passages.length, []);
|
|
204
|
+
return { citesKnowledge, pages, passages, skipped: [] };
|
|
117
205
|
};
|
|
118
206
|
exports.gatherReferenceContext = gatherReferenceContext;
|
|
119
|
-
/**
|
|
120
|
-
|
|
207
|
+
/**
|
|
208
|
+
* The one summary line of a gathering, for the logs: a warning when it was
|
|
209
|
+
* refused. Document titles stay out of the logs.
|
|
210
|
+
*/
|
|
211
|
+
const logContext = (pages, passages, skipped, refusal) => {
|
|
121
212
|
const parts = [`${pages} page${pages === 1 ? "" : "s"}`, `${passages} passage${passages === 1 ? "" : "s"}`];
|
|
122
213
|
if (skipped.length > 0) {
|
|
123
214
|
parts.push(`skipped knowledge bases: ${skipped.map((s) => `${s.knowledgeBaseId} (noAccess: ${s.noAccess})`).join(", ")}`);
|
|
124
215
|
}
|
|
125
|
-
if (noToken)
|
|
126
|
-
parts.push("no token
|
|
127
|
-
|
|
216
|
+
if (refusal?.noToken)
|
|
217
|
+
parts.push("no token");
|
|
218
|
+
if (refusal) {
|
|
219
|
+
const count = refusal.error.documents.length;
|
|
220
|
+
parts.push(`refused (${refusal.error.code}): ${count} document${count === 1 ? "" : "s"} unreadable`);
|
|
221
|
+
}
|
|
222
|
+
logger_js_1.default.log(null, refusal ? logger_js_1.default.levels.warn : logger_js_1.default.levels.info, `Reference context: ${parts.join("; ")}`);
|
|
128
223
|
};
|
|
129
224
|
/**
|
|
130
225
|
* The passages as a prompt shows them: who cites each, where it came from, and
|
|
@@ -141,20 +236,24 @@ const referencePassagesForPrompt = (context) => context.passages.map((passage) =
|
|
|
141
236
|
exports.referencePassagesForPrompt = referencePassagesForPrompt;
|
|
142
237
|
/**
|
|
143
238
|
* The tools a run is given. Never `search`, `map` or `crawl`: a run reads what
|
|
144
|
-
* its references point at and discovers nothing. `extract` only,
|
|
145
|
-
* there are pages to open
|
|
239
|
+
* its references point at and discovers nothing. `extract` only, only when
|
|
240
|
+
* there are pages to open, and kept to those pages: any other url the model
|
|
241
|
+
* asks for is refused (`allowedUrls`).
|
|
146
242
|
* @param context From `gatherReferenceContext`
|
|
147
|
-
* @returns `{ tavily: { tools: ["extract"] } }` with pages, else
|
|
148
|
-
* pages it returns `{}`, so a caller spreading it over a config
|
|
149
|
-
* has a `tavily` key keeps that key (and `tavily: true` means
|
|
150
|
-
* extract): callers must not carry a base `tavily` key.
|
|
243
|
+
* @returns `{ tavily: { tools: ["extract"], allowedUrls } }` with pages, else
|
|
244
|
+
* `{}`. With no pages it returns `{}`, so a caller spreading it over a config
|
|
245
|
+
* that already has a `tavily` key keeps that key (and `tavily: true` means
|
|
246
|
+
* search plus extract): callers must not carry a base `tavily` key.
|
|
151
247
|
*/
|
|
152
|
-
const toolsFor = (context) => context.pages.length > 0
|
|
248
|
+
const toolsFor = (context) => context.pages.length > 0
|
|
249
|
+
? { tavily: { tools: ["extract"], allowedUrls: context.pages.map((page) => page.url) } }
|
|
250
|
+
: {};
|
|
153
251
|
exports.toolsFor = toolsFor;
|
|
154
252
|
/**
|
|
155
253
|
* The stage prompt followed by the guidance for each kind of source the run
|
|
156
|
-
* has: pages, then passages; when it has neither
|
|
157
|
-
* guidance adds
|
|
254
|
+
* has: pages, then passages; when it has neither (knowledge cited and readable
|
|
255
|
+
* but no passage found included), the `none` guidance. An empty guidance adds
|
|
256
|
+
* nothing.
|
|
158
257
|
* @param stagePrompt The stage's own prompt
|
|
159
258
|
* @param context From `gatherReferenceContext`
|
|
160
259
|
* @param guidance From `sourceGuidanceFrom`
|
|
@@ -286,6 +385,7 @@ const sourceGuidanceFrom = (config) => ({
|
|
|
286
385
|
});
|
|
287
386
|
exports.sourceGuidanceFrom = sourceGuidanceFrom;
|
|
288
387
|
exports.default = {
|
|
388
|
+
KnowledgeAccessError,
|
|
289
389
|
REFERENCE_PASSAGES_KEY: exports.REFERENCE_PASSAGES_KEY,
|
|
290
390
|
citedReferences: exports.citedReferences,
|
|
291
391
|
composeSourceInstructions: exports.composeSourceInstructions,
|
package/dist/cjs/serve.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAWtC,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAwPpB;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,GAAG,KACT,OAAO,CAAC;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,uEAAuE;IACvE,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACpE,sEAAsE;IACtE,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,iEAAiE;IACjE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxD,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CACN,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,KACV,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpC;AAKD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC;AAEX,mFAAmF;AACnF,eAAO,MAAM,kBAAkB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,OACJ,CAAC;AAKvE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,GAAG,EAAE,SAAS,GAAG,KAAG,OAEhB,CAAC;AAKlD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,GAAG,EAAE,SAAS,GAAG,KAAG,OAGN,CAAC;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAWtC,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAwPpB;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,GAAG,KACT,OAAO,CAAC;IAAE,IAAI,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAEzC,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,uEAAuE;IACvE,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACpE,sEAAsE;IACtE,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,iEAAiE;IACjE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACxD,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,EAAE,CACN,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,KACV,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACpC;AAKD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;CAKhB,CAAC;AAEX,mFAAmF;AACnF,eAAO,MAAM,kBAAkB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,OACJ,CAAC;AAKvE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GAAI,OAAO,GAAG,EAAE,SAAS,GAAG,KAAG,OAEhB,CAAC;AAKlD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,GAAG,EAAE,SAAS,GAAG,KAAG,OAGN,CAAC;AAmKrD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,GAClB,MAAM,SAAS,EACf,UAAS,YAAiB,KACzB,OAAO,CAAC,IAAI,CA8Id,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,GAChB,MAAM,SAAS,EACf,UAAS,YAAiB,KACzB,IAAI,CAAC,MAyOP,CAAC"}
|
package/dist/cjs/serve.js
CHANGED
|
@@ -381,8 +381,15 @@ const safeParse = (value, fallback) => {
|
|
|
381
381
|
/**
|
|
382
382
|
* Agents that fail throw `new Error(JSON.stringify({ code, message }))`. Unwrap
|
|
383
383
|
* that back into a structured gRPC error frame; fall back to a 500 otherwise.
|
|
384
|
+
* A KnowledgeAccessError an agent did not catch (referenceContext) answers
|
|
385
|
+
* with its own code (403, 502) and message, which names the documents that
|
|
386
|
+
* could not be read. It is known by its name, so one thrown by another copy of
|
|
387
|
+
* this package in the agent's dependencies is known too.
|
|
384
388
|
*/
|
|
385
389
|
const toErrorFrame = (error) => {
|
|
390
|
+
if (error?.name === "KnowledgeAccessError" && typeof error.code === "number") {
|
|
391
|
+
return { code: error.code, message: String(error.message ?? "") };
|
|
392
|
+
}
|
|
386
393
|
try {
|
|
387
394
|
const parsed = JSON.parse(error?.message);
|
|
388
395
|
if (parsed && typeof parsed.code === "number") {
|
|
@@ -67,7 +67,10 @@ export interface SkippedSource {
|
|
|
67
67
|
knowledgeBaseId: string;
|
|
68
68
|
/** The HTTP status, when the platform answered one. */
|
|
69
69
|
status: number | null;
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* True when the platform refused the person (401, 403) or does not have the
|
|
72
|
+
* knowledge base (404); false when the search failed otherwise.
|
|
73
|
+
*/
|
|
71
74
|
noAccess: boolean;
|
|
72
75
|
message: string;
|
|
73
76
|
}
|
|
@@ -116,9 +119,11 @@ export declare const sourcesFromCoverage: (coverage: unknown) => KnowledgeSource
|
|
|
116
119
|
* model to cite. A source with documents is searched within them (in batches of
|
|
117
120
|
* SEARCH_DOCUMENT_IDS_MAX); one without, whole. A source the person may not
|
|
118
121
|
* read (401, 403, 404) is skipped: none of its passages are used and no more of
|
|
119
|
-
* its searches are made. A search that fails otherwise is
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
+
* its searches are made. A search that fails otherwise is tried once more; when
|
|
123
|
+
* that fails too it is reported and the passages its other searches found
|
|
124
|
+
* stand. A refusal is never tried again. Either way it is in `skipped`, once
|
|
125
|
+
* per knowledge base, and the passages of the others stand; whether a skip is
|
|
126
|
+
* an error is the caller's to say.
|
|
122
127
|
* @param options `sources`, `queries`, `search` (client-api
|
|
123
128
|
* `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK`
|
|
124
129
|
* per search (default DEFAULT_TOP_K)
|