@node-llm/core 1.9.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.
- package/README.md +89 -6
- package/dist/agent/Agent.d.ts +191 -0
- package/dist/agent/Agent.d.ts.map +1 -0
- package/dist/agent/Agent.js +272 -0
- package/dist/aliases.d.ts +102 -9
- package/dist/aliases.d.ts.map +1 -1
- package/dist/aliases.js +102 -9
- package/dist/chat/Chat.d.ts +1 -0
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +184 -131
- package/dist/chat/ChatOptions.d.ts +2 -0
- package/dist/chat/ChatOptions.d.ts.map +1 -1
- package/dist/chat/ChatStream.d.ts.map +1 -1
- package/dist/chat/ChatStream.js +109 -66
- package/dist/chat/Tool.d.ts +43 -2
- package/dist/chat/Tool.d.ts.map +1 -1
- package/dist/chat/Tool.js +50 -0
- package/dist/chat/ToolHandler.d.ts +10 -5
- package/dist/chat/ToolHandler.d.ts.map +1 -1
- package/dist/chat/ToolHandler.js +10 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/llm.d.ts +8 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +156 -59
- package/dist/middlewares/CostGuardMiddleware.d.ts +24 -0
- package/dist/middlewares/CostGuardMiddleware.d.ts.map +1 -0
- package/dist/middlewares/CostGuardMiddleware.js +23 -0
- package/dist/middlewares/PIIMaskMiddleware.d.ts +23 -0
- package/dist/middlewares/PIIMaskMiddleware.d.ts.map +1 -0
- package/dist/middlewares/PIIMaskMiddleware.js +41 -0
- package/dist/middlewares/UsageLoggerMiddleware.d.ts +22 -0
- package/dist/middlewares/UsageLoggerMiddleware.d.ts.map +1 -0
- package/dist/middlewares/UsageLoggerMiddleware.js +30 -0
- package/dist/middlewares/index.d.ts +4 -0
- package/dist/middlewares/index.d.ts.map +1 -0
- package/dist/middlewares/index.js +3 -0
- package/dist/models/models.json +1458 -448
- package/dist/providers/BaseProvider.d.ts +6 -1
- package/dist/providers/BaseProvider.d.ts.map +1 -1
- package/dist/providers/BaseProvider.js +19 -0
- package/dist/providers/openai/OpenAIProvider.d.ts +1 -1
- package/dist/providers/openai/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/openai/OpenAIProvider.js +13 -2
- package/dist/types/Middleware.d.ts +106 -0
- package/dist/types/Middleware.d.ts.map +1 -0
- package/dist/types/Middleware.js +1 -0
- package/dist/utils/middleware-runner.d.ts +7 -0
- package/dist/utils/middleware-runner.d.ts.map +1 -0
- package/dist/utils/middleware-runner.js +23 -0
- package/package.json +6 -2
package/dist/chat/Tool.d.ts
CHANGED
|
@@ -14,7 +14,32 @@ export interface ToolDefinition {
|
|
|
14
14
|
description?: string;
|
|
15
15
|
parameters: Record<string, unknown>;
|
|
16
16
|
};
|
|
17
|
-
handler?: (args: unknown) => Promise<string>;
|
|
17
|
+
handler?: (args: unknown) => Promise<string | ToolHalt>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Stops the agentic tool execution loop and returns the content as the final response.
|
|
21
|
+
* Return this from a tool's execute() method to immediately end the conversation turn.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* class PaymentTool extends Tool {
|
|
26
|
+
* async execute({ amount }) {
|
|
27
|
+
* if (amount > 10000) {
|
|
28
|
+
* return this.halt("Payment requires manager approval. Please contact support.");
|
|
29
|
+
* }
|
|
30
|
+
* return processPayment(amount);
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class ToolHalt {
|
|
36
|
+
readonly content: string;
|
|
37
|
+
constructor(content: string);
|
|
38
|
+
toString(): string;
|
|
39
|
+
toJSON(): {
|
|
40
|
+
halt: true;
|
|
41
|
+
content: string;
|
|
42
|
+
};
|
|
18
43
|
}
|
|
19
44
|
/**
|
|
20
45
|
* Anything that can be resolved into a ToolDefinition.
|
|
@@ -44,11 +69,27 @@ export declare abstract class Tool<T = Record<string, unknown>> {
|
|
|
44
69
|
* 'args' will be parsed and validated based on 'schema'.
|
|
45
70
|
*/
|
|
46
71
|
abstract execute(args: T): Promise<unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Stop the agentic loop and return this message as the final tool result.
|
|
74
|
+
* Use this when you want to end the conversation turn immediately.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* async execute({ amount }) {
|
|
79
|
+
* if (amount > 10000) {
|
|
80
|
+
* return this.halt("Payment requires manager approval.");
|
|
81
|
+
* }
|
|
82
|
+
* return processPayment(amount);
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
protected halt(message: string): ToolHalt;
|
|
47
87
|
/**
|
|
48
88
|
* Internal handler to bridge with LLM providers.
|
|
49
89
|
* Converts any result to a string (usually JSON).
|
|
90
|
+
* Preserves ToolHalt instances for the execution loop to detect.
|
|
50
91
|
*/
|
|
51
|
-
handler(args: T): Promise<string>;
|
|
92
|
+
handler(args: T): Promise<string | ToolHalt>;
|
|
52
93
|
/**
|
|
53
94
|
* Converts the tool definition and logic into a standard ToolDefinition interface.
|
|
54
95
|
* This is called automatically by NodeLLM when registering tools.
|
package/dist/chat/Tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../../src/chat/Tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../../src/chat/Tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;CACzD;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,QAAQ;aACS,OAAO,EAAE,MAAM;gBAAf,OAAO,EAAE,MAAM;IAE3C,QAAQ,IAAI,MAAM;IAIlB,MAAM,IAAI;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;CAG1C;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG;IAAE,QAAQ,IAAI,CAAA;CAAE,GAAG,cAAc,CAAC;AAEtE;;GAEG;AACH,8BAAsB,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpD;;OAEG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,SAAgB,WAAW,EAAE,MAAM,CAAC;IAEpC;;;OAGG;IACH,SAAgB,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE7E;;;OAGG;aACa,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAElD;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ;IAIzC;;;;OAIG;IACU,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC;IAYzD;;;OAGG;IACI,SAAS,IAAI,cAAc;CAuBnC"}
|
package/dist/chat/Tool.js
CHANGED
|
@@ -1,14 +1,64 @@
|
|
|
1
1
|
import { toJsonSchema } from "../schema/to-json-schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stops the agentic tool execution loop and returns the content as the final response.
|
|
4
|
+
* Return this from a tool's execute() method to immediately end the conversation turn.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* class PaymentTool extends Tool {
|
|
9
|
+
* async execute({ amount }) {
|
|
10
|
+
* if (amount > 10000) {
|
|
11
|
+
* return this.halt("Payment requires manager approval. Please contact support.");
|
|
12
|
+
* }
|
|
13
|
+
* return processPayment(amount);
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class ToolHalt {
|
|
19
|
+
content;
|
|
20
|
+
constructor(content) {
|
|
21
|
+
this.content = content;
|
|
22
|
+
}
|
|
23
|
+
toString() {
|
|
24
|
+
return this.content;
|
|
25
|
+
}
|
|
26
|
+
toJSON() {
|
|
27
|
+
return { halt: true, content: this.content };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
2
30
|
/**
|
|
3
31
|
* Subclass this to create tools with auto-generated schemas and type safety.
|
|
4
32
|
*/
|
|
5
33
|
export class Tool {
|
|
34
|
+
/**
|
|
35
|
+
* Stop the agentic loop and return this message as the final tool result.
|
|
36
|
+
* Use this when you want to end the conversation turn immediately.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* async execute({ amount }) {
|
|
41
|
+
* if (amount > 10000) {
|
|
42
|
+
* return this.halt("Payment requires manager approval.");
|
|
43
|
+
* }
|
|
44
|
+
* return processPayment(amount);
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
halt(message) {
|
|
49
|
+
return new ToolHalt(message);
|
|
50
|
+
}
|
|
6
51
|
/**
|
|
7
52
|
* Internal handler to bridge with LLM providers.
|
|
8
53
|
* Converts any result to a string (usually JSON).
|
|
54
|
+
* Preserves ToolHalt instances for the execution loop to detect.
|
|
9
55
|
*/
|
|
10
56
|
async handler(args) {
|
|
11
57
|
const result = await this.execute(args);
|
|
58
|
+
// Preserve ToolHalt for the execution loop to handle
|
|
59
|
+
if (result instanceof ToolHalt) {
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
12
62
|
if (result === undefined || result === null)
|
|
13
63
|
return "";
|
|
14
64
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { ToolExecutionMode } from "../constants.js";
|
|
2
2
|
import { ToolCall, ToolDefinition } from "./Tool.js";
|
|
3
|
+
/**
|
|
4
|
+
* Result of a tool execution, including halt status
|
|
5
|
+
*/
|
|
6
|
+
export interface ToolExecutionResult {
|
|
7
|
+
role: "tool";
|
|
8
|
+
tool_call_id: string;
|
|
9
|
+
content: string;
|
|
10
|
+
halted: boolean;
|
|
11
|
+
}
|
|
3
12
|
export declare class ToolHandler {
|
|
4
13
|
static shouldExecuteTools(toolCalls: ToolCall[] | undefined, mode?: ToolExecutionMode): boolean;
|
|
5
14
|
static requestToolConfirmation(toolCall: ToolCall, onConfirm?: (call: ToolCall) => Promise<boolean> | boolean): Promise<boolean>;
|
|
6
|
-
static execute(toolCall: ToolCall, tools: ToolDefinition[] | undefined, onStart?: (call: ToolCall) => void, onEnd?: (call: ToolCall, result: unknown) => void): Promise<
|
|
7
|
-
role: "tool";
|
|
8
|
-
tool_call_id: string;
|
|
9
|
-
content: string;
|
|
10
|
-
}>;
|
|
15
|
+
static execute(toolCall: ToolCall, tools: ToolDefinition[] | undefined, onStart?: (call: ToolCall) => void, onEnd?: (call: ToolCall, result: unknown) => void): Promise<ToolExecutionResult>;
|
|
11
16
|
}
|
|
12
17
|
//# sourceMappingURL=ToolHandler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToolHandler.d.ts","sourceRoot":"","sources":["../../src/chat/ToolHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ToolHandler.d.ts","sourceRoot":"","sources":["../../src/chat/ToolHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAY,MAAM,WAAW,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,MAAM,CAAC,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,iBAAiB,GAAG,OAAO;WAMlF,uBAAuB,CAClC,QAAQ,EAAE,QAAQ,EAClB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,GACzD,OAAO,CAAC,OAAO,CAAC;WAMN,OAAO,CAClB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,cAAc,EAAE,GAAG,SAAS,EACnC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,EAClC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAChD,OAAO,CAAC,mBAAmB,CAAC;CAgChC"}
|
package/dist/chat/ToolHandler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ToolExecutionMode } from "../constants.js";
|
|
2
2
|
import { ToolError } from "../errors/index.js";
|
|
3
|
+
import { ToolHalt } from "./Tool.js";
|
|
3
4
|
export class ToolHandler {
|
|
4
5
|
static shouldExecuteTools(toolCalls, mode) {
|
|
5
6
|
if (!toolCalls || toolCalls.length === 0)
|
|
@@ -21,13 +22,20 @@ export class ToolHandler {
|
|
|
21
22
|
if (tool?.handler) {
|
|
22
23
|
const args = JSON.parse(toolCall.function.arguments);
|
|
23
24
|
const result = await tool.handler(args);
|
|
24
|
-
|
|
25
|
+
// Check if this is a halt signal
|
|
26
|
+
const isHalt = typeof result === "object" && result !== null && result instanceof ToolHalt;
|
|
27
|
+
const content = isHalt
|
|
28
|
+
? result.content
|
|
29
|
+
: typeof result === "string"
|
|
30
|
+
? result
|
|
31
|
+
: JSON.stringify(result);
|
|
25
32
|
if (onEnd)
|
|
26
33
|
onEnd(toolCall, result);
|
|
27
34
|
return {
|
|
28
35
|
role: "tool",
|
|
29
36
|
tool_call_id: toolCall.id,
|
|
30
|
-
content
|
|
37
|
+
content,
|
|
38
|
+
halted: isHalt
|
|
31
39
|
};
|
|
32
40
|
}
|
|
33
41
|
else {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,11 @@ export * from "./chat/ChatResponse.js";
|
|
|
6
6
|
export * from "./chat/Chat.js";
|
|
7
7
|
export * from "./chat/ChatStream.js";
|
|
8
8
|
export * from "./streaming/Stream.js";
|
|
9
|
+
export * from "./errors/index.js";
|
|
10
|
+
export { Agent, defineAgent } from "./agent/Agent.js";
|
|
11
|
+
export type { AgentConfig } from "./agent/Agent.js";
|
|
12
|
+
export type { Middleware, MiddlewareContext } from "./types/Middleware.js";
|
|
13
|
+
export * from "./middlewares/index.js";
|
|
9
14
|
export { z } from "zod";
|
|
10
15
|
export { NodeLLM, LegacyNodeLLM, createLLM, NodeLLMCore, Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry } from "./llm.js";
|
|
11
16
|
export { config } from "./config.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,cAAc,wBAAwB,CAAC;AAEvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,eAAe,EAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EACL,QAAQ,EACR,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,cAAc,EACd,cAAc,EACd,KAAK,EACL,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ export * from "./chat/ChatResponse.js";
|
|
|
6
6
|
export * from "./chat/Chat.js";
|
|
7
7
|
export * from "./chat/ChatStream.js";
|
|
8
8
|
export * from "./streaming/Stream.js";
|
|
9
|
+
export * from "./errors/index.js";
|
|
10
|
+
export { Agent, defineAgent } from "./agent/Agent.js";
|
|
11
|
+
export * from "./middlewares/index.js";
|
|
9
12
|
export { z } from "zod";
|
|
10
13
|
export { NodeLLM, LegacyNodeLLM, createLLM, NodeLLMCore, Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry } from "./llm.js";
|
|
11
14
|
export { config } from "./config.js";
|
package/dist/llm.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { Transcription } from "./transcription/Transcription.js";
|
|
|
8
8
|
import { Moderation } from "./moderation/Moderation.js";
|
|
9
9
|
import { Embedding } from "./embedding/Embedding.js";
|
|
10
10
|
import { NodeLLMConfig } from "./config.js";
|
|
11
|
+
import { Middleware } from "./types/Middleware.js";
|
|
11
12
|
export interface RetryOptions {
|
|
12
13
|
attempts?: number;
|
|
13
14
|
delayMs?: number;
|
|
@@ -15,6 +16,7 @@ export interface RetryOptions {
|
|
|
15
16
|
type LLMConfig = {
|
|
16
17
|
provider?: Provider | string;
|
|
17
18
|
retry?: RetryOptions;
|
|
19
|
+
middlewares?: Middleware[];
|
|
18
20
|
defaultChatModel?: string;
|
|
19
21
|
defaultTranscriptionModel?: string;
|
|
20
22
|
defaultModerationModel?: string;
|
|
@@ -24,10 +26,11 @@ export declare class NodeLLMCore {
|
|
|
24
26
|
readonly config: NodeLLMConfig;
|
|
25
27
|
readonly provider?: Provider | undefined;
|
|
26
28
|
readonly retry: Required<RetryOptions>;
|
|
29
|
+
readonly middlewares: Middleware[];
|
|
27
30
|
private readonly defaults;
|
|
28
31
|
readonly models: typeof ModelRegistry;
|
|
29
32
|
readonly pricing: typeof PricingRegistry;
|
|
30
|
-
constructor(config: NodeLLMConfig, provider?: Provider | undefined, retry?: Required<RetryOptions>, defaults?: {
|
|
33
|
+
constructor(config: NodeLLMConfig, provider?: Provider | undefined, retry?: Required<RetryOptions>, middlewares?: Middleware[], defaults?: {
|
|
31
34
|
chat?: string;
|
|
32
35
|
transcription?: string;
|
|
33
36
|
moderation?: string;
|
|
@@ -57,6 +60,7 @@ export declare class NodeLLMCore {
|
|
|
57
60
|
quality?: string;
|
|
58
61
|
assumeModelExists?: boolean;
|
|
59
62
|
requestTimeout?: number;
|
|
63
|
+
middlewares?: Middleware[];
|
|
60
64
|
}): Promise<GeneratedImage>;
|
|
61
65
|
transcribe(file: string, options?: {
|
|
62
66
|
model?: string;
|
|
@@ -66,17 +70,20 @@ export declare class NodeLLMCore {
|
|
|
66
70
|
speakerReferences?: string[];
|
|
67
71
|
assumeModelExists?: boolean;
|
|
68
72
|
requestTimeout?: number;
|
|
73
|
+
middlewares?: Middleware[];
|
|
69
74
|
}): Promise<Transcription>;
|
|
70
75
|
moderate(input: string | string[], options?: {
|
|
71
76
|
model?: string;
|
|
72
77
|
assumeModelExists?: boolean;
|
|
73
78
|
requestTimeout?: number;
|
|
79
|
+
middlewares?: Middleware[];
|
|
74
80
|
}): Promise<Moderation>;
|
|
75
81
|
embed(input: string | string[], options?: {
|
|
76
82
|
model?: string;
|
|
77
83
|
dimensions?: number;
|
|
78
84
|
assumeModelExists?: boolean;
|
|
79
85
|
requestTimeout?: number;
|
|
86
|
+
middlewares?: Middleware[];
|
|
80
87
|
}): Promise<Embedding>;
|
|
81
88
|
}
|
|
82
89
|
export { Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry };
|
package/dist/llm.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAW9D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAUrD,OAAO,EAAU,aAAa,EAAiB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"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"}
|
package/dist/llm.js
CHANGED
|
@@ -10,6 +10,8 @@ import { ProviderNotConfiguredError, UnsupportedFeatureError, ModelCapabilityErr
|
|
|
10
10
|
import { resolveModelAlias } from "./model_aliases.js";
|
|
11
11
|
import { logger } from "./utils/logger.js";
|
|
12
12
|
import { config, Configuration } from "./config.js";
|
|
13
|
+
import { runMiddleware } from "./utils/middleware-runner.js";
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
13
15
|
// Provider registration map
|
|
14
16
|
const PROVIDER_REGISTRARS = {
|
|
15
17
|
openai: ensureOpenAIRegistered,
|
|
@@ -24,13 +26,15 @@ export class NodeLLMCore {
|
|
|
24
26
|
config;
|
|
25
27
|
provider;
|
|
26
28
|
retry;
|
|
29
|
+
middlewares;
|
|
27
30
|
defaults;
|
|
28
31
|
models = ModelRegistry;
|
|
29
32
|
pricing = PricingRegistry;
|
|
30
|
-
constructor(config, provider, retry = { attempts: 1, delayMs: 0 }, defaults = {}) {
|
|
33
|
+
constructor(config, provider, retry = { attempts: 1, delayMs: 0 }, middlewares = [], defaults = {}) {
|
|
31
34
|
this.config = config;
|
|
32
35
|
this.provider = provider;
|
|
33
36
|
this.retry = retry;
|
|
37
|
+
this.middlewares = middlewares;
|
|
34
38
|
this.defaults = defaults;
|
|
35
39
|
Object.freeze(this.config);
|
|
36
40
|
Object.freeze(this.retry);
|
|
@@ -59,7 +63,8 @@ export class NodeLLMCore {
|
|
|
59
63
|
...baseConfig,
|
|
60
64
|
...scopedConfig,
|
|
61
65
|
provider: providerName,
|
|
62
|
-
// Preserve defaults unless overridden
|
|
66
|
+
// Preserve middlewares and defaults unless overridden
|
|
67
|
+
middlewares: this.middlewares,
|
|
63
68
|
defaultChatModel: this.defaults.chat,
|
|
64
69
|
defaultTranscriptionModel: this.defaults.transcription,
|
|
65
70
|
defaultModerationModel: this.defaults.moderation,
|
|
@@ -85,13 +90,18 @@ export class NodeLLMCore {
|
|
|
85
90
|
}
|
|
86
91
|
return this.provider;
|
|
87
92
|
}
|
|
88
|
-
chat(model, options) {
|
|
93
|
+
chat(model, options = {}) {
|
|
89
94
|
if (!this.provider) {
|
|
90
95
|
throw new ProviderNotConfiguredError();
|
|
91
96
|
}
|
|
92
97
|
const rawModel = model || this.defaults.chat || this.provider.defaultModel("chat");
|
|
93
98
|
const resolvedModel = resolveModelAlias(rawModel, this.provider.id);
|
|
94
|
-
|
|
99
|
+
// Merge global middlewares with local ones
|
|
100
|
+
const combinedOptions = {
|
|
101
|
+
...options,
|
|
102
|
+
middlewares: [...this.middlewares, ...(options.middlewares || [])]
|
|
103
|
+
};
|
|
104
|
+
return new Chat(this.provider, resolvedModel, combinedOptions, this.retry);
|
|
95
105
|
}
|
|
96
106
|
async listModels() {
|
|
97
107
|
const provider = this.ensureProviderSupport("listModels");
|
|
@@ -102,82 +112,169 @@ export class NodeLLMCore {
|
|
|
102
112
|
}
|
|
103
113
|
async paint(prompt, options) {
|
|
104
114
|
const provider = this.ensureProviderSupport("paint");
|
|
105
|
-
const rawModel = options?.model;
|
|
106
|
-
const model = resolveModelAlias(rawModel
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
const rawModel = options?.model || provider.defaultModel("image");
|
|
116
|
+
const model = resolveModelAlias(rawModel, provider.id);
|
|
117
|
+
const requestId = randomUUID();
|
|
118
|
+
const state = {};
|
|
119
|
+
const context = {
|
|
120
|
+
requestId,
|
|
121
|
+
provider: provider.id,
|
|
122
|
+
model,
|
|
123
|
+
input: prompt,
|
|
124
|
+
imageOptions: options,
|
|
125
|
+
state
|
|
126
|
+
};
|
|
127
|
+
const middlewares = [...this.middlewares, ...(options?.middlewares || [])];
|
|
128
|
+
try {
|
|
129
|
+
await runMiddleware(middlewares, "onRequest", context);
|
|
130
|
+
const currentPrompt = context.input || prompt;
|
|
131
|
+
if (options?.assumeModelExists) {
|
|
132
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
133
|
+
}
|
|
134
|
+
else if (model &&
|
|
135
|
+
provider.capabilities &&
|
|
136
|
+
!provider.capabilities.supportsImageGeneration(model)) {
|
|
137
|
+
throw new ModelCapabilityError(model, "image generation");
|
|
138
|
+
}
|
|
139
|
+
const response = await provider.paint({
|
|
140
|
+
prompt: currentPrompt,
|
|
141
|
+
...options,
|
|
142
|
+
model,
|
|
143
|
+
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
144
|
+
});
|
|
145
|
+
const imageResult = new GeneratedImage(response);
|
|
146
|
+
await runMiddleware(middlewares, "onResponse", context, imageResult);
|
|
147
|
+
return imageResult;
|
|
109
148
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
throw new ModelCapabilityError(model, "image generation");
|
|
149
|
+
catch (error) {
|
|
150
|
+
await runMiddleware(middlewares, "onError", context, error);
|
|
151
|
+
throw error;
|
|
114
152
|
}
|
|
115
|
-
const response = await provider.paint({
|
|
116
|
-
prompt,
|
|
117
|
-
...options,
|
|
118
|
-
model,
|
|
119
|
-
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
120
|
-
});
|
|
121
|
-
return new GeneratedImage(response);
|
|
122
153
|
}
|
|
123
154
|
async transcribe(file, options) {
|
|
124
155
|
const provider = this.ensureProviderSupport("transcribe");
|
|
125
|
-
const rawModel = options?.model || this.defaults.transcription || "";
|
|
156
|
+
const rawModel = options?.model || this.defaults.transcription || provider.defaultModel("transcription");
|
|
126
157
|
const model = resolveModelAlias(rawModel, provider.id);
|
|
127
|
-
|
|
128
|
-
|
|
158
|
+
const requestId = randomUUID();
|
|
159
|
+
const state = {};
|
|
160
|
+
const context = {
|
|
161
|
+
requestId,
|
|
162
|
+
provider: provider.id,
|
|
163
|
+
model,
|
|
164
|
+
input: file,
|
|
165
|
+
transcriptionOptions: options,
|
|
166
|
+
state
|
|
167
|
+
};
|
|
168
|
+
const middlewares = [...this.middlewares, ...(options?.middlewares || [])];
|
|
169
|
+
try {
|
|
170
|
+
await runMiddleware(middlewares, "onRequest", context);
|
|
171
|
+
const currentFile = context.input || file;
|
|
172
|
+
if (options?.assumeModelExists) {
|
|
173
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
174
|
+
}
|
|
175
|
+
else if (model &&
|
|
176
|
+
provider.capabilities &&
|
|
177
|
+
!provider.capabilities.supportsTranscription(model)) {
|
|
178
|
+
throw new ModelCapabilityError(model, "transcription");
|
|
179
|
+
}
|
|
180
|
+
const response = await provider.transcribe({
|
|
181
|
+
file: currentFile,
|
|
182
|
+
...options,
|
|
183
|
+
model,
|
|
184
|
+
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
185
|
+
});
|
|
186
|
+
const transcriptionResult = new Transcription(response);
|
|
187
|
+
await runMiddleware(middlewares, "onResponse", context, transcriptionResult);
|
|
188
|
+
return transcriptionResult;
|
|
129
189
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
throw new ModelCapabilityError(model, "transcription");
|
|
190
|
+
catch (error) {
|
|
191
|
+
await runMiddleware(middlewares, "onError", context, error);
|
|
192
|
+
throw error;
|
|
134
193
|
}
|
|
135
|
-
const response = await provider.transcribe({
|
|
136
|
-
file,
|
|
137
|
-
...options,
|
|
138
|
-
model,
|
|
139
|
-
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
140
|
-
});
|
|
141
|
-
return new Transcription(response);
|
|
142
194
|
}
|
|
143
195
|
async moderate(input, options) {
|
|
144
196
|
const provider = this.ensureProviderSupport("moderate");
|
|
145
|
-
const rawModel = options?.model || this.defaults.moderation || "";
|
|
197
|
+
const rawModel = options?.model || this.defaults.moderation || provider.defaultModel("moderation");
|
|
146
198
|
const model = resolveModelAlias(rawModel, provider.id);
|
|
147
|
-
|
|
148
|
-
|
|
199
|
+
const requestId = randomUUID();
|
|
200
|
+
const state = {};
|
|
201
|
+
const context = {
|
|
202
|
+
requestId,
|
|
203
|
+
provider: provider.id,
|
|
204
|
+
model,
|
|
205
|
+
input,
|
|
206
|
+
moderationOptions: options,
|
|
207
|
+
state
|
|
208
|
+
};
|
|
209
|
+
const middlewares = [...this.middlewares, ...(options?.middlewares || [])];
|
|
210
|
+
try {
|
|
211
|
+
await runMiddleware(middlewares, "onRequest", context);
|
|
212
|
+
const currentInput = context.input || input;
|
|
213
|
+
if (options?.assumeModelExists) {
|
|
214
|
+
logger.warn(`Skipping validation for model ${model}`);
|
|
215
|
+
}
|
|
216
|
+
else if (model &&
|
|
217
|
+
provider.capabilities &&
|
|
218
|
+
!provider.capabilities.supportsModeration(model)) {
|
|
219
|
+
throw new ModelCapabilityError(model, "moderation");
|
|
220
|
+
}
|
|
221
|
+
const response = await provider.moderate({
|
|
222
|
+
input: currentInput,
|
|
223
|
+
...options,
|
|
224
|
+
model,
|
|
225
|
+
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
226
|
+
});
|
|
227
|
+
const moderationResult = new Moderation(response);
|
|
228
|
+
await runMiddleware(middlewares, "onResponse", context, moderationResult);
|
|
229
|
+
return moderationResult;
|
|
149
230
|
}
|
|
150
|
-
|
|
151
|
-
|
|
231
|
+
catch (error) {
|
|
232
|
+
await runMiddleware(middlewares, "onError", context, error);
|
|
233
|
+
throw error;
|
|
152
234
|
}
|
|
153
|
-
const response = await provider.moderate({
|
|
154
|
-
input,
|
|
155
|
-
...options,
|
|
156
|
-
model,
|
|
157
|
-
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
158
|
-
});
|
|
159
|
-
return new Moderation(response);
|
|
160
235
|
}
|
|
161
236
|
async embed(input, options) {
|
|
162
237
|
const provider = this.ensureProviderSupport("embed");
|
|
163
|
-
const rawModel = options?.model || this.defaults.embedding || "";
|
|
238
|
+
const rawModel = options?.model || this.defaults.embedding || provider.defaultModel("embedding");
|
|
164
239
|
const model = resolveModelAlias(rawModel, provider.id);
|
|
165
|
-
const
|
|
166
|
-
|
|
240
|
+
const requestId = randomUUID();
|
|
241
|
+
const state = {};
|
|
242
|
+
const context = {
|
|
243
|
+
requestId,
|
|
244
|
+
provider: provider.id,
|
|
167
245
|
model,
|
|
168
|
-
|
|
169
|
-
|
|
246
|
+
input,
|
|
247
|
+
embeddingOptions: options,
|
|
248
|
+
state
|
|
170
249
|
};
|
|
171
|
-
|
|
172
|
-
|
|
250
|
+
const middlewares = [...this.middlewares, ...(options?.middlewares || [])];
|
|
251
|
+
try {
|
|
252
|
+
await runMiddleware(middlewares, "onRequest", context);
|
|
253
|
+
// Re-read input from context as it might have been modified
|
|
254
|
+
const currentInput = context.input || input;
|
|
255
|
+
const request = {
|
|
256
|
+
input: currentInput,
|
|
257
|
+
model,
|
|
258
|
+
dimensions: options?.dimensions,
|
|
259
|
+
requestTimeout: options?.requestTimeout ?? this.config.requestTimeout
|
|
260
|
+
};
|
|
261
|
+
if (options?.assumeModelExists) {
|
|
262
|
+
logger.warn(`Skipping validation for model ${request.model}`);
|
|
263
|
+
}
|
|
264
|
+
else if (request.model &&
|
|
265
|
+
provider.capabilities &&
|
|
266
|
+
!provider.capabilities.supportsEmbeddings(request.model)) {
|
|
267
|
+
throw new ModelCapabilityError(request.model, "embeddings");
|
|
268
|
+
}
|
|
269
|
+
const response = await provider.embed(request);
|
|
270
|
+
const embeddingResult = new Embedding(response);
|
|
271
|
+
await runMiddleware(middlewares, "onResponse", context, embeddingResult);
|
|
272
|
+
return embeddingResult;
|
|
173
273
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
throw new ModelCapabilityError(request.model, "embeddings");
|
|
274
|
+
catch (error) {
|
|
275
|
+
await runMiddleware(middlewares, "onError", context, error);
|
|
276
|
+
throw error;
|
|
178
277
|
}
|
|
179
|
-
const response = await provider.embed(request);
|
|
180
|
-
return new Embedding(response);
|
|
181
278
|
}
|
|
182
279
|
}
|
|
183
280
|
export { Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry };
|
|
@@ -230,7 +327,7 @@ export function createLLM(options = {}) {
|
|
|
230
327
|
moderation: options.defaultModerationModel,
|
|
231
328
|
embedding: options.defaultEmbeddingModel
|
|
232
329
|
};
|
|
233
|
-
return new NodeLLMCore(baseConfig, providerInstance, retry, defaults);
|
|
330
|
+
return new NodeLLMCore(baseConfig, providerInstance, retry, options.middlewares || [], defaults);
|
|
234
331
|
}
|
|
235
332
|
/**
|
|
236
333
|
* DEFAULT IMMUTABLE INSTANCE
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Middleware, MiddlewareContext } from "../types/Middleware.js";
|
|
2
|
+
import { ChatResponseString } from "../chat/ChatResponse.js";
|
|
3
|
+
export interface CostGuardOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum allowed cost (in USD) for a single request sequence.
|
|
6
|
+
*/
|
|
7
|
+
maxCost: number;
|
|
8
|
+
/**
|
|
9
|
+
* Callback when the limit is exceeded.
|
|
10
|
+
*/
|
|
11
|
+
onLimitExceeded?: (ctx: MiddlewareContext, currentCost: number) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Middleware that monitors accumulated cost during a session (especially multi-turn tool calls)
|
|
15
|
+
* and throws an error if a defined limit is exceeded.
|
|
16
|
+
*/
|
|
17
|
+
export declare class CostGuardMiddleware implements Middleware {
|
|
18
|
+
private options;
|
|
19
|
+
readonly name = "CostGuard";
|
|
20
|
+
private accumulatedCost;
|
|
21
|
+
constructor(options: CostGuardOptions);
|
|
22
|
+
onResponse(ctx: MiddlewareContext, result: ChatResponseString): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=CostGuardMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CostGuardMiddleware.d.ts","sourceRoot":"","sources":["../../src/middlewares/CostGuardMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACzE;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,UAAU;IAIxC,OAAO,CAAC,OAAO;IAH3B,SAAgB,IAAI,eAAe;IACnC,OAAO,CAAC,eAAe,CAAa;gBAEhB,OAAO,EAAE,gBAAgB;IAMvC,UAAU,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;CAWpF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware that monitors accumulated cost during a session (especially multi-turn tool calls)
|
|
3
|
+
* and throws an error if a defined limit is exceeded.
|
|
4
|
+
*/
|
|
5
|
+
export class CostGuardMiddleware {
|
|
6
|
+
options;
|
|
7
|
+
name = "CostGuard";
|
|
8
|
+
accumulatedCost = 0;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.options = options;
|
|
11
|
+
if (options.maxCost <= 0) {
|
|
12
|
+
throw new Error("CostGuard maxCost must be greater than 0");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async onResponse(ctx, result) {
|
|
16
|
+
const cost = result.usage?.cost || 0;
|
|
17
|
+
this.accumulatedCost += cost;
|
|
18
|
+
if (this.accumulatedCost > this.options.maxCost) {
|
|
19
|
+
this.options.onLimitExceeded?.(ctx, this.accumulatedCost);
|
|
20
|
+
throw new Error(`[CostGuard] Budget exceeded. Accumulated cost $${this.accumulatedCost.toFixed(6)} exceeds limit $${this.options.maxCost.toFixed(6)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|