promptlayer 1.0.59 → 1.0.61

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "promptlayer",
3
3
  "license": "MIT",
4
- "version": "1.0.59",
4
+ "version": "1.0.61",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -13,6 +13,7 @@
13
13
  "scripts": {
14
14
  "build": "tsup-node",
15
15
  "lint": "tsc",
16
+ "test": "vitest run",
16
17
  "release": "npm run build && npm publish"
17
18
  },
18
19
  "devDependencies": {
@@ -20,13 +21,14 @@
20
21
  "@anthropic-ai/sdk": "^0.57.0",
21
22
  "@anthropic-ai/vertex-sdk": "^0.11.5",
22
23
  "@aws-sdk/client-bedrock-runtime": "^3.864.0",
23
- "@google/genai": "^1.8.0",
24
+ "@google/genai": "^1.45.0",
24
25
  "@mistralai/mistralai": "^1.7.5",
25
26
  "@types/ably": "^1.0.0",
26
27
  "@types/node": "^20.8.0",
27
28
  "openai": "^6.7.0",
28
29
  "tsup": "^8.5.1",
29
30
  "typescript": "^5.2.2",
31
+ "vitest": "^2.1.9",
30
32
  "zod": "^3.25.0"
31
33
  },
32
34
  "dependencies": {
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  utilLogRequest,
28
28
  vertexaiRequest,
29
29
  } from "@/utils/utils";
30
+ import { categorizeError } from "@/utils/errors";
30
31
  import { streamResponse } from "@/utils/streaming";
31
32
  import * as opentelemetry from "@opentelemetry/api";
32
33
 
@@ -252,8 +253,6 @@ export class PromptLayer {
252
253
  );
253
254
  }
254
255
 
