@stackfactor/agent-utils 1.10.0 → 1.11.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.
@@ -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 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 };
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,MAAM,uBAAuB,CAAC;AACrD,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,CAAC;AAElD,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.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.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,5 +61,7 @@ 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 = __importDefault(require("./referenceContext.js"));
65
+ exports.referenceContext = referenceContext_js_1.default;
64
66
  const tavily_js_1 = require("./tavily.js");
65
67
  Object.defineProperty(exports, "checkUrlsReachable", { enumerable: true, get: function () { return tavily_js_1.checkUrlsReachable; } });
@@ -0,0 +1,191 @@
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
+ /** The short ids of every STACKFACTOR reference that cites this passage's document. */
14
+ references: string[];
15
+ document: string | null;
16
+ section: string | null;
17
+ text: string;
18
+ chunkId: string;
19
+ documentId: string;
20
+ knowledgeBaseId: string;
21
+ }
22
+ /** What a list of references points at. */
23
+ export interface ReferenceContext {
24
+ pages: ReferencePage[];
25
+ passages: ReferencePassage[];
26
+ skipped: SkippedSource[];
27
+ /** True when the references cite at least one knowledge base document, whether or not it could be read. */
28
+ citesKnowledge: boolean;
29
+ }
30
+ /**
31
+ * What a list of references points at: its pages, and the passages of the
32
+ * documents its STACKFACTOR references cite. One search per knowledge base per
33
+ * query (per batch of 500 documents), however many references there are. With
34
+ * no token no search is made and the pages are still listed. A knowledge base
35
+ * the person cannot open is in `skipped`; the other passages stand.
36
+ * @param options `references` (a skill's, a microskill's…), `queries` to
37
+ * search the cited documents with, `search` (client-api
38
+ * `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
39
+ * search (default 5)
40
+ * @returns `{ pages, passages, skipped, citesKnowledge }`
41
+ */
42
+ export declare const gatherReferenceContext: (options: {
43
+ references: unknown;
44
+ queries: string[];
45
+ search: KnowledgeSearch;
46
+ token: string | null | undefined;
47
+ topK?: number;
48
+ }) => Promise<ReferenceContext>;
49
+ /**
50
+ * The passages as a prompt shows them: who cites each, where it came from, and
51
+ * its text. The ids that locate it in the platform are left out.
52
+ * @param context From `gatherReferenceContext`
53
+ * @returns `[{ references, document, section, text }]`, for the model's input
54
+ */
55
+ export declare const referencePassagesForPrompt: (context: ReferenceContext) => {
56
+ references: string[];
57
+ document: string | null;
58
+ section: string | null;
59
+ text: string;
60
+ }[];
61
+ /** The guidance an agent's config gives for each kind of source it may be handed. */
62
+ export interface SourceGuidance {
63
+ pages: string;
64
+ passages: string;
65
+ none: string;
66
+ }
67
+ /** A reference as the platform stores it. `visibility` is left to the caller. */
68
+ export interface StoredReference {
69
+ kind: string;
70
+ title: string;
71
+ description?: string;
72
+ url?: string;
73
+ publication?: {
74
+ author?: string;
75
+ publisher?: string;
76
+ identifier?: string;
77
+ locator?: string;
78
+ };
79
+ origin: string;
80
+ visibility?: string;
81
+ target?: {
82
+ elementType: string;
83
+ elementId: string;
84
+ parentId?: string;
85
+ };
86
+ knowledgeBase?: {
87
+ knowledgeBaseId: string;
88
+ documentId: string;
89
+ chunkId?: string;
90
+ sectionTitle?: string | null;
91
+ };
92
+ }
93
+ /**
94
+ * 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, and only when
96
+ * there are pages to open.
97
+ * @param context From `gatherReferenceContext`
98
+ * @returns `{ tavily: { tools: ["extract"] } }` with pages, else `{}`. With no
99
+ * pages it returns `{}`, so a caller spreading it over a config that already
100
+ * has a `tavily` key keeps that key (and `tavily: true` means search plus
101
+ * extract): callers must not carry a base `tavily` key.
102
+ */
103
+ export declare const toolsFor: (context: ReferenceContext) => {
104
+ tavily?: {
105
+ tools: string[];
106
+ };
107
+ };
108
+ /**
109
+ * The stage prompt followed by the guidance for each kind of source the run
110
+ * has: pages, then passages; when it has neither, the `none` guidance. An empty
111
+ * guidance adds nothing.
112
+ * @param stagePrompt The stage's own prompt
113
+ * @param context From `gatherReferenceContext`
114
+ * @param guidance From `sourceGuidanceFrom`
115
+ * @returns The sections joined with a blank line
116
+ */
117
+ export declare const composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
118
+ /**
119
+ * A reference as a model is shown it. A STACKFACTOR reference loses its pointer
120
+ * and its url (ids mean nothing to a model, and the url is behind the
121
+ * organization's own sign-in); the model cites it by short id.
122
+ * @param reference A supplied reference
123
+ * @returns The reference; a STACKFACTOR one without `_id`, `origin`, `visibility`,
124
+ * `target`, `knowledgeBase` and `url`
125
+ */
126
+ export declare const referenceForModel: <T extends {
127
+ kind?: string;
128
+ }>(reference: T) => T;
129
+ /**
130
+ * The supplied references as a model is shown them, each under its short id
131
+ * `r<N>` (N the index in the supplied list) as `_id`, set last so a stored
132
+ * reference's own id never wins. Non-object entries are skipped but keep their
133
+ * index, so the ids stay aligned with `citedReferences`.
134
+ * @param references The supplied list
135
+ */
136
+ export declare const referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
137
+ /**
138
+ * A reference from the flat projection the host sends (or the flat shape a
139
+ * model emits) in the shape the platform stores: nested `publication`,
140
+ * `relatedTo` folded into `description`, a STACKFACTOR reference's pointer and
141
+ * target kept. `visibility` is never set; the caller decides it.
142
+ * @param reference The flat reference
143
+ * @param origin Default `"AI_GENERATED"`
144
+ */
145
+ export declare const toStoredReference: (reference: any, origin?: string) => StoredReference;
146
+ /**
147
+ * The supplied references a model cited by short id, stored. Ids are matched
148
+ * trimmed and case-insensitively; unknown and non-string ids are dropped and
149
+ * each reference appears once, at its first citation.
150
+ * @param ids The model's cited ids (`["r0", "r3"]`)
151
+ * @param supplied The list the ids index into
152
+ * @param origin Default `"AI_GENERATED"`
153
+ */
154
+ export declare const citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
155
+ /**
156
+ * The three guidance texts an agent's config holds. A missing or non-string
157
+ * value is an empty string.
158
+ * @param config The agent's config
159
+ */
160
+ export declare const sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
161
+ declare const _default: {
162
+ REFERENCE_PASSAGES_KEY: string;
163
+ citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
164
+ composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
165
+ gatherReferenceContext: (options: {
166
+ references: unknown;
167
+ queries: string[];
168
+ search: KnowledgeSearch;
169
+ token: string | null | undefined;
170
+ topK?: number;
171
+ }) => Promise<ReferenceContext>;
172
+ referenceForModel: <T extends {
173
+ kind?: string;
174
+ }>(reference: T) => T;
175
+ referencePassagesForPrompt: (context: ReferenceContext) => {
176
+ references: string[];
177
+ document: string | null;
178
+ section: string | null;
179
+ text: string;
180
+ }[];
181
+ referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
182
+ sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
183
+ toStoredReference: (reference: any, origin?: string) => StoredReference;
184
+ toolsFor: (context: ReferenceContext) => {
185
+ tavily?: {
186
+ tools: string[];
187
+ };
188
+ };
189
+ };
190
+ export default _default;
191
+ //# sourceMappingURL=referenceContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referenceContext.d.ts","sourceRoot":"","sources":["../../src/referenceContext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
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;
7
+ //
8
+ // Reference context — gathering what a list of references points at
9
+ //
10
+ // An agent that reads its references never discovers new sources. It reads
11
+ // what they point at:
12
+ //
13
+ // - pages: WEB and PUBLICATION references with an http(s) url, which the
14
+ // agent opens through Tavily `extract`. A STACKFACTOR reference's url is
15
+ // the document's page at its source and is never opened as a page;
16
+ // - passages: the passages of the knowledge base documents STACKFACTOR
17
+ // references cite, searched under the run's own token, so a run reads only
18
+ // what the person it acts for may open.
19
+ //
20
+ // A reference is cited by its short id `r<N>`, N being its index in the
21
+ // supplied list, whatever its kind.
22
+ //
23
+ const logger_js_1 = __importDefault(require("./logger.js"));
24
+ const stackfactorKnowledge_js_1 = require("./stackfactorKnowledge.js");
25
+ /** How many passages one search asks for when the caller does not say. */
26
+ const DEFAULT_REFERENCE_TOP_K = 5;
27
+ /** The prompt key the passages are handed to the model under. */
28
+ exports.REFERENCE_PASSAGES_KEY = "Knowledge Base Passages";
29
+ const text = (value) => (typeof value === "string" ? value.trim() : "");
30
+ const id = (value) => typeof value === "string" ? value.trim() : value != null && typeof value === "object" ? String(value) : "";
31
+ const shortId = (index) => `r${index}`;
32
+ /** The document a STACKFACTOR reference cites, or "" when it cites none. */
33
+ const documentOf = (reference) => {
34
+ const target = reference.target ?? {};
35
+ return (id(reference.knowledgeBase?.documentId) ||
36
+ (target.elementType === stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE ? id(target.elementId) : ""));
37
+ };
38
+ /** The kinds the platform retired; it reads them as PUBLICATION. */
39
+ const RETIRED_KINDS = new Set(["DOCUMENT", "KNOWLEDGE_BASE", "NOTE"]);
40
+ /** A reference's kind as the platform reads it: missing or retired is PUBLICATION. */
41
+ const resolveKind = (reference) => {
42
+ const kind = reference?.kind;
43
+ return typeof kind !== "string" || kind === "" || RETIRED_KINDS.has(kind) ? "PUBLICATION" : kind;
44
+ };
45
+ /** The pages among the references, each url once, under the first reference that has it. */
46
+ const pagesOf = (references) => {
47
+ const pages = [];
48
+ const seen = new Set();
49
+ references.forEach((reference, index) => {
50
+ if (!reference || typeof reference !== "object")
51
+ return;
52
+ const kind = resolveKind(reference);
53
+ if (kind !== "WEB" && kind !== "PUBLICATION")
54
+ return;
55
+ const url = text(reference.url);
56
+ if (!/^https?:\/\//i.test(url) || seen.has(url))
57
+ return;
58
+ seen.add(url);
59
+ pages.push({ id: shortId(index), title: text(reference.title) || url, url });
60
+ });
61
+ return pages;
62
+ };
63
+ /** The short ids of the STACKFACTOR references citing each document. */
64
+ const citersByDocument = (references) => {
65
+ const citers = new Map();
66
+ references.forEach((reference, index) => {
67
+ if (reference?.kind !== stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.KIND)
68
+ return;
69
+ const documentId = documentOf(reference);
70
+ if (documentId)
71
+ citers.set(documentId, [...(citers.get(documentId) ?? []), shortId(index)]);
72
+ });
73
+ return citers;
74
+ };
75
+ /**
76
+ * What a list of references points at: its pages, and the passages of the
77
+ * documents its STACKFACTOR references cite. One search per knowledge base per
78
+ * query (per batch of 500 documents), however many references there are. With
79
+ * no token no search is made and the pages are still listed. A knowledge base
80
+ * the person cannot open is in `skipped`; the other passages stand.
81
+ * @param options `references` (a skill's, a microskill's…), `queries` to
82
+ * search the cited documents with, `search` (client-api
83
+ * `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
84
+ * search (default 5)
85
+ * @returns `{ pages, passages, skipped, citesKnowledge }`
86
+ */
87
+ const gatherReferenceContext = async (options) => {
88
+ const references = Array.isArray(options.references) ? options.references : [];
89
+ const sources = (0, stackfactorKnowledge_js_1.sourcesFromReferences)(references);
90
+ const citesKnowledge = sources.length > 0;
91
+ const pages = pagesOf(references);
92
+ if (!options.token || !citesKnowledge) {
93
+ logContext(pages.length, 0, [], citesKnowledge && !options.token);
94
+ return { citesKnowledge, pages, passages: [], skipped: [] };
95
+ }
96
+ const found = await (0, stackfactorKnowledge_js_1.retrievePassages)({
97
+ queries: options.queries,
98
+ search: options.search,
99
+ sources,
100
+ token: options.token,
101
+ topK: options.topK ?? DEFAULT_REFERENCE_TOP_K,
102
+ });
103
+ const citers = citersByDocument(references);
104
+ const passages = found.passages
105
+ .filter((passage) => citers.has(passage.documentId))
106
+ .map((passage) => ({
107
+ chunkId: passage.chunkId,
108
+ document: passage.documentName,
109
+ documentId: passage.documentId,
110
+ knowledgeBaseId: passage.knowledgeBaseId,
111
+ references: citers.get(passage.documentId),
112
+ section: passage.sectionTitle,
113
+ text: passage.text,
114
+ }));
115
+ logContext(pages.length, passages.length, found.skipped, false);
116
+ return { citesKnowledge, pages, passages, skipped: found.skipped };
117
+ };
118
+ exports.gatherReferenceContext = gatherReferenceContext;
119
+ /** The one summary line of a gathering, for the logs. */
120
+ const logContext = (pages, passages, skipped, noToken) => {
121
+ const parts = [`${pages} page${pages === 1 ? "" : "s"}`, `${passages} passage${passages === 1 ? "" : "s"}`];
122
+ if (skipped.length > 0) {
123
+ parts.push(`skipped knowledge bases: ${skipped.map((s) => `${s.knowledgeBaseId} (noAccess: ${s.noAccess})`).join(", ")}`);
124
+ }
125
+ if (noToken)
126
+ parts.push("no token, so no passages");
127
+ logger_js_1.default.log(null, logger_js_1.default.levels.info, `Reference context: ${parts.join("; ")}`);
128
+ };
129
+ /**
130
+ * The passages as a prompt shows them: who cites each, where it came from, and
131
+ * its text. The ids that locate it in the platform are left out.
132
+ * @param context From `gatherReferenceContext`
133
+ * @returns `[{ references, document, section, text }]`, for the model's input
134
+ */
135
+ const referencePassagesForPrompt = (context) => context.passages.map((passage) => ({
136
+ document: passage.document,
137
+ references: passage.references,
138
+ section: passage.section,
139
+ text: passage.text,
140
+ }));
141
+ exports.referencePassagesForPrompt = referencePassagesForPrompt;
142
+ /**
143
+ * 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, and only when
145
+ * there are pages to open.
146
+ * @param context From `gatherReferenceContext`
147
+ * @returns `{ tavily: { tools: ["extract"] } }` with pages, else `{}`. With no
148
+ * pages it returns `{}`, so a caller spreading it over a config that already
149
+ * has a `tavily` key keeps that key (and `tavily: true` means search plus
150
+ * extract): callers must not carry a base `tavily` key.
151
+ */
152
+ const toolsFor = (context) => context.pages.length > 0 ? { tavily: { tools: ["extract"] } } : {};
153
+ exports.toolsFor = toolsFor;
154
+ /**
155
+ * The stage prompt followed by the guidance for each kind of source the run
156
+ * has: pages, then passages; when it has neither, the `none` guidance. An empty
157
+ * guidance adds nothing.
158
+ * @param stagePrompt The stage's own prompt
159
+ * @param context From `gatherReferenceContext`
160
+ * @param guidance From `sourceGuidanceFrom`
161
+ * @returns The sections joined with a blank line
162
+ */
163
+ const composeSourceInstructions = (stagePrompt, context, guidance) => {
164
+ const sections = [];
165
+ if (context.pages.length > 0)
166
+ sections.push(guidance.pages);
167
+ if (context.passages.length > 0)
168
+ sections.push(guidance.passages);
169
+ if (sections.length === 0)
170
+ sections.push(guidance.none);
171
+ return [stagePrompt, ...sections].filter(Boolean).join("\n\n");
172
+ };
173
+ exports.composeSourceInstructions = composeSourceInstructions;
174
+ /**
175
+ * A reference as a model is shown it. A STACKFACTOR reference loses its pointer
176
+ * and its url (ids mean nothing to a model, and the url is behind the
177
+ * organization's own sign-in); the model cites it by short id.
178
+ * @param reference A supplied reference
179
+ * @returns The reference; a STACKFACTOR one without `_id`, `origin`, `visibility`,
180
+ * `target`, `knowledgeBase` and `url`
181
+ */
182
+ const referenceForModel = (reference) => {
183
+ if (reference?.kind !== stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.KIND)
184
+ return reference;
185
+ const { _id: _i, origin: _o, visibility: _v, target: _target, knowledgeBase: _knowledgeBase, url: _url, ...rest } = reference;
186
+ return rest;
187
+ };
188
+ exports.referenceForModel = referenceForModel;
189
+ /**
190
+ * The supplied references as a model is shown them, each under its short id
191
+ * `r<N>` (N the index in the supplied list) as `_id`, set last so a stored
192
+ * reference's own id never wins. Non-object entries are skipped but keep their
193
+ * index, so the ids stay aligned with `citedReferences`.
194
+ * @param references The supplied list
195
+ */
196
+ const referencesForModel = (references) => {
197
+ const shown = [];
198
+ (Array.isArray(references) ? references : []).forEach((reference, index) => {
199
+ if (!reference || typeof reference !== "object")
200
+ return;
201
+ const { _id: _ignored, ...rest } = (0, exports.referenceForModel)(reference);
202
+ shown.push({ ...rest, _id: shortId(index) });
203
+ });
204
+ return shown;
205
+ };
206
+ exports.referencesForModel = referencesForModel;
207
+ /** What a STACKFACTOR reference points at, as the platform stores it. */
208
+ const stackfactorPointers = (reference) => {
209
+ if (reference.kind !== stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.KIND)
210
+ return {};
211
+ const pointer = reference.knowledgeBase;
212
+ if (pointer?.knowledgeBaseId && pointer?.documentId) {
213
+ return {
214
+ knowledgeBase: { ...pointer },
215
+ target: {
216
+ elementType: stackfactorKnowledge_js_1.STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE,
217
+ elementId: pointer.documentId,
218
+ parentId: pointer.knowledgeBaseId,
219
+ },
220
+ };
221
+ }
222
+ return reference.target?.elementType && reference.target?.elementId ? { target: { ...reference.target } } : {};
223
+ };
224
+ /**
225
+ * A reference from the flat projection the host sends (or the flat shape a
226
+ * model emits) in the shape the platform stores: nested `publication`,
227
+ * `relatedTo` folded into `description`, a STACKFACTOR reference's pointer and
228
+ * target kept. `visibility` is never set; the caller decides it.
229
+ * @param reference The flat reference
230
+ * @param origin Default `"AI_GENERATED"`
231
+ */
232
+ const toStoredReference = (reference, origin = "AI_GENERATED") => {
233
+ const publication = {
234
+ ...(reference.author ? { author: reference.author } : {}),
235
+ ...(reference.publisher ? { publisher: reference.publisher } : {}),
236
+ ...(reference.identifier ? { identifier: reference.identifier } : {}),
237
+ ...(reference.locator ? { locator: reference.locator } : {}),
238
+ ...(reference.publication || {}),
239
+ };
240
+ const description = [reference.description, reference.relatedTo ? `Related to: ${reference.relatedTo}` : null]
241
+ .filter(Boolean)
242
+ .join(" \u2014 ");
243
+ return {
244
+ kind: reference.kind,
245
+ title: reference.title,
246
+ ...(description ? { description } : {}),
247
+ ...(reference.url ? { url: reference.url } : {}),
248
+ ...(Object.keys(publication).length > 0 ? { publication } : {}),
249
+ ...stackfactorPointers(reference),
250
+ origin,
251
+ };
252
+ };
253
+ exports.toStoredReference = toStoredReference;
254
+ /**
255
+ * The supplied references a model cited by short id, stored. Ids are matched
256
+ * trimmed and case-insensitively; unknown and non-string ids are dropped and
257
+ * each reference appears once, at its first citation.
258
+ * @param ids The model's cited ids (`["r0", "r3"]`)
259
+ * @param supplied The list the ids index into
260
+ * @param origin Default `"AI_GENERATED"`
261
+ */
262
+ const citedReferences = (ids, supplied, origin) => {
263
+ const list = Array.isArray(supplied) ? supplied : [];
264
+ const taken = new Set();
265
+ const cited = [];
266
+ for (const raw of Array.isArray(ids) ? ids : []) {
267
+ const match = typeof raw === "string" ? /^r(\d+)$/.exec(raw.trim().toLowerCase()) : null;
268
+ const index = match ? Number(match[1]) : -1;
269
+ if (!list[index] || typeof list[index] !== "object" || taken.has(index))
270
+ continue;
271
+ taken.add(index);
272
+ cited.push((0, exports.toStoredReference)(list[index], origin));
273
+ }
274
+ return cited;
275
+ };
276
+ exports.citedReferences = citedReferences;
277
+ /**
278
+ * The three guidance texts an agent's config holds. A missing or non-string
279
+ * value is an empty string.
280
+ * @param config The agent's config
281
+ */
282
+ const sourceGuidanceFrom = (config) => ({
283
+ pages: text(config?.referencedPagesGuidance),
284
+ passages: text(config?.knowledgeBasePassagesGuidance),
285
+ none: text(config?.noReferencesGuidance),
286
+ });
287
+ exports.sourceGuidanceFrom = sourceGuidanceFrom;
288
+ exports.default = {
289
+ REFERENCE_PASSAGES_KEY: exports.REFERENCE_PASSAGES_KEY,
290
+ citedReferences: exports.citedReferences,
291
+ composeSourceInstructions: exports.composeSourceInstructions,
292
+ gatherReferenceContext: exports.gatherReferenceContext,
293
+ referenceForModel: exports.referenceForModel,
294
+ referencePassagesForPrompt: exports.referencePassagesForPrompt,
295
+ referencesForModel: exports.referencesForModel,
296
+ sourceGuidanceFrom: exports.sourceGuidanceFrom,
297
+ toStoredReference: exports.toStoredReference,
298
+ toolsFor: exports.toolsFor,
299
+ };
@@ -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 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 };
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,MAAM,uBAAuB,CAAC;AACrD,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,CAAC;AAElD,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 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 };
@@ -0,0 +1,191 @@
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
+ /** The short ids of every STACKFACTOR reference that cites this passage's document. */
14
+ references: string[];
15
+ document: string | null;
16
+ section: string | null;
17
+ text: string;
18
+ chunkId: string;
19
+ documentId: string;
20
+ knowledgeBaseId: string;
21
+ }
22
+ /** What a list of references points at. */
23
+ export interface ReferenceContext {
24
+ pages: ReferencePage[];
25
+ passages: ReferencePassage[];
26
+ skipped: SkippedSource[];
27
+ /** True when the references cite at least one knowledge base document, whether or not it could be read. */
28
+ citesKnowledge: boolean;
29
+ }
30
+ /**
31
+ * What a list of references points at: its pages, and the passages of the
32
+ * documents its STACKFACTOR references cite. One search per knowledge base per
33
+ * query (per batch of 500 documents), however many references there are. With
34
+ * no token no search is made and the pages are still listed. A knowledge base
35
+ * the person cannot open is in `skipped`; the other passages stand.
36
+ * @param options `references` (a skill's, a microskill's…), `queries` to
37
+ * search the cited documents with, `search` (client-api
38
+ * `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
39
+ * search (default 5)
40
+ * @returns `{ pages, passages, skipped, citesKnowledge }`
41
+ */
42
+ export declare const gatherReferenceContext: (options: {
43
+ references: unknown;
44
+ queries: string[];
45
+ search: KnowledgeSearch;
46
+ token: string | null | undefined;
47
+ topK?: number;
48
+ }) => Promise<ReferenceContext>;
49
+ /**
50
+ * The passages as a prompt shows them: who cites each, where it came from, and
51
+ * its text. The ids that locate it in the platform are left out.
52
+ * @param context From `gatherReferenceContext`
53
+ * @returns `[{ references, document, section, text }]`, for the model's input
54
+ */
55
+ export declare const referencePassagesForPrompt: (context: ReferenceContext) => {
56
+ references: string[];
57
+ document: string | null;
58
+ section: string | null;
59
+ text: string;
60
+ }[];
61
+ /** The guidance an agent's config gives for each kind of source it may be handed. */
62
+ export interface SourceGuidance {
63
+ pages: string;
64
+ passages: string;
65
+ none: string;
66
+ }
67
+ /** A reference as the platform stores it. `visibility` is left to the caller. */
68
+ export interface StoredReference {
69
+ kind: string;
70
+ title: string;
71
+ description?: string;
72
+ url?: string;
73
+ publication?: {
74
+ author?: string;
75
+ publisher?: string;
76
+ identifier?: string;
77
+ locator?: string;
78
+ };
79
+ origin: string;
80
+ visibility?: string;
81
+ target?: {
82
+ elementType: string;
83
+ elementId: string;
84
+ parentId?: string;
85
+ };
86
+ knowledgeBase?: {
87
+ knowledgeBaseId: string;
88
+ documentId: string;
89
+ chunkId?: string;
90
+ sectionTitle?: string | null;
91
+ };
92
+ }
93
+ /**
94
+ * 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, and only when
96
+ * there are pages to open.
97
+ * @param context From `gatherReferenceContext`
98
+ * @returns `{ tavily: { tools: ["extract"] } }` with pages, else `{}`. With no
99
+ * pages it returns `{}`, so a caller spreading it over a config that already
100
+ * has a `tavily` key keeps that key (and `tavily: true` means search plus
101
+ * extract): callers must not carry a base `tavily` key.
102
+ */
103
+ export declare const toolsFor: (context: ReferenceContext) => {
104
+ tavily?: {
105
+ tools: string[];
106
+ };
107
+ };
108
+ /**
109
+ * The stage prompt followed by the guidance for each kind of source the run
110
+ * has: pages, then passages; when it has neither, the `none` guidance. An empty
111
+ * guidance adds nothing.
112
+ * @param stagePrompt The stage's own prompt
113
+ * @param context From `gatherReferenceContext`
114
+ * @param guidance From `sourceGuidanceFrom`
115
+ * @returns The sections joined with a blank line
116
+ */
117
+ export declare const composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
118
+ /**
119
+ * A reference as a model is shown it. A STACKFACTOR reference loses its pointer
120
+ * and its url (ids mean nothing to a model, and the url is behind the
121
+ * organization's own sign-in); the model cites it by short id.
122
+ * @param reference A supplied reference
123
+ * @returns The reference; a STACKFACTOR one without `_id`, `origin`, `visibility`,
124
+ * `target`, `knowledgeBase` and `url`
125
+ */
126
+ export declare const referenceForModel: <T extends {
127
+ kind?: string;
128
+ }>(reference: T) => T;
129
+ /**
130
+ * The supplied references as a model is shown them, each under its short id
131
+ * `r<N>` (N the index in the supplied list) as `_id`, set last so a stored
132
+ * reference's own id never wins. Non-object entries are skipped but keep their
133
+ * index, so the ids stay aligned with `citedReferences`.
134
+ * @param references The supplied list
135
+ */
136
+ export declare const referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
137
+ /**
138
+ * A reference from the flat projection the host sends (or the flat shape a
139
+ * model emits) in the shape the platform stores: nested `publication`,
140
+ * `relatedTo` folded into `description`, a STACKFACTOR reference's pointer and
141
+ * target kept. `visibility` is never set; the caller decides it.
142
+ * @param reference The flat reference
143
+ * @param origin Default `"AI_GENERATED"`
144
+ */
145
+ export declare const toStoredReference: (reference: any, origin?: string) => StoredReference;
146
+ /**
147
+ * The supplied references a model cited by short id, stored. Ids are matched
148
+ * trimmed and case-insensitively; unknown and non-string ids are dropped and
149
+ * each reference appears once, at its first citation.
150
+ * @param ids The model's cited ids (`["r0", "r3"]`)
151
+ * @param supplied The list the ids index into
152
+ * @param origin Default `"AI_GENERATED"`
153
+ */
154
+ export declare const citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
155
+ /**
156
+ * The three guidance texts an agent's config holds. A missing or non-string
157
+ * value is an empty string.
158
+ * @param config The agent's config
159
+ */
160
+ export declare const sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
161
+ declare const _default: {
162
+ REFERENCE_PASSAGES_KEY: string;
163
+ citedReferences: (ids: unknown, supplied: unknown, origin?: string) => StoredReference[];
164
+ composeSourceInstructions: (stagePrompt: string, context: ReferenceContext, guidance: SourceGuidance) => string;
165
+ gatherReferenceContext: (options: {
166
+ references: unknown;
167
+ queries: string[];
168
+ search: KnowledgeSearch;
169
+ token: string | null | undefined;
170
+ topK?: number;
171
+ }) => Promise<ReferenceContext>;
172
+ referenceForModel: <T extends {
173
+ kind?: string;
174
+ }>(reference: T) => T;
175
+ referencePassagesForPrompt: (context: ReferenceContext) => {
176
+ references: string[];
177
+ document: string | null;
178
+ section: string | null;
179
+ text: string;
180
+ }[];
181
+ referencesForModel: (references: unknown) => Array<Record<string, unknown>>;
182
+ sourceGuidanceFrom: (config: Record<string, unknown>) => SourceGuidance;
183
+ toStoredReference: (reference: any, origin?: string) => StoredReference;
184
+ toolsFor: (context: ReferenceContext) => {
185
+ tavily?: {
186
+ tools: string[];
187
+ };
188
+ };
189
+ };
190
+ export default _default;
191
+ //# sourceMappingURL=referenceContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referenceContext.d.ts","sourceRoot":"","sources":["../../src/referenceContext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,284 @@
1
+ //
2
+ // Reference context — gathering what a list of references points at
3
+ //
4
+ // An agent that reads its references never discovers new sources. It reads
5
+ // what they point at:
6
+ //
7
+ // - pages: WEB and PUBLICATION references with an http(s) url, which the
8
+ // agent opens through Tavily `extract`. A STACKFACTOR reference's url is
9
+ // the document's page at its source and is never opened as a page;
10
+ // - passages: the passages of the knowledge base documents STACKFACTOR
11
+ // references cite, searched under the run's own token, so a run reads only
12
+ // what the person it acts for may open.
13
+ //
14
+ // A reference is cited by its short id `r<N>`, N being its index in the
15
+ // supplied list, whatever its kind.
16
+ //
17
+ import logger from "./logger.js";
18
+ import { STACKFACTOR_REFERENCE, retrievePassages, sourcesFromReferences, } from "./stackfactorKnowledge.js";
19
+ /** How many passages one search asks for when the caller does not say. */
20
+ const DEFAULT_REFERENCE_TOP_K = 5;
21
+ /** The prompt key the passages are handed to the model under. */
22
+ export const REFERENCE_PASSAGES_KEY = "Knowledge Base Passages";
23
+ const text = (value) => (typeof value === "string" ? value.trim() : "");
24
+ const id = (value) => typeof value === "string" ? value.trim() : value != null && typeof value === "object" ? String(value) : "";
25
+ const shortId = (index) => `r${index}`;
26
+ /** The document a STACKFACTOR reference cites, or "" when it cites none. */
27
+ const documentOf = (reference) => {
28
+ const target = reference.target ?? {};
29
+ return (id(reference.knowledgeBase?.documentId) ||
30
+ (target.elementType === STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE ? id(target.elementId) : ""));
31
+ };
32
+ /** The kinds the platform retired; it reads them as PUBLICATION. */
33
+ const RETIRED_KINDS = new Set(["DOCUMENT", "KNOWLEDGE_BASE", "NOTE"]);
34
+ /** A reference's kind as the platform reads it: missing or retired is PUBLICATION. */
35
+ const resolveKind = (reference) => {
36
+ const kind = reference?.kind;
37
+ return typeof kind !== "string" || kind === "" || RETIRED_KINDS.has(kind) ? "PUBLICATION" : kind;
38
+ };
39
+ /** The pages among the references, each url once, under the first reference that has it. */
40
+ const pagesOf = (references) => {
41
+ const pages = [];
42
+ const seen = new Set();
43
+ references.forEach((reference, index) => {
44
+ if (!reference || typeof reference !== "object")
45
+ return;
46
+ const kind = resolveKind(reference);
47
+ if (kind !== "WEB" && kind !== "PUBLICATION")
48
+ return;
49
+ const url = text(reference.url);
50
+ if (!/^https?:\/\//i.test(url) || seen.has(url))
51
+ return;
52
+ seen.add(url);
53
+ pages.push({ id: shortId(index), title: text(reference.title) || url, url });
54
+ });
55
+ return pages;
56
+ };
57
+ /** The short ids of the STACKFACTOR references citing each document. */
58
+ const citersByDocument = (references) => {
59
+ const citers = new Map();
60
+ references.forEach((reference, index) => {
61
+ if (reference?.kind !== STACKFACTOR_REFERENCE.KIND)
62
+ return;
63
+ const documentId = documentOf(reference);
64
+ if (documentId)
65
+ citers.set(documentId, [...(citers.get(documentId) ?? []), shortId(index)]);
66
+ });
67
+ return citers;
68
+ };
69
+ /**
70
+ * What a list of references points at: its pages, and the passages of the
71
+ * documents its STACKFACTOR references cite. One search per knowledge base per
72
+ * query (per batch of 500 documents), however many references there are. With
73
+ * no token no search is made and the pages are still listed. A knowledge base
74
+ * the person cannot open is in `skipped`; the other passages stand.
75
+ * @param options `references` (a skill's, a microskill's…), `queries` to
76
+ * search the cited documents with, `search` (client-api
77
+ * `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK` per
78
+ * search (default 5)
79
+ * @returns `{ pages, passages, skipped, citesKnowledge }`
80
+ */
81
+ export const gatherReferenceContext = async (options) => {
82
+ const references = Array.isArray(options.references) ? options.references : [];
83
+ const sources = sourcesFromReferences(references);
84
+ const citesKnowledge = sources.length > 0;
85
+ const pages = pagesOf(references);
86
+ if (!options.token || !citesKnowledge) {
87
+ logContext(pages.length, 0, [], citesKnowledge && !options.token);
88
+ return { citesKnowledge, pages, passages: [], skipped: [] };
89
+ }
90
+ const found = await retrievePassages({
91
+ queries: options.queries,
92
+ search: options.search,
93
+ sources,
94
+ token: options.token,
95
+ topK: options.topK ?? DEFAULT_REFERENCE_TOP_K,
96
+ });
97
+ const citers = citersByDocument(references);
98
+ const passages = found.passages
99
+ .filter((passage) => citers.has(passage.documentId))
100
+ .map((passage) => ({
101
+ chunkId: passage.chunkId,
102
+ document: passage.documentName,
103
+ documentId: passage.documentId,
104
+ knowledgeBaseId: passage.knowledgeBaseId,
105
+ references: citers.get(passage.documentId),
106
+ section: passage.sectionTitle,
107
+ text: passage.text,
108
+ }));
109
+ logContext(pages.length, passages.length, found.skipped, false);
110
+ return { citesKnowledge, pages, passages, skipped: found.skipped };
111
+ };
112
+ /** The one summary line of a gathering, for the logs. */
113
+ const logContext = (pages, passages, skipped, noToken) => {
114
+ const parts = [`${pages} page${pages === 1 ? "" : "s"}`, `${passages} passage${passages === 1 ? "" : "s"}`];
115
+ if (skipped.length > 0) {
116
+ parts.push(`skipped knowledge bases: ${skipped.map((s) => `${s.knowledgeBaseId} (noAccess: ${s.noAccess})`).join(", ")}`);
117
+ }
118
+ if (noToken)
119
+ parts.push("no token, so no passages");
120
+ logger.log(null, logger.levels.info, `Reference context: ${parts.join("; ")}`);
121
+ };
122
+ /**
123
+ * The passages as a prompt shows them: who cites each, where it came from, and
124
+ * its text. The ids that locate it in the platform are left out.
125
+ * @param context From `gatherReferenceContext`
126
+ * @returns `[{ references, document, section, text }]`, for the model's input
127
+ */
128
+ export const referencePassagesForPrompt = (context) => context.passages.map((passage) => ({
129
+ document: passage.document,
130
+ references: passage.references,
131
+ section: passage.section,
132
+ text: passage.text,
133
+ }));
134
+ /**
135
+ * The tools a run is given. Never `search`, `map` or `crawl`: a run reads what
136
+ * its references point at and discovers nothing. `extract` only, and only when
137
+ * there are pages to open.
138
+ * @param context From `gatherReferenceContext`
139
+ * @returns `{ tavily: { tools: ["extract"] } }` with pages, else `{}`. With no
140
+ * pages it returns `{}`, so a caller spreading it over a config that already
141
+ * has a `tavily` key keeps that key (and `tavily: true` means search plus
142
+ * extract): callers must not carry a base `tavily` key.
143
+ */
144
+ export const toolsFor = (context) => context.pages.length > 0 ? { tavily: { tools: ["extract"] } } : {};
145
+ /**
146
+ * The stage prompt followed by the guidance for each kind of source the run
147
+ * has: pages, then passages; when it has neither, the `none` guidance. An empty
148
+ * guidance adds nothing.
149
+ * @param stagePrompt The stage's own prompt
150
+ * @param context From `gatherReferenceContext`
151
+ * @param guidance From `sourceGuidanceFrom`
152
+ * @returns The sections joined with a blank line
153
+ */
154
+ export const composeSourceInstructions = (stagePrompt, context, guidance) => {
155
+ const sections = [];
156
+ if (context.pages.length > 0)
157
+ sections.push(guidance.pages);
158
+ if (context.passages.length > 0)
159
+ sections.push(guidance.passages);
160
+ if (sections.length === 0)
161
+ sections.push(guidance.none);
162
+ return [stagePrompt, ...sections].filter(Boolean).join("\n\n");
163
+ };
164
+ /**
165
+ * A reference as a model is shown it. A STACKFACTOR reference loses its pointer
166
+ * and its url (ids mean nothing to a model, and the url is behind the
167
+ * organization's own sign-in); the model cites it by short id.
168
+ * @param reference A supplied reference
169
+ * @returns The reference; a STACKFACTOR one without `_id`, `origin`, `visibility`,
170
+ * `target`, `knowledgeBase` and `url`
171
+ */
172
+ export const referenceForModel = (reference) => {
173
+ if (reference?.kind !== STACKFACTOR_REFERENCE.KIND)
174
+ return reference;
175
+ const { _id: _i, origin: _o, visibility: _v, target: _target, knowledgeBase: _knowledgeBase, url: _url, ...rest } = reference;
176
+ return rest;
177
+ };
178
+ /**
179
+ * The supplied references as a model is shown them, each under its short id
180
+ * `r<N>` (N the index in the supplied list) as `_id`, set last so a stored
181
+ * reference's own id never wins. Non-object entries are skipped but keep their
182
+ * index, so the ids stay aligned with `citedReferences`.
183
+ * @param references The supplied list
184
+ */
185
+ export const referencesForModel = (references) => {
186
+ const shown = [];
187
+ (Array.isArray(references) ? references : []).forEach((reference, index) => {
188
+ if (!reference || typeof reference !== "object")
189
+ return;
190
+ const { _id: _ignored, ...rest } = referenceForModel(reference);
191
+ shown.push({ ...rest, _id: shortId(index) });
192
+ });
193
+ return shown;
194
+ };
195
+ /** What a STACKFACTOR reference points at, as the platform stores it. */
196
+ const stackfactorPointers = (reference) => {
197
+ if (reference.kind !== STACKFACTOR_REFERENCE.KIND)
198
+ return {};
199
+ const pointer = reference.knowledgeBase;
200
+ if (pointer?.knowledgeBaseId && pointer?.documentId) {
201
+ return {
202
+ knowledgeBase: { ...pointer },
203
+ target: {
204
+ elementType: STACKFACTOR_REFERENCE.TARGET_ELEMENT_TYPE,
205
+ elementId: pointer.documentId,
206
+ parentId: pointer.knowledgeBaseId,
207
+ },
208
+ };
209
+ }
210
+ return reference.target?.elementType && reference.target?.elementId ? { target: { ...reference.target } } : {};
211
+ };
212
+ /**
213
+ * A reference from the flat projection the host sends (or the flat shape a
214
+ * model emits) in the shape the platform stores: nested `publication`,
215
+ * `relatedTo` folded into `description`, a STACKFACTOR reference's pointer and
216
+ * target kept. `visibility` is never set; the caller decides it.
217
+ * @param reference The flat reference
218
+ * @param origin Default `"AI_GENERATED"`
219
+ */
220
+ export const toStoredReference = (reference, origin = "AI_GENERATED") => {
221
+ const publication = {
222
+ ...(reference.author ? { author: reference.author } : {}),
223
+ ...(reference.publisher ? { publisher: reference.publisher } : {}),
224
+ ...(reference.identifier ? { identifier: reference.identifier } : {}),
225
+ ...(reference.locator ? { locator: reference.locator } : {}),
226
+ ...(reference.publication || {}),
227
+ };
228
+ const description = [reference.description, reference.relatedTo ? `Related to: ${reference.relatedTo}` : null]
229
+ .filter(Boolean)
230
+ .join(" \u2014 ");
231
+ return {
232
+ kind: reference.kind,
233
+ title: reference.title,
234
+ ...(description ? { description } : {}),
235
+ ...(reference.url ? { url: reference.url } : {}),
236
+ ...(Object.keys(publication).length > 0 ? { publication } : {}),
237
+ ...stackfactorPointers(reference),
238
+ origin,
239
+ };
240
+ };
241
+ /**
242
+ * The supplied references a model cited by short id, stored. Ids are matched
243
+ * trimmed and case-insensitively; unknown and non-string ids are dropped and
244
+ * each reference appears once, at its first citation.
245
+ * @param ids The model's cited ids (`["r0", "r3"]`)
246
+ * @param supplied The list the ids index into
247
+ * @param origin Default `"AI_GENERATED"`
248
+ */
249
+ export const citedReferences = (ids, supplied, origin) => {
250
+ const list = Array.isArray(supplied) ? supplied : [];
251
+ const taken = new Set();
252
+ const cited = [];
253
+ for (const raw of Array.isArray(ids) ? ids : []) {
254
+ const match = typeof raw === "string" ? /^r(\d+)$/.exec(raw.trim().toLowerCase()) : null;
255
+ const index = match ? Number(match[1]) : -1;
256
+ if (!list[index] || typeof list[index] !== "object" || taken.has(index))
257
+ continue;
258
+ taken.add(index);
259
+ cited.push(toStoredReference(list[index], origin));
260
+ }
261
+ return cited;
262
+ };
263
+ /**
264
+ * The three guidance texts an agent's config holds. A missing or non-string
265
+ * value is an empty string.
266
+ * @param config The agent's config
267
+ */
268
+ export const sourceGuidanceFrom = (config) => ({
269
+ pages: text(config?.referencedPagesGuidance),
270
+ passages: text(config?.knowledgeBasePassagesGuidance),
271
+ none: text(config?.noReferencesGuidance),
272
+ });
273
+ export default {
274
+ REFERENCE_PASSAGES_KEY,
275
+ citedReferences,
276
+ composeSourceInstructions,
277
+ gatherReferenceContext,
278
+ referenceForModel,
279
+ referencePassagesForPrompt,
280
+ referencesForModel,
281
+ sourceGuidanceFrom,
282
+ toStoredReference,
283
+ toolsFor,
284
+ };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.10.0",
6
+ "version": "1.11.0",
7
7
  "description": "",
8
8
  "main": "dist/cjs/index.js",
9
9
  "module": "dist/esm/index.js",