@modelrelay/sdk 0.24.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -227
- package/dist/index.cjs +350 -5
- package/dist/index.d.cts +989 -731
- package/dist/index.d.ts +989 -731
- package/dist/index.js +345 -5
- package/package.json +1 -1
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.
|
|
343
|
+
version: "0.27.0",
|
|
344
344
|
description: "TypeScript SDK for the ModelRelay API",
|
|
345
345
|
type: "module",
|
|
346
346
|
main: "dist/index.cjs",
|
|
@@ -1100,6 +1100,58 @@ async function executeWithRetry(registry, toolCalls, options = {}) {
|
|
|
1100
1100
|
return Array.from(successfulResults.values());
|
|
1101
1101
|
}
|
|
1102
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
|
+
|
|
1103
1155
|
// src/chat.ts
|
|
1104
1156
|
var CUSTOMER_ID_HEADER = "X-ModelRelay-Customer-Id";
|
|
1105
1157
|
var REQUEST_ID_HEADER = "X-ModelRelay-Chat-Request-Id";
|
|
@@ -1297,6 +1349,158 @@ var ChatCompletionsClient = class {
|
|
|
1297
1349
|
trace
|
|
1298
1350
|
);
|
|
1299
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
|
+
}
|
|
1300
1504
|
};
|
|
1301
1505
|
var CustomerChatClient = class {
|
|
1302
1506
|
constructor(http, auth, customerId, defaultMetadata, metrics, trace) {
|
|
@@ -1461,6 +1665,123 @@ var CustomerChatClient = class {
|
|
|
1461
1665
|
trace
|
|
1462
1666
|
);
|
|
1463
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
|
+
}
|
|
1464
1785
|
};
|
|
1465
1786
|
var ChatCompletionsStream = class {
|
|
1466
1787
|
constructor(response, requestId, context, metrics, trace) {
|
|
@@ -1480,7 +1801,13 @@ var ChatCompletionsStream = class {
|
|
|
1480
1801
|
this.closed = true;
|
|
1481
1802
|
try {
|
|
1482
1803
|
await this.response.body?.cancel(reason);
|
|
1483
|
-
} 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
|
+
}
|
|
1484
1811
|
}
|
|
1485
1812
|
}
|
|
1486
1813
|
async *[Symbol.asyncIterator]() {
|
|
@@ -1579,7 +1906,13 @@ var StructuredJSONStream = class {
|
|
|
1579
1906
|
this.closed = true;
|
|
1580
1907
|
try {
|
|
1581
1908
|
await this.response.body?.cancel(reason);
|
|
1582
|
-
} 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
|
+
}
|
|
1583
1916
|
}
|
|
1584
1917
|
}
|
|
1585
1918
|
async *[Symbol.asyncIterator]() {
|
|
@@ -1693,11 +2026,13 @@ var StructuredJSONStream = class {
|
|
|
1693
2026
|
if (rawType === "completion") {
|
|
1694
2027
|
this.sawTerminal = true;
|
|
1695
2028
|
}
|
|
2029
|
+
const completeFieldsArray = Array.isArray(obj.complete_fields) ? obj.complete_fields.filter((f) => typeof f === "string") : [];
|
|
1696
2030
|
const event = {
|
|
1697
2031
|
type: rawType,
|
|
1698
2032
|
// biome-ignore lint/suspicious/noExplicitAny: payload is untyped json
|
|
1699
2033
|
payload: obj.payload,
|
|
1700
|
-
requestId: this.requestId
|
|
2034
|
+
requestId: this.requestId,
|
|
2035
|
+
completeFields: new Set(completeFieldsArray)
|
|
1701
2036
|
};
|
|
1702
2037
|
return event;
|
|
1703
2038
|
}
|
|
@@ -1780,7 +2115,7 @@ function mapChatEvent(raw, requestId) {
|
|
|
1780
2115
|
if (raw.data) {
|
|
1781
2116
|
try {
|
|
1782
2117
|
parsed = JSON.parse(raw.data);
|
|
1783
|
-
} catch {
|
|
2118
|
+
} catch (err) {
|
|
1784
2119
|
parsed = raw.data;
|
|
1785
2120
|
}
|
|
1786
2121
|
}
|
|
@@ -2692,6 +3027,8 @@ export {
|
|
|
2692
3027
|
ResponseFormatTypes,
|
|
2693
3028
|
SDK_VERSION,
|
|
2694
3029
|
StopReasons,
|
|
3030
|
+
StructuredDecodeError,
|
|
3031
|
+
StructuredExhaustedError,
|
|
2695
3032
|
StructuredJSONStream,
|
|
2696
3033
|
TiersClient,
|
|
2697
3034
|
ToolArgsError,
|
|
@@ -2714,6 +3051,7 @@ export {
|
|
|
2714
3051
|
createUsage,
|
|
2715
3052
|
createUserMessage,
|
|
2716
3053
|
createWebTool,
|
|
3054
|
+
defaultRetryHandler,
|
|
2717
3055
|
executeWithRetry,
|
|
2718
3056
|
firstToolCall,
|
|
2719
3057
|
formatToolErrorForModel,
|
|
@@ -2734,11 +3072,13 @@ export {
|
|
|
2734
3072
|
parseToolArgs,
|
|
2735
3073
|
parseToolArgsRaw,
|
|
2736
3074
|
respondToToolCall,
|
|
3075
|
+
responseFormatFromZod,
|
|
2737
3076
|
stopReasonToString,
|
|
2738
3077
|
toolChoiceAuto,
|
|
2739
3078
|
toolChoiceNone,
|
|
2740
3079
|
toolChoiceRequired,
|
|
2741
3080
|
toolResultMessage,
|
|
2742
3081
|
tryParseToolArgs,
|
|
3082
|
+
validateWithZod,
|
|
2743
3083
|
zodToJsonSchema
|
|
2744
3084
|
};
|