@drip-sdk/node 1.0.10 → 1.1.1
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 +154 -592
- package/dist/core.cjs +3 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +762 -0
- package/dist/core.d.ts +760 -0
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -0
- package/dist/express.cjs +2 -2
- package/dist/express.cjs.map +1 -1
- package/dist/express.d.cts +3 -3
- package/dist/express.d.ts +3 -3
- package/dist/express.js +2 -2
- package/dist/express.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +746 -54
- package/dist/index.d.ts +746 -54
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/langchain.cjs +3 -0
- package/dist/langchain.cjs.map +1 -0
- package/dist/langchain.d.cts +290 -0
- package/dist/langchain.d.ts +290 -0
- package/dist/langchain.js +3 -0
- package/dist/langchain.js.map +1 -0
- package/dist/middleware.cjs +2 -2
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.d.cts +3 -3
- package/dist/middleware.d.ts +3 -3
- package/dist/middleware.js +2 -2
- package/dist/middleware.js.map +1 -1
- package/dist/next.cjs +2 -2
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +3 -3
- package/dist/next.d.ts +3 -3
- package/dist/next.js +2 -2
- package/dist/next.js.map +1 -1
- package/dist/{types-D8mMON4v.d.ts → types-B2qwDadD.d.ts} +1 -1
- package/dist/{types-92iVqLtE.d.cts → types-Bo8SiUdl.d.cts} +1 -1
- package/package.json +23 -1
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drip LangChain integration.
|
|
3
|
+
*
|
|
4
|
+
* This module provides callback handlers for tracking LangChain LLM, tool,
|
|
5
|
+
* chain, and agent usage with automatic billing through the Drip API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { DripCallbackHandler } from '@drip-sdk/node/langchain';
|
|
10
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
11
|
+
*
|
|
12
|
+
* const handler = new DripCallbackHandler({
|
|
13
|
+
* apiKey: 'sk_live_...',
|
|
14
|
+
* customerId: 'cus_123',
|
|
15
|
+
* workflow: 'chatbot',
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const llm = new ChatOpenAI({
|
|
19
|
+
* callbacks: [handler],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const response = await llm.invoke('Hello, world!');
|
|
23
|
+
* // Usage is automatically tracked and billed
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Pricing per 1M tokens for a model.
|
|
30
|
+
*/
|
|
31
|
+
interface ModelPricing {
|
|
32
|
+
/** Cost per 1M input/prompt tokens in USD */
|
|
33
|
+
input: number;
|
|
34
|
+
/** Cost per 1M output/completion tokens in USD */
|
|
35
|
+
output: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* OpenAI pricing per 1M tokens (as of late 2024).
|
|
39
|
+
*/
|
|
40
|
+
declare const OPENAI_PRICING: Record<string, ModelPricing>;
|
|
41
|
+
/**
|
|
42
|
+
* Anthropic pricing per 1M tokens.
|
|
43
|
+
*/
|
|
44
|
+
declare const ANTHROPIC_PRICING: Record<string, ModelPricing>;
|
|
45
|
+
/**
|
|
46
|
+
* Get pricing for a model by name.
|
|
47
|
+
*
|
|
48
|
+
* @param modelName - The model name/identifier.
|
|
49
|
+
* @returns Pricing object with input/output costs per 1M tokens, or undefined if unknown.
|
|
50
|
+
*/
|
|
51
|
+
declare function getModelPricing(modelName: string): ModelPricing | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate the cost for a model invocation.
|
|
54
|
+
*
|
|
55
|
+
* @param modelName - The model name.
|
|
56
|
+
* @param inputTokens - Number of input/prompt tokens.
|
|
57
|
+
* @param outputTokens - Number of output/completion tokens.
|
|
58
|
+
* @returns Cost in USD, or undefined if pricing is unknown.
|
|
59
|
+
*/
|
|
60
|
+
declare function calculateCost(modelName: string, inputTokens: number, outputTokens: number): number | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Serialized representation from LangChain.
|
|
63
|
+
*/
|
|
64
|
+
interface Serialized {
|
|
65
|
+
name?: string;
|
|
66
|
+
id?: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* LLM result from LangChain.
|
|
70
|
+
*/
|
|
71
|
+
interface LLMResult {
|
|
72
|
+
llm_output?: {
|
|
73
|
+
token_usage?: {
|
|
74
|
+
prompt_tokens?: number;
|
|
75
|
+
completion_tokens?: number;
|
|
76
|
+
total_tokens?: number;
|
|
77
|
+
};
|
|
78
|
+
} | null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Agent action from LangChain.
|
|
82
|
+
*/
|
|
83
|
+
interface AgentAction {
|
|
84
|
+
tool: string;
|
|
85
|
+
toolInput: string | Record<string, unknown>;
|
|
86
|
+
log: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Agent finish from LangChain.
|
|
90
|
+
*/
|
|
91
|
+
interface AgentFinish {
|
|
92
|
+
returnValues: Record<string, unknown>;
|
|
93
|
+
log: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Document from LangChain.
|
|
97
|
+
*/
|
|
98
|
+
interface Document {
|
|
99
|
+
pageContent: string;
|
|
100
|
+
metadata: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Configuration options for DripCallbackHandler.
|
|
104
|
+
*/
|
|
105
|
+
interface DripCallbackHandlerOptions {
|
|
106
|
+
/**
|
|
107
|
+
* Drip API key. Falls back to DRIP_API_KEY environment variable.
|
|
108
|
+
*/
|
|
109
|
+
apiKey?: string;
|
|
110
|
+
/**
|
|
111
|
+
* The customer ID to bill usage to.
|
|
112
|
+
* Can be set later via the `customerId` property.
|
|
113
|
+
*/
|
|
114
|
+
customerId?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Workflow name or ID for grouping runs.
|
|
117
|
+
* @default "langchain"
|
|
118
|
+
*/
|
|
119
|
+
workflow?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Base URL for the Drip API.
|
|
122
|
+
*/
|
|
123
|
+
baseUrl?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Whether to automatically create runs when LLM calls start.
|
|
126
|
+
* @default true
|
|
127
|
+
*/
|
|
128
|
+
autoCreateRun?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Whether to emit events on errors.
|
|
131
|
+
* @default true
|
|
132
|
+
*/
|
|
133
|
+
emitOnError?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Additional metadata to attach to all events.
|
|
136
|
+
*/
|
|
137
|
+
metadata?: Record<string, unknown>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* LangChain callback handler for Drip usage tracking.
|
|
141
|
+
*
|
|
142
|
+
* This handler automatically tracks LLM calls, tool usage, chain executions,
|
|
143
|
+
* and agent actions, emitting events to the Drip API for billing.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* import { DripCallbackHandler } from '@drip-sdk/node/langchain';
|
|
148
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
149
|
+
*
|
|
150
|
+
* const handler = new DripCallbackHandler({
|
|
151
|
+
* apiKey: 'sk_live_...',
|
|
152
|
+
* customerId: 'cus_123',
|
|
153
|
+
* workflow: 'chatbot',
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* const llm = new ChatOpenAI({
|
|
157
|
+
* callbacks: [handler],
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* const response = await llm.invoke('Hello!');
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare class DripCallbackHandler {
|
|
164
|
+
private readonly _client;
|
|
165
|
+
private _customerId;
|
|
166
|
+
private readonly _workflow;
|
|
167
|
+
private readonly _autoCreateRun;
|
|
168
|
+
private readonly _emitOnError;
|
|
169
|
+
private readonly _baseMetadata;
|
|
170
|
+
private _currentRunId;
|
|
171
|
+
private readonly _llmCalls;
|
|
172
|
+
private readonly _toolCalls;
|
|
173
|
+
private readonly _chainCalls;
|
|
174
|
+
private readonly _agentCalls;
|
|
175
|
+
constructor(options?: DripCallbackHandlerOptions);
|
|
176
|
+
/**
|
|
177
|
+
* Get the customer ID.
|
|
178
|
+
* @throws Error if customer ID is not set.
|
|
179
|
+
*/
|
|
180
|
+
get customerId(): string;
|
|
181
|
+
/**
|
|
182
|
+
* Set the customer ID.
|
|
183
|
+
*/
|
|
184
|
+
set customerId(value: string);
|
|
185
|
+
/**
|
|
186
|
+
* Get the current run ID.
|
|
187
|
+
*/
|
|
188
|
+
get runId(): string | null;
|
|
189
|
+
/**
|
|
190
|
+
* Manually start a new run.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Run options.
|
|
193
|
+
* @returns The created run ID.
|
|
194
|
+
*/
|
|
195
|
+
startRun(options?: {
|
|
196
|
+
externalRunId?: string;
|
|
197
|
+
correlationId?: string;
|
|
198
|
+
metadata?: Record<string, unknown>;
|
|
199
|
+
}): Promise<string>;
|
|
200
|
+
/**
|
|
201
|
+
* Manually end the current run.
|
|
202
|
+
*
|
|
203
|
+
* @param status - Final status.
|
|
204
|
+
* @param errorMessage - Error message for failed runs.
|
|
205
|
+
*/
|
|
206
|
+
endRun(status?: 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'TIMEOUT', errorMessage?: string): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Ensure a run exists, creating one if autoCreateRun is enabled.
|
|
209
|
+
*/
|
|
210
|
+
private _ensureRun;
|
|
211
|
+
/**
|
|
212
|
+
* Emit an event to the Drip API.
|
|
213
|
+
*/
|
|
214
|
+
private _emitEvent;
|
|
215
|
+
/**
|
|
216
|
+
* Called when LLM starts running.
|
|
217
|
+
*/
|
|
218
|
+
handleLLMStart(serialized: Serialized, prompts: string[], runId: string, _parentRunId?: string, _extraParams?: Record<string, unknown>, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
219
|
+
/**
|
|
220
|
+
* Called when LLM ends running.
|
|
221
|
+
*/
|
|
222
|
+
handleLLMEnd(response: LLMResult, runId: string, _parentRunId?: string): Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Called when LLM errors.
|
|
225
|
+
*/
|
|
226
|
+
handleLLMError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Called on new LLM token (streaming).
|
|
229
|
+
* Tokens are tracked at completion, not per-token.
|
|
230
|
+
*/
|
|
231
|
+
handleLLMNewToken(_token: string, _idx: {
|
|
232
|
+
prompt: number;
|
|
233
|
+
completion: number;
|
|
234
|
+
}, _runId: string, _parentRunId?: string): void;
|
|
235
|
+
/**
|
|
236
|
+
* Called when chat model starts running.
|
|
237
|
+
*/
|
|
238
|
+
handleChatModelStart(serialized: Serialized, messages: unknown[][], runId: string, _parentRunId?: string, _extraParams?: Record<string, unknown>, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
239
|
+
/**
|
|
240
|
+
* Called when tool starts running.
|
|
241
|
+
*/
|
|
242
|
+
handleToolStart(serialized: Serialized, inputStr: string, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
243
|
+
/**
|
|
244
|
+
* Called when tool ends running.
|
|
245
|
+
*/
|
|
246
|
+
handleToolEnd(output: string, runId: string, _parentRunId?: string): Promise<void>;
|
|
247
|
+
/**
|
|
248
|
+
* Called when tool errors.
|
|
249
|
+
*/
|
|
250
|
+
handleToolError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
251
|
+
/**
|
|
252
|
+
* Called when chain starts running.
|
|
253
|
+
*/
|
|
254
|
+
handleChainStart(serialized: Serialized, inputs: Record<string, unknown>, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
255
|
+
/**
|
|
256
|
+
* Called when chain ends running.
|
|
257
|
+
*/
|
|
258
|
+
handleChainEnd(outputs: Record<string, unknown>, runId: string, _parentRunId?: string): Promise<void>;
|
|
259
|
+
/**
|
|
260
|
+
* Called when chain errors.
|
|
261
|
+
*/
|
|
262
|
+
handleChainError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
263
|
+
/**
|
|
264
|
+
* Called when agent takes an action.
|
|
265
|
+
*/
|
|
266
|
+
handleAgentAction(action: AgentAction, runId: string, _parentRunId?: string): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Called when agent finishes.
|
|
269
|
+
*/
|
|
270
|
+
handleAgentEnd(finish: AgentFinish, runId: string, _parentRunId?: string): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Called when retriever starts running.
|
|
273
|
+
*/
|
|
274
|
+
handleRetrieverStart(serialized: Serialized, query: string, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
275
|
+
/**
|
|
276
|
+
* Called when retriever ends running.
|
|
277
|
+
*/
|
|
278
|
+
handleRetrieverEnd(documents: Document[], runId: string, _parentRunId?: string): Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* Called when retriever errors.
|
|
281
|
+
*/
|
|
282
|
+
handleRetrieverError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
283
|
+
/**
|
|
284
|
+
* Called when arbitrary text is received.
|
|
285
|
+
* Optional: override to track text events if needed.
|
|
286
|
+
*/
|
|
287
|
+
handleText(_text: string, _runId: string, _parentRunId?: string): void;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export { ANTHROPIC_PRICING, DripCallbackHandler, type DripCallbackHandlerOptions, type ModelPricing, OPENAI_PRICING, calculateCost, getModelPricing };
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drip LangChain integration.
|
|
3
|
+
*
|
|
4
|
+
* This module provides callback handlers for tracking LangChain LLM, tool,
|
|
5
|
+
* chain, and agent usage with automatic billing through the Drip API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { DripCallbackHandler } from '@drip-sdk/node/langchain';
|
|
10
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
11
|
+
*
|
|
12
|
+
* const handler = new DripCallbackHandler({
|
|
13
|
+
* apiKey: 'sk_live_...',
|
|
14
|
+
* customerId: 'cus_123',
|
|
15
|
+
* workflow: 'chatbot',
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const llm = new ChatOpenAI({
|
|
19
|
+
* callbacks: [handler],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const response = await llm.invoke('Hello, world!');
|
|
23
|
+
* // Usage is automatically tracked and billed
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Pricing per 1M tokens for a model.
|
|
30
|
+
*/
|
|
31
|
+
interface ModelPricing {
|
|
32
|
+
/** Cost per 1M input/prompt tokens in USD */
|
|
33
|
+
input: number;
|
|
34
|
+
/** Cost per 1M output/completion tokens in USD */
|
|
35
|
+
output: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* OpenAI pricing per 1M tokens (as of late 2024).
|
|
39
|
+
*/
|
|
40
|
+
declare const OPENAI_PRICING: Record<string, ModelPricing>;
|
|
41
|
+
/**
|
|
42
|
+
* Anthropic pricing per 1M tokens.
|
|
43
|
+
*/
|
|
44
|
+
declare const ANTHROPIC_PRICING: Record<string, ModelPricing>;
|
|
45
|
+
/**
|
|
46
|
+
* Get pricing for a model by name.
|
|
47
|
+
*
|
|
48
|
+
* @param modelName - The model name/identifier.
|
|
49
|
+
* @returns Pricing object with input/output costs per 1M tokens, or undefined if unknown.
|
|
50
|
+
*/
|
|
51
|
+
declare function getModelPricing(modelName: string): ModelPricing | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate the cost for a model invocation.
|
|
54
|
+
*
|
|
55
|
+
* @param modelName - The model name.
|
|
56
|
+
* @param inputTokens - Number of input/prompt tokens.
|
|
57
|
+
* @param outputTokens - Number of output/completion tokens.
|
|
58
|
+
* @returns Cost in USD, or undefined if pricing is unknown.
|
|
59
|
+
*/
|
|
60
|
+
declare function calculateCost(modelName: string, inputTokens: number, outputTokens: number): number | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Serialized representation from LangChain.
|
|
63
|
+
*/
|
|
64
|
+
interface Serialized {
|
|
65
|
+
name?: string;
|
|
66
|
+
id?: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* LLM result from LangChain.
|
|
70
|
+
*/
|
|
71
|
+
interface LLMResult {
|
|
72
|
+
llm_output?: {
|
|
73
|
+
token_usage?: {
|
|
74
|
+
prompt_tokens?: number;
|
|
75
|
+
completion_tokens?: number;
|
|
76
|
+
total_tokens?: number;
|
|
77
|
+
};
|
|
78
|
+
} | null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Agent action from LangChain.
|
|
82
|
+
*/
|
|
83
|
+
interface AgentAction {
|
|
84
|
+
tool: string;
|
|
85
|
+
toolInput: string | Record<string, unknown>;
|
|
86
|
+
log: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Agent finish from LangChain.
|
|
90
|
+
*/
|
|
91
|
+
interface AgentFinish {
|
|
92
|
+
returnValues: Record<string, unknown>;
|
|
93
|
+
log: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Document from LangChain.
|
|
97
|
+
*/
|
|
98
|
+
interface Document {
|
|
99
|
+
pageContent: string;
|
|
100
|
+
metadata: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Configuration options for DripCallbackHandler.
|
|
104
|
+
*/
|
|
105
|
+
interface DripCallbackHandlerOptions {
|
|
106
|
+
/**
|
|
107
|
+
* Drip API key. Falls back to DRIP_API_KEY environment variable.
|
|
108
|
+
*/
|
|
109
|
+
apiKey?: string;
|
|
110
|
+
/**
|
|
111
|
+
* The customer ID to bill usage to.
|
|
112
|
+
* Can be set later via the `customerId` property.
|
|
113
|
+
*/
|
|
114
|
+
customerId?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Workflow name or ID for grouping runs.
|
|
117
|
+
* @default "langchain"
|
|
118
|
+
*/
|
|
119
|
+
workflow?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Base URL for the Drip API.
|
|
122
|
+
*/
|
|
123
|
+
baseUrl?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Whether to automatically create runs when LLM calls start.
|
|
126
|
+
* @default true
|
|
127
|
+
*/
|
|
128
|
+
autoCreateRun?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Whether to emit events on errors.
|
|
131
|
+
* @default true
|
|
132
|
+
*/
|
|
133
|
+
emitOnError?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Additional metadata to attach to all events.
|
|
136
|
+
*/
|
|
137
|
+
metadata?: Record<string, unknown>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* LangChain callback handler for Drip usage tracking.
|
|
141
|
+
*
|
|
142
|
+
* This handler automatically tracks LLM calls, tool usage, chain executions,
|
|
143
|
+
* and agent actions, emitting events to the Drip API for billing.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* import { DripCallbackHandler } from '@drip-sdk/node/langchain';
|
|
148
|
+
* import { ChatOpenAI } from '@langchain/openai';
|
|
149
|
+
*
|
|
150
|
+
* const handler = new DripCallbackHandler({
|
|
151
|
+
* apiKey: 'sk_live_...',
|
|
152
|
+
* customerId: 'cus_123',
|
|
153
|
+
* workflow: 'chatbot',
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* const llm = new ChatOpenAI({
|
|
157
|
+
* callbacks: [handler],
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* const response = await llm.invoke('Hello!');
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare class DripCallbackHandler {
|
|
164
|
+
private readonly _client;
|
|
165
|
+
private _customerId;
|
|
166
|
+
private readonly _workflow;
|
|
167
|
+
private readonly _autoCreateRun;
|
|
168
|
+
private readonly _emitOnError;
|
|
169
|
+
private readonly _baseMetadata;
|
|
170
|
+
private _currentRunId;
|
|
171
|
+
private readonly _llmCalls;
|
|
172
|
+
private readonly _toolCalls;
|
|
173
|
+
private readonly _chainCalls;
|
|
174
|
+
private readonly _agentCalls;
|
|
175
|
+
constructor(options?: DripCallbackHandlerOptions);
|
|
176
|
+
/**
|
|
177
|
+
* Get the customer ID.
|
|
178
|
+
* @throws Error if customer ID is not set.
|
|
179
|
+
*/
|
|
180
|
+
get customerId(): string;
|
|
181
|
+
/**
|
|
182
|
+
* Set the customer ID.
|
|
183
|
+
*/
|
|
184
|
+
set customerId(value: string);
|
|
185
|
+
/**
|
|
186
|
+
* Get the current run ID.
|
|
187
|
+
*/
|
|
188
|
+
get runId(): string | null;
|
|
189
|
+
/**
|
|
190
|
+
* Manually start a new run.
|
|
191
|
+
*
|
|
192
|
+
* @param options - Run options.
|
|
193
|
+
* @returns The created run ID.
|
|
194
|
+
*/
|
|
195
|
+
startRun(options?: {
|
|
196
|
+
externalRunId?: string;
|
|
197
|
+
correlationId?: string;
|
|
198
|
+
metadata?: Record<string, unknown>;
|
|
199
|
+
}): Promise<string>;
|
|
200
|
+
/**
|
|
201
|
+
* Manually end the current run.
|
|
202
|
+
*
|
|
203
|
+
* @param status - Final status.
|
|
204
|
+
* @param errorMessage - Error message for failed runs.
|
|
205
|
+
*/
|
|
206
|
+
endRun(status?: 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'TIMEOUT', errorMessage?: string): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Ensure a run exists, creating one if autoCreateRun is enabled.
|
|
209
|
+
*/
|
|
210
|
+
private _ensureRun;
|
|
211
|
+
/**
|
|
212
|
+
* Emit an event to the Drip API.
|
|
213
|
+
*/
|
|
214
|
+
private _emitEvent;
|
|
215
|
+
/**
|
|
216
|
+
* Called when LLM starts running.
|
|
217
|
+
*/
|
|
218
|
+
handleLLMStart(serialized: Serialized, prompts: string[], runId: string, _parentRunId?: string, _extraParams?: Record<string, unknown>, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
219
|
+
/**
|
|
220
|
+
* Called when LLM ends running.
|
|
221
|
+
*/
|
|
222
|
+
handleLLMEnd(response: LLMResult, runId: string, _parentRunId?: string): Promise<void>;
|
|
223
|
+
/**
|
|
224
|
+
* Called when LLM errors.
|
|
225
|
+
*/
|
|
226
|
+
handleLLMError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
227
|
+
/**
|
|
228
|
+
* Called on new LLM token (streaming).
|
|
229
|
+
* Tokens are tracked at completion, not per-token.
|
|
230
|
+
*/
|
|
231
|
+
handleLLMNewToken(_token: string, _idx: {
|
|
232
|
+
prompt: number;
|
|
233
|
+
completion: number;
|
|
234
|
+
}, _runId: string, _parentRunId?: string): void;
|
|
235
|
+
/**
|
|
236
|
+
* Called when chat model starts running.
|
|
237
|
+
*/
|
|
238
|
+
handleChatModelStart(serialized: Serialized, messages: unknown[][], runId: string, _parentRunId?: string, _extraParams?: Record<string, unknown>, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
239
|
+
/**
|
|
240
|
+
* Called when tool starts running.
|
|
241
|
+
*/
|
|
242
|
+
handleToolStart(serialized: Serialized, inputStr: string, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
243
|
+
/**
|
|
244
|
+
* Called when tool ends running.
|
|
245
|
+
*/
|
|
246
|
+
handleToolEnd(output: string, runId: string, _parentRunId?: string): Promise<void>;
|
|
247
|
+
/**
|
|
248
|
+
* Called when tool errors.
|
|
249
|
+
*/
|
|
250
|
+
handleToolError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
251
|
+
/**
|
|
252
|
+
* Called when chain starts running.
|
|
253
|
+
*/
|
|
254
|
+
handleChainStart(serialized: Serialized, inputs: Record<string, unknown>, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
255
|
+
/**
|
|
256
|
+
* Called when chain ends running.
|
|
257
|
+
*/
|
|
258
|
+
handleChainEnd(outputs: Record<string, unknown>, runId: string, _parentRunId?: string): Promise<void>;
|
|
259
|
+
/**
|
|
260
|
+
* Called when chain errors.
|
|
261
|
+
*/
|
|
262
|
+
handleChainError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
263
|
+
/**
|
|
264
|
+
* Called when agent takes an action.
|
|
265
|
+
*/
|
|
266
|
+
handleAgentAction(action: AgentAction, runId: string, _parentRunId?: string): Promise<void>;
|
|
267
|
+
/**
|
|
268
|
+
* Called when agent finishes.
|
|
269
|
+
*/
|
|
270
|
+
handleAgentEnd(finish: AgentFinish, runId: string, _parentRunId?: string): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Called when retriever starts running.
|
|
273
|
+
*/
|
|
274
|
+
handleRetrieverStart(serialized: Serialized, query: string, runId: string, _parentRunId?: string, _tags?: string[], _metadata?: Record<string, unknown>): void;
|
|
275
|
+
/**
|
|
276
|
+
* Called when retriever ends running.
|
|
277
|
+
*/
|
|
278
|
+
handleRetrieverEnd(documents: Document[], runId: string, _parentRunId?: string): Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* Called when retriever errors.
|
|
281
|
+
*/
|
|
282
|
+
handleRetrieverError(error: Error, runId: string, _parentRunId?: string): Promise<void>;
|
|
283
|
+
/**
|
|
284
|
+
* Called when arbitrary text is received.
|
|
285
|
+
* Optional: override to track text events if needed.
|
|
286
|
+
*/
|
|
287
|
+
handleText(_text: string, _runId: string, _parentRunId?: string): void;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export { ANTHROPIC_PRICING, DripCallbackHandler, type DripCallbackHandlerOptions, type ModelPricing, OPENAI_PRICING, calculateCost, getModelPricing };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {createHash}from'crypto';var v=(o=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(o,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):o)(function(o){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+o+'" is not supported')});var G=0;function b(o,...t){let e=++G,r=t.filter(n=>n!==void 0).map(String);r.push(String(e));let s=createHash("sha256").update(r.join("|")).digest("hex").slice(0,24);return `${o}_${s}`}var S=class{_total=0;_flushed=false;_flushCount=0;_chargeFn;_options;constructor(t,e){this._chargeFn=t,this._options=e;}get total(){return this._total}get isFlushed(){return this._flushed}get flushCount(){return this._flushCount}async add(t){return t<=0?null:(this._total+=t,this._options.onAdd?.(t,this._total),this._options.flushThreshold!==void 0&&this._total>=this._options.flushThreshold?this.flush():null)}addSync(t){t<=0||(this._total+=t,this._options.onAdd?.(t,this._total));}async flush(){let t=this._total;if(this._total=0,t===0)return {success:true,quantity:0,charge:null,isReplay:false};let e=this._options.idempotencyKey?`${this._options.idempotencyKey}_flush_${this._flushCount}`:b("stream",this._options.customerId,this._options.meter,t,this._flushCount),r=await this._chargeFn({customerId:this._options.customerId,meter:this._options.meter,quantity:t,idempotencyKey:e,metadata:this._options.metadata});this._flushed=true,this._flushCount++;let s={success:r.success,quantity:t,charge:r.charge,isReplay:r.isReplay};return this._options.onFlush?.(s),s}reset(){this._total=0;}};var z={requestsPerSecond:100,burstSize:200,enabled:true},E=class{config;tokens;lastRefill;constructor(t){this.config={...z,...t},this.tokens=this.config.burstSize,this.lastRefill=Date.now();}refill(){let t=Date.now(),e=(t-this.lastRefill)/1e3;this.tokens=Math.min(this.config.burstSize,this.tokens+e*this.config.requestsPerSecond),this.lastRefill=t;}async acquire(t){if(!this.config.enabled)return true;let e=t!==void 0?Date.now()+t:void 0;for(;;){if(this.refill(),this.tokens>=1)return this.tokens-=1,true;let r=(1-this.tokens)/this.config.requestsPerSecond*1e3;if(e!==void 0){let s=e-Date.now();if(s<=0)return false;await this.sleep(Math.min(r,s));}else await this.sleep(r);}}tryAcquire(){return this.config.enabled?(this.refill(),this.tokens>=1?(this.tokens-=1,true):false):true}get availableTokens(){return this.refill(),this.tokens}sleep(t){return new Promise(e=>setTimeout(e,t))}};var I=class o extends Error{attempts;lastError;constructor(t,e){super(`Retry exhausted after ${t} attempts: ${e.message}`),this.name="RetryExhaustedError",this.attempts=t,this.lastError=e,Object.setPrototypeOf(this,o.prototype);}};function N(o,t){let e=t.baseDelayMs*Math.pow(t.exponentialBase,o);if(e=Math.min(e,t.maxDelayMs),t.jitter>0){let r=e*t.jitter;e+=Math.random()*2*r-r;}return Math.max(0,e)}function $(o,t){if(o instanceof Error){if(o.message.includes("fetch")||o.message.includes("network")||o.message.includes("ECONNREFUSED")||o.message.includes("ETIMEDOUT"))return true;let e=o.statusCode;if(e!==void 0)return t.retryableStatusCodes.includes(e)}return false}var J={failureThreshold:5,successThreshold:2,timeoutMs:3e4,enabled:true},P=class o extends Error{circuitName;timeUntilRetryMs;constructor(t,e){super(`Circuit '${t}' is open. Retry in ${Math.round(e)}ms`),this.name="CircuitBreakerOpenError",this.circuitName=t,this.timeUntilRetryMs=e,Object.setPrototypeOf(this,o.prototype);}},M=class{name;config;state="closed";failureCount=0;successCount=0;lastFailureTime=null;constructor(t,e){this.name=t,this.config={...J,...e};}getState(){return this.checkStateTransition(),this.state}checkStateTransition(){this.state==="open"&&this.lastFailureTime!==null&&Date.now()-this.lastFailureTime>=this.config.timeoutMs&&(this.state="half_open",this.successCount=0);}recordSuccess(){this.config.enabled&&(this.state==="half_open"?(this.successCount+=1,this.successCount>=this.config.successThreshold&&(this.state="closed",this.failureCount=0)):this.state==="closed"&&(this.failureCount=0));}recordFailure(){this.config.enabled&&(this.failureCount+=1,this.lastFailureTime=Date.now(),this.state==="half_open"?this.state="open":this.state==="closed"&&this.failureCount>=this.config.failureThreshold&&(this.state="open"));}allowRequest(){return !this.config.enabled||(this.checkStateTransition(),this.state==="closed")?true:this.state==="half_open"}getTimeUntilRetry(){if(this.state!=="open"||this.lastFailureTime===null)return 0;let t=Date.now()-this.lastFailureTime;return Math.max(0,this.config.timeoutMs-t)}reset(){this.state="closed",this.failureCount=0,this.successCount=0,this.lastFailureTime=null;}},x=class{windowSize;metrics=[];totalRequests=0;totalSuccesses=0;totalFailures=0;constructor(t=1e3){this.windowSize=t;}record(t){for(this.metrics.push(t),this.totalRequests+=1,t.success?this.totalSuccesses+=1:this.totalFailures+=1;this.metrics.length>this.windowSize;)this.metrics.shift();}getSummary(){if(this.metrics.length===0)return {windowSize:0,totalRequests:0,totalSuccesses:0,totalFailures:0,successRate:0,avgLatencyMs:0,minLatencyMs:0,maxLatencyMs:0,p50LatencyMs:0,p95LatencyMs:0,p99LatencyMs:0,requestsByEndpoint:{},errorsByType:{}};let t=this.metrics.map(i=>i.durationMs).sort((i,a)=>i-a),e=this.metrics.filter(i=>i.success).length,r={};for(let i of this.metrics)r[i.endpoint]=(r[i.endpoint]??0)+1;let s={};for(let i of this.metrics)i.error&&(s[i.error]=(s[i.error]??0)+1);let n=t.reduce((i,a)=>i+a,0);return {windowSize:this.metrics.length,totalRequests:this.totalRequests,totalSuccesses:this.totalSuccesses,totalFailures:this.totalFailures,successRate:e/this.metrics.length*100,avgLatencyMs:n/t.length,minLatencyMs:t[0],maxLatencyMs:t[t.length-1],p50LatencyMs:t[Math.floor(t.length*.5)],p95LatencyMs:t[Math.floor(t.length*.95)],p99LatencyMs:t[Math.floor(t.length*.99)],requestsByEndpoint:r,errorsByType:s}}reset(){this.metrics.length=0,this.totalRequests=0,this.totalSuccesses=0,this.totalFailures=0;}};function R(){return {rateLimiter:{requestsPerSecond:100,burstSize:200,enabled:true},retry:{maxRetries:3,baseDelayMs:100,maxDelayMs:1e4,exponentialBase:2,jitter:.1,retryableStatusCodes:[429,500,502,503,504],enabled:true},circuitBreaker:{failureThreshold:5,successThreshold:2,timeoutMs:3e4,enabled:true},collectMetrics:true}}function D(){return {rateLimiter:{requestsPerSecond:1e3,burstSize:2e3,enabled:true},retry:{maxRetries:2,baseDelayMs:50,maxDelayMs:5e3,exponentialBase:2,jitter:.1,retryableStatusCodes:[429,500,502,503,504],enabled:true},circuitBreaker:{failureThreshold:10,successThreshold:3,timeoutMs:15e3,enabled:true},collectMetrics:true}}var C=class{config;rateLimiter;circuitBreaker;metrics;constructor(t){this.config={...R(),...t,rateLimiter:{...R().rateLimiter,...t?.rateLimiter},retry:{...R().retry,...t?.retry},circuitBreaker:{...R().circuitBreaker,...t?.circuitBreaker}},this.rateLimiter=new E(this.config.rateLimiter),this.circuitBreaker=new M("drip_api",this.config.circuitBreaker),this.metrics=this.config.collectMetrics?new x:null;}async execute(t,e="UNKNOWN",r="unknown"){let s=performance.now(),n=0,i=null;if(!await this.rateLimiter.acquire(3e4))throw new Error("Rate limiter timeout");if(!this.circuitBreaker.allowRequest())throw new P(this.circuitBreaker.name,this.circuitBreaker.getTimeUntilRetry());for(let u=0;u<=this.config.retry.maxRetries;u++)try{let l=await t();if(this.circuitBreaker.recordSuccess(),this.metrics){let d=performance.now()-s;this.metrics.record({method:e,endpoint:r,statusCode:200,durationMs:d,success:!0,timestamp:Date.now(),retryCount:n});}return l}catch(l){if(i=l instanceof Error?l:new Error(String(l)),this.config.retry.enabled&&$(l,this.config.retry)&&u<this.config.retry.maxRetries){n+=1;let f=N(u,this.config.retry);await this.sleep(f);continue}if(this.circuitBreaker.recordFailure(),this.metrics){let f=performance.now()-s,y=l.statusCode??null;this.metrics.record({method:e,endpoint:r,statusCode:y,durationMs:f,success:false,timestamp:Date.now(),error:i.name,retryCount:n});}throw l}throw i?new I(this.config.retry.maxRetries+1,i):new Error("Unexpected execution path")}getMetrics(){return this.metrics?.getSummary()??null}getHealth(){return {circuitBreaker:{state:this.circuitBreaker.getState(),timeUntilRetryMs:this.circuitBreaker.getTimeUntilRetry()},rateLimiter:{availableTokens:this.rateLimiter.availableTokens,requestsPerSecond:this.config.rateLimiter.requestsPerSecond},metrics:this.getMetrics()}}sleep(t){return new Promise(e=>setTimeout(e,t))}};var L={maxAttempts:3,baseDelayMs:100,maxDelayMs:5e3};function Y(o){return o instanceof Error&&(o.message.includes("fetch")||o.message.includes("network"))?true:o instanceof p?o.statusCode>=500||o.statusCode===408||o.statusCode===429:false}async function V(o,t={}){let e=t.maxAttempts??L.maxAttempts,r=t.baseDelayMs??L.baseDelayMs,s=t.maxDelayMs??L.maxDelayMs,n=t.isRetryable??Y,i;for(let a=1;a<=e;a++)try{return await o()}catch(u){if(i=u,a===e||!n(u))throw u;let l=Math.min(r*Math.pow(2,a-1)+Math.random()*100,s);await new Promise(d=>setTimeout(d,l));}throw i}var p=class o extends Error{constructor(e,r,s){super(e);this.statusCode=r;this.code=s;this.name="DripError",Object.setPrototypeOf(this,o.prototype);}},k=class{apiKey;baseUrl;timeout;resilience;keyType;constructor(t={}){let e=t.apiKey??(typeof process<"u"?process.env.DRIP_API_KEY:void 0),r=t.baseUrl??(typeof process<"u"?process.env.DRIP_BASE_URL:void 0);if(!e)throw new Error("Drip API key is required. Either pass { apiKey } to constructor or set DRIP_API_KEY environment variable.");this.apiKey=e,this.baseUrl=r||"https://drip-app-hlunj.ondigitalocean.app/v1",this.timeout=t.timeout||3e4,e.startsWith("sk_")?this.keyType="secret":e.startsWith("pk_")?this.keyType="public":this.keyType="unknown",t.resilience===true?this.resilience=new C(R()):t.resilience==="high-throughput"?this.resilience=new C(D()):t.resilience&&typeof t.resilience=="object"?this.resilience=new C(t.resilience):this.resilience=null;}assertSecretKey(t){if(this.keyType==="public")throw new p(`${t} requires a secret key (sk_). You are using a public key (pk_), which cannot access this endpoint. Use a secret key for webhook, API key, and feature flag management.`,403,"PUBLIC_KEY_NOT_ALLOWED")}async request(t,e={}){let r=(e.method??"GET").toUpperCase();return this.resilience?this.resilience.execute(()=>this.rawRequest(t,e),r,t):this.rawRequest(t,e)}async rawRequest(t,e={}){let r=new AbortController,s=setTimeout(()=>r.abort(),this.timeout);try{let n=await fetch(`${this.baseUrl}${t}`,{...e,signal:r.signal,headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`,...e.headers}});if(n.status===204)return {success:!0};let i=await n.json();if(!n.ok)throw new p(i.message||i.error||"Request failed",n.status,i.code);return i}catch(n){throw n instanceof p?n:n instanceof Error&&n.name==="AbortError"?new p("Request timed out",408,"TIMEOUT"):new p(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(s);}}async ping(){let t=new AbortController,e=setTimeout(()=>t.abort(),this.timeout),r=this.baseUrl;r.endsWith("/v1/")?r=r.slice(0,-4):r.endsWith("/v1")&&(r=r.slice(0,-3)),r=r.replace(/\/+$/,"");let s=Date.now();try{let n=await fetch(`${r}/health`,{signal:t.signal,headers:{Authorization:`Bearer ${this.apiKey}`}}),i=Date.now()-s,a="unknown",u=Date.now();try{let l=await n.json();typeof l.status=="string"&&(a=l.status),typeof l.timestamp=="number"&&(u=l.timestamp);}catch{a=n.ok?"healthy":`error:${n.status}`;}return !n.ok&&a==="unknown"&&(a=`error:${n.status}`),{ok:n.ok&&a==="healthy",status:a,latencyMs:i,timestamp:u}}catch(n){throw n instanceof Error&&n.name==="AbortError"?new p("Request timed out",408,"TIMEOUT"):new p(n instanceof Error?n.message:"Unknown error",0,"UNKNOWN")}finally{clearTimeout(e);}}getMetrics(){return this.resilience?.getMetrics()??null}getHealth(){return this.resilience?.getHealth()??null}async createCustomer(t){return this.request("/customers",{method:"POST",body:JSON.stringify(t)})}async getCustomer(t){return this.request(`/customers/${t}`)}async listCustomers(t){let e=new URLSearchParams;t?.limit&&e.set("limit",t.limit.toString()),t?.status&&e.set("status",t.status);let r=e.toString(),s=r?`/customers?${r}`:"/customers";return this.request(s)}async getBalance(t){return this.request(`/customers/${t}/balance`)}async charge(t){let e=t.idempotencyKey??b("chg",t.customerId,t.meter,t.quantity);return this.request("/usage",{method:"POST",body:JSON.stringify({customerId:t.customerId,usageType:t.meter,quantity:t.quantity,idempotencyKey:e,metadata:t.metadata})})}async wrapApiCall(t){let e=t.idempotencyKey??`wrap_${Date.now()}_${Math.random().toString(36).slice(2,11)}`,r=await t.call(),s=t.extractUsage(r),n=await V(()=>this.charge({customerId:t.customerId,meter:t.meter,quantity:s,idempotencyKey:e,metadata:t.metadata}),t.retryOptions);return {result:r,charge:n,idempotencyKey:e}}async trackUsage(t){let e=t.idempotencyKey??b("track",t.customerId,t.meter,t.quantity);return this.request("/usage/internal",{method:"POST",body:JSON.stringify({customerId:t.customerId,usageType:t.meter,quantity:t.quantity,idempotencyKey:e,units:t.units,description:t.description,metadata:t.metadata})})}async getCharge(t){return this.request(`/charges/${t}`)}async listCharges(t){let e=new URLSearchParams;t?.customerId&&e.set("customerId",t.customerId),t?.status&&e.set("status",t.status),t?.limit&&e.set("limit",t.limit.toString()),t?.offset&&e.set("offset",t.offset.toString());let r=e.toString(),s=r?`/charges?${r}`:"/charges";return this.request(s)}async getChargeStatus(t){return this.request(`/charges/${t}/status`)}async checkout(t){let e=await this.request("/checkout",{method:"POST",body:JSON.stringify({customer_id:t.customerId,external_customer_id:t.externalCustomerId,amount:t.amount,return_url:t.returnUrl,cancel_url:t.cancelUrl,metadata:t.metadata})});return {id:e.id,url:e.url,expiresAt:e.expires_at,amountUsd:e.amount_usd}}async createWebhook(t){return this.assertSecretKey("createWebhook()"),this.request("/webhooks",{method:"POST",body:JSON.stringify(t)})}async listWebhooks(){return this.assertSecretKey("listWebhooks()"),this.request("/webhooks")}async getWebhook(t){return this.assertSecretKey("getWebhook()"),this.request(`/webhooks/${t}`)}async deleteWebhook(t){return this.assertSecretKey("deleteWebhook()"),this.request(`/webhooks/${t}`,{method:"DELETE"})}async testWebhook(t){return this.assertSecretKey("testWebhook()"),this.request(`/webhooks/${t}/test`,{method:"POST"})}async rotateWebhookSecret(t){return this.assertSecretKey("rotateWebhookSecret()"),this.request(`/webhooks/${t}/rotate-secret`,{method:"POST"})}async createWorkflow(t){return this.request("/workflows",{method:"POST",body:JSON.stringify(t)})}async listWorkflows(){return this.request("/workflows")}async startRun(t){return this.request("/runs",{method:"POST",body:JSON.stringify(t)})}async endRun(t,e){return this.request(`/runs/${t}`,{method:"PATCH",body:JSON.stringify(e)})}async getRun(t){return this.request(`/runs/${t}`)}async getRunTimeline(t,e){let r=new URLSearchParams;e?.limit&&r.set("limit",e.limit.toString()),e?.cursor&&r.set("cursor",e.cursor),e?.includeAnomalies!==void 0&&r.set("includeAnomalies",String(e.includeAnomalies)),e?.collapseRetries!==void 0&&r.set("collapseRetries",String(e.collapseRetries));let s=r.toString(),n=s?`/runs/${t}/timeline?${s}`:`/runs/${t}/timeline`;return this.request(n)}async emitEvent(t){let e=t.idempotencyKey??b("evt",t.runId,t.eventType,t.quantity);return this.request("/run-events",{method:"POST",body:JSON.stringify({...t,idempotencyKey:e})})}async emitEventsBatch(t){return this.request("/run-events/batch",{method:"POST",body:JSON.stringify({events:t})})}async listMeters(){let t=await this.request("/pricing-plans");return {data:t.data.map(e=>({id:e.id,name:e.name,meter:e.unitType,unitPriceUsd:e.unitPriceUsd,isActive:e.isActive})),count:t.count}}async estimateFromUsage(t){let e=t.periodStart instanceof Date?t.periodStart.toISOString():t.periodStart,r=t.periodEnd instanceof Date?t.periodEnd.toISOString():t.periodEnd;return this.request("/dashboard/cost-estimate/from-usage",{method:"POST",body:JSON.stringify({customerId:t.customerId,periodStart:e,periodEnd:r,defaultUnitPrice:t.defaultUnitPrice,includeChargedEvents:t.includeChargedEvents,usageTypes:t.usageTypes,customPricing:t.customPricing})})}async estimateFromHypothetical(t){return this.request("/dashboard/cost-estimate/hypothetical",{method:"POST",body:JSON.stringify({items:t.items,defaultUnitPrice:t.defaultUnitPrice,customPricing:t.customPricing})})}async recordRun(t){let e=Date.now(),r=t.workflow,s=t.workflow;if(!t.workflow.startsWith("wf_"))try{let m=(await this.listWorkflows()).data.find(c=>c.slug===t.workflow||c.id===t.workflow);if(m)r=m.id,s=m.name;else {let c=await this.createWorkflow({name:t.workflow.replace(/[_-]/g," ").replace(/\b\w/g,g=>g.toUpperCase()),slug:t.workflow,productSurface:"AGENT"});r=c.id,s=c.name;}}catch{r=t.workflow;}let n=await this.startRun({customerId:t.customerId,workflowId:r,externalRunId:t.externalRunId,correlationId:t.correlationId,metadata:t.metadata}),i=0,a=0;if(t.events.length>0){let w=t.events.map((c,g)=>({runId:n.id,eventType:c.eventType,quantity:c.quantity,units:c.units,description:c.description,costUnits:c.costUnits,metadata:c.metadata,idempotencyKey:t.externalRunId?`${t.externalRunId}:${c.eventType}:${g}`:b("run",n.id,c.eventType,g)})),m=await this.emitEventsBatch(w);i=m.created,a=m.duplicates;}let u=await this.endRun(n.id,{status:t.status,errorMessage:t.errorMessage,errorCode:t.errorCode}),l=Date.now()-e,d=t.events.length>0?`${i} events recorded`:"no events",y=`${t.status==="COMPLETED"?"\u2713":t.status==="FAILED"?"\u2717":"\u25CB"} ${s}: ${d} (${u.durationMs??l}ms)`;return {run:{id:n.id,workflowId:r,workflowName:s,status:t.status,durationMs:u.durationMs},events:{created:i,duplicates:a},totalCostUnits:u.totalCostUnits,summary:y}}static generateIdempotencyKey(t){let r=[t.customerId,t.runId??"no_run",t.stepName,String(t.sequence??0)].join("|");return `drip_${v("crypto").createHash("sha256").update(r).digest("hex").slice(0,32)}_${t.stepName.slice(0,16)}`}static async verifyWebhookSignature(t,e,r,s=300){if(!t||!e||!r)return false;try{let n=e.split(","),i=n.find(h=>h.startsWith("t=")),a=n.find(h=>h.startsWith("v1="));if(!i||!a)return !1;let u=parseInt(i.slice(2),10),l=a.slice(3);if(isNaN(u))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-u)>s)return !1;let f=`${u}.${t}`,y=new TextEncoder,w=y.encode(r),m=y.encode(f),c=globalThis.crypto?.subtle??v("crypto").webcrypto.subtle,g=await c.importKey("raw",w,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),H=await c.sign("HMAC",g,m),O=Array.from(new Uint8Array(H)).map(h=>h.toString(16).padStart(2,"0")).join("");if(l.length!==O.length)return !1;let U=0;for(let h=0;h<l.length;h++)U|=l.charCodeAt(h)^O.charCodeAt(h);return U===0}catch{return false}}static verifyWebhookSignatureSync(t,e,r,s=300){if(!t||!e||!r)return false;try{let n=e.split(","),i=n.find(g=>g.startsWith("t=")),a=n.find(g=>g.startsWith("v1="));if(!i||!a)return !1;let u=parseInt(i.slice(2),10),l=a.slice(3);if(isNaN(u))return !1;let d=Math.floor(Date.now()/1e3);if(Math.abs(d-u)>s)return !1;let f=v("crypto"),y=`${u}.${t}`,w=f.createHmac("sha256",r).update(y).digest("hex"),m=Buffer.from(l),c=Buffer.from(w);return m.length!==c.length?!1:f.timingSafeEqual(m,c)}catch{return false}}static generateWebhookSignature(t,e,r){let s=v("crypto"),n=r??Math.floor(Date.now()/1e3),i=`${n}.${t}`,a=s.createHmac("sha256",e).update(i).digest("hex");return `t=${n},v1=${a}`}createStreamMeter(t){return new S(this.charge.bind(this),t)}};var A=null;function Q(){return A||(A=new k),A}new Proxy({},{get(o,t){let e=Q(),r=e[t];return typeof r=="function"?r.bind(e):r}});var W={"gpt-4o":{input:2.5,output:10},"gpt-4o-mini":{input:.15,output:.6},"gpt-4-turbo":{input:10,output:30},"gpt-4":{input:30,output:60},"gpt-4-32k":{input:60,output:120},"gpt-3.5-turbo":{input:.5,output:1.5},"gpt-3.5-turbo-16k":{input:3,output:4},"text-embedding-3-small":{input:.02,output:0},"text-embedding-3-large":{input:.13,output:0},"text-embedding-ada-002":{input:.1,output:0}},B={"claude-3-5-sonnet":{input:3,output:15},"claude-3-opus":{input:15,output:75},"claude-3-sonnet":{input:3,output:15},"claude-3-haiku":{input:.25,output:1.25},"claude-2.1":{input:8,output:24},"claude-2.0":{input:8,output:24},"claude-instant-1.2":{input:.8,output:2.4}};function F(o){let t=o.toLowerCase();for(let[e,r]of Object.entries(W))if(t.includes(e))return r;for(let[e,r]of Object.entries(B))if(t.includes(e))return r}function K(o,t,e){let r=F(o);if(r===void 0)return;let s=t/1e6*r.input,n=e/1e6*r.output;return s+n}var q=class{_client;_customerId;_workflow;_autoCreateRun;_emitOnError;_baseMetadata;_currentRunId=null;_llmCalls=new Map;_toolCalls=new Map;_chainCalls=new Map;_agentCalls=new Map;constructor(t={}){this._client=new k({apiKey:t.apiKey??process.env.DRIP_API_KEY??"",baseUrl:t.baseUrl}),this._customerId=t.customerId,this._workflow=t.workflow??"langchain",this._autoCreateRun=t.autoCreateRun??true,this._emitOnError=t.emitOnError??true,this._baseMetadata=t.metadata??{};}get customerId(){if(this._customerId===void 0)throw new Error("customerId must be set before using the handler");return this._customerId}set customerId(t){this._customerId=t;}get runId(){return this._currentRunId}async startRun(t={}){let e=await this._client.recordRun({customerId:this.customerId,workflow:this._workflow,events:[],status:"COMPLETED",externalRunId:t.externalRunId,correlationId:t.correlationId,metadata:{...this._baseMetadata,...t.metadata??{}}});return this._currentRunId=e.run.id,this._currentRunId}async endRun(t="COMPLETED",e){this._currentRunId&&(await this._client.endRun(this._currentRunId,{status:t,errorMessage:e}),this._currentRunId=null);}async _ensureRun(){if(this._currentRunId===null)if(this._autoCreateRun){let t=await this._client.startRun({customerId:this.customerId,workflowId:this._workflow,metadata:this._baseMetadata});this._currentRunId=t.id;}else throw new Error("No active run. Call startRun() first.");return this._currentRunId}async _emitEvent(t){let e=await this._ensureRun(),r;t.idempotencySuffix&&(r=k.generateIdempotencyKey({customerId:this.customerId,stepName:`${t.eventType}:${t.idempotencySuffix}`,runId:e})),await this._client.emitEvent({runId:e,eventType:t.eventType,quantity:t.quantity,units:t.units,description:t.description,costUnits:t.costUnits,idempotencyKey:r,metadata:{...this._baseMetadata,...t.metadata??{}}});}handleLLMStart(t,e,r,s,n,i,a){let u=t.name??t.id?.at(-1)??"unknown";this._llmCalls.set(r,{runId:r,model:u,startTime:Date.now(),prompts:e,inputTokens:0,outputTokens:0,totalTokens:0,error:null});}async handleLLMEnd(t,e,r){let s=this._llmCalls.get(e);if(this._llmCalls.delete(e),!s)return;let n=Date.now()-s.startTime,i=t.llm_output?.token_usage??{},a=i.prompt_tokens??0,u=i.completion_tokens??0,l=i.total_tokens??a+u,d=K(s.model,a,u);await this._emitEvent({eventType:"llm.completion",quantity:l,units:"tokens",description:`LLM call to ${s.model}`,costUnits:d,metadata:{model:s.model,inputTokens:a,outputTokens:u,latencyMs:n,promptCount:s.prompts.length},idempotencySuffix:e});}async handleLLMError(t,e,r){let s=this._llmCalls.get(e);if(this._llmCalls.delete(e),!!s&&this._emitOnError){let n=Date.now()-s.startTime;await this._emitEvent({eventType:"llm.error",quantity:1,units:"errors",description:`LLM error: ${t.name}`,metadata:{model:s.model,errorType:t.name,errorMessage:t.message,latencyMs:n},idempotencySuffix:e});}}handleLLMNewToken(t,e,r,s){}handleChatModelStart(t,e,r,s,n,i,a){let u=t.name??t.id?.at(-1)??"unknown",l=e.map(d=>JSON.stringify(d));this._llmCalls.set(r,{runId:r,model:u,startTime:Date.now(),prompts:l,inputTokens:0,outputTokens:0,totalTokens:0,error:null});}handleToolStart(t,e,r,s,n,i){let a=t.name??"unknown_tool";this._toolCalls.set(r,{runId:r,toolName:a,startTime:Date.now(),inputStr:e.slice(0,1e3),outputStr:"",error:null});}async handleToolEnd(t,e,r){let s=this._toolCalls.get(e);if(this._toolCalls.delete(e),!s)return;let n=Date.now()-s.startTime;await this._emitEvent({eventType:"tool.call",quantity:1,units:"calls",description:`Tool: ${s.toolName}`,metadata:{toolName:s.toolName,latencyMs:n,inputPreview:s.inputStr.slice(0,200),outputPreview:String(t).slice(0,200)},idempotencySuffix:e});}async handleToolError(t,e,r){let s=this._toolCalls.get(e);if(this._toolCalls.delete(e),!!s&&this._emitOnError){let n=Date.now()-s.startTime;await this._emitEvent({eventType:"tool.error",quantity:1,units:"errors",description:`Tool error: ${s.toolName}`,metadata:{toolName:s.toolName,errorType:t.name,errorMessage:t.message,latencyMs:n},idempotencySuffix:e});}}handleChainStart(t,e,r,s,n,i){let a=t.name??t.id?.at(-1)??"unknown";this._chainCalls.set(r,{runId:r,chainType:a,startTime:Date.now(),inputs:e,outputs:{},error:null});}async handleChainEnd(t,e,r){let s=this._chainCalls.get(e);if(this._chainCalls.delete(e),!s)return;let n=Date.now()-s.startTime;await this._emitEvent({eventType:"chain.execution",quantity:1,units:"executions",description:`Chain: ${s.chainType}`,metadata:{chainType:s.chainType,latencyMs:n,inputKeys:Object.keys(s.inputs),outputKeys:Object.keys(t)},idempotencySuffix:e});}async handleChainError(t,e,r){let s=this._chainCalls.get(e);if(this._chainCalls.delete(e),!!s&&this._emitOnError){let n=Date.now()-s.startTime;await this._emitEvent({eventType:"chain.error",quantity:1,units:"errors",description:`Chain error: ${s.chainType}`,metadata:{chainType:s.chainType,errorType:t.name,errorMessage:t.message,latencyMs:n},idempotencySuffix:e});}}async handleAgentAction(t,e,r){let s=this._agentCalls.get(e);s||(s={runId:e,startTime:Date.now(),actions:[],finalOutput:null,error:null},this._agentCalls.set(e,s));let n=typeof t.toolInput=="string"?t.toolInput:JSON.stringify(t.toolInput);s.actions.push({tool:t.tool,toolInput:n.slice(0,500),log:t.log?.slice(0,500)??null}),await this._emitEvent({eventType:"agent.action",quantity:1,units:"actions",description:`Agent action: ${t.tool}`,metadata:{tool:t.tool,actionCount:s.actions.length},idempotencySuffix:`${e}:${s.actions.length}`});}async handleAgentEnd(t,e,r){let s=this._agentCalls.get(e);this._agentCalls.delete(e);let n=0,i=0;s&&(n=Date.now()-s.startTime,i=s.actions.length),await this._emitEvent({eventType:"agent.finish",quantity:i||1,units:"actions",description:"Agent run completed",metadata:{latencyMs:n,actionCount:i,outputPreview:JSON.stringify(t.returnValues).slice(0,500)},idempotencySuffix:e});}handleRetrieverStart(t,e,r,s,n,i){let a=t.name??"retriever";this._toolCalls.set(r,{runId:r,toolName:`retriever:${a}`,startTime:Date.now(),inputStr:e.slice(0,1e3),outputStr:"",error:null});}async handleRetrieverEnd(t,e,r){let s=this._toolCalls.get(e);if(this._toolCalls.delete(e),!s)return;let n=Date.now()-s.startTime;await this._emitEvent({eventType:"retriever.query",quantity:t.length,units:"documents",description:`Retriever: ${s.toolName}`,metadata:{retriever:s.toolName,queryPreview:s.inputStr.slice(0,200),documentCount:t.length,latencyMs:n},idempotencySuffix:e});}async handleRetrieverError(t,e,r){let s=this._toolCalls.get(e);if(this._toolCalls.delete(e),!!s&&this._emitOnError){let n=Date.now()-s.startTime;await this._emitEvent({eventType:"retriever.error",quantity:1,units:"errors",description:`Retriever error: ${s.toolName}`,metadata:{retriever:s.toolName,errorType:t.name,errorMessage:t.message,latencyMs:n},idempotencySuffix:e});}}handleText(t,e,r){}};
|
|
2
|
+
export{B as ANTHROPIC_PRICING,q as DripCallbackHandler,W as OPENAI_PRICING,K as calculateCost,F as getModelPricing};//# sourceMappingURL=langchain.js.map
|
|
3
|
+
//# sourceMappingURL=langchain.js.map
|