@modelrelay/sdk 0.23.0 → 0.25.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/dist/index.js CHANGED
@@ -340,7 +340,7 @@ function isTokenReusable(token) {
340
340
  // package.json
341
341
  var package_default = {
342
342
  name: "@modelrelay/sdk",
343
- version: "0.22.0",
343
+ version: "0.25.1",
344
344
  description: "TypeScript SDK for the ModelRelay API",
345
345
  type: "module",
346
346
  main: "dist/index.cjs",
@@ -406,6 +406,12 @@ function createUsage(inputTokens, outputTokens, totalTokens) {
406
406
  totalTokens: totalTokens ?? inputTokens + outputTokens
407
407
  };
408
408
  }
409
+ var MessageRoles = {
410
+ User: "user",
411
+ Assistant: "assistant",
412
+ System: "system",
413
+ Tool: "tool"
414
+ };
409
415
  var ToolTypes = {
410
416
  Function: "function",
411
417
  Web: "web",
@@ -1094,10 +1100,68 @@ async function executeWithRetry(registry, toolCalls, options = {}) {
1094
1100
  return Array.from(successfulResults.values());
1095
1101
  }
1096
1102
 
1103
+ // src/structured.ts
1104
+ var StructuredDecodeError = class extends Error {
1105
+ constructor(message, rawJson, attempt) {
1106
+ super(`structured output decode error (attempt ${attempt}): ${message}`);
1107
+ this.name = "StructuredDecodeError";
1108
+ this.rawJson = rawJson;
1109
+ this.attempt = attempt;
1110
+ }
1111
+ };
1112
+ var StructuredExhaustedError = class extends Error {
1113
+ constructor(lastRawJson, allAttempts, finalError) {
1114
+ const errorMsg = finalError.kind === "decode" ? finalError.message : finalError.issues.map((i) => i.message).join("; ");
1115
+ super(
1116
+ `structured output failed after ${allAttempts.length} attempts: ${errorMsg}`
1117
+ );
1118
+ this.name = "StructuredExhaustedError";
1119
+ this.lastRawJson = lastRawJson;
1120
+ this.allAttempts = allAttempts;
1121
+ this.finalError = finalError;
1122
+ }
1123
+ };
1124
+ var defaultRetryHandler = {
1125
+ onValidationError(_attempt, _rawJson, error, _originalMessages) {
1126
+ const errorMsg = error.kind === "decode" ? error.message : error.issues.map((i) => `${i.path ?? ""}: ${i.message}`).join("; ");
1127
+ return [
1128
+ {
1129
+ role: "user",
1130
+ content: `The previous response did not match the expected schema. Error: ${errorMsg}. Please provide a response that matches the schema exactly.`
1131
+ }
1132
+ ];
1133
+ }
1134
+ };
1135
+ function responseFormatFromZod(schema, name = "response") {
1136
+ const jsonSchema = zodToJsonSchema(schema);
1137
+ return {
1138
+ type: "json_schema",
1139
+ json_schema: {
1140
+ name,
1141
+ schema: jsonSchema,
1142
+ strict: true
1143
+ }
1144
+ };
1145
+ }
1146
+ function validateWithZod(schema, data) {
1147
+ const result = schema.safeParse(data);
1148
+ if (result.success) {
1149
+ return { success: true, data: result.data };
1150
+ }
1151
+ const errorMsg = result.error && typeof result.error === "object" && "message" in result.error ? String(result.error.message) : "validation failed";
1152
+ return { success: false, error: errorMsg };
1153
+ }
1154
+
1097
1155
  // src/chat.ts
1156
+ var CUSTOMER_ID_HEADER = "X-ModelRelay-Customer-Id";
1098
1157
  var REQUEST_ID_HEADER = "X-ModelRelay-Chat-Request-Id";
1099
1158
  var ChatClient = class {
1100
1159
  constructor(http, auth, cfg = {}) {
1160
+ this.http = http;
1161
+ this.auth = auth;
1162
+ this.defaultMetadata = cfg.defaultMetadata;
1163
+ this.metrics = cfg.metrics;
1164
+ this.trace = cfg.trace;
1101
1165
  this.completions = new ChatCompletionsClient(
1102
1166
  http,
1103
1167
  auth,
@@ -1106,6 +1170,30 @@ var ChatClient = class {
1106
1170
  cfg.trace
1107
1171
  );
1108
1172
  }
1173
+ /**
1174
+ * Create a customer-attributed chat client for the given customer ID.
1175
+ * The customer's tier determines the model - no model parameter is needed or allowed.
1176
+ *
1177
+ * @example
1178
+ * ```typescript
1179
+ * const stream = await client.chat.forCustomer("user-123").create({
1180
+ * messages: [{ role: "user", content: "Hello!" }],
1181
+ * });
1182
+ * ```
1183
+ */
1184
+ forCustomer(customerId) {
1185
+ if (!customerId?.trim()) {
1186
+ throw new ConfigError("customerId is required");
1187
+ }
1188
+ return new CustomerChatClient(
1189
+ this.http,
1190
+ this.auth,
1191
+ customerId,
1192
+ this.defaultMetadata,
1193
+ this.metrics,
1194
+ this.trace
1195
+ );
1196
+ }
1109
1197
  };
1110
1198
  var ChatCompletionsClient = class {
1111
1199
  constructor(http, auth, defaultMetadata, metrics, trace) {
@@ -1125,7 +1213,7 @@ var ChatCompletionsClient = class {
1125
1213
  if (!hasUserMessage(params.messages)) {
1126
1214
  throw new ConfigError("at least one user message is required");
1127
1215
  }
1128
- const authHeaders = await this.auth.authForChat(params.customerId);
1216
+ const authHeaders = await this.auth.authForChat();
1129
1217
  const body = buildProxyBody(
1130
1218
  params,
1131
1219
  mergeMetadata(this.defaultMetadata, params.metadata, options.metadata)
@@ -1205,7 +1293,7 @@ var ChatCompletionsClient = class {
1205
1293
  "responseFormat with type=json_object or json_schema is required for structured streaming"
1206
1294
  );
1207
1295
  }
1208
- const authHeaders = await this.auth.authForChat(params.customerId);
1296
+ const authHeaders = await this.auth.authForChat();
1209
1297
  const body = buildProxyBody(
1210
1298
  params,
1211
1299
  mergeMetadata(this.defaultMetadata, params.metadata, options.metadata)
@@ -1261,6 +1349,439 @@ var ChatCompletionsClient = class {
1261
1349
  trace
1262
1350
  );
1263
1351
  }
1352
+ /**
1353
+ * Send a structured output request with a Zod schema.
1354
+ *
1355
+ * Auto-generates JSON schema from the Zod schema, validates the response,
1356
+ * and retries on validation failure if configured.
1357
+ *
1358
+ * @param schema - A Zod schema defining the expected response structure
1359
+ * @param params - Chat completion parameters (excluding responseFormat)
1360
+ * @param options - Request options including retry configuration
1361
+ * @returns A typed result with the parsed value
1362
+ *
1363
+ * @example
1364
+ * ```typescript
1365
+ * import { z } from 'zod';
1366
+ *
1367
+ * const PersonSchema = z.object({
1368
+ * name: z.string(),
1369
+ * age: z.number(),
1370
+ * });
1371
+ *
1372
+ * const result = await client.chat.completions.structured(
1373
+ * PersonSchema,
1374
+ * { model: "claude-sonnet-4-20250514", messages: [...] },
1375
+ * { maxRetries: 2 }
1376
+ * );
1377
+ * ```
1378
+ */
1379
+ async structured(schema, params, options = {}) {
1380
+ const {
1381
+ maxRetries = 0,
1382
+ retryHandler = defaultRetryHandler,
1383
+ schemaName,
1384
+ ...requestOptions
1385
+ } = options;
1386
+ const responseFormat = responseFormatFromZod(schema, schemaName);
1387
+ const fullParams = {
1388
+ ...params,
1389
+ responseFormat,
1390
+ stream: false
1391
+ };
1392
+ let messages = [...params.messages];
1393
+ const attempts = [];
1394
+ const maxAttempts = maxRetries + 1;
1395
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1396
+ const response = await this.create(
1397
+ { ...fullParams, messages },
1398
+ { ...requestOptions, stream: false }
1399
+ );
1400
+ const rawJson = response.content.join("");
1401
+ const requestId = response.requestId;
1402
+ try {
1403
+ const parsed = JSON.parse(rawJson);
1404
+ const validated = validateWithZod(schema, parsed);
1405
+ if (validated.success) {
1406
+ return {
1407
+ value: validated.data,
1408
+ attempts: attempt,
1409
+ requestId
1410
+ };
1411
+ }
1412
+ const error = {
1413
+ kind: "validation",
1414
+ issues: [{ message: validated.error }]
1415
+ };
1416
+ attempts.push({ attempt, rawJson, error });
1417
+ if (attempt >= maxAttempts) {
1418
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1419
+ }
1420
+ const retryMessages = retryHandler.onValidationError(
1421
+ attempt,
1422
+ rawJson,
1423
+ error,
1424
+ params.messages
1425
+ );
1426
+ if (!retryMessages) {
1427
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1428
+ }
1429
+ messages = [
1430
+ ...params.messages,
1431
+ { role: "assistant", content: rawJson },
1432
+ ...retryMessages
1433
+ ];
1434
+ } catch (e) {
1435
+ if (e instanceof StructuredExhaustedError) {
1436
+ throw e;
1437
+ }
1438
+ const error = {
1439
+ kind: "decode",
1440
+ message: e instanceof Error ? e.message : String(e)
1441
+ };
1442
+ attempts.push({ attempt, rawJson, error });
1443
+ if (attempt >= maxAttempts) {
1444
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1445
+ }
1446
+ const retryMessages = retryHandler.onValidationError(
1447
+ attempt,
1448
+ rawJson,
1449
+ error,
1450
+ params.messages
1451
+ );
1452
+ if (!retryMessages) {
1453
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1454
+ }
1455
+ messages = [
1456
+ ...params.messages,
1457
+ { role: "assistant", content: rawJson },
1458
+ ...retryMessages
1459
+ ];
1460
+ }
1461
+ }
1462
+ throw new Error(
1463
+ `Internal error: structured output loop exited unexpectedly after ${maxAttempts} attempts (this is a bug, please report it)`
1464
+ );
1465
+ }
1466
+ /**
1467
+ * Stream structured output with a Zod schema.
1468
+ *
1469
+ * Auto-generates JSON schema from the Zod schema. Note that streaming
1470
+ * does not support retries - for retry behavior, use `structured()`.
1471
+ *
1472
+ * @param schema - A Zod schema defining the expected response structure
1473
+ * @param params - Chat completion parameters (excluding responseFormat)
1474
+ * @param options - Request options
1475
+ * @returns A structured JSON stream
1476
+ *
1477
+ * @example
1478
+ * ```typescript
1479
+ * import { z } from 'zod';
1480
+ *
1481
+ * const PersonSchema = z.object({
1482
+ * name: z.string(),
1483
+ * age: z.number(),
1484
+ * });
1485
+ *
1486
+ * const stream = await client.chat.completions.streamStructured(
1487
+ * PersonSchema,
1488
+ * { model: "claude-sonnet-4-20250514", messages: [...] },
1489
+ * );
1490
+ *
1491
+ * for await (const event of stream) {
1492
+ * console.log(event.type, event.payload);
1493
+ * }
1494
+ * ```
1495
+ */
1496
+ async streamStructured(schema, params, options = {}) {
1497
+ const { schemaName, ...requestOptions } = options;
1498
+ const responseFormat = responseFormatFromZod(schema, schemaName);
1499
+ return this.streamJSON(
1500
+ { ...params, responseFormat },
1501
+ requestOptions
1502
+ );
1503
+ }
1504
+ };
1505
+ var CustomerChatClient = class {
1506
+ constructor(http, auth, customerId, defaultMetadata, metrics, trace) {
1507
+ this.http = http;
1508
+ this.auth = auth;
1509
+ this.customerId = customerId;
1510
+ this.defaultMetadata = defaultMetadata;
1511
+ this.metrics = metrics;
1512
+ this.trace = trace;
1513
+ }
1514
+ async create(params, options = {}) {
1515
+ const stream = options.stream ?? params.stream ?? true;
1516
+ const metrics = mergeMetrics(this.metrics, options.metrics);
1517
+ const trace = mergeTrace(this.trace, options.trace);
1518
+ if (!params?.messages?.length) {
1519
+ throw new ConfigError("at least one message is required");
1520
+ }
1521
+ if (!hasUserMessage(params.messages)) {
1522
+ throw new ConfigError("at least one user message is required");
1523
+ }
1524
+ const authHeaders = await this.auth.authForChat(this.customerId);
1525
+ const body = buildCustomerProxyBody(
1526
+ params,
1527
+ mergeMetadata(this.defaultMetadata, params.metadata, options.metadata)
1528
+ );
1529
+ const requestId = params.requestId || options.requestId;
1530
+ const headers = {
1531
+ ...options.headers || {},
1532
+ [CUSTOMER_ID_HEADER]: this.customerId
1533
+ };
1534
+ if (requestId) {
1535
+ headers[REQUEST_ID_HEADER] = requestId;
1536
+ }
1537
+ const baseContext = {
1538
+ method: "POST",
1539
+ path: "/llm/proxy",
1540
+ model: void 0,
1541
+ // Model is determined by tier
1542
+ requestId
1543
+ };
1544
+ const response = await this.http.request("/llm/proxy", {
1545
+ method: "POST",
1546
+ body,
1547
+ headers,
1548
+ apiKey: authHeaders.apiKey,
1549
+ accessToken: authHeaders.accessToken,
1550
+ accept: stream ? "text/event-stream" : "application/json",
1551
+ raw: true,
1552
+ signal: options.signal,
1553
+ timeoutMs: options.timeoutMs ?? (stream ? 0 : void 0),
1554
+ useDefaultTimeout: !stream,
1555
+ connectTimeoutMs: options.connectTimeoutMs,
1556
+ retry: options.retry,
1557
+ metrics,
1558
+ trace,
1559
+ context: baseContext
1560
+ });
1561
+ const resolvedRequestId = requestIdFromHeaders(response.headers) || requestId || void 0;
1562
+ if (!response.ok) {
1563
+ throw await parseErrorResponse(response);
1564
+ }
1565
+ if (!stream) {
1566
+ const payload = await response.json();
1567
+ const result = normalizeChatResponse(payload, resolvedRequestId);
1568
+ if (metrics?.usage) {
1569
+ const ctx = {
1570
+ ...baseContext,
1571
+ requestId: resolvedRequestId ?? baseContext.requestId,
1572
+ responseId: result.id
1573
+ };
1574
+ metrics.usage({ usage: result.usage, context: ctx });
1575
+ }
1576
+ return result;
1577
+ }
1578
+ const streamContext = {
1579
+ ...baseContext,
1580
+ requestId: resolvedRequestId ?? baseContext.requestId
1581
+ };
1582
+ return new ChatCompletionsStream(
1583
+ response,
1584
+ resolvedRequestId,
1585
+ streamContext,
1586
+ metrics,
1587
+ trace
1588
+ );
1589
+ }
1590
+ /**
1591
+ * Stream structured JSON responses using the NDJSON contract.
1592
+ * The request must include a structured responseFormat.
1593
+ */
1594
+ async streamJSON(params, options = {}) {
1595
+ const metrics = mergeMetrics(this.metrics, options.metrics);
1596
+ const trace = mergeTrace(this.trace, options.trace);
1597
+ if (!params?.messages?.length) {
1598
+ throw new ConfigError("at least one message is required");
1599
+ }
1600
+ if (!hasUserMessage(params.messages)) {
1601
+ throw new ConfigError("at least one user message is required");
1602
+ }
1603
+ if (!params.responseFormat || params.responseFormat.type !== "json_object" && params.responseFormat.type !== "json_schema") {
1604
+ throw new ConfigError(
1605
+ "responseFormat with type=json_object or json_schema is required for structured streaming"
1606
+ );
1607
+ }
1608
+ const authHeaders = await this.auth.authForChat(this.customerId);
1609
+ const body = buildCustomerProxyBody(
1610
+ params,
1611
+ mergeMetadata(this.defaultMetadata, params.metadata, options.metadata)
1612
+ );
1613
+ const requestId = params.requestId || options.requestId;
1614
+ const headers = {
1615
+ ...options.headers || {},
1616
+ [CUSTOMER_ID_HEADER]: this.customerId
1617
+ };
1618
+ if (requestId) {
1619
+ headers[REQUEST_ID_HEADER] = requestId;
1620
+ }
1621
+ const baseContext = {
1622
+ method: "POST",
1623
+ path: "/llm/proxy",
1624
+ model: void 0,
1625
+ // Model is determined by tier
1626
+ requestId
1627
+ };
1628
+ const response = await this.http.request("/llm/proxy", {
1629
+ method: "POST",
1630
+ body,
1631
+ headers,
1632
+ apiKey: authHeaders.apiKey,
1633
+ accessToken: authHeaders.accessToken,
1634
+ accept: "application/x-ndjson",
1635
+ raw: true,
1636
+ signal: options.signal,
1637
+ timeoutMs: options.timeoutMs ?? 0,
1638
+ useDefaultTimeout: false,
1639
+ connectTimeoutMs: options.connectTimeoutMs,
1640
+ retry: options.retry,
1641
+ metrics,
1642
+ trace,
1643
+ context: baseContext
1644
+ });
1645
+ const resolvedRequestId = requestIdFromHeaders(response.headers) || requestId || void 0;
1646
+ if (!response.ok) {
1647
+ throw await parseErrorResponse(response);
1648
+ }
1649
+ const contentType = response.headers.get("Content-Type") || "";
1650
+ if (!/application\/(x-)?ndjson/i.test(contentType)) {
1651
+ throw new TransportError(
1652
+ `expected NDJSON structured stream, got Content-Type ${contentType || "missing"}`,
1653
+ { kind: "request" }
1654
+ );
1655
+ }
1656
+ const streamContext = {
1657
+ ...baseContext,
1658
+ requestId: resolvedRequestId ?? baseContext.requestId
1659
+ };
1660
+ return new StructuredJSONStream(
1661
+ response,
1662
+ resolvedRequestId,
1663
+ streamContext,
1664
+ metrics,
1665
+ trace
1666
+ );
1667
+ }
1668
+ /**
1669
+ * Send a structured output request with a Zod schema for customer-attributed calls.
1670
+ *
1671
+ * Auto-generates JSON schema from the Zod schema, validates the response,
1672
+ * and retries on validation failure if configured.
1673
+ *
1674
+ * @param schema - A Zod schema defining the expected response structure
1675
+ * @param params - Customer chat parameters (excluding responseFormat)
1676
+ * @param options - Request options including retry configuration
1677
+ * @returns A typed result with the parsed value
1678
+ */
1679
+ async structured(schema, params, options = {}) {
1680
+ const {
1681
+ maxRetries = 0,
1682
+ retryHandler = defaultRetryHandler,
1683
+ schemaName,
1684
+ ...requestOptions
1685
+ } = options;
1686
+ const responseFormat = responseFormatFromZod(schema, schemaName);
1687
+ const fullParams = {
1688
+ ...params,
1689
+ responseFormat,
1690
+ stream: false
1691
+ };
1692
+ let messages = [...params.messages];
1693
+ const attempts = [];
1694
+ const maxAttempts = maxRetries + 1;
1695
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1696
+ const response = await this.create(
1697
+ { ...fullParams, messages },
1698
+ { ...requestOptions, stream: false }
1699
+ );
1700
+ const rawJson = response.content.join("");
1701
+ const requestId = response.requestId;
1702
+ try {
1703
+ const parsed = JSON.parse(rawJson);
1704
+ const validated = validateWithZod(schema, parsed);
1705
+ if (validated.success) {
1706
+ return {
1707
+ value: validated.data,
1708
+ attempts: attempt,
1709
+ requestId
1710
+ };
1711
+ }
1712
+ const error = {
1713
+ kind: "validation",
1714
+ issues: [{ message: validated.error }]
1715
+ };
1716
+ attempts.push({ attempt, rawJson, error });
1717
+ if (attempt >= maxAttempts) {
1718
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1719
+ }
1720
+ const retryMessages = retryHandler.onValidationError(
1721
+ attempt,
1722
+ rawJson,
1723
+ error,
1724
+ params.messages
1725
+ );
1726
+ if (!retryMessages) {
1727
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1728
+ }
1729
+ messages = [
1730
+ ...params.messages,
1731
+ { role: "assistant", content: rawJson },
1732
+ ...retryMessages
1733
+ ];
1734
+ } catch (e) {
1735
+ if (e instanceof StructuredExhaustedError) {
1736
+ throw e;
1737
+ }
1738
+ const error = {
1739
+ kind: "decode",
1740
+ message: e instanceof Error ? e.message : String(e)
1741
+ };
1742
+ attempts.push({ attempt, rawJson, error });
1743
+ if (attempt >= maxAttempts) {
1744
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1745
+ }
1746
+ const retryMessages = retryHandler.onValidationError(
1747
+ attempt,
1748
+ rawJson,
1749
+ error,
1750
+ params.messages
1751
+ );
1752
+ if (!retryMessages) {
1753
+ throw new StructuredExhaustedError(rawJson, attempts, error);
1754
+ }
1755
+ messages = [
1756
+ ...params.messages,
1757
+ { role: "assistant", content: rawJson },
1758
+ ...retryMessages
1759
+ ];
1760
+ }
1761
+ }
1762
+ throw new Error(
1763
+ `Internal error: structured output loop exited unexpectedly after ${maxAttempts} attempts (this is a bug, please report it)`
1764
+ );
1765
+ }
1766
+ /**
1767
+ * Stream structured output with a Zod schema for customer-attributed calls.
1768
+ *
1769
+ * Auto-generates JSON schema from the Zod schema. Note that streaming
1770
+ * does not support retries - for retry behavior, use `structured()`.
1771
+ *
1772
+ * @param schema - A Zod schema defining the expected response structure
1773
+ * @param params - Customer chat parameters (excluding responseFormat)
1774
+ * @param options - Request options
1775
+ * @returns A structured JSON stream
1776
+ */
1777
+ async streamStructured(schema, params, options = {}) {
1778
+ const { schemaName, ...requestOptions } = options;
1779
+ const responseFormat = responseFormatFromZod(schema, schemaName);
1780
+ return this.streamJSON(
1781
+ { ...params, responseFormat },
1782
+ requestOptions
1783
+ );
1784
+ }
1264
1785
  };
1265
1786
  var ChatCompletionsStream = class {
1266
1787
  constructor(response, requestId, context, metrics, trace) {
@@ -1280,7 +1801,13 @@ var ChatCompletionsStream = class {
1280
1801
  this.closed = true;
1281
1802
  try {
1282
1803
  await this.response.body?.cancel(reason);
1283
- } catch {
1804
+ } catch (err) {
1805
+ if (this.trace?.streamError) {
1806
+ this.trace.streamError({
1807
+ context: this.context,
1808
+ error: err instanceof Error ? err : new Error(String(err))
1809
+ });
1810
+ }
1284
1811
  }
1285
1812
  }
1286
1813
  async *[Symbol.asyncIterator]() {
@@ -1379,7 +1906,13 @@ var StructuredJSONStream = class {
1379
1906
  this.closed = true;
1380
1907
  try {
1381
1908
  await this.response.body?.cancel(reason);
1382
- } catch {
1909
+ } catch (err) {
1910
+ if (this.trace?.streamError) {
1911
+ this.trace.streamError({
1912
+ context: this.context,
1913
+ error: err instanceof Error ? err : new Error(String(err))
1914
+ });
1915
+ }
1383
1916
  }
1384
1917
  }
1385
1918
  async *[Symbol.asyncIterator]() {
@@ -1580,7 +2113,7 @@ function mapChatEvent(raw, requestId) {
1580
2113
  if (raw.data) {
1581
2114
  try {
1582
2115
  parsed = JSON.parse(raw.data);
1583
- } catch {
2116
+ } catch (err) {
1584
2117
  parsed = raw.data;
1585
2118
  }
1586
2119
  }
@@ -1752,10 +2285,25 @@ function buildProxyBody(params, metadata) {
1752
2285
  if (params.responseFormat) body.response_format = params.responseFormat;
1753
2286
  return body;
1754
2287
  }
2288
+ function buildCustomerProxyBody(params, metadata) {
2289
+ const body = {
2290
+ messages: normalizeMessages(params.messages)
2291
+ };
2292
+ if (typeof params.maxTokens === "number") body.max_tokens = params.maxTokens;
2293
+ if (typeof params.temperature === "number")
2294
+ body.temperature = params.temperature;
2295
+ if (metadata && Object.keys(metadata).length > 0) body.metadata = metadata;
2296
+ if (params.stop?.length) body.stop = params.stop;
2297
+ if (params.stopSequences?.length) body.stop_sequences = params.stopSequences;
2298
+ if (params.tools?.length) body.tools = normalizeTools(params.tools);
2299
+ if (params.toolChoice) body.tool_choice = normalizeToolChoice(params.toolChoice);
2300
+ if (params.responseFormat) body.response_format = params.responseFormat;
2301
+ return body;
2302
+ }
1755
2303
  function normalizeMessages(messages) {
1756
2304
  return messages.map((msg) => {
1757
2305
  const normalized = {
1758
- role: msg.role || "user",
2306
+ role: msg.role,
1759
2307
  content: msg.content
1760
2308
  };
1761
2309
  if (msg.toolCalls?.length) {
@@ -2464,17 +3012,21 @@ export {
2464
3012
  ChatClient,
2465
3013
  ChatCompletionsStream,
2466
3014
  ConfigError,
3015
+ CustomerChatClient,
2467
3016
  CustomersClient,
2468
3017
  DEFAULT_BASE_URL,
2469
3018
  DEFAULT_CLIENT_HEADER,
2470
3019
  DEFAULT_CONNECT_TIMEOUT_MS,
2471
3020
  DEFAULT_REQUEST_TIMEOUT_MS,
2472
3021
  ErrorCodes,
3022
+ MessageRoles,
2473
3023
  ModelRelay,
2474
3024
  ModelRelayError,
2475
3025
  ResponseFormatTypes,
2476
3026
  SDK_VERSION,
2477
3027
  StopReasons,
3028
+ StructuredDecodeError,
3029
+ StructuredExhaustedError,
2478
3030
  StructuredJSONStream,
2479
3031
  TiersClient,
2480
3032
  ToolArgsError,
@@ -2497,6 +3049,7 @@ export {
2497
3049
  createUsage,
2498
3050
  createUserMessage,
2499
3051
  createWebTool,
3052
+ defaultRetryHandler,
2500
3053
  executeWithRetry,
2501
3054
  firstToolCall,
2502
3055
  formatToolErrorForModel,
@@ -2517,11 +3070,13 @@ export {
2517
3070
  parseToolArgs,
2518
3071
  parseToolArgsRaw,
2519
3072
  respondToToolCall,
3073
+ responseFormatFromZod,
2520
3074
  stopReasonToString,
2521
3075
  toolChoiceAuto,
2522
3076
  toolChoiceNone,
2523
3077
  toolChoiceRequired,
2524
3078
  toolResultMessage,
2525
3079
  tryParseToolArgs,
3080
+ validateWithZod,
2526
3081
  zodToJsonSchema
2527
3082
  };