@modelrelay/sdk 8.1.0 → 9.0.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.
@@ -0,0 +1,1199 @@
1
+ // src/errors.ts
2
+ var ErrorCodes = {
3
+ NOT_FOUND: "NOT_FOUND",
4
+ VALIDATION_ERROR: "VALIDATION_ERROR",
5
+ RATE_LIMIT: "RATE_LIMIT",
6
+ UNAUTHORIZED: "UNAUTHORIZED",
7
+ FORBIDDEN: "FORBIDDEN",
8
+ CONFLICT: "CONFLICT",
9
+ INTERNAL_ERROR: "INTERNAL_ERROR",
10
+ SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE",
11
+ INVALID_INPUT: "INVALID_INPUT",
12
+ PAYMENT_REQUIRED: "PAYMENT_REQUIRED",
13
+ METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED"
14
+ };
15
+ var ModelRelayError = class extends Error {
16
+ constructor(message, opts) {
17
+ super(message);
18
+ this.name = this.constructor.name;
19
+ this.category = opts.category;
20
+ this.status = opts.status;
21
+ this.code = opts.code;
22
+ this.requestId = opts.requestId;
23
+ this.fields = opts.fields;
24
+ this.data = opts.data;
25
+ this.retries = opts.retries;
26
+ this.cause = opts.cause;
27
+ }
28
+ };
29
+ var ConfigError = class extends ModelRelayError {
30
+ constructor(message, data) {
31
+ super(message, { category: "config", status: 400, data });
32
+ }
33
+ };
34
+ var TransportError = class extends ModelRelayError {
35
+ constructor(message, opts) {
36
+ super(message, {
37
+ category: "transport",
38
+ status: opts.kind === "timeout" ? 408 : 0,
39
+ retries: opts.retries,
40
+ cause: opts.cause,
41
+ data: opts.cause
42
+ });
43
+ this.kind = opts.kind;
44
+ }
45
+ };
46
+ var StreamProtocolError = class extends TransportError {
47
+ constructor(opts) {
48
+ const got = opts.receivedContentType?.trim() || "<missing>";
49
+ super(`expected NDJSON stream (${opts.expectedContentType}), got Content-Type ${got}`, {
50
+ kind: "request"
51
+ });
52
+ this.expectedContentType = opts.expectedContentType;
53
+ this.receivedContentType = opts.receivedContentType?.trim() || void 0;
54
+ this.status = opts.status;
55
+ }
56
+ };
57
+ var StreamTimeoutError = class extends ModelRelayError {
58
+ constructor(streamKind, timeoutMs) {
59
+ const label = streamKind === "ttft" ? "TTFT" : streamKind === "idle" ? "idle" : "total";
60
+ super(`stream ${label} timeout after ${timeoutMs}ms`, { category: "transport", status: 408 });
61
+ this.kind = streamKind;
62
+ this.timeoutMs = timeoutMs;
63
+ }
64
+ };
65
+ var APIError = class extends ModelRelayError {
66
+ constructor(message, opts) {
67
+ super(message, {
68
+ category: "api",
69
+ status: opts.status,
70
+ code: opts.code,
71
+ requestId: opts.requestId,
72
+ fields: opts.fields,
73
+ data: opts.data,
74
+ retries: opts.retries
75
+ });
76
+ }
77
+ /** Returns true if the error is a not found error. */
78
+ isNotFound() {
79
+ return this.code === ErrorCodes.NOT_FOUND;
80
+ }
81
+ /** Returns true if the error is a validation error. */
82
+ isValidation() {
83
+ return this.code === ErrorCodes.VALIDATION_ERROR || this.code === ErrorCodes.INVALID_INPUT;
84
+ }
85
+ /** Returns true if the error is a rate limit error. */
86
+ isRateLimit() {
87
+ return this.code === ErrorCodes.RATE_LIMIT;
88
+ }
89
+ /** Returns true if the error is an unauthorized error. */
90
+ isUnauthorized() {
91
+ return this.code === ErrorCodes.UNAUTHORIZED;
92
+ }
93
+ /** Returns true if the error is a forbidden error. */
94
+ isForbidden() {
95
+ return this.code === ErrorCodes.FORBIDDEN;
96
+ }
97
+ /** Returns true if the error is a service unavailable error. */
98
+ isUnavailable() {
99
+ return this.code === ErrorCodes.SERVICE_UNAVAILABLE;
100
+ }
101
+ };
102
+ var WorkflowValidationError = class extends ModelRelayError {
103
+ constructor(opts) {
104
+ const msg = opts.issues.length === 0 ? "workflow validation error" : opts.issues[0]?.message || "workflow validation error";
105
+ super(msg, {
106
+ category: "api",
107
+ status: opts.status,
108
+ requestId: opts.requestId,
109
+ data: opts.data,
110
+ retries: opts.retries
111
+ });
112
+ this.issues = opts.issues;
113
+ }
114
+ };
115
+ var ToolArgumentError = class extends ModelRelayError {
116
+ constructor(opts) {
117
+ super(opts.message, {
118
+ category: "config",
119
+ status: 400,
120
+ cause: opts.cause
121
+ });
122
+ this.toolCallId = opts.toolCallId;
123
+ this.toolName = opts.toolName;
124
+ this.rawArguments = opts.rawArguments;
125
+ }
126
+ };
127
+ var PathEscapeError = class extends ModelRelayError {
128
+ constructor(opts) {
129
+ super(`path escapes sandbox: ${opts.requestedPath}`, {
130
+ category: "config",
131
+ status: 403
132
+ });
133
+ this.requestedPath = opts.requestedPath;
134
+ this.resolvedPath = opts.resolvedPath;
135
+ }
136
+ };
137
+ var AgentMaxTurnsError = class extends ModelRelayError {
138
+ constructor(maxTurns) {
139
+ super(`agent exceeded maximum turns (${maxTurns}) without completing`, {
140
+ category: "config",
141
+ status: 400
142
+ });
143
+ this.maxTurns = maxTurns;
144
+ }
145
+ };
146
+ async function parseErrorResponse(response, retries) {
147
+ const requestId = response.headers.get("X-ModelRelay-Request-Id") || response.headers.get("X-Request-Id") || void 0;
148
+ const fallbackMessage = response.statusText || "Request failed";
149
+ const status = response.status || 500;
150
+ let bodyText = "";
151
+ let bodyReadErr;
152
+ try {
153
+ bodyText = await response.text();
154
+ } catch (err) {
155
+ bodyReadErr = err;
156
+ }
157
+ if (!bodyText) {
158
+ return new APIError(fallbackMessage, {
159
+ status,
160
+ requestId,
161
+ retries,
162
+ data: bodyReadErr ? {
163
+ body_read_error: bodyReadErr instanceof Error ? bodyReadErr.message : String(bodyReadErr)
164
+ } : void 0
165
+ });
166
+ }
167
+ try {
168
+ const parsed = JSON.parse(bodyText);
169
+ const parsedObj = typeof parsed === "object" && parsed !== null ? parsed : null;
170
+ const issues = Array.isArray(parsedObj?.issues) ? parsedObj?.issues : null;
171
+ if (status === 400 && issues && issues.length > 0) {
172
+ const normalized = [];
173
+ for (const raw of issues) {
174
+ if (!raw || typeof raw !== "object") continue;
175
+ const obj = raw;
176
+ const code = typeof obj.code === "string" ? obj.code : "";
177
+ const path = typeof obj.path === "string" ? obj.path : "";
178
+ const message = typeof obj.message === "string" ? obj.message : "";
179
+ if (!code || !path || !message) continue;
180
+ normalized.push({ code, path, message });
181
+ }
182
+ if (normalized.length > 0) {
183
+ return new WorkflowValidationError({
184
+ status,
185
+ requestId,
186
+ issues: normalized,
187
+ retries,
188
+ data: parsed
189
+ });
190
+ }
191
+ }
192
+ if (parsedObj?.error && typeof parsedObj.error === "object") {
193
+ const errPayload = parsedObj.error;
194
+ const message = errPayload?.message || fallbackMessage;
195
+ const code = errPayload?.code || void 0;
196
+ const fields = Array.isArray(errPayload?.fields) ? errPayload?.fields : void 0;
197
+ const parsedStatus = typeof errPayload?.status === "number" ? errPayload.status : status;
198
+ return new APIError(message, {
199
+ status: parsedStatus,
200
+ code,
201
+ fields,
202
+ requestId: parsedObj?.request_id || parsedObj?.requestId || requestId,
203
+ data: parsed,
204
+ retries
205
+ });
206
+ }
207
+ if (parsedObj?.message || parsedObj?.code) {
208
+ const message = parsedObj.message || fallbackMessage;
209
+ return new APIError(message, {
210
+ status,
211
+ code: parsedObj.code,
212
+ fields: parsedObj.fields,
213
+ requestId: parsedObj?.request_id || parsedObj?.requestId || requestId,
214
+ data: parsed,
215
+ retries
216
+ });
217
+ }
218
+ return new APIError(fallbackMessage, {
219
+ status,
220
+ requestId,
221
+ data: parsed,
222
+ retries
223
+ });
224
+ } catch {
225
+ return new APIError(bodyText, { status, requestId, retries });
226
+ }
227
+ }
228
+
229
+ // package.json
230
+ var package_default = {
231
+ name: "@modelrelay/sdk",
232
+ version: "9.0.0",
233
+ description: "TypeScript SDK for the ModelRelay API",
234
+ type: "module",
235
+ main: "dist/index.cjs",
236
+ module: "dist/index.js",
237
+ types: "dist/index.d.ts",
238
+ exports: {
239
+ ".": {
240
+ types: "./dist/index.d.ts",
241
+ import: "./dist/index.js",
242
+ require: "./dist/index.cjs"
243
+ },
244
+ "./billing": {
245
+ types: "./dist/billing/index.d.ts",
246
+ import: "./dist/billing/index.js",
247
+ require: "./dist/billing/index.cjs"
248
+ },
249
+ "./node": {
250
+ types: "./dist/node.d.ts",
251
+ import: "./dist/node.js",
252
+ require: "./dist/node.cjs"
253
+ }
254
+ },
255
+ publishConfig: {
256
+ access: "public"
257
+ },
258
+ files: [
259
+ "dist"
260
+ ],
261
+ scripts: {
262
+ build: "tsup src/index.ts src/node.ts src/billing/index.ts --format esm,cjs --dts --external playwright",
263
+ dev: "tsup src/index.ts src/node.ts src/billing/index.ts --format esm,cjs --dts --watch",
264
+ lint: "tsc --noEmit --project tsconfig.lint.json",
265
+ test: "vitest run",
266
+ "generate:types": "openapi-typescript ../../api/openapi/api.json -o src/generated/api.ts"
267
+ },
268
+ keywords: [
269
+ "modelrelay",
270
+ "llm",
271
+ "sdk",
272
+ "typescript"
273
+ ],
274
+ author: "Shane Vitarana",
275
+ license: "Apache-2.0",
276
+ dependencies: {
277
+ "fast-json-patch": "^3.1.1",
278
+ zod: "^3.25.76"
279
+ },
280
+ peerDependencies: {
281
+ "better-sqlite3": "^9.6.0",
282
+ playwright: ">=1.40.0"
283
+ },
284
+ peerDependenciesMeta: {
285
+ "better-sqlite3": {
286
+ optional: true
287
+ },
288
+ playwright: {
289
+ optional: true
290
+ }
291
+ },
292
+ devDependencies: {
293
+ "@types/better-sqlite3": "^7.6.11",
294
+ "@types/node": "^25.0.3",
295
+ "openapi-typescript": "^7.10.1",
296
+ playwright: "^1.57.0",
297
+ tsup: "^8.5.1",
298
+ typescript: "^5.9.3",
299
+ vitest: "^2.1.9"
300
+ }
301
+ };
302
+
303
+ // src/types.ts
304
+ var SDK_VERSION = package_default.version || "0.0.0";
305
+ var DEFAULT_BASE_URL = "https://api.modelrelay.ai/api/v1";
306
+ var DEFAULT_CLIENT_HEADER = `modelrelay-ts/${SDK_VERSION}`;
307
+ var DEFAULT_CONNECT_TIMEOUT_MS = 5e3;
308
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
309
+ var StopReasons = {
310
+ Completed: "completed",
311
+ Stop: "stop",
312
+ StopSequence: "stop_sequence",
313
+ EndTurn: "end_turn",
314
+ MaxTokens: "max_tokens",
315
+ MaxLength: "max_len",
316
+ MaxContext: "max_context",
317
+ ToolCalls: "tool_calls",
318
+ TimeLimit: "time_limit",
319
+ ContentFilter: "content_filter",
320
+ Incomplete: "incomplete",
321
+ Unknown: "unknown"
322
+ };
323
+ function asProviderId(value) {
324
+ return value;
325
+ }
326
+ function asModelId(value) {
327
+ return value;
328
+ }
329
+ function asTierCode(value) {
330
+ return value;
331
+ }
332
+ var SubscriptionStatuses = {
333
+ Active: "active",
334
+ Trialing: "trialing",
335
+ PastDue: "past_due",
336
+ Canceled: "canceled",
337
+ Unpaid: "unpaid",
338
+ Incomplete: "incomplete",
339
+ IncompleteExpired: "incomplete_expired",
340
+ Paused: "paused"
341
+ };
342
+ var BillingProviders = {
343
+ Stripe: "stripe",
344
+ Crypto: "crypto",
345
+ AppStore: "app_store",
346
+ External: "external"
347
+ };
348
+ function createUsage(inputTokens, outputTokens, totalTokens) {
349
+ return {
350
+ inputTokens,
351
+ outputTokens,
352
+ totalTokens: totalTokens ?? inputTokens + outputTokens
353
+ };
354
+ }
355
+ var MessageRoles = {
356
+ User: "user",
357
+ Assistant: "assistant",
358
+ System: "system",
359
+ Tool: "tool"
360
+ };
361
+ var ContentPartTypes = {
362
+ Text: "text"
363
+ };
364
+ var InputItemTypes = {
365
+ Message: "message"
366
+ };
367
+ var OutputItemTypes = {
368
+ Message: "message"
369
+ };
370
+ var ToolTypes = {
371
+ Function: "function",
372
+ XSearch: "x_search",
373
+ CodeExecution: "code_execution"
374
+ };
375
+ var ToolChoiceTypes = {
376
+ Auto: "auto",
377
+ Required: "required",
378
+ None: "none"
379
+ };
380
+ var OutputFormatTypes = {
381
+ Text: "text",
382
+ JsonSchema: "json_schema"
383
+ };
384
+ function mergeMetrics(base, override) {
385
+ if (!base && !override) return void 0;
386
+ return {
387
+ ...base || {},
388
+ ...override || {}
389
+ };
390
+ }
391
+ function mergeTrace(base, override) {
392
+ if (!base && !override) return void 0;
393
+ return {
394
+ ...base || {},
395
+ ...override || {}
396
+ };
397
+ }
398
+ function normalizeStopReason(value) {
399
+ if (value === void 0 || value === null) return void 0;
400
+ const str = String(value).trim();
401
+ const lower = str.toLowerCase();
402
+ for (const reason of Object.values(StopReasons)) {
403
+ if (lower === reason) return reason;
404
+ }
405
+ switch (lower) {
406
+ case "length":
407
+ return StopReasons.MaxLength;
408
+ default:
409
+ return { other: str };
410
+ }
411
+ }
412
+ function stopReasonToString(value) {
413
+ if (!value) return void 0;
414
+ if (typeof value === "string") return value;
415
+ return value.other?.trim() || void 0;
416
+ }
417
+ function normalizeModelId(value) {
418
+ if (value === void 0 || value === null) return void 0;
419
+ const str = String(value).trim();
420
+ if (!str) return void 0;
421
+ return str;
422
+ }
423
+ function modelToString(value) {
424
+ return String(value).trim();
425
+ }
426
+
427
+ // src/tools.ts
428
+ function createUserMessage(content) {
429
+ return {
430
+ type: "message",
431
+ role: "user",
432
+ content: [{ type: "text", text: content }]
433
+ };
434
+ }
435
+ function createAssistantMessage(content) {
436
+ return {
437
+ type: "message",
438
+ role: "assistant",
439
+ content: [{ type: "text", text: content }]
440
+ };
441
+ }
442
+ function createSystemMessage(content) {
443
+ return {
444
+ type: "message",
445
+ role: "system",
446
+ content: [{ type: "text", text: content }]
447
+ };
448
+ }
449
+ function createToolCall(id, name, args, type = ToolTypes.Function) {
450
+ return {
451
+ id,
452
+ type,
453
+ function: createFunctionCall(name, args)
454
+ };
455
+ }
456
+ function createFunctionCall(name, args) {
457
+ return { name, arguments: args };
458
+ }
459
+ function zodToJsonSchema(schema, options = {}) {
460
+ const result = convertZodType(schema);
461
+ if (options.includeSchema) {
462
+ const schemaVersion = options.target === "draft-04" ? "http://json-schema.org/draft-04/schema#" : options.target === "draft-2019-09" ? "https://json-schema.org/draft/2019-09/schema" : options.target === "draft-2020-12" ? "https://json-schema.org/draft/2020-12/schema" : "http://json-schema.org/draft-07/schema#";
463
+ return { $schema: schemaVersion, ...result };
464
+ }
465
+ return result;
466
+ }
467
+ function convertZodType(schema) {
468
+ const def = schema._def;
469
+ const typeName = def.typeName;
470
+ switch (typeName) {
471
+ case "ZodString":
472
+ return convertZodString(def);
473
+ case "ZodNumber":
474
+ return convertZodNumber(def);
475
+ case "ZodBoolean":
476
+ return { type: "boolean" };
477
+ case "ZodNull":
478
+ return { type: "null" };
479
+ case "ZodArray":
480
+ return convertZodArray(def);
481
+ case "ZodObject":
482
+ return convertZodObject(def);
483
+ case "ZodEnum":
484
+ return convertZodEnum(def);
485
+ case "ZodNativeEnum":
486
+ return convertZodNativeEnum(def);
487
+ case "ZodLiteral":
488
+ return { const: def.value };
489
+ case "ZodUnion":
490
+ return convertZodUnion(def);
491
+ case "ZodOptional": {
492
+ const inner = convertZodType(def.innerType);
493
+ if (def.description && !inner.description) {
494
+ inner.description = def.description;
495
+ }
496
+ return inner;
497
+ }
498
+ case "ZodNullable":
499
+ return convertZodNullable(def);
500
+ case "ZodDefault":
501
+ return {
502
+ ...convertZodType(def.innerType),
503
+ default: def.defaultValue()
504
+ };
505
+ case "ZodEffects":
506
+ return convertZodType(def.schema);
507
+ case "ZodRecord":
508
+ return convertZodRecord(def);
509
+ case "ZodTuple":
510
+ return convertZodTuple(def);
511
+ case "ZodAny":
512
+ case "ZodUnknown":
513
+ return {};
514
+ default:
515
+ throw new ConfigError(
516
+ `sdk: unsupported Zod schema type ${JSON.stringify(typeName)}; pass JSON Schema directly or use a full converter like zod-to-json-schema`,
517
+ { typeName }
518
+ );
519
+ }
520
+ }
521
+ function convertZodString(def) {
522
+ const result = { type: "string" };
523
+ const checks = def.checks;
524
+ if (checks) {
525
+ for (const check of checks) {
526
+ switch (check.kind) {
527
+ case "min":
528
+ result.minLength = check.value;
529
+ break;
530
+ case "max":
531
+ result.maxLength = check.value;
532
+ break;
533
+ case "length":
534
+ result.minLength = check.value;
535
+ result.maxLength = check.value;
536
+ break;
537
+ case "email":
538
+ result.format = "email";
539
+ break;
540
+ case "url":
541
+ result.format = "uri";
542
+ break;
543
+ case "uuid":
544
+ result.format = "uuid";
545
+ break;
546
+ case "datetime":
547
+ result.format = "date-time";
548
+ break;
549
+ case "regex":
550
+ result.pattern = check.value.source;
551
+ break;
552
+ }
553
+ }
554
+ }
555
+ if (def.description) {
556
+ result.description = def.description;
557
+ }
558
+ return result;
559
+ }
560
+ function convertZodNumber(def) {
561
+ const result = { type: "number" };
562
+ const checks = def.checks;
563
+ if (checks) {
564
+ for (const check of checks) {
565
+ switch (check.kind) {
566
+ case "int":
567
+ result.type = "integer";
568
+ break;
569
+ case "min":
570
+ if (check.inclusive === false) {
571
+ result.exclusiveMinimum = check.value;
572
+ } else {
573
+ result.minimum = check.value;
574
+ }
575
+ break;
576
+ case "max":
577
+ if (check.inclusive === false) {
578
+ result.exclusiveMaximum = check.value;
579
+ } else {
580
+ result.maximum = check.value;
581
+ }
582
+ break;
583
+ case "multipleOf":
584
+ result.multipleOf = check.value;
585
+ break;
586
+ }
587
+ }
588
+ }
589
+ if (def.description) {
590
+ result.description = def.description;
591
+ }
592
+ return result;
593
+ }
594
+ function convertZodArray(def) {
595
+ const result = {
596
+ type: "array",
597
+ items: convertZodType(def.type)
598
+ };
599
+ if (def.minLength !== void 0 && def.minLength !== null) {
600
+ result.minItems = def.minLength.value;
601
+ }
602
+ if (def.maxLength !== void 0 && def.maxLength !== null) {
603
+ result.maxItems = def.maxLength.value;
604
+ }
605
+ if (def.description) {
606
+ result.description = def.description;
607
+ }
608
+ return result;
609
+ }
610
+ function convertZodObject(def) {
611
+ const shape = def.shape;
612
+ const shapeObj = typeof shape === "function" ? shape() : shape;
613
+ const properties = {};
614
+ const required = [];
615
+ for (const [key, value] of Object.entries(shapeObj)) {
616
+ properties[key] = convertZodType(value);
617
+ const valueDef = value._def;
618
+ const isOptional = valueDef.typeName === "ZodOptional" || valueDef.typeName === "ZodDefault" || valueDef.typeName === "ZodNullable" && valueDef.innerType?._def?.typeName === "ZodDefault";
619
+ if (!isOptional) {
620
+ required.push(key);
621
+ }
622
+ }
623
+ const result = {
624
+ type: "object",
625
+ properties
626
+ };
627
+ if (required.length > 0) {
628
+ result.required = required;
629
+ }
630
+ if (def.description) {
631
+ result.description = def.description;
632
+ }
633
+ const unknownKeys = def.unknownKeys;
634
+ if (unknownKeys === "strict") {
635
+ result.additionalProperties = false;
636
+ }
637
+ return result;
638
+ }
639
+ function convertZodEnum(def) {
640
+ const result = {
641
+ type: "string",
642
+ enum: def.values
643
+ };
644
+ if (def.description) {
645
+ result.description = def.description;
646
+ }
647
+ return result;
648
+ }
649
+ function convertZodNativeEnum(def) {
650
+ const enumValues = def.values;
651
+ const values = Object.values(enumValues).filter(
652
+ (v) => typeof v === "string" || typeof v === "number"
653
+ );
654
+ const result = { enum: values };
655
+ if (def.description) {
656
+ result.description = def.description;
657
+ }
658
+ return result;
659
+ }
660
+ function convertZodUnion(def) {
661
+ const options = def.options;
662
+ const result = {
663
+ anyOf: options.map(convertZodType)
664
+ };
665
+ if (def.description) {
666
+ result.description = def.description;
667
+ }
668
+ return result;
669
+ }
670
+ function convertZodNullable(def) {
671
+ const inner = convertZodType(def.innerType);
672
+ return {
673
+ anyOf: [inner, { type: "null" }]
674
+ };
675
+ }
676
+ function convertZodRecord(def) {
677
+ const result = {
678
+ type: "object",
679
+ additionalProperties: convertZodType(def.valueType)
680
+ };
681
+ if (def.description) {
682
+ result.description = def.description;
683
+ }
684
+ return result;
685
+ }
686
+ function convertZodTuple(def) {
687
+ const items = def.items;
688
+ const result = {
689
+ type: "array",
690
+ items: items.map(convertZodType),
691
+ minItems: items.length,
692
+ maxItems: items.length
693
+ };
694
+ if (def.description) {
695
+ result.description = def.description;
696
+ }
697
+ return result;
698
+ }
699
+ function createFunctionToolFromSchema(name, description, schema, options) {
700
+ const jsonSchema = zodToJsonSchema(schema, options);
701
+ return createFunctionTool(name, description, jsonSchema);
702
+ }
703
+ function createTypedTool(def) {
704
+ const jsonSchema = zodToJsonSchema(def.parameters, def.options);
705
+ const tool = createFunctionTool(def.name, def.description, jsonSchema);
706
+ Object.defineProperty(tool, "_schema", {
707
+ value: def.parameters,
708
+ enumerable: false
709
+ });
710
+ return tool;
711
+ }
712
+ function createFunctionTool(name, description, parameters) {
713
+ const fn = { name, description };
714
+ if (parameters) {
715
+ fn.parameters = parameters;
716
+ }
717
+ return {
718
+ type: ToolTypes.Function,
719
+ function: fn
720
+ };
721
+ }
722
+ function toolChoiceAuto() {
723
+ return { type: ToolChoiceTypes.Auto };
724
+ }
725
+ function toolChoiceRequired() {
726
+ return { type: ToolChoiceTypes.Required };
727
+ }
728
+ function toolChoiceNone() {
729
+ return { type: ToolChoiceTypes.None };
730
+ }
731
+ function hasToolCalls(response) {
732
+ for (const item of response.output || []) {
733
+ if (item?.toolCalls?.length) return true;
734
+ }
735
+ return false;
736
+ }
737
+ function firstToolCall(response) {
738
+ for (const item of response.output || []) {
739
+ const call = item?.toolCalls?.[0];
740
+ if (call) return call;
741
+ }
742
+ return void 0;
743
+ }
744
+ function toolResultMessage(toolCallId, result) {
745
+ const content = typeof result === "string" ? result : JSON.stringify(result);
746
+ return {
747
+ type: "message",
748
+ role: "tool",
749
+ toolCallId,
750
+ content: [{ type: "text", text: content }]
751
+ };
752
+ }
753
+ function respondToToolCall(call, result) {
754
+ return toolResultMessage(call.id, result);
755
+ }
756
+ function assistantMessageWithToolCalls(content, toolCalls) {
757
+ return {
758
+ type: "message",
759
+ role: "assistant",
760
+ content: [{ type: "text", text: content }],
761
+ toolCalls
762
+ };
763
+ }
764
+ var ToolCallAccumulator = class {
765
+ constructor() {
766
+ this.calls = /* @__PURE__ */ new Map();
767
+ }
768
+ /**
769
+ * Processes a streaming tool call delta.
770
+ * Returns true if this started a new tool call.
771
+ */
772
+ processDelta(delta) {
773
+ const existing = this.calls.get(delta.index);
774
+ if (!existing) {
775
+ this.calls.set(delta.index, {
776
+ id: delta.id ?? "",
777
+ type: delta.type ?? ToolTypes.Function,
778
+ function: {
779
+ name: delta.function?.name ?? "",
780
+ arguments: delta.function?.arguments ?? ""
781
+ }
782
+ });
783
+ return true;
784
+ }
785
+ if (delta.function) {
786
+ if (delta.function.name) {
787
+ existing.function = existing.function ?? { name: "", arguments: "" };
788
+ existing.function.name = delta.function.name;
789
+ }
790
+ if (delta.function.arguments) {
791
+ existing.function = existing.function ?? { name: "", arguments: "" };
792
+ existing.function.arguments += delta.function.arguments;
793
+ }
794
+ }
795
+ return false;
796
+ }
797
+ /**
798
+ * Returns all accumulated tool calls in index order.
799
+ */
800
+ getToolCalls() {
801
+ if (this.calls.size === 0) {
802
+ return [];
803
+ }
804
+ const maxIdx = Math.max(...this.calls.keys());
805
+ const result = [];
806
+ for (let i = 0; i <= maxIdx; i++) {
807
+ const call = this.calls.get(i);
808
+ if (call) {
809
+ result.push(call);
810
+ }
811
+ }
812
+ return result;
813
+ }
814
+ /**
815
+ * Returns a specific tool call by index, or undefined if not found.
816
+ */
817
+ getToolCall(index) {
818
+ return this.calls.get(index);
819
+ }
820
+ /**
821
+ * Clears all accumulated tool calls.
822
+ */
823
+ reset() {
824
+ this.calls.clear();
825
+ }
826
+ };
827
+ var ToolArgsError = class extends Error {
828
+ constructor(message, toolCallId, toolName, rawArguments) {
829
+ super(message);
830
+ this.name = "ToolArgsError";
831
+ this.toolCallId = toolCallId;
832
+ this.toolName = toolName;
833
+ this.rawArguments = rawArguments;
834
+ }
835
+ };
836
+ function parseToolArgsWithSchema(call, schema) {
837
+ const toolName = call.function?.name ?? "unknown";
838
+ const rawArgs = call.function?.arguments ?? "";
839
+ let parsed;
840
+ try {
841
+ parsed = rawArgs ? JSON.parse(rawArgs) : {};
842
+ } catch (err) {
843
+ const message = err instanceof Error ? err.message : "Invalid JSON in arguments";
844
+ throw new ToolArgsError(
845
+ `Failed to parse arguments for tool '${toolName}': ${message}`,
846
+ call.id,
847
+ toolName,
848
+ rawArgs
849
+ );
850
+ }
851
+ try {
852
+ return schema.parse(parsed);
853
+ } catch (err) {
854
+ let message;
855
+ if (err instanceof Error) {
856
+ const zodErr = err;
857
+ if (zodErr.errors && Array.isArray(zodErr.errors)) {
858
+ const issues = zodErr.errors.map((e) => {
859
+ const path = e.path.length > 0 ? `${e.path.join(".")}: ` : "";
860
+ return `${path}${e.message}`;
861
+ }).join("; ");
862
+ message = issues;
863
+ } else {
864
+ message = err.message;
865
+ }
866
+ } else {
867
+ message = String(err);
868
+ }
869
+ throw new ToolArgsError(
870
+ `Invalid arguments for tool '${toolName}': ${message}`,
871
+ call.id,
872
+ toolName,
873
+ rawArgs
874
+ );
875
+ }
876
+ }
877
+ function parseTypedToolCall(call, tool) {
878
+ if (!call.function) {
879
+ throw new ToolArgsError(
880
+ "Tool call missing function",
881
+ call.id,
882
+ tool.function.name,
883
+ ""
884
+ );
885
+ }
886
+ if (call.function.name !== tool.function.name) {
887
+ throw new ToolArgsError(
888
+ `Expected tool '${tool.function.name}', got '${call.function.name}'`,
889
+ call.id,
890
+ tool.function.name,
891
+ call.function.arguments ?? ""
892
+ );
893
+ }
894
+ const parsed = parseToolArgsWithSchema(call, tool._schema);
895
+ return {
896
+ ...call,
897
+ function: {
898
+ ...call.function,
899
+ arguments: parsed
900
+ }
901
+ };
902
+ }
903
+ function getTypedToolCall(response, tool) {
904
+ for (const item of response.output || []) {
905
+ for (const call of item?.toolCalls || []) {
906
+ if (call.function?.name === tool.function.name) {
907
+ return parseTypedToolCall(call, tool);
908
+ }
909
+ }
910
+ }
911
+ return void 0;
912
+ }
913
+ function getTypedToolCalls(response, tool) {
914
+ const result = [];
915
+ for (const item of response.output || []) {
916
+ for (const call of item?.toolCalls || []) {
917
+ if (call.function?.name === tool.function.name) {
918
+ result.push(parseTypedToolCall(call, tool));
919
+ }
920
+ }
921
+ }
922
+ return result;
923
+ }
924
+ function getToolName(call) {
925
+ return call.function?.name ?? "";
926
+ }
927
+ function getToolArgsRaw(call) {
928
+ return call.function?.arguments ?? "";
929
+ }
930
+ function getToolArgs(call) {
931
+ const raw = call.function?.arguments ?? "";
932
+ if (!raw) return { ok: true, args: {} };
933
+ try {
934
+ return { ok: true, args: JSON.parse(raw) };
935
+ } catch (err) {
936
+ return {
937
+ ok: false,
938
+ error: err instanceof Error ? err.message : "Invalid JSON",
939
+ raw
940
+ };
941
+ }
942
+ }
943
+ function getAllToolCalls(response) {
944
+ const calls = [];
945
+ for (const item of response.output || []) {
946
+ if (item.toolCalls) {
947
+ calls.push(...item.toolCalls);
948
+ }
949
+ }
950
+ return calls;
951
+ }
952
+ function getAssistantText(response) {
953
+ const texts = [];
954
+ for (const item of response.output || []) {
955
+ if (item.role === "assistant" && item.content) {
956
+ for (const part of item.content) {
957
+ if (part.type === "text" && part.text) {
958
+ texts.push(part.text);
959
+ }
960
+ }
961
+ }
962
+ }
963
+ return texts.join("");
964
+ }
965
+ var ToolRegistry = class {
966
+ constructor() {
967
+ this.handlers = /* @__PURE__ */ new Map();
968
+ }
969
+ /**
970
+ * Registers a handler function for a tool name.
971
+ * @param name - The tool name (must match the function name in the tool definition)
972
+ * @param handler - Function to execute when this tool is called
973
+ * @returns this for chaining
974
+ */
975
+ register(name, handler) {
976
+ this.handlers.set(name, handler);
977
+ return this;
978
+ }
979
+ /**
980
+ * Unregisters a tool handler.
981
+ * @param name - The tool name to unregister
982
+ * @returns true if the handler was removed, false if it didn't exist
983
+ */
984
+ unregister(name) {
985
+ return this.handlers.delete(name);
986
+ }
987
+ /**
988
+ * Checks if a handler is registered for the given tool name.
989
+ */
990
+ has(name) {
991
+ return this.handlers.has(name);
992
+ }
993
+ /**
994
+ * Returns the list of registered tool names.
995
+ */
996
+ getRegisteredTools() {
997
+ return Array.from(this.handlers.keys());
998
+ }
999
+ /**
1000
+ * Executes a single tool call.
1001
+ * @param call - The tool call to execute
1002
+ * @returns The execution result
1003
+ */
1004
+ async execute(call) {
1005
+ const toolName = call.function?.name ?? "";
1006
+ const handler = this.handlers.get(toolName);
1007
+ if (!handler) {
1008
+ return {
1009
+ toolCallId: call.id,
1010
+ toolName,
1011
+ result: null,
1012
+ error: `Unknown tool: '${toolName}'. Available tools: ${this.getRegisteredTools().join(", ") || "none"}`
1013
+ };
1014
+ }
1015
+ let args;
1016
+ try {
1017
+ args = call.function?.arguments ? JSON.parse(call.function.arguments) : {};
1018
+ } catch (err) {
1019
+ const errorMessage = err instanceof Error ? err.message : String(err);
1020
+ return {
1021
+ toolCallId: call.id,
1022
+ toolName,
1023
+ result: null,
1024
+ error: `Invalid JSON in arguments: ${errorMessage}`,
1025
+ isRetryable: true
1026
+ };
1027
+ }
1028
+ try {
1029
+ const result = await handler(args, call);
1030
+ return {
1031
+ toolCallId: call.id,
1032
+ toolName,
1033
+ result
1034
+ };
1035
+ } catch (err) {
1036
+ const isRetryable = err instanceof ToolArgsError || err instanceof ToolArgumentError;
1037
+ const errorMessage = err instanceof Error ? err.message : String(err);
1038
+ return {
1039
+ toolCallId: call.id,
1040
+ toolName,
1041
+ result: null,
1042
+ error: errorMessage,
1043
+ isRetryable
1044
+ };
1045
+ }
1046
+ }
1047
+ /**
1048
+ * Executes multiple tool calls in parallel.
1049
+ * @param calls - Array of tool calls to execute
1050
+ * @returns Array of execution results in the same order as input
1051
+ */
1052
+ async executeAll(calls) {
1053
+ return Promise.all(calls.map((call) => this.execute(call)));
1054
+ }
1055
+ /**
1056
+ * Converts execution results to tool result messages.
1057
+ * Useful for appending to the conversation history.
1058
+ * @param results - Array of execution results
1059
+ * @returns Array of tool result input items (role "tool")
1060
+ */
1061
+ resultsToMessages(results) {
1062
+ return results.map((r) => {
1063
+ const content = r.error ? `Error: ${r.error}` : typeof r.result === "string" ? r.result : JSON.stringify(r.result);
1064
+ return toolResultMessage(r.toolCallId, content);
1065
+ });
1066
+ }
1067
+ };
1068
+ function formatToolErrorForModel(result) {
1069
+ const lines = [
1070
+ `Tool call error for '${result.toolName}': ${result.error}`
1071
+ ];
1072
+ if (result.isRetryable) {
1073
+ lines.push("");
1074
+ lines.push("Please correct the arguments and try again.");
1075
+ }
1076
+ return lines.join("\n");
1077
+ }
1078
+ function hasRetryableErrors(results) {
1079
+ return results.some((r) => r.error && r.isRetryable);
1080
+ }
1081
+ function getRetryableErrors(results) {
1082
+ return results.filter((r) => r.error && r.isRetryable);
1083
+ }
1084
+ function createRetryMessages(results) {
1085
+ return results.filter((r) => r.error && r.isRetryable).map((r) => toolResultMessage(r.toolCallId, formatToolErrorForModel(r)));
1086
+ }
1087
+ async function executeWithRetry(registry, toolCalls, options = {}) {
1088
+ const maxRetries = options.maxRetries ?? 2;
1089
+ let currentCalls = toolCalls;
1090
+ let attempt = 0;
1091
+ const successfulResults = /* @__PURE__ */ new Map();
1092
+ while (attempt <= maxRetries) {
1093
+ const results = await registry.executeAll(currentCalls);
1094
+ for (const result of results) {
1095
+ if (!result.error || !result.isRetryable) {
1096
+ successfulResults.set(result.toolCallId, result);
1097
+ }
1098
+ }
1099
+ const retryableResults = getRetryableErrors(results);
1100
+ if (retryableResults.length === 0 || !options.onRetry) {
1101
+ for (const result of results) {
1102
+ if (result.error && result.isRetryable) {
1103
+ successfulResults.set(result.toolCallId, result);
1104
+ }
1105
+ }
1106
+ return Array.from(successfulResults.values());
1107
+ }
1108
+ attempt++;
1109
+ if (attempt > maxRetries) {
1110
+ for (const result of retryableResults) {
1111
+ successfulResults.set(result.toolCallId, result);
1112
+ }
1113
+ return Array.from(successfulResults.values());
1114
+ }
1115
+ const errorMessages = createRetryMessages(retryableResults);
1116
+ const newCalls = await options.onRetry(errorMessages, attempt);
1117
+ if (newCalls.length === 0) {
1118
+ for (const result of retryableResults) {
1119
+ successfulResults.set(result.toolCallId, result);
1120
+ }
1121
+ return Array.from(successfulResults.values());
1122
+ }
1123
+ currentCalls = newCalls;
1124
+ }
1125
+ return Array.from(successfulResults.values());
1126
+ }
1127
+
1128
+ export {
1129
+ ErrorCodes,
1130
+ ModelRelayError,
1131
+ ConfigError,
1132
+ TransportError,
1133
+ StreamProtocolError,
1134
+ StreamTimeoutError,
1135
+ APIError,
1136
+ WorkflowValidationError,
1137
+ ToolArgumentError,
1138
+ PathEscapeError,
1139
+ AgentMaxTurnsError,
1140
+ parseErrorResponse,
1141
+ SDK_VERSION,
1142
+ DEFAULT_BASE_URL,
1143
+ DEFAULT_CLIENT_HEADER,
1144
+ DEFAULT_CONNECT_TIMEOUT_MS,
1145
+ DEFAULT_REQUEST_TIMEOUT_MS,
1146
+ StopReasons,
1147
+ asProviderId,
1148
+ asModelId,
1149
+ asTierCode,
1150
+ SubscriptionStatuses,
1151
+ BillingProviders,
1152
+ createUsage,
1153
+ MessageRoles,
1154
+ ContentPartTypes,
1155
+ InputItemTypes,
1156
+ OutputItemTypes,
1157
+ ToolTypes,
1158
+ ToolChoiceTypes,
1159
+ OutputFormatTypes,
1160
+ mergeMetrics,
1161
+ mergeTrace,
1162
+ normalizeStopReason,
1163
+ stopReasonToString,
1164
+ normalizeModelId,
1165
+ modelToString,
1166
+ createUserMessage,
1167
+ createAssistantMessage,
1168
+ createSystemMessage,
1169
+ createToolCall,
1170
+ createFunctionCall,
1171
+ zodToJsonSchema,
1172
+ createFunctionToolFromSchema,
1173
+ createTypedTool,
1174
+ createFunctionTool,
1175
+ toolChoiceAuto,
1176
+ toolChoiceRequired,
1177
+ toolChoiceNone,
1178
+ hasToolCalls,
1179
+ firstToolCall,
1180
+ toolResultMessage,
1181
+ respondToToolCall,
1182
+ assistantMessageWithToolCalls,
1183
+ ToolCallAccumulator,
1184
+ ToolArgsError,
1185
+ parseTypedToolCall,
1186
+ getTypedToolCall,
1187
+ getTypedToolCalls,
1188
+ getToolName,
1189
+ getToolArgsRaw,
1190
+ getToolArgs,
1191
+ getAllToolCalls,
1192
+ getAssistantText,
1193
+ ToolRegistry,
1194
+ formatToolErrorForModel,
1195
+ hasRetryableErrors,
1196
+ getRetryableErrors,
1197
+ createRetryMessages,
1198
+ executeWithRetry
1199
+ };