@stackfactor/agent-utils 1.4.3 → 1.7.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/index.d.ts +5 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/langChain.d.ts +24 -4
- package/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +218 -172
- 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/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/index.d.ts +5 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/langChain.d.ts +24 -4
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +218 -172
- 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/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 +9 -4
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) });
|
package/dist/cjs/tavily.d.ts
CHANGED
|
@@ -86,6 +86,10 @@ declare const _default: {
|
|
|
86
86
|
assertTavilyUsable: (config: any, options: TavilyConfig) => void;
|
|
87
87
|
buildTavilyTools: (config: any, options: TavilyConfig, usageTracker?: UsageTracker | null) => any[];
|
|
88
88
|
getTavilyOptions: (config: any) => TavilyConfig | null;
|
|
89
|
+
recordTavilyUsage: (tracker: UsageTracker | null | undefined, _config: any, credits: number, sources: {
|
|
90
|
+
url: string;
|
|
91
|
+
title?: string;
|
|
92
|
+
}[]) => void;
|
|
89
93
|
};
|
|
90
94
|
export default _default;
|
|
91
95
|
//# sourceMappingURL=tavily.d.ts.map
|
package/dist/cjs/tavily.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tavily.d.ts","sourceRoot":"","sources":["../../src/tavily.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tavily.d.ts","sourceRoot":"","sources":["../../src/tavily.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA0BnD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,CAAC;AAEpE;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,YAAY,CAAC;IAC3D,kFAAkF;IAClF,YAAY,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IACpC,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,GAAG,KAAG,YAAY,GAAG,IAI7D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,EAAE,SAAS,YAAY,KAAG,IAsBvE,CAAC;AAsLF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,GAAG,EACX,SAAS,YAAY,EACrB,eAAc,YAAY,GAAG,IAAW,KACvC,GAAG,EA2PL,CAAC;;iCA5dyC,GAAG,WAAW,YAAY,KAAG,IAAI;+BA8NlE,GAAG,WACF,YAAY,iBACP,YAAY,GAAG,IAAI,KAChC,GAAG,EAAE;+BAhPiC,GAAG,KAAG,YAAY,GAAG,IAAI;iCAsIvD,YAAY,GAAG,IAAI,GAAG,SAAS,WAC/B,GAAG,WACH,MAAM,WACN;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,KACzC,IAAI;;AAmWP,wBAKE"}
|
package/dist/cjs/tavily.js
CHANGED
|
@@ -10,9 +10,8 @@ const const_js_1 = __importDefault(require("./const.js"));
|
|
|
10
10
|
const errorHandling_js_1 = __importDefault(require("./errorHandling.js"));
|
|
11
11
|
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
12
12
|
const runtimeContext_js_1 = require("./runtimeContext.js");
|
|
13
|
+
const usage_js_1 = require("./usage.js");
|
|
13
14
|
const TAVILY_API_BASE = "https://api.tavily.com";
|
|
14
|
-
/** Tavily list price per credit, used when the integration defines no rate. */
|
|
15
|
-
const DEFAULT_CREDIT_COST_USD = 0.008;
|
|
16
15
|
/**
|
|
17
16
|
* Context budgets, in characters, applied to everything a tool hands back to
|
|
18
17
|
* the model. Tavily returns whatever the page holds, and unlike a provider's
|
|
@@ -129,19 +128,25 @@ const callTavily = async (endpoint, body, apiKey, timeoutSeconds) => {
|
|
|
129
128
|
throw errorHandling_js_1.default.create(const_js_1.default.HTTP_CODES.INTERNAL_SERVER_ERROR, `Tavily ${endpoint} returned ${response.status}: ${detail.slice(0, 500)}`);
|
|
130
129
|
}
|
|
131
130
|
};
|
|
131
|
+
/** The name Tavily's credits are counted and priced under. */
|
|
132
|
+
const TAVILY_MODEL = "tavily";
|
|
132
133
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* `tavilyCredits`. Sources land on
|
|
137
|
-
* URL across the whole run, so
|
|
138
|
-
* require when this output is
|
|
139
|
-
*
|
|
140
|
-
* @param
|
|
134
|
+
* Counts one Tavily call's credits and records the URLs it returned. Credits
|
|
135
|
+
* come from the response's own `usage` block; they are counted into the
|
|
136
|
+
* request's usage ledger, which is reported to the platform, and into the
|
|
137
|
+
* caller's tracker under `tavilyCredits`. Sources land on
|
|
138
|
+
* `tracker.webSearchSources`, deduplicated by URL across the whole run, so
|
|
139
|
+
* callers have the citation list Tavily's terms require when this output is
|
|
140
|
+
* shown to end users.
|
|
141
|
+
* @param tracker - The caller's usage accumulator, when it passed one
|
|
142
|
+
* @param _config - No longer read: it carried the rate, which is the platform's to say
|
|
141
143
|
* @param credits - Credits reported by the Tavily response
|
|
142
144
|
* @param sources - URLs (and titles where known) the call returned
|
|
143
145
|
*/
|
|
144
|
-
const recordTavilyUsage = (tracker,
|
|
146
|
+
const recordTavilyUsage = (tracker, _config, credits, sources) => {
|
|
147
|
+
if (Number.isFinite(credits) && credits > 0) {
|
|
148
|
+
(0, usage_js_1.recordUsage)(TAVILY_MODEL, "credits", credits);
|
|
149
|
+
}
|
|
145
150
|
if (!tracker)
|
|
146
151
|
return;
|
|
147
152
|
if (typeof tracker.cost !== "number")
|
|
@@ -149,13 +154,6 @@ const recordTavilyUsage = (tracker, config, credits, sources) => {
|
|
|
149
154
|
if (!tracker.tokens || typeof tracker.tokens !== "object")
|
|
150
155
|
tracker.tokens = {};
|
|
151
156
|
if (Number.isFinite(credits) && credits > 0) {
|
|
152
|
-
const configured = Number(config?.["tavily-credit-costs"]);
|
|
153
|
-
const rate = Number.isFinite(configured)
|
|
154
|
-
? configured
|
|
155
|
-
: DEFAULT_CREDIT_COST_USD;
|
|
156
|
-
const addedCost = credits * rate;
|
|
157
|
-
if (Number.isFinite(addedCost) && addedCost > 0)
|
|
158
|
-
tracker.cost += addedCost;
|
|
159
157
|
tracker.tokens.tavilyCredits =
|
|
160
158
|
(tracker.tokens.tavilyCredits || 0) + credits;
|
|
161
159
|
}
|
|
@@ -401,4 +399,5 @@ exports.default = {
|
|
|
401
399
|
assertTavilyUsable: exports.assertTavilyUsable,
|
|
402
400
|
buildTavilyTools: exports.buildTavilyTools,
|
|
403
401
|
getTavilyOptions: exports.getTavilyOptions,
|
|
402
|
+
recordTavilyUsage,
|
|
404
403
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { type RequestContext } from "./runtimeContext.js";
|
|
2
|
+
/**
|
|
3
|
+
* What an agent used, and how the platform gets to know.
|
|
4
|
+
*
|
|
5
|
+
* An agent says WHAT it used — a model, a unit, an amount — and the platform
|
|
6
|
+
* says what that costs, who is charged and what it was for. Everything that
|
|
7
|
+
* calls a model through this package counts what the call used into the
|
|
8
|
+
* request's {@link UsageLedger}; {@link serve} and {@link runOnce} report the
|
|
9
|
+
* ledger to the platform while the work runs and when it ends, whether it
|
|
10
|
+
* ended well or not. An agent does nothing for this to happen.
|
|
11
|
+
*
|
|
12
|
+
* An agent that calls a provider itself — its own SDK, an HTTP request —
|
|
13
|
+
* counts what that used with {@link recordUsage}.
|
|
14
|
+
*/
|
|
15
|
+
/** What usage is counted in; the units the platform has rates for. */
|
|
16
|
+
export declare const USAGE_UNITS: readonly ["inputTokens", "outputTokens", "imageInputTokens", "imageOutputTokens", "characters", "seconds", "credits"];
|
|
17
|
+
export type UsageUnit = (typeof USAGE_UNITS)[number];
|
|
18
|
+
export interface UsageEntry {
|
|
19
|
+
model: string;
|
|
20
|
+
unit: UsageUnit;
|
|
21
|
+
amount: number;
|
|
22
|
+
}
|
|
23
|
+
/** Sends one report to the platform. Rejects when the platform did not take it. */
|
|
24
|
+
export type ReportUsage = (usage: UsageEntry[], reportId: string, token: string) => Promise<unknown>;
|
|
25
|
+
/** How often work that is still running reports what it used so far. */
|
|
26
|
+
export declare const USAGE_REPORT_INTERVAL_MS = 60000;
|
|
27
|
+
/**
|
|
28
|
+
* What one request used and has not reported yet, summed by model and unit.
|
|
29
|
+
*/
|
|
30
|
+
export declare class UsageLedger {
|
|
31
|
+
private pending;
|
|
32
|
+
/** Adds to what is pending. Anything that is not a positive amount of a known unit is ignored. */
|
|
33
|
+
add(model: string, unit: UsageUnit, amount: number): void;
|
|
34
|
+
/** What is pending, which then no longer is. */
|
|
35
|
+
take(): UsageEntry[];
|
|
36
|
+
/** True when there is nothing to report. */
|
|
37
|
+
get isEmpty(): boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Counts what the running request used. For an agent that calls a provider
|
|
41
|
+
* itself; what is called through `langChain` is counted already. Outside a
|
|
42
|
+
* request there is nothing to count into, and nothing happens.
|
|
43
|
+
* @param model - The model's id, as its provider names it
|
|
44
|
+
* @param unit - What the amount is counted in
|
|
45
|
+
* @param amount - How much
|
|
46
|
+
*/
|
|
47
|
+
export declare const recordUsage: (model: string, unit: UsageUnit, amount: number) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Reports what the request used and has not reported yet. Never throws, and
|
|
50
|
+
* never changes what the work answers: the work happened, and a platform that
|
|
51
|
+
* cannot be told what it used right now is told by the next report, or not at
|
|
52
|
+
* all — which is logged as an error, with what was used.
|
|
53
|
+
*
|
|
54
|
+
* @param context - The request whose ledger is reported
|
|
55
|
+
* @param options - `report` sends a report (default: the platform's route);
|
|
56
|
+
* `last` says no other report follows, so what cannot be sent is given up on
|
|
57
|
+
* rather than kept for the next one
|
|
58
|
+
*/
|
|
59
|
+
export declare const reportUsage: (context: Pick<RequestContext, "usage" | "request"> | undefined, options?: {
|
|
60
|
+
report?: ReportUsage;
|
|
61
|
+
last?: boolean;
|
|
62
|
+
retryBaseMs?: number;
|
|
63
|
+
}) => Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Reports what the request used so far every {@link USAGE_REPORT_INTERVAL_MS}
|
|
66
|
+
* while the work runs, so work that dies has reported most of what it used.
|
|
67
|
+
* @returns Stops it
|
|
68
|
+
*/
|
|
69
|
+
export declare const reportUsageWhileRunning: (context: Pick<RequestContext, "usage" | "request">, options?: {
|
|
70
|
+
report?: ReportUsage;
|
|
71
|
+
intervalMs?: number;
|
|
72
|
+
retryBaseMs?: number;
|
|
73
|
+
}) => (() => void);
|
|
74
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/usage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;;;;;;;;;;GAYG;AAEH,sEAAsE;AACtE,eAAO,MAAM,WAAW,uHAQd,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,mFAAmF;AACnF,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,UAAU,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,OAAO,CAAC,CAAC;AAOtB,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAI/C;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAiC;IAEhD,kGAAkG;IAClG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAkBzD,gDAAgD;IAChD,IAAI,IAAI,UAAU,EAAE;IAMpB,4CAA4C;IAC5C,IAAI,OAAO,IAAI,OAAO,CAErB;CACF;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,EAAE,MAAM,SAAS,EAAE,QAAQ,MAAM,KAAG,IAE5E,CAAC;AA8BF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,GACtB,SAAS,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC,GAAG,SAAS,EAC9D,UAAS;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,KAC3E,OAAO,CAAC,IAAI,CAuCd,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,SAAS,CAAC,EAClD,UAAS;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,KAChF,CAAC,MAAM,IAAI,CAMb,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
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.reportUsageWhileRunning = exports.reportUsage = exports.recordUsage = exports.UsageLedger = exports.USAGE_REPORT_INTERVAL_MS = exports.USAGE_UNITS = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const client_api_1 = require("@stackfactor/client-api");
|
|
9
|
+
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
10
|
+
const runtimeContext_js_1 = require("./runtimeContext.js");
|
|
11
|
+
/**
|
|
12
|
+
* What an agent used, and how the platform gets to know.
|
|
13
|
+
*
|
|
14
|
+
* An agent says WHAT it used — a model, a unit, an amount — and the platform
|
|
15
|
+
* says what that costs, who is charged and what it was for. Everything that
|
|
16
|
+
* calls a model through this package counts what the call used into the
|
|
17
|
+
* request's {@link UsageLedger}; {@link serve} and {@link runOnce} report the
|
|
18
|
+
* ledger to the platform while the work runs and when it ends, whether it
|
|
19
|
+
* ended well or not. An agent does nothing for this to happen.
|
|
20
|
+
*
|
|
21
|
+
* An agent that calls a provider itself — its own SDK, an HTTP request —
|
|
22
|
+
* counts what that used with {@link recordUsage}.
|
|
23
|
+
*/
|
|
24
|
+
/** What usage is counted in; the units the platform has rates for. */
|
|
25
|
+
exports.USAGE_UNITS = [
|
|
26
|
+
"inputTokens",
|
|
27
|
+
"outputTokens",
|
|
28
|
+
"imageInputTokens",
|
|
29
|
+
"imageOutputTokens",
|
|
30
|
+
"characters",
|
|
31
|
+
"seconds",
|
|
32
|
+
"credits",
|
|
33
|
+
];
|
|
34
|
+
/** Entries one report may carry (the platform's limit). */
|
|
35
|
+
const REPORT_ENTRIES_MAX = 100;
|
|
36
|
+
/** How often a report is tried before it is given up on, and the first wait between tries. */
|
|
37
|
+
const REPORT_ATTEMPTS = 3;
|
|
38
|
+
const REPORT_RETRY_BASE_MS = 500;
|
|
39
|
+
/** How often work that is still running reports what it used so far. */
|
|
40
|
+
exports.USAGE_REPORT_INTERVAL_MS = 60_000;
|
|
41
|
+
const keyOf = (model, unit) => `${model}\n${unit}`;
|
|
42
|
+
/**
|
|
43
|
+
* What one request used and has not reported yet, summed by model and unit.
|
|
44
|
+
*/
|
|
45
|
+
class UsageLedger {
|
|
46
|
+
pending = new Map();
|
|
47
|
+
/** Adds to what is pending. Anything that is not a positive amount of a known unit is ignored. */
|
|
48
|
+
add(model, unit, amount) {
|
|
49
|
+
if (typeof model !== "string" ||
|
|
50
|
+
model.trim().length === 0 ||
|
|
51
|
+
!exports.USAGE_UNITS.includes(unit) ||
|
|
52
|
+
typeof amount !== "number" ||
|
|
53
|
+
!Number.isFinite(amount) ||
|
|
54
|
+
amount <= 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const name = model.trim();
|
|
58
|
+
const key = keyOf(name, unit);
|
|
59
|
+
const entry = this.pending.get(key);
|
|
60
|
+
if (entry)
|
|
61
|
+
entry.amount += amount;
|
|
62
|
+
else
|
|
63
|
+
this.pending.set(key, { model: name, unit, amount });
|
|
64
|
+
}
|
|
65
|
+
/** What is pending, which then no longer is. */
|
|
66
|
+
take() {
|
|
67
|
+
const entries = [...this.pending.values()];
|
|
68
|
+
this.pending = new Map();
|
|
69
|
+
return entries;
|
|
70
|
+
}
|
|
71
|
+
/** True when there is nothing to report. */
|
|
72
|
+
get isEmpty() {
|
|
73
|
+
return this.pending.size === 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.UsageLedger = UsageLedger;
|
|
77
|
+
/**
|
|
78
|
+
* Counts what the running request used. For an agent that calls a provider
|
|
79
|
+
* itself; what is called through `langChain` is counted already. Outside a
|
|
80
|
+
* request there is nothing to count into, and nothing happens.
|
|
81
|
+
* @param model - The model's id, as its provider names it
|
|
82
|
+
* @param unit - What the amount is counted in
|
|
83
|
+
* @param amount - How much
|
|
84
|
+
*/
|
|
85
|
+
const recordUsage = (model, unit, amount) => {
|
|
86
|
+
(0, runtimeContext_js_1.getContext)()?.usage?.add(model, unit, amount);
|
|
87
|
+
};
|
|
88
|
+
exports.recordUsage = recordUsage;
|
|
89
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
90
|
+
const defaultReport = (usage, reportId, token) => client_api_1.integration.reportRunUsage(usage, reportId, token);
|
|
91
|
+
/**
|
|
92
|
+
* Sends one report, again when it fails, under the same name every time: the
|
|
93
|
+
* platform charges a report it has seen only once.
|
|
94
|
+
*/
|
|
95
|
+
const send = async (entries, token, report, retryBaseMs) => {
|
|
96
|
+
const reportId = (0, node_crypto_1.randomUUID)();
|
|
97
|
+
for (let attempt = 1;; attempt++) {
|
|
98
|
+
try {
|
|
99
|
+
await report(entries, reportId, token);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (attempt >= REPORT_ATTEMPTS)
|
|
104
|
+
throw error;
|
|
105
|
+
await delay(retryBaseMs * 2 ** (attempt - 1));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Reports what the request used and has not reported yet. Never throws, and
|
|
111
|
+
* never changes what the work answers: the work happened, and a platform that
|
|
112
|
+
* cannot be told what it used right now is told by the next report, or not at
|
|
113
|
+
* all — which is logged as an error, with what was used.
|
|
114
|
+
*
|
|
115
|
+
* @param context - The request whose ledger is reported
|
|
116
|
+
* @param options - `report` sends a report (default: the platform's route);
|
|
117
|
+
* `last` says no other report follows, so what cannot be sent is given up on
|
|
118
|
+
* rather than kept for the next one
|
|
119
|
+
*/
|
|
120
|
+
const reportUsage = async (context, options = {}) => {
|
|
121
|
+
const ledger = context?.usage;
|
|
122
|
+
if (!ledger || ledger.isEmpty)
|
|
123
|
+
return;
|
|
124
|
+
const token = context.request?.authToken ?? context.request?.authorization;
|
|
125
|
+
const entries = ledger.take();
|
|
126
|
+
if (!token) {
|
|
127
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.error, `usage was not reported, the request carries no token: ${JSON.stringify(entries)}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
for (let start = 0; start < entries.length; start += REPORT_ENTRIES_MAX) {
|
|
131
|
+
const chunk = entries.slice(start, start + REPORT_ENTRIES_MAX);
|
|
132
|
+
try {
|
|
133
|
+
await send(chunk, token, options.report ?? defaultReport, options.retryBaseMs ?? REPORT_RETRY_BASE_MS);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (options.last) {
|
|
137
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.error, `usage could not be reported (${error?.message ?? error}): ${JSON.stringify(chunk)}`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
for (const entry of chunk)
|
|
141
|
+
ledger.add(entry.model, entry.unit, entry.amount);
|
|
142
|
+
logger_js_1.default.log(null, logger_js_1.default.levels.warn, `usage could not be reported, it is kept for the next report: ${error?.message ?? error}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
exports.reportUsage = reportUsage;
|
|
148
|
+
/**
|
|
149
|
+
* Reports what the request used so far every {@link USAGE_REPORT_INTERVAL_MS}
|
|
150
|
+
* while the work runs, so work that dies has reported most of what it used.
|
|
151
|
+
* @returns Stops it
|
|
152
|
+
*/
|
|
153
|
+
const reportUsageWhileRunning = (context, options = {}) => {
|
|
154
|
+
const timer = setInterval(() => {
|
|
155
|
+
void (0, exports.reportUsage)(context, { report: options.report, retryBaseMs: options.retryBaseMs });
|
|
156
|
+
}, options.intervalMs ?? exports.USAGE_REPORT_INTERVAL_MS);
|
|
157
|
+
timer.unref?.();
|
|
158
|
+
return () => clearInterval(timer);
|
|
159
|
+
};
|
|
160
|
+
exports.reportUsageWhileRunning = reportUsageWhileRunning;
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import constants from "./const.js";
|
|
|
2
2
|
import errorHandling, { AppError } from "./errorHandling.js";
|
|
3
3
|
import langChain from "./langChain.js";
|
|
4
4
|
import logger from "./logger.js";
|
|
5
|
-
import { serve } from "./serve.js";
|
|
5
|
+
import { serve, runOnce, isRunOnceExecution, EXECUTION_ENV } from "./serve.js";
|
|
6
6
|
import { callAgent, checkAgent } from "./client.js";
|
|
7
7
|
import * as runtimeContext from "./runtimeContext.js";
|
|
8
|
+
import { recordUsage, USAGE_UNITS } from "./usage.js";
|
|
8
9
|
export { constants };
|
|
9
10
|
export { errorHandling, AppError };
|
|
10
11
|
export type { ParsedError } from "./errorHandling.js";
|
|
@@ -12,9 +13,11 @@ export { langChain };
|
|
|
12
13
|
export type { UsageTracker } from "./langChain.js";
|
|
13
14
|
export type { TavilyConfig, TavilyToolName } from "./tavily.js";
|
|
14
15
|
export { logger };
|
|
15
|
-
export { serve };
|
|
16
|
+
export { serve, runOnce, isRunOnceExecution, EXECUTION_ENV };
|
|
16
17
|
export { callAgent };
|
|
17
18
|
export { checkAgent };
|
|
18
19
|
export type { AgentExecuteRequest, CallAgentOptions, CheckAgentOptions, AgentHealth, } from "./client.js";
|
|
19
20
|
export { runtimeContext };
|
|
21
|
+
export { recordUsage, USAGE_UNITS };
|
|
22
|
+
export type { UsageEntry, UsageUnit } from "./usage.js";
|
|
20
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,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;AAEtD,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,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"}
|