@stackfactor/agent-utils 1.10.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.
@@ -60,6 +60,10 @@ const assertTavilyUsable = (config, options) => {
60
60
  if (!config?.tavilyAPIKey) {
61
61
  throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, "Tavily tools are enabled but config.tavilyAPIKey is missing.");
62
62
  }
63
+ if (options.allowedUrls !== undefined &&
64
+ !(Array.isArray(options.allowedUrls) && options.allowedUrls.every((url) => typeof url === "string"))) {
65
+ throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.BAD_REQUEST, "config.tavily.allowedUrls must be a list of URLs.");
66
+ }
63
67
  const unknown = (options.tools || []).filter((name) => !["search", "extract", "crawl", "map"].includes(name));
64
68
  if (unknown.length > 0) {
65
69
  throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.BAD_REQUEST, `Unknown Tavily tool(s): ${unknown.join(", ")}. Valid values are search, extract, crawl, map.`);
@@ -168,6 +172,52 @@ const recordTavilyUsage = (tracker, _config, credits, sources) => {
168
172
  }
169
173
  }
170
174
  };
175
+ /**
176
+ * Adds the URLs `web_extract` is about to ask Tavily for to
177
+ * `tracker.attemptedUrls`, each once across the run. Recorded before the call,
178
+ * so a URL the call then fails on is still there.
179
+ * @param tracker - The caller's usage accumulator, when it passed one
180
+ * @param urls - The URLs sent
181
+ */
182
+ const recordAttemptedUrls = (tracker, urls) => {
183
+ if (!tracker || urls.length === 0)
184
+ return;
185
+ const attempted = tracker.attemptedUrls || (tracker.attemptedUrls = []);
186
+ for (const url of urls) {
187
+ if (!attempted.includes(url))
188
+ attempted.push(url);
189
+ }
190
+ };
191
+ /**
192
+ * How a URL is matched, against Tavily's answer or `allowedUrls`: trimmed,
193
+ * lowercased, no trailing slash.
194
+ */
195
+ const urlMatchKey = (url) => url.trim().replace(/\/+$/, "").toLowerCase();
196
+ /** What `web_extract` answers for each URL `allowedUrls` refused. */
197
+ const REFUSED_HEADING = "Refused, not read (only the referenced pages may be read):";
198
+ /**
199
+ * Splits the URLs the model asked `web_extract` for into those it may read —
200
+ * as `allowedUrls` lists them — and those it may not, each once. With no
201
+ * `allowedUrls`, every URL may be read, as asked.
202
+ * @param urls - The URLs the model asked for
203
+ * @param allowed - `allowedUrls` by match key, or `null` when unset
204
+ */
205
+ const screenUrls = (urls, allowed) => {
206
+ if (!allowed)
207
+ return { read: urls, refused: [] };
208
+ const read = [];
209
+ const refused = [];
210
+ for (const url of urls) {
211
+ const listed = allowed.get(urlMatchKey(url));
212
+ if (listed === undefined) {
213
+ if (!refused.includes(url))
214
+ refused.push(url);
215
+ }
216
+ else if (!read.includes(listed))
217
+ read.push(listed);
218
+ }
219
+ return { read, refused };
220
+ };
171
221
  /**
172
222
  * Trims one document to whatever the per-URL and per-call budgets allow,
173
223
  * appending a note when anything was cut.
@@ -238,6 +288,9 @@ const buildTavilyTools = (config, options, usageTracker = null) => {
238
288
  const maxCharsPerUrl = options.maxCharsPerUrl ?? DEFAULT_MAX_CHARS_PER_URL;
239
289
  const maxCharsTotal = options.maxCharsTotal ?? DEFAULT_MAX_CHARS_TOTAL;
240
290
  const crawlLimit = options.crawlLimit ?? DEFAULT_CRAWL_LIMIT;
291
+ const allowed = Array.isArray(options.allowedUrls)
292
+ ? new Map(options.allowedUrls.map((url) => [urlMatchKey(url), url.trim()]))
293
+ : null;
241
294
  const newBudget = () => ({
242
295
  remaining: maxCharsTotal,
243
296
  perUrl: maxCharsPerUrl,
@@ -285,8 +338,22 @@ const buildTavilyTools = (config, options, usageTracker = null) => {
285
338
  }
286
339
  if (enabled.includes("extract")) {
287
340
  tools.push((0, langchain_1.tool)(async ({ urls, query }) => {
341
+ // Outside `allowedUrls` nothing is sent: the model is told per URL,
342
+ // and the run goes on with what it may read.
343
+ const { read, refused } = screenUrls(urls, allowed);
344
+ const refusal = refused.length
345
+ ? `${REFUSED_HEADING}\n${refused
346
+ .map((url) => `- ${url}: not one of the referenced pages`)
347
+ .join("\n")}`
348
+ : "";
349
+ if (refused.length > 0) {
350
+ logger_js_1.default.log(null, logger_js_1.default.levels.warn, `Tavily extract refused ${refused.length} URL(s) not among the allowed pages: ${refused.join(", ")}`);
351
+ }
352
+ if (read.length === 0)
353
+ return refusal;
354
+ recordAttemptedUrls(usageTracker, read);
288
355
  const data = await callTavily("extract", {
289
- urls,
356
+ urls: read,
290
357
  extract_depth: options.extractDepth,
291
358
  format,
292
359
  // `query` switches the API from whole-document extraction to
@@ -317,10 +384,14 @@ const buildTavilyTools = (config, options, usageTracker = null) => {
317
384
  .join("\n");
318
385
  rendered += `\n\n---\n\nFailed to extract:\n${lines}`;
319
386
  }
387
+ if (refusal)
388
+ rendered += `\n\n---\n\n${refusal}`;
320
389
  return rendered;
321
390
  }, {
322
391
  name: "web_extract",
323
- description: "Read the content of specific URLs. Pass a query to get back only the passages relevant to it — much cheaper and usually sufficient. Omit the query to retrieve the whole document, which is appropriate when you need its full structure. Long documents are truncated, and the result says so when that happens.",
392
+ description: `Read the content of specific URLs. Pass a query to get back only the passages relevant to it — much cheaper and usually sufficient. Omit the query to retrieve the whole document, which is appropriate when you need its full structure. Long documents are truncated, and the result says so when that happens.${allowed
393
+ ? " Only the referenced pages can be read; any other URL is refused."
394
+ : ""}`,
324
395
  schema: zod_1.z.object({
325
396
  urls: zod_1.z
326
397
  .array(zod_1.z.string())
@@ -399,8 +470,6 @@ exports.buildTavilyTools = buildTavilyTools;
399
470
  const EXTRACT_MAX_URLS = 20;
400
471
  /** Seconds. A reachability check needs the page fetched, not rendered at length. */
