@stackfactor/agent-utils 1.4.3 → 1.8.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 +81 -6
- package/dist/cjs/errorHandling.d.ts.map +1 -1
- package/dist/cjs/errorHandling.js +10 -5
- package/dist/cjs/index.d.ts +8 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +9 -1
- package/dist/cjs/langChain.d.ts +25 -5
- package/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +244 -179
- package/dist/cjs/runtimeContext.d.ts +3 -0
- package/dist/cjs/runtimeContext.d.ts.map +1 -1
- package/dist/cjs/serve.d.ts +88 -0
- package/dist/cjs/serve.d.ts.map +1 -1
- package/dist/cjs/serve.js +230 -3
- package/dist/cjs/stackfactorKnowledge.d.ts +182 -0
- package/dist/cjs/stackfactorKnowledge.d.ts.map +1 -0
- package/dist/cjs/stackfactorKnowledge.js +274 -0
- package/dist/cjs/tavily.d.ts +4 -0
- package/dist/cjs/tavily.d.ts.map +1 -1
- package/dist/cjs/tavily.js +17 -18
- package/dist/cjs/usage.d.ts +74 -0
- package/dist/cjs/usage.d.ts.map +1 -0
- package/dist/cjs/usage.js +160 -0
- package/dist/esm/errorHandling.d.ts.map +1 -1
- package/dist/esm/errorHandling.js +10 -5
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +6 -2
- package/dist/esm/langChain.d.ts +25 -5
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +244 -179
- package/dist/esm/runtimeContext.d.ts +3 -0
- package/dist/esm/runtimeContext.d.ts.map +1 -1
- package/dist/esm/serve.d.ts +88 -0
- package/dist/esm/serve.d.ts.map +1 -1
- package/dist/esm/serve.js +226 -3
- package/dist/esm/stackfactorKnowledge.d.ts +182 -0
- package/dist/esm/stackfactorKnowledge.d.ts.map +1 -0
- package/dist/esm/stackfactorKnowledge.js +266 -0
- package/dist/esm/tavily.d.ts +4 -0
- package/dist/esm/tavily.d.ts.map +1 -1
- package/dist/esm/tavily.js +17 -18
- package/dist/esm/usage.d.ts +74 -0
- package/dist/esm/usage.d.ts.map +1 -0
- package/dist/esm/usage.js +150 -0
- package/package.json +14 -8
package/dist/cjs/serve.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
import { type ReportUsage } from "./usage.js";
|
|
2
3
|
/**
|
|
3
4
|
* The agent entry point. Reads `params` / `config` / `onProgress` from globals
|
|
4
5
|
* (populated per-request by {@link serve}) and returns the structured result.
|
|
@@ -22,7 +23,94 @@ export interface ServeOptions {
|
|
|
22
23
|
host?: string;
|
|
23
24
|
/** Override the auth check (e.g. in tests). Defaults to {@link defaultAuthenticate}. */
|
|
24
25
|
authenticate?: Authenticator;
|
|
26
|
+
/** Run-once mode only: override the envelope fetch (e.g. in tests). */
|
|
27
|
+
fetchEnvelope?: (batchJobId: string, token: string) => Promise<any>;
|
|
28
|
+
/** Run-once mode only: override the run lifecycle (e.g. in tests). */
|
|
29
|
+
lifecycle?: RunLifecycle;
|
|
30
|
+
/** Run-once mode only: override process exit (e.g. in tests). */
|
|
31
|
+
exit?: (code: number) => void;
|
|
32
|
+
/** Override how what the work used is reported to the platform (e.g. in tests). */
|
|
33
|
+
reportUsage?: ReportUsage;
|
|
34
|
+
/** Override how often running work reports what it used so far (e.g. in tests). */
|
|
35
|
+
usageReportIntervalMs?: number;
|
|
25
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* How an execution reports its own run to the platform: it claims the run
|
|
39
|
+
* before doing the work, says it is alive while it does, and settles it with
|
|
40
|
+
* the outcome. Every call carries the execution's AGENT token, which the
|
|
41
|
+
* platform minted for this run and which names it — which run is never the
|
|
42
|
+
* execution's to assert.
|
|
43
|
+
*/
|
|
44
|
+
export interface RunLifecycle {
|
|
45
|
+
claim: (token: string) => Promise<{
|
|
46
|
+
claimed: boolean;
|
|
47
|
+
}>;
|
|
48
|
+
heartbeat: (token: string) => Promise<void>;
|
|
49
|
+
settle: (status: number, outcome: unknown, token: string) => Promise<{
|
|
50
|
+
settled: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Environment a Cloud Run JOB execution is started with by the platform
|
|
55
|
+
* (stackfactor-batch-jobs, agentJobExecutions.ts): references only — the
|
|
56
|
+
* event record, the integration, the tenant, and a token minted for this
|
|
57
|
+
* execution alone. Their presence is what switches {@link serve} into run-once
|
|
58
|
+
* mode; the payload and the tenant's configuration are fetched, never passed.
|
|
59
|
+
*/
|
|
60
|
+
export declare const EXECUTION_ENV: {
|
|
61
|
+
readonly BATCH_JOB_ID: "SF_EXECUTION_BATCH_JOB_ID";
|
|
62
|
+
readonly INTEGRATION_ID: "SF_EXECUTION_INTEGRATION_ID";
|
|
63
|
+
readonly TENANT_ID: "SF_EXECUTION_TENANT_ID";
|
|
64
|
+
readonly TOKEN: "SF_EXECUTION_TOKEN";
|
|
65
|
+
};
|
|
66
|
+
/** True when this process was started as a job execution rather than a service. */
|
|
67
|
+
export declare const isRunOnceExecution: (env?: NodeJS.ProcessEnv) => boolean;
|
|
68
|
+
/**
|
|
69
|
+
* True for the one kind of run that is ALLOWED to carry no StackFactor token: a
|
|
70
|
+
* delivery to a webhook declared `requireToken: false`. There the platform
|
|
71
|
+
* authenticates nobody and passes the provider's request to the integration as
|
|
72
|
+
* it arrived, so there is no token to validate and no session to build — the
|
|
73
|
+
* handler verifies its provider itself, and brings its own API key (from its
|
|
74
|
+
* configuration) if it has to act on the platform.
|
|
75
|
+
*
|
|
76
|
+
* This does not open the agent up. The Execute RPC is reachable only by callers
|
|
77
|
+
* holding Cloud Run's invoker role — the backend and the batch worker — so a
|
|
78
|
+
* request with no token means the platform CHOSE to send none, and it only ever
|
|
79
|
+
* does that for such a webhook. A token that IS present is always validated,
|
|
80
|
+
* whatever the event, and every other event still requires one.
|
|
81
|
+
*/
|
|
82
|
+
export declare const isAnonymousWebhookRun: (event: any, request: any) => boolean;
|
|
83
|
+
/**
|
|
84
|
+
* True for the runs that are ALLOWED to carry no StackFactor token, because
|
|
85
|
+
* the platform starts them with no identity on purpose:
|
|
86
|
+
* - a delivery to a `requireToken: false` webhook (isAnonymousWebhookRun);
|
|
87
|
+
* - a scheduled run: the clock is nobody.
|
|
88
|
+
* Both run with `session: null`. Since backend-core's decision record §11 the
|
|
89
|
+
* platform starts both with a token of their own (the integration's managed
|
|
90
|
+
* account in the tenant), so against a current platform neither is ever
|
|
91
|
+
* tokenless and this answers false; it stays for a platform that predates
|
|
92
|
+
* that, and can go once none does. The reasoning of isAnonymousWebhookRun holds
|
|
93
|
+
* for both: only the platform can reach Execute or start an execution, so no
|
|
94
|
+
* token means the platform chose to send none. A token that IS present is
|
|
95
|
+
* always validated, and every other event still requires one.
|
|
96
|
+
*/
|
|
97
|
+
export declare const isAnonymousRun: (event: any, request: any) => boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Run-once mode: the same agent, started as one Cloud Run JOB execution for
|
|
100
|
+
* one platform event (`runAs: job`). Fetches the execution's envelope from the
|
|
101
|
+
* backend with the execution's token — exactly what a service call would have
|
|
102
|
+
* received in its Execute request — binds the same {@link RequestContext} the
|
|
103
|
+
* gRPC path binds, runs the handler once, and exits: 0 on success, 1 on any
|
|
104
|
+
* failure so Cloud Run retries the task. SIGTERM (Cloud Run cancelling the
|
|
105
|
+
* execution or its task timeout) aborts the in-flight work.
|
|
106
|
+
*
|
|
107
|
+
* The execution reports its own run: it claims it before doing the work (an
|
|
108
|
+
* execution that loses the claim exits 0 without repeating it), says it is
|
|
109
|
+
* alive while it runs, and settles it with the outcome. The handler is
|
|
110
|
+
* written once and does not know which runtime it is on, nor that any of this
|
|
111
|
+
* is happening.
|
|
112
|
+
*/
|
|
113
|
+
export declare const runOnce: (main: AgentMain, options?: ServeOptions) => Promise<void>;
|
|
26
114
|
/**
|
|
27
115
|
* Start a gRPC server that exposes `main` as the fleet-standard `Agent.Execute`
|
|
28
116
|
* RPC. Per request it binds a {@link RequestContext} (so the agent's globals are
|
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;
|
|
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;AA4JrD;;;;;;;;;;;;;;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
|
@@ -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.serve = void 0;
|
|
39
|
+
exports.serve = exports.runOnce = exports.isAnonymousRun = exports.isAnonymousWebhookRun = exports.isRunOnceExecution = exports.EXECUTION_ENV = void 0;
|
|
40
40
|
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
41
41
|
const node_fs_1 = require("node:fs");
|
|
42
42
|
const node_path_1 = require("node:path");
|
|
@@ -45,6 +45,7 @@ const client_api_1 = require("@stackfactor/client-api");
|
|
|
45
45
|
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
46
46
|
const agentProto_js_1 = require("./agentProto.js");
|
|
47
47
|
const runtimeContext_js_1 = require("./runtimeContext.js");
|
|
48
|
+
const usage_js_1 = require("./usage.js");
|
|
48
49
|
// Genuine dynamic `import()` that survives TypeScript's CJS downlevelling (which
|
|
49
50
|
// would otherwise turn `import()` into `require()` and break file:// URLs and
|
|
50
51
|
// ESM check modules). Built once; see the call site in runSelfCheck.
|
|
@@ -234,6 +235,63 @@ const runSelfCheck = async (checkCode, config, session) => {
|
|
|
234
235
|
clearTimeout(timer);
|
|
235
236
|
}
|
|
236
237
|
};
|
|
238
|
+
/** How often a running execution says it is still alive. */
|
|
239
|
+
const HEARTBEAT_MS = 30_000;
|
|
240
|
+
/**
|
|
241
|
+
* Environment a Cloud Run JOB execution is started with by the platform
|
|
242
|
+
* (stackfactor-batch-jobs, agentJobExecutions.ts): references only — the
|
|
243
|
+
* event record, the integration, the tenant, and a token minted for this
|
|
244
|
+
* execution alone. Their presence is what switches {@link serve} into run-once
|
|
245
|
+
* mode; the payload and the tenant's configuration are fetched, never passed.
|
|
246
|
+
*/
|
|
247
|
+
exports.EXECUTION_ENV = {
|
|
248
|
+
BATCH_JOB_ID: "SF_EXECUTION_BATCH_JOB_ID",
|
|
249
|
+
INTEGRATION_ID: "SF_EXECUTION_INTEGRATION_ID",
|
|
250
|
+
TENANT_ID: "SF_EXECUTION_TENANT_ID",
|
|
251
|
+
TOKEN: "SF_EXECUTION_TOKEN",
|
|
252
|
+
};
|
|
253
|
+
/** True when this process was started as a job execution rather than a service. */
|
|
254
|
+
const isRunOnceExecution = (env = process.env) => Boolean(env[exports.EXECUTION_ENV.BATCH_JOB_ID] && env[exports.EXECUTION_ENV.TOKEN]);
|
|
255
|
+
exports.isRunOnceExecution = isRunOnceExecution;
|
|
256
|
+
/** `ExecuteRequest.event` of an inbound webhook delivery (backend-core EVENT_TYPE.WEBHOOK_RECEIVED). */
|
|
257
|
+
const WEBHOOK_RECEIVED = 350;
|
|
258
|
+
/**
|
|
259
|
+
* True for the one kind of run that is ALLOWED to carry no StackFactor token: a
|
|
260
|
+
* delivery to a webhook declared `requireToken: false`. There the platform
|
|
261
|
+
* authenticates nobody and passes the provider's request to the integration as
|
|
262
|
+
* it arrived, so there is no token to validate and no session to build — the
|
|
263
|
+
* handler verifies its provider itself, and brings its own API key (from its
|
|
264
|
+
* configuration) if it has to act on the platform.
|
|
265
|
+
*
|
|
266
|
+
* This does not open the agent up. The Execute RPC is reachable only by callers
|
|
267
|
+
* holding Cloud Run's invoker role — the backend and the batch worker — so a
|
|
268
|
+
* request with no token means the platform CHOSE to send none, and it only ever
|
|
269
|
+
* does that for such a webhook. A token that IS present is always validated,
|
|
270
|
+
* whatever the event, and every other event still requires one.
|
|
271
|
+
*/
|
|
272
|
+
const isAnonymousWebhookRun = (event, request) => Number(event) === WEBHOOK_RECEIVED &&
|
|
273
|
+
!(request?.authToken ?? request?.authorization);
|
|
274
|
+
exports.isAnonymousWebhookRun = isAnonymousWebhookRun;
|
|
275
|
+
/** `ExecuteRequest.event` of a scheduled run (backend-core EVENT_TYPE.SCHEDULED_RUN). */
|
|
276
|
+
const SCHEDULED_RUN = 510;
|
|
277
|
+
/**
|
|
278
|
+
* True for the runs that are ALLOWED to carry no StackFactor token, because
|
|
279
|
+
* the platform starts them with no identity on purpose:
|
|
280
|
+
* - a delivery to a `requireToken: false` webhook (isAnonymousWebhookRun);
|
|
281
|
+
* - a scheduled run: the clock is nobody.
|
|
282
|
+
* Both run with `session: null`. Since backend-core's decision record §11 the
|
|
283
|
+
* platform starts both with a token of their own (the integration's managed
|
|
284
|
+
* account in the tenant), so against a current platform neither is ever
|
|
285
|
+
* tokenless and this answers false; it stays for a platform that predates
|
|
286
|
+
* that, and can go once none does. The reasoning of isAnonymousWebhookRun holds
|
|
287
|
+
* for both: only the platform can reach Execute or start an execution, so no
|
|
288
|
+
* token means the platform chose to send none. A token that IS present is
|
|
289
|
+
* always validated, and every other event still requires one.
|
|
290
|
+
*/
|
|
291
|
+
const isAnonymousRun = (event, request) => (0, exports.isAnonymousWebhookRun)(event, request) ||
|
|
292
|
+
(Number(event) === SCHEDULED_RUN &&
|
|
293
|
+
!(request?.authToken ?? request?.authorization));
|
|
294
|
+
exports.isAnonymousRun = isAnonymousRun;
|
|
237
295
|
/** Marks an auth failure so the handler can map it to gRPC UNAUTHENTICATED. */
|
|
238
296
|
class UnauthenticatedError extends Error {
|
|
239
297
|
}
|
|
@@ -336,6 +394,150 @@ const toErrorFrame = (error) => {
|
|
|
336
394
|
}
|
|
337
395
|
return { code: 500, message: String(error?.message ?? error) };
|
|
338
396
|
};
|
|
397
|
+
/** How the platform records a settled run (backend-core BATCH_JOB.STATUS). */
|
|
398
|
+
const RUN_STATUS = { COMPLETED: 2, FAILED: 3 };
|
|
399
|
+
/**
|
|
400
|
+
* Settles the run this execution claimed, if it claimed one. Never throws and
|
|
401
|
+
* never changes the execution's own outcome: the work either happened or it
|
|
402
|
+
* did not, and a platform that cannot be told so right now will time the run
|
|
403
|
+
* out on its own. `settled: false` means it already did.
|
|
404
|
+
*/
|
|
405
|
+
const settleRun = async (claimed, lifecycle, status, outcome, batchJobId) => {
|
|
406
|
+
if (!claimed)
|
|
407
|
+
return;
|
|
408
|
+
try {
|
|
409
|
+
const answer = await lifecycle.settle(status, outcome ?? null, claimed.token);
|
|
410
|
+
if (!answer?.settled) {
|
|
411
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.warn, `run-once execution for event record ${batchJobId}: the run was no longer running, so its outcome was not recorded`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.warn, `run-once execution for event record ${batchJobId}: settling the run failed: ${error?.message ?? error}`);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
/**
|
|
419
|
+
* Run-once mode: the same agent, started as one Cloud Run JOB execution for
|
|
420
|
+
* one platform event (`runAs: job`). Fetches the execution's envelope from the
|
|
421
|
+
* backend with the execution's token — exactly what a service call would have
|
|
422
|
+
* received in its Execute request — binds the same {@link RequestContext} the
|
|
423
|
+
* gRPC path binds, runs the handler once, and exits: 0 on success, 1 on any
|
|
424
|
+
* failure so Cloud Run retries the task. SIGTERM (Cloud Run cancelling the
|
|
425
|
+
* execution or its task timeout) aborts the in-flight work.
|
|
426
|
+
*
|
|
427
|
+
* The execution reports its own run: it claims it before doing the work (an
|
|
428
|
+
* execution that loses the claim exits 0 without repeating it), says it is
|
|
429
|
+
* alive while it runs, and settles it with the outcome. The handler is
|
|
430
|
+
* written once and does not know which runtime it is on, nor that any of this
|
|
431
|
+
* is happening.
|
|
432
|
+
*/
|
|
433
|
+
const runOnce = async (main, options = {}) => {
|
|
434
|
+
(0, runtimeContext_js_1.installGlobals)();
|
|
435
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
436
|
+
const batchJobId = process.env[exports.EXECUTION_ENV.BATCH_JOB_ID] ?? "";
|
|
437
|
+
const token = process.env[exports.EXECUTION_ENV.TOKEN] ?? "";
|
|
438
|
+
const fetchEnvelope = options.fetchEnvelope ??
|
|
439
|
+
((id, tok) => client_api_1.integration.getExecutionEnvelope(id, tok));
|
|
440
|
+
const authenticate = options.authenticate ?? defaultAuthenticate;
|
|
441
|
+
const abort = new AbortController();
|
|
442
|
+
const onSignal = () => abort.abort();
|
|
443
|
+
process.once("SIGTERM", onSignal);
|
|
444
|
+
process.once("SIGINT", onSignal);
|
|
445
|
+
const lifecycle = options.lifecycle ?? {
|
|
446
|
+
claim: client_api_1.integration.claimExecution,
|
|
447
|
+
heartbeat: client_api_1.integration.heartbeatExecution,
|
|
448
|
+
settle: client_api_1.integration.settleExecution,
|
|
449
|
+
};
|
|
450
|
+
// Set once the run is ours: only an execution that claimed a run settles it.
|
|
451
|
+
let claimed = null;
|
|
452
|
+
let heartbeat = null;
|
|
453
|
+
// What the run used is reported before it is settled, however it ended:
|
|
454
|
+
// settling revokes the token the report is made with.
|
|
455
|
+
let reportWhatWasUsed = async () => { };
|
|
456
|
+
let stopReporting = () => { };
|
|
457
|
+
try {
|
|
458
|
+
const req = await fetchEnvelope(batchJobId, token);
|
|
459
|
+
const request = safeParse(req?.request_json, {});
|
|
460
|
+
// A scheduled run carries no identity by design: see isAnonymousRun.
|
|
461
|
+
const session = (0, exports.isAnonymousRun)(req?.event, request)
|
|
462
|
+
? null
|
|
463
|
+
: await authenticate(request);
|
|
464
|
+
const context = {
|
|
465
|
+
config: safeParse(req?.config_json, {}),
|
|
466
|
+
params: {
|
|
467
|
+
contentType: req?.content_type,
|
|
468
|
+
data: safeParse(req?.data_json, {}),
|
|
469
|
+
},
|
|
470
|
+
request: { ...request, session },
|
|
471
|
+
event: req?.event ?? 0,
|
|
472
|
+
onProgress: (update) => {
|
|
473
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.info, `progress ${Math.round(update?.progress ?? 0)}%: ${update?.message ?? ""}`);
|
|
474
|
+
},
|
|
475
|
+
signal: abort.signal,
|
|
476
|
+
session,
|
|
477
|
+
usage: new usage_js_1.UsageLedger(),
|
|
478
|
+
};
|
|
479
|
+
reportWhatWasUsed = () => (0, usage_js_1.reportUsage)(context, { report: options.reportUsage, last: true });
|
|
480
|
+
let entry = main;
|
|
481
|
+
const entryPath = String(req?.code ?? "").trim();
|
|
482
|
+
if (entryPath) {
|
|
483
|
+
const loaded = await loadAgentModule(entryPath, "handler");
|
|
484
|
+
if (loaded.reason) {
|
|
485
|
+
throw new Error(`entry module "${entryPath}" could not be loaded (${loaded.reason}): ${loaded.detail}`);
|
|
486
|
+
}
|
|
487
|
+
entry = loaded.fn;
|
|
488
|
+
}
|
|
489
|
+
// Claim before doing anything. Of however many executions the platform may
|
|
490
|
+
// start for one run — a retried task, a redelivered message — exactly one
|
|
491
|
+
// wins; the others exit 0 without repeating the work, which is not a
|
|
492
|
+
// failure and must not be retried. The execution's token names its run
|
|
493
|
+
// (every run, scheduled ones included, is started with one), so nothing
|
|
494
|
+
// else is sent.
|
|
495
|
+
const answer = await lifecycle.claim(token);
|
|
496
|
+
if (!answer?.claimed) {
|
|
497
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.info, `run-once execution for event record ${batchJobId}: another execution already claimed this run, nothing to do`);
|
|
498
|
+
exit(0);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
claimed = { token };
|
|
502
|
+
heartbeat = setInterval(() => {
|
|
503
|
+
void lifecycle
|
|
504
|
+
.heartbeat(token)
|
|
505
|
+
.catch((error) => logger_js_1.default.log(null, logger_js_1.default.levels.warn, `run-once execution for event record ${batchJobId}: heartbeat failed: ${error?.message ?? error}`));
|
|
506
|
+
}, HEARTBEAT_MS);
|
|
507
|
+
heartbeat.unref?.();
|
|
508
|
+
stopReporting = (0, usage_js_1.reportUsageWhileRunning)(context, {
|
|
509
|
+
report: options.reportUsage,
|
|
510
|
+
intervalMs: options.usageReportIntervalMs,
|
|
511
|
+
});
|
|
512
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.info, `run-once execution for event record ${batchJobId} (${req?.content_type ?? ""}) starting`);
|
|
513
|
+
const result = await (0, runtimeContext_js_1.runWithContext)(context, () => entry(abort.signal));
|
|
514
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.info, `run-once execution for event record ${batchJobId} completed: ${JSON.stringify(result ?? null).slice(0, 500)}`);
|
|
515
|
+
stopReporting();
|
|
516
|
+
await reportWhatWasUsed();
|
|
517
|
+
await settleRun(claimed, lifecycle, RUN_STATUS.COMPLETED, result, batchJobId);
|
|
518
|
+
exit(0);
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
const frame = toErrorFrame(error);
|
|
522
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.error, `run-once execution for event record ${batchJobId} failed${abort.signal.aborted ? " (aborted)" : ""}: ${frame.code} ${frame.message}`);
|
|
523
|
+
// Work that failed still used what it used.
|
|
524
|
+
stopReporting();
|
|
525
|
+
await reportWhatWasUsed();
|
|
526
|
+
// The run is ours to close whether it went well or not: a run left
|
|
527
|
+
// running is one the platform has to time out, and its credential lives
|
|
528
|
+
// until it does.
|
|
529
|
+
await settleRun(claimed, lifecycle, RUN_STATUS.FAILED, frame, batchJobId);
|
|
530
|
+
exit(1);
|
|
531
|
+
}
|
|
532
|
+
finally {
|
|
533
|
+
stopReporting();
|
|
534
|
+
if (heartbeat)
|
|
535
|
+
clearInterval(heartbeat);
|
|
536
|
+
process.off("SIGTERM", onSignal);
|
|
537
|
+
process.off("SIGINT", onSignal);
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
exports.runOnce = runOnce;
|
|
339
541
|
/**
|
|
340
542
|
* Start a gRPC server that exposes `main` as the fleet-standard `Agent.Execute`
|
|
341
543
|
* RPC. Per request it binds a {@link RequestContext} (so the agent's globals are
|
|
@@ -348,6 +550,12 @@ const toErrorFrame = (error) => {
|
|
|
348
550
|
* serve(require("./src/main"));
|
|
349
551
|
*/
|
|
350
552
|
const serve = (main, options = {}) => {
|
|
553
|
+
// Started as a job execution: run the handler once and exit instead of
|
|
554
|
+
// serving. Same image, same entrypoint; the environment decides.
|
|
555
|
+
if ((0, exports.isRunOnceExecution)()) {
|
|
556
|
+
void (0, exports.runOnce)(main, options);
|
|
557
|
+
return new grpc.Server();
|
|
558
|
+
}
|
|
351
559
|
(0, runtimeContext_js_1.installGlobals)();
|
|
352
560
|
const port = options.port ?? (Number(process.env.PORT) || 8080);
|
|
353
561
|
const host = options.host ?? "0.0.0.0";
|
|
@@ -370,9 +578,13 @@ const serve = (main, options = {}) => {
|
|
|
370
578
|
};
|
|
371
579
|
const handle = async () => {
|
|
372
580
|
// Authenticate first — refuse the call when the token is missing/invalid.
|
|
373
|
-
|
|
581
|
+
// The exceptions carry no token by design and run with no session: see
|
|
582
|
+
// isAnonymousRun.
|
|
583
|
+
let session = null;
|
|
374
584
|
try {
|
|
375
|
-
|
|
585
|
+
if (!(0, exports.isAnonymousRun)(req.event, request)) {
|
|
586
|
+
session = await authenticate(request);
|
|
587
|
+
}
|
|
376
588
|
}
|
|
377
589
|
catch (error) {
|
|
378
590
|
const message = error?.message ?? "Unauthenticated";
|
|
@@ -397,6 +609,7 @@ const serve = (main, options = {}) => {
|
|
|
397
609
|
onProgress,
|
|
398
610
|
signal: abort.signal,
|
|
399
611
|
session,
|
|
612
|
+
usage: new usage_js_1.UsageLedger(),
|
|
400
613
|
};
|
|
401
614
|
// Which function actually runs. Default is the agent's own `main` — the
|
|
402
615
|
// path every caller took before `code` existed, and still the path taken
|
|
@@ -427,8 +640,21 @@ const serve = (main, options = {}) => {
|
|
|
427
640
|
}
|
|
428
641
|
entry = loaded.fn;
|
|
429
642
|
}
|
|
643
|
+
// What the call used is reported before it is answered, however it
|
|
644
|
+
// ended — a call that failed, or that its caller gave up on, still used
|
|
645
|
+
// what it used — because the platform revokes the call's token as soon
|
|
646
|
+
// as it has the answer.
|
|
647
|
+
const stopReporting = (0, usage_js_1.reportUsageWhileRunning)(context, {
|
|
648
|
+
report: options.reportUsage,
|
|
649
|
+
intervalMs: options.usageReportIntervalMs,
|
|
650
|
+
});
|
|
651
|
+
const reportWhatWasUsed = async () => {
|
|
652
|
+
stopReporting();
|
|
653
|
+
await (0, usage_js_1.reportUsage)(context, { report: options.reportUsage, last: true });
|
|
654
|
+
};
|
|
430
655
|
try {
|
|
431
656
|
const result = await (0, runtimeContext_js_1.runWithContext)(context, () => entry(abort.signal));
|
|
657
|
+
await reportWhatWasUsed();
|
|
432
658
|
if (!abort.signal.aborted) {
|
|
433
659
|
call.write({
|
|
434
660
|
result: { result_json: JSON.stringify(result ?? null) },
|
|
@@ -436,6 +662,7 @@ const serve = (main, options = {}) => {
|
|
|
436
662
|
}
|
|
437
663
|
}
|
|
438
664
|
catch (error) {
|
|
665
|
+
await reportWhatWasUsed();
|
|
439
666
|
if (!abort.signal.aborted) {
|
|
440
667
|
logger_js_1.default.log(null, logger_js_1.default.levels.error, `agent Execute failed: ${error?.message ?? error}`);
|
|
441
668
|
call.write({ error: toErrorFrame(error) });
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/** What a STACKFACTOR reference to a knowledge base document carries (backend-core REFERENCE). */
|
|
2
|
+
export declare const STACKFACTOR_REFERENCE: Readonly<{
|
|
3
|
+
KIND: "STACKFACTOR";
|
|
4
|
+
TARGET_ELEMENT_TYPE: "KNOWLEDGE_BASE_DOCUMENT";
|
|
5
|
+
ORIGIN: "KB_EXTRACTION";
|
|
6
|
+
VISIBILITY: "EDIT";
|
|
7
|
+
}>;
|
|
8
|
+
/** How many documents one search may be kept to (the backend's bound); more are split. */
|
|
9
|
+
export declare const SEARCH_DOCUMENT_IDS_MAX = 500;
|
|
10
|
+
/** How long a query may be (the backend's bound); longer ones are cut. */
|
|
11
|
+
export declare const QUERY_MAX_LENGTH = 4000;
|
|
12
|
+
/** How many passages one search asks for when the caller does not say. */
|
|
13
|
+
export declare const DEFAULT_TOP_K = 8;
|
|
14
|
+
/** A chunk as the platform's search answers it (client-api `RetrievedChunk`). */
|
|
15
|
+
export interface KnowledgeChunk {
|
|
16
|
+
_id: string;
|
|
17
|
+
knowledgeBaseId?: string;
|
|
18
|
+
documentId: string;
|
|
19
|
+
documentName?: string | null;
|
|
20
|
+
sectionTitle?: string | null;
|
|
21
|
+
pageNumber?: number | null;
|
|
22
|
+
text?: string;
|
|
23
|
+
skills?: {
|
|
24
|
+
name: string | null;
|
|
25
|
+
microSkills?: string[];
|
|
26
|
+
}[];
|
|
27
|
+
score?: number | null;
|
|
28
|
+
[field: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
/** The platform's search, as client-api's `knowledgeBaseAgent.search` is called. */
|
|
31
|
+
export type KnowledgeSearch = (knowledgeBaseId: string, query: string, options: {
|
|
32
|
+
topK?: number;
|
|
33
|
+
documentIds?: string[];
|
|
34
|
+
}, token: string) => Promise<{
|
|
35
|
+
chunks: KnowledgeChunk[];
|
|
36
|
+
}>;
|
|
37
|
+
/** Where to search: a whole knowledge base, or only some of its documents. */
|
|
38
|
+
export interface KnowledgeSource {
|
|
39
|
+
knowledgeBaseId: string;
|
|
40
|
+
/** Only these documents; omitted, the whole knowledge base. */
|
|
41
|
+
documentIds?: string[];
|
|
42
|
+
}
|
|
43
|
+
/** A passage handed to the model, tagged so it can cite it. */
|
|
44
|
+
export interface GroundingPassage {
|
|
45
|
+
/** "k1", "k2"… in the order they rank. */
|
|
46
|
+
tag: string;
|
|
47
|
+
chunkId: string;
|
|
48
|
+
knowledgeBaseId: string;
|
|
49
|
+
documentId: string;
|
|
50
|
+
documentName: string | null;
|
|
51
|
+
sectionTitle: string | null;
|
|
52
|
+
pageNumber: number | null;
|
|
53
|
+
text: string;
|
|
54
|
+
/** The skills its passage teaches, as labelling named them. */
|
|
55
|
+
skills: {
|
|
56
|
+
name: string | null;
|
|
57
|
+
microSkills: string[];
|
|
58
|
+
}[];
|
|
59
|
+
score: number | null;
|
|
60
|
+
}
|
|
61
|
+
/** A knowledge base that could not be searched, and why. */
|
|
62
|
+
export interface SkippedSource {
|
|
63
|
+
knowledgeBaseId: string;
|
|
64
|
+
/** The HTTP status, when the platform answered one. */
|
|
65
|
+
status: number | null;
|
|
66
|
+
/** True when the person may not read it (or it is gone): expected, not a fault. */
|
|
67
|
+
noAccess: boolean;
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
/** A STACKFACTOR reference to the knowledge base document a passage came from. */
|
|
71
|
+
export interface StackFactorReference {
|
|
72
|
+
kind: "STACKFACTOR";
|
|
73
|
+
title: string;
|
|
74
|
+
description: string | null;
|
|
75
|
+
target: {
|
|
76
|
+
elementType: "KNOWLEDGE_BASE_DOCUMENT";
|
|
77
|
+
elementId: string;
|
|
78
|
+
parentId: string;
|
|
79
|
+
};
|
|
80
|
+
knowledgeBase: {
|
|
81
|
+
knowledgeBaseId: string;
|
|
82
|
+
documentId: string;
|
|
83
|
+
chunkId: string;
|
|
84
|
+
sectionTitle: string | null;
|
|
85
|
+
};
|
|
86
|
+
origin: "KB_EXTRACTION";
|
|
87
|
+
visibility: "EDIT";
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The knowledge bases, and the documents in them, that a list of references
|
|
91
|
+
* cites: its STACKFACTOR references to knowledge base documents, by their
|
|
92
|
+
* `knowledgeBase` ids, or by their `target` when only that is there. Any other
|
|
93
|
+
* reference is passed over. Each knowledge base once, its documents once each,
|
|
94
|
+
* in the order they first appear.
|
|
95
|
+
* @param references A skill's (or a microskill's) references
|
|
96
|
+
* @returns The sources to search
|
|
97
|
+
*/
|
|
98
|
+
export declare const sourcesFromReferences: (references: unknown) => KnowledgeSource[];
|
|
99
|
+
/**
|
|
100
|
+
* The knowledge bases skill coverage found (client-api
|
|
101
|
+
* `knowledgeBase.getSkillCoverage`): every one the person can open that holds
|
|
102
|
+
* the skill, each searched whole.
|
|
103
|
+
* @param coverage The coverage answer, `{ knowledgeBases: [{ _id }] }`
|
|
104
|
+
* @returns The sources to search
|
|
105
|
+
*/
|
|
106
|
+
export declare const sourcesFromCoverage: (coverage: unknown) => KnowledgeSource[];
|
|
107
|
+
/**
|
|
108
|
+
* Searches every source for every query, under the person's access, and hands
|
|
109
|
+
* back the passages found, best first, each once, tagged "k1", "k2"… for the
|
|
110
|
+
* model to cite. A source with documents is searched within them (in batches of
|
|
111
|
+
* SEARCH_DOCUMENT_IDS_MAX); one without, whole. A source the person may not
|
|
112
|
+
* read (401, 403, 404) is skipped: none of its passages are used and no more of
|
|
113
|
+
* its searches are made. A search that fails otherwise is reported and the
|
|
114
|
+
* passages its other searches found stand. Either way it is in `skipped`, once
|
|
115
|
+
* per knowledge base, and the passages of the others stand.
|
|
116
|
+
* @param options `sources`, `queries`, `search` (client-api
|
|
117
|
+
* `knowledgeBaseAgent.search`), `token` (the run's AGENT token), `topK`
|
|
118
|
+
* per search (default DEFAULT_TOP_K)
|
|
119
|
+
* @returns `{ passages, skipped }`
|
|
120
|
+
*/
|
|
121
|
+
export declare const retrievePassages: (options: {
|
|
122
|
+
sources: KnowledgeSource[];
|
|
123
|
+
queries: string[];
|
|
124
|
+
search: KnowledgeSearch;
|
|
125
|
+
token: string;
|
|
126
|
+
topK?: number;
|
|
127
|
+
}) => Promise<{
|
|
128
|
+
passages: GroundingPassage[];
|
|
129
|
+
skipped: SkippedSource[];
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* The passages as a prompt shows them: tag, where each came from, and its text.
|
|
133
|
+
* @param passages From `retrievePassages`
|
|
134
|
+
* @returns `[{ tag, document, section, text }]`, for the model's input
|
|
135
|
+
*/
|
|
136
|
+
export declare const passagesForPrompt: (passages: GroundingPassage[]) => {
|
|
137
|
+
tag: string;
|
|
138
|
+
document: string | null;
|
|
139
|
+
section: string | null;
|
|
140
|
+
text: string;
|
|
141
|
+
}[];
|
|
142
|
+
/**
|
|
143
|
+
* STACKFACTOR references for passages: one per passage, in their order, with no
|
|
144
|
+
* cap. With `tags`, only the passages the model cited by tag (any tag it made
|
|
145
|
+
* up is passed over); without, every passage.
|
|
146
|
+
* @param passages From `retrievePassages`
|
|
147
|
+
* @param tags The tags the model cited ("k3", "K3" and " k3 " alike)
|
|
148
|
+
* @returns The references, ready for a skill's, a microskill's or a question's `references`
|
|
149
|
+
*/
|
|
150
|
+
export declare const referencesFor: (passages: GroundingPassage[], tags?: unknown[]) => StackFactorReference[];
|
|
151
|
+
declare const _default: {
|
|
152
|
+
DEFAULT_TOP_K: number;
|
|
153
|
+
QUERY_MAX_LENGTH: number;
|
|
154
|
+
SEARCH_DOCUMENT_IDS_MAX: number;
|
|
155
|
+
STACKFACTOR_REFERENCE: Readonly<{
|
|
156
|
+
KIND: "STACKFACTOR";
|
|
157
|
+
TARGET_ELEMENT_TYPE: "KNOWLEDGE_BASE_DOCUMENT";
|
|
158
|
+
ORIGIN: "KB_EXTRACTION";
|
|
159
|
+
VISIBILITY: "EDIT";
|
|
160
|
+
}>;
|
|
161
|
+
passagesForPrompt: (passages: GroundingPassage[]) => {
|
|
162
|
+
tag: string;
|
|
163
|
+
document: string | null;
|
|
164
|
+
section: string | null;
|
|
165
|
+
text: string;
|
|
166
|
+
}[];
|
|
167
|
+
referencesFor: (passages: GroundingPassage[], tags?: unknown[]) => StackFactorReference[];
|
|
168
|
+
retrievePassages: (options: {
|
|
169
|
+
sources: KnowledgeSource[];
|
|
170
|
+
queries: string[];
|
|
171
|
+
search: KnowledgeSearch;
|
|
172
|
+
token: string;
|
|
173
|
+
topK?: number;
|
|
174
|
+
}) => Promise<{
|
|
175
|
+
passages: GroundingPassage[];
|
|
176
|
+
skipped: SkippedSource[];
|
|
177
|
+
}>;
|
|
178
|
+
sourcesFromCoverage: (coverage: unknown) => KnowledgeSource[];
|
|
179
|
+
sourcesFromReferences: (references: unknown) => KnowledgeSource[];
|
|
180
|
+
};
|
|
181
|
+
export default _default;
|
|
182
|
+
//# sourceMappingURL=stackfactorKnowledge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stackfactorKnowledge.d.ts","sourceRoot":"","sources":["../../src/stackfactorKnowledge.ts"],"names":[],"mappings":"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"}
|