255
- const response = await request_function(promptBlueprint!, kwargs);
256
-
257
256
  const _trackRequest = (body: object) => {
258
257
  const request_end_time = new Date().toISOString();
259
258
  return trackRequest(
@@ -280,6 +279,22 @@ export class PromptLayer {
280
279
  );
281
280
  };
282
281
 
282
+ let response: any;
283
+ try {
284
+ response = await request_function(promptBlueprint!, kwargs);
285
+ } catch (llmError: unknown) {
286
+ const errorType = categorizeError(llmError);
287
+ const errorMessage =
288
+ llmError instanceof Error ? llmError.message : String(llmError);
289
+ await _trackRequest({
290
+ request_response: {},
291
+ status: "ERROR",
292
+ error_type: errorType,
293
+ error_message: errorMessage,
294
+ });
295
+ throw llmError;
296
+ }
297
+
283
298
  if (stream)
284
299
  return streamResponse(
285
300
  response,
@@ -0,0 +1,146 @@
1
+ import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
2
+
3
+ // Mock modules before importing the subject
4
+ vi.mock("@/utils/utils", () => ({
5
+ trackRequest: vi.fn().mockResolvedValue({ request_id: 1, prompt_blueprint: {} }),
6
+ configureProviderSettings: vi.fn().mockReturnValue({
7
+ provider_type: "openai",
8
+ kwargs: { model: "gpt-4" },
9
+ }),
10
+ getProviderConfig: vi.fn().mockReturnValue({
11
+ function_name: "openai.chat.completions.create",
12
+ stream_function: null,
13
+ }),
14
+ openaiRequest: vi.fn().mockResolvedValue({ choices: [{ message: { content: "hi" } }] }),
15
+ anthropicRequest: vi.fn(),
16
+ azureOpenAIRequest: vi.fn(),
17
+ googleRequest: vi.fn(),
18
+ mistralRequest: vi.fn(),
19
+ vertexaiRequest: vi.fn(),
20
+ amazonBedrockRequest: vi.fn(),
21
+ anthropicBedrockRequest: vi.fn(),
22
+ readEnv: vi.fn().mockReturnValue("test-api-key"),
23
+ runWorkflowRequest: vi.fn(),
24
+ utilLogRequest: vi.fn(),
25
+ }));
26
+
27
+ vi.mock("@/templates", () => {
28
+ return {
29
+ TemplateManager: class {
30
+ get = vi.fn().mockResolvedValue({
31
+ id: 1,
32
+ version: 1,
33
+ prompt_template: { type: "chat", messages: [] },
34
+ metadata: { model: { provider: "openai", name: "gpt-4", parameters: {} } },
35
+ llm_kwargs: { model: "gpt-4" },
36
+ custom_provider: null,
37
+ });
38
+ },
39
+ };
40
+ });
41
+
42
+ vi.mock("@/tracing", () => {
43
+ const fakeSpan = {
44
+ setAttribute: vi.fn(),
45
+ setStatus: vi.fn(),
46
+ end: vi.fn(),
47
+ spanContext: () => ({ spanId: "test-span-id" }),
48
+ };
49
+ return {
50
+ getTracer: () => ({
51
+ startActiveSpan: (_name: string, fn: (span: any) => any) => fn(fakeSpan),
52
+ }),
53
+ setupTracing: vi.fn(),
54
+ };
55
+ });
56
+
57
+ vi.mock("@/groups", () => ({
58
+ GroupManager: class {},
59
+ }));
60
+
61
+ vi.mock("@/track", () => ({
62
+ TrackManager: class {},
63
+ }));
64
+
65
+ vi.mock("@/span-wrapper", () => ({
66
+ wrapWithSpan: vi.fn(),
67
+ }));
68
+
69
+ vi.mock("@/utils/streaming", () => ({
70
+ streamResponse: vi.fn().mockReturnValue({ async *[Symbol.asyncIterator]() {} }),
71
+ }));
72
+
73
+ import { PromptLayer } from "@/index";
74
+ import { trackRequest, openaiRequest } from "@/utils/utils";
75
+ import { RateLimitError } from "openai";
76
+
77
+ describe("run() error tracking", () => {
78
+ let client: PromptLayer;
79
+
80
+ beforeEach(() => {
81
+ vi.clearAllMocks();
82
+ client = new PromptLayer({ apiKey: "test-api-key" });
83
+ });
84
+
85
+ it("tracks error with UNKNOWN_ERROR type and re-throws when LLM call fails", async () => {
86
+ const llmError = new Error("model overloaded");
87
+ (openaiRequest as Mock).mockRejectedValueOnce(llmError);
88
+
89
+ await expect(
90
+ client.run({ promptName: "test-prompt" })
91
+ ).rejects.toThrow("model overloaded");
92
+
93
+ expect(trackRequest).toHaveBeenCalledWith(
94
+ expect.any(String),
95
+ expect.objectContaining({
96
+ request_response: {},
97
+ status: "ERROR",
98
+ error_type: "UNKNOWN_ERROR",
99
+ error_message: "model overloaded",
100
+ }),
101
+ true
102
+ );
103
+ });
104
+
105
+ it("tracks PROVIDER_RATE_LIMIT when LLM throws RateLimitError", async () => {
106
+ const rateLimitError = new RateLimitError(
107
+ 429, undefined, "Too Many Requests", undefined
108
+ );
109
+ (openaiRequest as Mock).mockRejectedValueOnce(rateLimitError);
110
+
111
+ await expect(
112
+ client.run({ promptName: "test-prompt" })
113
+ ).rejects.toThrow("Too Many Requests");
114
+
115
+ expect(trackRequest).toHaveBeenCalledWith(
116
+ expect.any(String),
117
+ expect.objectContaining({
118
+ request_response: {},
119
+ status: "ERROR",
120
+ error_type: "PROVIDER_RATE_LIMIT",
121
+ error_message: expect.stringContaining("Too Many Requests"),
122
+ }),
123
+ true
124
+ );
125
+ });
126
+
127
+ it("calls trackRequest without error fields on success", async () => {
128
+ const successResponse = { choices: [{ message: { content: "hello" } }] };
129
+ (openaiRequest as Mock).mockResolvedValueOnce(successResponse);
130
+
131
+ await client.run({ promptName: "test-prompt" });
132
+
133
+ expect(trackRequest).toHaveBeenCalledWith(
134
+ expect.any(String),
135
+ expect.objectContaining({
136
+ request_response: successResponse,
137
+ }),
138
+ true
139
+ );
140
+
141
+ const callArgs = (trackRequest as Mock).mock.calls[0][1];
142
+ expect(callArgs).not.toHaveProperty("error_type");
143
+ expect(callArgs).not.toHaveProperty("error_message");
144
+ expect(callArgs).not.toHaveProperty("status");
145
+ });
146
+ });
package/src/types.ts CHANGED
@@ -34,6 +34,9 @@ export interface TrackRequest {
34
34
  return_data?: boolean;
35
35
  group_id?: number;
36
36
  span_id?: string;
37
+ status?: "SUCCESS" | "WARNING" | "ERROR";
38
+ error_type?: string;
39
+ error_message?: string;
37
40
  [k: string]: unknown;
38
41
  }
39
42
 
@@ -90,15 +93,59 @@ const templateFormat = ["f-string", "jinja2"] as const;
90
93
 
91
94
  export type TemplateFormat = (typeof templateFormat)[number];
92
95
 
96
+ export type FileAnnotation = {
97
+ type: "file_citation";
98
+ index: number;
99
+ file_id: string;
100
+ filename: string;
101
+ };
102
+
103
+ export type WebAnnotation = {
104
+ type: "url_citation";
105
+ title: string;
106
+ url: string;
107
+ start_index: number;
108
+ end_index: number;
109
+ cited_text?: string;
110
+ encrypted_index?: string;
111
+ };
112
+
113
+ export type MapAnnotation = {
114
+ type: "map_citation";
115
+ title: string;
116
+ url: string;
117
+ place_id?: string;
118
+ start_index: number;
119
+ end_index: number;
120
+ cited_text?: string;
121
+ };
122
+
123
+ export type ContainerFileAnnotation = {
124
+ type: "container_file_citation";
125
+ container_id: string;
126
+ start_index?: number;
127
+ end_index?: number;
128
+ filename?: string;
129
+ file_id?: string;
130
+ };
131
+
132
+ export type Annotation =
133
+ | WebAnnotation
134
+ | FileAnnotation
135
+ | MapAnnotation
136
+ | ContainerFileAnnotation;
137
+
93
138
  export type ImageUrl = {
94
139
  url: string;
140
+ detail?: string;
95
141
  };
96
142
 
97
143
  export type TextContent = {
98
144
  id?: string;
99
145
  type: "text";
100
146
  text: string;
101
- annotations?: Record<string, unknown>[];
147
+ annotations?: Annotation[];
148
+ thought_signature?: string;
102
149
  };
103
150
 
104
151
  export type ThinkingContent = {
@@ -113,17 +160,20 @@ export type CodeContent = {
113
160
  container_id?: string;
114
161
  type: "code";
115
162
  code: string;
163
+ language?: string;
116
164
  };
117
165
 
118
166
  export type ImageContent = {
119
167
  type: "image_url";
120
168
  image_url: ImageUrl;
169
+ image_variable?: string;
121
170
  };
122
171
 
123
172
  export type Media = {
124
173
  title: string;
125
174
  type: string;
126
- url: string;
175
+ url?: string;
176
+ format?: "base64" | "url" | "neither";
127
177
  };
128
178
 
129
179
  export type MediaContent = {
@@ -136,32 +186,270 @@ export type MediaVariable = {
136
186
  name: string;
137
187
  };
138
188
 
189
+ export type OutputMediaContent = {
190
+ type: "output_media";
191
+ id?: string;
192
+ url: string;
193
+ mime_type?: string;
194
+ media_type?: "image" | "video" | "audio";
195
+ provider_metadata?: Record<string, unknown>;
196
+ };
197
+
198
+ export type ServerToolUseContent = {
199
+ type: "server_tool_use";
200
+ id: string;
201
+ name: string;
202
+ input?: Record<string, unknown>;
203
+ };
204
+
205
+ export type WebSearchResult = {
206
+ type: "web_search_result";
207
+ url?: string;
208
+ title?: string;
209
+ encrypted_content?: string;
210
+ page_age?: string;
211
+ };
212
+
213
+ export type WebSearchToolResultContent = {
214
+ type: "web_search_tool_result";
215
+ tool_use_id: string;
216
+ content?: WebSearchResult[];
217
+ };
218
+
219
+ export type CodeExecutionResultContent = {
220
+ type: "code_execution_result";
221
+ output: string;
222
+ outcome?: string;
223
+ };
224
+
225
+ export type McpListToolsContent = {
226
+ type: "mcp_list_tools";
227
+ id?: string;
228
+ server_label?: string;
229
+ tools?: Record<string, unknown>[];
230
+ error?: string | Record<string, unknown>;
231
+ };
232
+
233
+ export type McpCallContent = {
234
+ type: "mcp_call";
235
+ id?: string;
236
+ name?: string;
237
+ server_label?: string;
238
+ arguments?: string;
239
+ output?: string;
240
+ error?: string | Record<string, unknown>;
241
+ approval_request_id?: string;
242
+ };
243
+
244
+ export type McpApprovalRequestContent = {
245
+ type: "mcp_approval_request";
246
+ id?: string;
247
+ name?: string;
248
+ arguments?: string;
249
+ server_label?: string;
250
+ };
251
+
252
+ export type McpApprovalResponseContent = {
253
+ type: "mcp_approval_response";
254
+ approval_request_id: string;
255
+ approve: boolean;
256
+ };
257
+
258
+ export type BashCodeExecutionToolResultContent = {
259
+ type: "bash_code_execution_tool_result";
260
+ tool_use_id: string;
261
+ content?: Record<string, unknown>;
262
+ };
263
+
264
+ export type TextEditorCodeExecutionToolResultContent = {
265
+ type: "text_editor_code_execution_tool_result";
266
+ tool_use_id: string;
267
+ content?: Record<string, unknown>;
268
+ };
269
+
270
+ export type ShellCallContent = {
271
+ type: "shell_call";
272
+ id?: string;
273
+ call_id?: string;
274
+ action?: Record<string, unknown>;
275
+ status?: string;
276
+ };
277
+
278
+ export type ShellCallOutputContent = {
279
+ type: "shell_call_output";
280
+ id?: string;
281
+ call_id?: string;
282
+ output?: Record<string, unknown>[];
283
+ status?: string;
284
+ };
285
+
286
+ export type ApplyPatchCallContent = {
287
+ type: "apply_patch_call";
288
+ id?: string;
289
+ call_id?: string;
290
+ operation?: Record<string, unknown>;
291
+ status?: string;
292
+ };
293
+
294
+ export type ApplyPatchCallOutputContent = {
295
+ type: "apply_patch_call_output";
296
+ id?: string;
297
+ call_id?: string;
298
+ output?: string;
299
+ status?: string;
300
+ };
301
+
139
302
  export type Content =
140
303
  | TextContent
141
304
  | ThinkingContent
142
305
  | CodeContent
143
306
  | ImageContent
144
307
  | MediaContent
145
- | MediaVariable;
308
+ | MediaVariable
309
+ | OutputMediaContent
310
+ | ServerToolUseContent
311
+ | WebSearchToolResultContent
312
+ | CodeExecutionResultContent
313
+ | McpListToolsContent
314
+ | McpCallContent
315
+ | McpApprovalRequestContent
316
+ | McpApprovalResponseContent
317
+ | BashCodeExecutionToolResultContent
318
+ | TextEditorCodeExecutionToolResultContent
319
+ | ShellCallContent
320
+ | ShellCallOutputContent
321
+ | ApplyPatchCallContent
322
+ | ApplyPatchCallOutputContent;
146
323
 
147
324
  export type Function_ = {
148
325
  name: string;
149
326
  description: string;
327
+ strict?: boolean;
150
328
  parameters: Record<string, unknown>;
151
329
  };
152
330
 
153
- export type Tool = {
154
- id: string;
155
- tool_id?: string;
331
+ export type FunctionCall = {
332
+ name: string;
333
+ arguments: string;
334
+ };
335
+
336
+ export type WebSearchToolFilters = {
337
+ allowed_domains?: string[];
338
+ };
339
+
340
+ export type WebSearchToolUserLocation = {
341
+ city?: string;
342
+ country?: string;
343
+ region?: string;
344
+ timezone?: string;
345
+ type: "approximate";
346
+ };
347
+
348
+ export type OpenAIWebSearchToolConfig = {
349
+ type: "web_search" | "web_search_2025_08_26";
350
+ filters?: WebSearchToolFilters;
351
+ search_context_size?: "low" | "medium" | "high";
352
+ user_location?: WebSearchToolUserLocation;
353
+ };
354
+
355
+ export type ComparisonFilter = {
356
+ key: string;
357
+ value: string | number | boolean;
358
+ operation: "eq" | "ne" | "gt" | "gte" | "lt" | "lte";
359
+ };
360
+
361
+ export type CompoundFilter = {
362
+ operator: "and" | "or";
363
+ operands: (ComparisonFilter | CompoundFilter)[];
364
+ };
365
+
366
+ export type RankingOptions = {
367
+ ranker?: "auto" | "default-2024-11-15";
368
+ score_threshold?: number;
369
+ };
370
+
371
+ export type FileSearchToolConfig = {
372
+ type: "file_search";
373
+ vector_store_ids: string[];
374
+ filters?: ComparisonFilter | CompoundFilter;
375
+ max_num_results?: number;
376
+ ranking_options?: RankingOptions;
377
+ };
378
+
379
+ export type CodeInterpreterToolConfig = {
380
+ type: "code_interpreter";
381
+ container?: Record<string, unknown>;
382
+ };
383
+
384
+ export type ImageGenerationToolConfig = {
385
+ type: "image_generation";
386
+ };
387
+
388
+ export type ShellToolConfig = {
389
+ type: "shell";
390
+ environment?: Record<string, unknown>;
391
+ };
392
+
393
+ export type ApplyPatchToolConfig = {
394
+ type: "apply_patch";
395
+ };
396
+
397
+ export type McpToolApprovalFilter = {
398
+ tool_names?: string[];
399
+ };
400
+
401
+ export type McpToolApproval = {
402
+ never?: McpToolApprovalFilter;
403
+ always?: McpToolApprovalFilter;
404
+ };
405
+
406
+ export type McpToolConfig = {
407
+ type: "mcp";
408
+ server_label: string;
409
+ server_url?: string;
410
+ server_description?: string;
411
+ connector_id?: string;
412
+ authorization?: string;
413
+ allowed_tools?: string[];
414
+ require_approval?: string | McpToolApproval;
415
+ };
416
+
417
+ export type BuiltInToolConfig =
418
+ | OpenAIWebSearchToolConfig
419
+ | FileSearchToolConfig
420
+ | CodeInterpreterToolConfig
421
+ | ImageGenerationToolConfig
422
+ | McpToolConfig
423
+ | ShellToolConfig
424
+ | ApplyPatchToolConfig;
425
+
426
+ export type FunctionTool = {
156
427
  type: "function";
157
428
  function: Function_;
158
429
  };
159
430
 
160
- export type FunctionCall = {
431
+ export type BuiltInTool = {
432
+ id: string;
161
433
  name: string;
162
- arguments: string;
434
+ description: string;
435
+ provider: string;
436
+ type:
437
+ | "web_search"
438
+ | "file_search"
439
+ | "code_interpreter"
440
+ | "image_generation"
441
+ | "google_maps"
442
+ | "url_context"
443
+ | "mcp"
444
+ | "bash"
445
+ | "shell"
446
+ | "apply_patch"
447
+ | "text_editor";
448
+ config: BuiltInToolConfig;
163
449
  };
164
450
 
451
+ export type Tool = FunctionTool | BuiltInTool;
452
+
165
453
  export type SystemMessage = {
166
454
  role: "system";
167
455
  input_variables?: string[];
@@ -180,6 +468,7 @@ export type UserMessage = {
180
468
 
181
469
  export type ToolCall = {
182
470
  id: string;
471
+ tool_id?: string;
183
472
  type: "function";
184
473
  function: FunctionCall;
185
474
  };
@@ -206,7 +495,7 @@ export type ToolMessage = {
206
495
  role: "tool";
207
496
  input_variables?: string[];
208
497
  template_format?: TemplateFormat;
209
- content: Content[];
498
+ content?: Content[];
210
499
  tool_call_id: string;
211
500
  name?: string;
212
501
  };
@@ -265,8 +554,11 @@ export type PromptTemplate = CompletionPromptTemplate | ChatPromptTemplate;
265
554
  export type Model = {
266
555
  api_type?: string;
267
556
  provider: string;
557
+ model_config_display_name?: string;
558
+ base_model?: string;
268
559
  name: string;
269
560
  parameters: Record<string, unknown>;
561
+ display_params?: Record<string, string | boolean | null>;
270
562
  };
271
563
 
272
564
  export type Metadata = {
@@ -282,6 +574,10 @@ export type PromptBlueprint = {
282
574
  prompt_template: PromptTemplate;
283
575
  commit_message?: string;
284
576
  metadata?: Metadata;
577
+ provider_base_url_name?: string;
578
+ report_id?: number;
579
+ inference_client_name?: string;
580
+ provider_id?: number;
285
581
  };
286
582
 
287
583
  export type PublishPromptTemplate = BasePromptTemplate &
@@ -353,6 +649,9 @@ export interface LogRequest {
353
649
  prompt_id?: number;
354
650
  score_name?: string;
355
651
  api_type?: string;
652
+ status?: "SUCCESS" | "WARNING" | "ERROR";
653
+ error_type?: string;
654
+ error_message?: string;
356
655
  }
357
656
 
358
657
  export interface RequestLog {