401
472
  const REACHABILITY_TIMEOUT_SECONDS = 20;
402
- /** How a URL is matched against Tavily's answer: trimmed, lowercased, no trailing slash. */
403
- const urlMatchKey = (url) => url.trim().replace(/\/+$/, "").toLowerCase();
404
473
  /** True for an `http:` or `https:` URL; false for anything else, unparsable included. */
405
474
  const isWebUrl = (url) => {
406
475
  try {
@@ -7,6 +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, { KnowledgeAccessError } from "./referenceContext.js";
10
11
  import { checkUrlsReachable } from "./tavily.js";
11
12
  export { constants };
12
13
  export { errorHandling, AppError };
@@ -23,6 +24,7 @@ export type { AgentExecuteRequest, CallAgentOptions, CheckAgentOptions, AgentHea
23
24
  export { runtimeContext };
24
25
  export { recordUsage, USAGE_UNITS };
25
26
  export type { UsageEntry, UsageUnit } from "./usage.js";
26
- export { stackfactorKnowledge };
27
+ export { stackfactorKnowledge, referenceContext, KnowledgeAccessError };
27
28
  export type { GroundingPassage, KnowledgeChunk, KnowledgeSearch, KnowledgeSource, SkippedSource, StackFactorReference, } from "./stackfactorKnowledge.js";
29
+ export type { ReferenceContext, ReferencePage, ReferencePassage, SourceGuidance, StoredReference, } from "./referenceContext.js";
28
30
  //# sourceMappingURL=index.d.ts.map
@@ -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,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,CAAC;AAEhC,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,eAAe,EACf,aAAa,EACb,oBAAoB,GACrB,MAAM,2BAA2B,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/esm/index.js CHANGED
@@ -7,6 +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, { KnowledgeAccessError } from "./referenceContext.js";
10
11
  import { checkUrlsReachable } from "./tavily.js";
11
12
  export { constants };
12
13
  export { errorHandling, AppError };
@@ -18,4 +19,4 @@ export { callAgent };
18
19
  export { checkAgent };
19
20
  export { runtimeContext };
20
21
  export { recordUsage, USAGE_UNITS };
21
- export { stackfactorKnowledge };
22
+ export { stackfactorKnowledge, referenceContext, KnowledgeAccessError };
@@ -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;CACtD,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;sCApxC9B,MAAM,KAAG,OAAO;0CA+FZ,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;oCAghBF,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;0CAx6C8B,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;;AA28CT,wBAkBE"}
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"}
@@ -1203,8 +1203,9 @@ const parseAgenticJsonResponse = (rawContent, schema) => {
1203
1203
  *
1204
1204
  * Setting `config.tavily` adds the Tavily web tools (`web_search`, `web_extract`, and
1205
1205
  * optionally `web_map` / `web_crawl`). They execute in this process, so they require
1206
- * `config.agentic` to be `true`; the credits spent and the URLs returned are recorded
1207
- * on `usageTracker`.
1206
+ * `config.agentic` to be `true`; the credits spent, the URLs returned and the URLs
1207
+ * `web_extract` asked for are recorded on `usageTracker`. `tavily.allowedUrls` keeps
1208
+ * `web_extract` to those URLs.
1208
1209
  * @param modelName - The model identifier, e.g. `"gpt-4o"`, `"claude-3-5-sonnet"`,
1209
1210
  * `"gemini-1.5-pro"`
1210
1211
  * @param config - Configuration object with API keys, `temperature`, optional `agentic`
@@ -0,0 +1,238 @@
1
+ import { KnowledgeSearch, SkippedSource } from "./stackfactorKnowledge.js";
2
+ /** The prompt key the passages are handed to the model under. */
3
+ export declare const REFERENCE_PASSAGES_KEY = "Knowledge Base Passages";
4
+ /** A web or publication page a reference points at. */
5
+ export interface ReferencePage {
6
+ /** The reference's short id, "r0"… */
7
+ id: string;
8
+ title: string;
9
+ url: string;
10
+ }
11
+ /** A passage of a document that references cite. */
12
+ export interface ReferencePassage {
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
+ */
17
+ references: string[];
18
+ document: string | null;
19
+ section: string | null;
20
+ text: string;
21
+ chunkId: string;
22
+ documentId: string;
23
+ knowledgeBaseId: string;
24
+ }
25
+ /** What a list of references points at. */
26
+ export interface ReferenceContext {
27
+ pages: ReferencePage[];
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
+ */
33
+ skipped: SkippedSource[];
34
+ /** True when the references cite at least one knowledge base document (all of them readable, or it would have thrown). */
35
+ citesKnowledge: boolean;
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
+ }
59
+ /**
60
+ * What a list of references points at: its pages, and the passages of the
61
+ * documents its STACKFACTOR references cite. One search per knowledge base per
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.
72
+ * @param options `references` (a skill's, a microskill's…), `queries` to
73
+ * search the cited documents with, `search` (client-api
74
+ * `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
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
79
+ */
80
+ export declare const gatherReferenceContext: (options: {
81
+ references: unknown;
82
+ queries: string[];
83
+ search: KnowledgeSearch;
84
+ token: string | null | undefined;
85
+ topK?: number;
86
+ maxPassages?: number;
87
+ maxPages?: number;
88
+ }) => Promise<ReferenceContext>;
89
+ /**
90
+ * The passages as a prompt shows them: who cites each, where it came from, and
91
+ * its text. The ids that locate it in the platform are left out.
92
+ * @param context From `gatherReferenceContext`
93
+ * @returns `[{ references, document, section, text }]`, for the model's input
94
+ */
95
+ export declare const referencePassagesForPrompt: (context: ReferenceContext) => {
96
+ references: string[];
97
+ document: string | null;
98
+ section: string | null;
99
+ text: string;
100
+ }[];
101
+ /** The guidance an agent's config gives for each kind of source it may be handed. */
102
+ export interface SourceGuidance {
103
+ pages: string;
104
+ passages: string;
105
+ none: string;
106
+ }
107
+ /** A reference as the platform stores it. `visibility` is left to the caller. */
108
+ export interface StoredReference {
109
+ kind: string;
110
+ title: string;
111
+ description?: string;
112
+ url?: string;
113
+ publication?: {
114
+ author?: string;
115
+ publisher?: string;
116
+ identifier?: string;
117
+ locator?: string;
118
+ };
119
+ origin: string;
120
+ visibility?: string;
121
+ target?: {
122
+ elementType: string;
123
+ elementId: string;
124
+ parentId?: string;
125
+ };
126
+ knowledgeBase?: {
127
+ knowledgeBaseId: string;
128
+ documentId: string;
129
+ chunkId?: string;
130
+ sectionTitle?: string | null;
131
+ };
132
+ }
133
+ /**
134
+ * The tools a run is given. Never `search`, `map` or `crawl`: a run reads what
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`).
138
+ * @param context From `gatherReferenceContext`
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.
143
+ */
144
+ export declare const toolsFor: (context: ReferenceContext) => {
145
+ tavily?: {
146
+ tools: string[];
147
+ allowedUrls: string[];
148
+ };
149
+ };
150
+ /**
151
+ * The stage prompt followed by the guidance for each kind of source the run
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.
155
+ * @param stagePrompt The stage's own prompt
156
+ * @param context From `gatherReferenceContext`
157
+ * @param guidance From `sourceGuidanceFrom`
158
+ * @returns The sections joined with a blank line
159
+ */
160
+ export declare const composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
161
+ /**
162
+ * A reference as a model is shown it. A STACKFACTOR reference loses its pointer
163
+ * and its url (ids mean nothing to a model, and the url is behind the
164
+ * organization's own sign-in); the model cites it by short id.
165
+ * @param reference A supplied reference
166
+ * @returns The reference; a STACKFACTOR one without `_id`, `origin`, `visibility`,
167
+ * `target`, `knowledgeBase` and `url`
168
+ */
169
+ export declare const referenceForModel: <T extends {
170
+ kind?: string;
171
+ }>(reference: T) => T;
172
+ /**
173
+ * The supplied references as a model is shown them, each under its short id
174
+ * `r<N>` (N the index in the supplied list) as `_id`, set last so a stored
175
+ * reference's own id never wins. Non-object entries are skipped but keep their
176
+ * index, so the ids stay aligned with `citedReferences`.
177
+ * @param references The supplied list
178
+ */
179
+ export declare const referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
180
+ /**
181
+ * A reference from the flat projection the host sends (or the flat shape a
182
+ * model emits) in the shape the platform stores: nested `publication`,
183
+ * `relatedTo` folded into `description`, a STACKFACTOR reference's pointer and
184
+ * target kept. `visibility` is never set; the caller decides it.
185
+ * @param reference The flat reference
186
+ * @param origin Default `"AI_GENERATED"`
187
+ */
188
+ export declare const toStoredReference: (reference: any, origin?: string) => StoredReference;
189
+ /**
190
+ * The supplied references a model cited by short id, stored. Ids are matched
191
+ * trimmed and case-insensitively; unknown and non-string ids are dropped and
192
+ * each reference appears once, at its first citation.
193
+ * @param ids The model's cited ids (`["r0", "r3"]`)
194
+ * @param supplied The list the ids index into
195
+ * @param origin Default `"AI_GENERATED"`
196
+ */
197
+ export declare const citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
198
+ /**
199
+ * The three guidance texts an agent's config holds. A missing or non-string
200
+ * value is an empty string.
201
+ * @param config The agent's config
202
+ */
203
+ export declare const sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
204
+ declare const _default: {
205
+ KnowledgeAccessError: typeof KnowledgeAccessError;
206
+ REFERENCE_PASSAGES_KEY: string;
207
+ citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
208
+ composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
209
+ gatherReferenceContext: (options: {
210
+ references: unknown;
211
+ queries: string[];
212
+ search: KnowledgeSearch;
213
+ token: string | null | undefined;
214
+ topK?: number;
215
+ maxPassages?: number;
216
+ maxPages?: number;
217
+ }) => Promise<ReferenceContext>;
218
+ referenceForModel: <T extends {
219
+ kind?: string;
220
+ }>(reference: T) => T;
221
+ referencePassagesForPrompt: (context: ReferenceContext) => {
222
+ references: string[];
223
+ document: string | null;
224
+ section: string | null;
225
+ text: string;
226
+ }[];
227
+ referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
228
+ sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
229
+ toStoredReference: (reference: any, origin?: string) => StoredReference;
230
+ toolsFor: (context: ReferenceContext) => {
231
+ tavily?: {
232
+ tools: string[];
233
+ allowedUrls: string[];
234
+ };
235
+ };
236
+ };
237
+ export default _default;
238
+ //# sourceMappingURL=referenceContext.d.ts.map
@@ -0,0 +1 @@
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"}