@modelrelay/sdk 0.27.0 → 0.30.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/dist/index.cjs +83 -119
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +83 -119
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -437,7 +437,7 @@ function isTokenReusable(token) {
|
|
|
437
437
|
// package.json
|
|
438
438
|
var package_default = {
|
|
439
439
|
name: "@modelrelay/sdk",
|
|
440
|
-
version: "0.
|
|
440
|
+
version: "0.30.0",
|
|
441
441
|
description: "TypeScript SDK for the ModelRelay API",
|
|
442
442
|
type: "module",
|
|
443
443
|
main: "dist/index.cjs",
|
|
@@ -527,7 +527,6 @@ var ToolChoiceTypes = {
|
|
|
527
527
|
};
|
|
528
528
|
var ResponseFormatTypes = {
|
|
529
529
|
Text: "text",
|
|
530
|
-
JsonObject: "json_object",
|
|
531
530
|
JsonSchema: "json_schema"
|
|
532
531
|
};
|
|
533
532
|
function mergeMetrics(base, override) {
|
|
@@ -1332,7 +1331,7 @@ var ChatCompletionsClient = class {
|
|
|
1332
1331
|
headers,
|
|
1333
1332
|
apiKey: authHeaders.apiKey,
|
|
1334
1333
|
accessToken: authHeaders.accessToken,
|
|
1335
|
-
accept: stream ? "
|
|
1334
|
+
accept: stream ? "application/x-ndjson" : "application/json",
|
|
1336
1335
|
raw: true,
|
|
1337
1336
|
signal: options.signal,
|
|
1338
1337
|
timeoutMs: options.timeoutMs ?? (stream ? 0 : void 0),
|
|
@@ -1385,9 +1384,9 @@ var ChatCompletionsClient = class {
|
|
|
1385
1384
|
if (!hasUserMessage(params.messages)) {
|
|
1386
1385
|
throw new ConfigError("at least one user message is required");
|
|
1387
1386
|
}
|
|
1388
|
-
if (!params.responseFormat || params.responseFormat.type !== "
|
|
1387
|
+
if (!params.responseFormat || params.responseFormat.type !== "json_schema") {
|
|
1389
1388
|
throw new ConfigError(
|
|
1390
|
-
"responseFormat with type=
|
|
1389
|
+
"responseFormat with type=json_schema is required for structured streaming"
|
|
1391
1390
|
);
|
|
1392
1391
|
}
|
|
1393
1392
|
const authHeaders = await this.auth.authForChat();
|
|
@@ -1644,7 +1643,7 @@ var CustomerChatClient = class {
|
|
|
1644
1643
|
headers,
|
|
1645
1644
|
apiKey: authHeaders.apiKey,
|
|
1646
1645
|
accessToken: authHeaders.accessToken,
|
|
1647
|
-
accept: stream ? "
|
|
1646
|
+
accept: stream ? "application/x-ndjson" : "application/json",
|
|
1648
1647
|
raw: true,
|
|
1649
1648
|
signal: options.signal,
|
|
1650
1649
|
timeoutMs: options.timeoutMs ?? (stream ? 0 : void 0),
|
|
@@ -1697,9 +1696,9 @@ var CustomerChatClient = class {
|
|
|
1697
1696
|
if (!hasUserMessage(params.messages)) {
|
|
1698
1697
|
throw new ConfigError("at least one user message is required");
|
|
1699
1698
|
}
|
|
1700
|
-
if (!params.responseFormat || params.responseFormat.type !== "
|
|
1699
|
+
if (!params.responseFormat || params.responseFormat.type !== "json_schema") {
|
|
1701
1700
|
throw new ConfigError(
|
|
1702
|
-
"responseFormat with type=
|
|
1701
|
+
"responseFormat with type=json_schema is required for structured streaming"
|
|
1703
1702
|
);
|
|
1704
1703
|
}
|
|
1705
1704
|
const authHeaders = await this.auth.authForChat(this.customerId);
|
|
@@ -1926,9 +1925,9 @@ var ChatCompletionsStream = class {
|
|
|
1926
1925
|
}
|
|
1927
1926
|
const { value, done } = await reader.read();
|
|
1928
1927
|
if (done) {
|
|
1929
|
-
const {
|
|
1930
|
-
for (const
|
|
1931
|
-
const parsed =
|
|
1928
|
+
const { records: records2 } = consumeNDJSONBuffer(buffer, true);
|
|
1929
|
+
for (const line of records2) {
|
|
1930
|
+
const parsed = mapNDJSONChatEvent(line, this.requestId);
|
|
1932
1931
|
if (parsed) {
|
|
1933
1932
|
this.handleStreamEvent(parsed);
|
|
1934
1933
|
yield parsed;
|
|
@@ -1937,10 +1936,10 @@ var ChatCompletionsStream = class {
|
|
|
1937
1936
|
return;
|
|
1938
1937
|
}
|
|
1939
1938
|
buffer += decoder.decode(value, { stream: true });
|
|
1940
|
-
const {
|
|
1939
|
+
const { records, remainder } = consumeNDJSONBuffer(buffer);
|
|
1941
1940
|
buffer = remainder;
|
|
1942
|
-
for (const
|
|
1943
|
-
const parsed =
|
|
1941
|
+
for (const line of records) {
|
|
1942
|
+
const parsed = mapNDJSONChatEvent(line, this.requestId);
|
|
1944
1943
|
if (parsed) {
|
|
1945
1944
|
this.handleStreamEvent(parsed);
|
|
1946
1945
|
yield parsed;
|
|
@@ -2152,48 +2151,6 @@ var StructuredJSONStream = class {
|
|
|
2152
2151
|
this.trace.streamEvent({ context: this.context, event });
|
|
2153
2152
|
}
|
|
2154
2153
|
};
|
|
2155
|
-
function consumeSSEBuffer(buffer, flush = false) {
|
|
2156
|
-
const events = [];
|
|
2157
|
-
let eventName = "";
|
|
2158
|
-
let dataLines = [];
|
|
2159
|
-
let remainder = "";
|
|
2160
|
-
const lines = buffer.split(/\r?\n/);
|
|
2161
|
-
const lastIndex = lines.length - 1;
|
|
2162
|
-
const limit = flush ? lines.length : Math.max(0, lastIndex);
|
|
2163
|
-
const pushEvent = () => {
|
|
2164
|
-
if (!eventName && dataLines.length === 0) {
|
|
2165
|
-
return;
|
|
2166
|
-
}
|
|
2167
|
-
events.push({
|
|
2168
|
-
event: eventName || "message",
|
|
2169
|
-
data: dataLines.join("\n")
|
|
2170
|
-
});
|
|
2171
|
-
eventName = "";
|
|
2172
|
-
dataLines = [];
|
|
2173
|
-
};
|
|
2174
|
-
for (let i = 0; i < limit; i++) {
|
|
2175
|
-
const line = lines[i];
|
|
2176
|
-
if (line === "") {
|
|
2177
|
-
pushEvent();
|
|
2178
|
-
continue;
|
|
2179
|
-
}
|
|
2180
|
-
if (line.startsWith(":")) {
|
|
2181
|
-
continue;
|
|
2182
|
-
}
|
|
2183
|
-
if (line.startsWith("event:")) {
|
|
2184
|
-
eventName = line.slice(6).trim();
|
|
2185
|
-
} else if (line.startsWith("data:")) {
|
|
2186
|
-
dataLines.push(line.slice(5).trimStart());
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
|
-
if (flush) {
|
|
2190
|
-
pushEvent();
|
|
2191
|
-
remainder = "";
|
|
2192
|
-
} else {
|
|
2193
|
-
remainder = lines[lastIndex] ?? "";
|
|
2194
|
-
}
|
|
2195
|
-
return { events, remainder };
|
|
2196
|
-
}
|
|
2197
2154
|
function consumeNDJSONBuffer(buffer, flush = false) {
|
|
2198
2155
|
const lines = buffer.split(/\r?\n/);
|
|
2199
2156
|
const records = [];
|
|
@@ -2207,29 +2164,79 @@ function consumeNDJSONBuffer(buffer, flush = false) {
|
|
|
2207
2164
|
const remainder = flush ? "" : lines[lastIndex] ?? "";
|
|
2208
2165
|
return { records, remainder };
|
|
2209
2166
|
}
|
|
2210
|
-
function
|
|
2211
|
-
let parsed
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2167
|
+
function mapNDJSONChatEvent(line, requestId) {
|
|
2168
|
+
let parsed;
|
|
2169
|
+
try {
|
|
2170
|
+
parsed = JSON.parse(line);
|
|
2171
|
+
} catch (err) {
|
|
2172
|
+
console.warn(
|
|
2173
|
+
`[ModelRelay SDK] Failed to parse NDJSON line: ${err instanceof Error ? err.message : String(err)}`,
|
|
2174
|
+
{ line: line.substring(0, 200), requestId }
|
|
2175
|
+
);
|
|
2176
|
+
return null;
|
|
2177
|
+
}
|
|
2178
|
+
if (!parsed || typeof parsed !== "object") {
|
|
2179
|
+
console.warn("[ModelRelay SDK] NDJSON record is not an object", {
|
|
2180
|
+
parsed,
|
|
2181
|
+
requestId
|
|
2182
|
+
});
|
|
2183
|
+
return null;
|
|
2184
|
+
}
|
|
2185
|
+
const obj = parsed;
|
|
2186
|
+
const recordType = String(obj.type || "").trim().toLowerCase();
|
|
2187
|
+
if (recordType === "keepalive") {
|
|
2188
|
+
return null;
|
|
2189
|
+
}
|
|
2190
|
+
if (!recordType) {
|
|
2191
|
+
console.warn("[ModelRelay SDK] NDJSON record missing 'type' field", {
|
|
2192
|
+
obj,
|
|
2193
|
+
requestId
|
|
2194
|
+
});
|
|
2195
|
+
return null;
|
|
2196
|
+
}
|
|
2197
|
+
let type;
|
|
2198
|
+
switch (recordType) {
|
|
2199
|
+
case "start":
|
|
2200
|
+
type = "message_start";
|
|
2201
|
+
break;
|
|
2202
|
+
case "update":
|
|
2203
|
+
type = "message_delta";
|
|
2204
|
+
break;
|
|
2205
|
+
case "completion":
|
|
2206
|
+
type = "message_stop";
|
|
2207
|
+
break;
|
|
2208
|
+
case "error":
|
|
2209
|
+
type = "custom";
|
|
2210
|
+
break;
|
|
2211
|
+
// Tool use event types
|
|
2212
|
+
case "tool_use_start":
|
|
2213
|
+
type = "tool_use_start";
|
|
2214
|
+
break;
|
|
2215
|
+
case "tool_use_delta":
|
|
2216
|
+
type = "tool_use_delta";
|
|
2217
|
+
break;
|
|
2218
|
+
case "tool_use_stop":
|
|
2219
|
+
type = "tool_use_stop";
|
|
2220
|
+
break;
|
|
2221
|
+
default:
|
|
2222
|
+
type = "custom";
|
|
2223
|
+
}
|
|
2224
|
+
const usage = normalizeUsage(obj.usage);
|
|
2225
|
+
const responseId = obj.request_id;
|
|
2226
|
+
const model = normalizeModelId(obj.model);
|
|
2227
|
+
const stopReason = normalizeStopReason(obj.stop_reason);
|
|
2228
|
+
let textDelta;
|
|
2229
|
+
if (obj.payload && typeof obj.payload === "object") {
|
|
2230
|
+
if (typeof obj.payload.content === "string") {
|
|
2231
|
+
textDelta = obj.payload.content;
|
|
2217
2232
|
}
|
|
2218
2233
|
}
|
|
2219
|
-
const
|
|
2220
|
-
const
|
|
2221
|
-
const type = normalizeEventType(raw.event, p);
|
|
2222
|
-
const usage = normalizeUsage(p.usage);
|
|
2223
|
-
const responseId = p.response_id || p.id || p?.message?.id;
|
|
2224
|
-
const model = normalizeModelId(p.model || p?.message?.model);
|
|
2225
|
-
const stopReason = normalizeStopReason(p.stop_reason);
|
|
2226
|
-
const textDelta = extractTextDelta(p);
|
|
2227
|
-
const toolCallDelta = extractToolCallDelta(p, type);
|
|
2228
|
-
const toolCalls = extractToolCalls(p, type);
|
|
2234
|
+
const toolCallDelta = extractToolCallDelta(obj, type);
|
|
2235
|
+
const toolCalls = extractToolCalls(obj, type);
|
|
2229
2236
|
return {
|
|
2230
2237
|
type,
|
|
2231
|
-
event:
|
|
2232
|
-
data:
|
|
2238
|
+
event: recordType,
|
|
2239
|
+
data: obj,
|
|
2233
2240
|
textDelta,
|
|
2234
2241
|
toolCallDelta,
|
|
2235
2242
|
toolCalls,
|
|
@@ -2238,52 +2245,9 @@ function mapChatEvent(raw, requestId) {
|
|
|
2238
2245
|
stopReason,
|
|
2239
2246
|
usage,
|
|
2240
2247
|
requestId,
|
|
2241
|
-
raw:
|
|
2248
|
+
raw: line
|
|
2242
2249
|
};
|
|
2243
2250
|
}
|
|
2244
|
-
function normalizeEventType(eventName, payload) {
|
|
2245
|
-
const hint = String(
|
|
2246
|
-
payload?.type || payload?.event || eventName || ""
|
|
2247
|
-
).trim();
|
|
2248
|
-
switch (hint) {
|
|
2249
|
-
case "message_start":
|
|
2250
|
-
return "message_start";
|
|
2251
|
-
case "message_delta":
|
|
2252
|
-
return "message_delta";
|
|
2253
|
-
case "message_stop":
|
|
2254
|
-
return "message_stop";
|
|
2255
|
-
case "tool_use_start":
|
|
2256
|
-
return "tool_use_start";
|
|
2257
|
-
case "tool_use_delta":
|
|
2258
|
-
return "tool_use_delta";
|
|
2259
|
-
case "tool_use_stop":
|
|
2260
|
-
return "tool_use_stop";
|
|
2261
|
-
case "ping":
|
|
2262
|
-
return "ping";
|
|
2263
|
-
default:
|
|
2264
|
-
return "custom";
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
function extractTextDelta(payload) {
|
|
2268
|
-
if (!payload || typeof payload !== "object") {
|
|
2269
|
-
return void 0;
|
|
2270
|
-
}
|
|
2271
|
-
if (typeof payload.text_delta === "string" && payload.text_delta !== "") {
|
|
2272
|
-
return payload.text_delta;
|
|
2273
|
-
}
|
|
2274
|
-
if (typeof payload.delta === "string") {
|
|
2275
|
-
return payload.delta;
|
|
2276
|
-
}
|
|
2277
|
-
if (payload.delta && typeof payload.delta === "object") {
|
|
2278
|
-
if (typeof payload.delta.text === "string") {
|
|
2279
|
-
return payload.delta.text;
|
|
2280
|
-
}
|
|
2281
|
-
if (typeof payload.delta.content === "string") {
|
|
2282
|
-
return payload.delta.content;
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
return void 0;
|
|
2286
|
-
}
|
|
2287
2251
|
function extractToolCallDelta(payload, type) {
|
|
2288
2252
|
if (!payload || typeof payload !== "object") {
|
|
2289
2253
|
return void 0;
|
package/dist/index.d.cts
CHANGED
|
@@ -350,7 +350,6 @@ interface ToolCall {
|
|
|
350
350
|
}
|
|
351
351
|
declare const ResponseFormatTypes: {
|
|
352
352
|
readonly Text: "text";
|
|
353
|
-
readonly JsonObject: "json_object";
|
|
354
353
|
readonly JsonSchema: "json_schema";
|
|
355
354
|
};
|
|
356
355
|
type ResponseFormatType = (typeof ResponseFormatTypes)[keyof typeof ResponseFormatTypes];
|
|
@@ -385,8 +384,8 @@ interface ChatCompletionCreateParams {
|
|
|
385
384
|
*/
|
|
386
385
|
toolChoice?: ToolChoice;
|
|
387
386
|
/**
|
|
388
|
-
* Structured outputs configuration. When set with type `
|
|
389
|
-
*
|
|
387
|
+
* Structured outputs configuration. When set with type `json_schema`,
|
|
388
|
+
* the backend validates and returns structured JSON.
|
|
390
389
|
*/
|
|
391
390
|
responseFormat?: ResponseFormat;
|
|
392
391
|
/**
|
|
@@ -418,8 +417,8 @@ interface CustomerChatParams {
|
|
|
418
417
|
*/
|
|
419
418
|
toolChoice?: ToolChoice;
|
|
420
419
|
/**
|
|
421
|
-
* Structured outputs configuration. When set with type `
|
|
422
|
-
*
|
|
420
|
+
* Structured outputs configuration. When set with type `json_schema`,
|
|
421
|
+
* the backend validates and returns structured JSON.
|
|
423
422
|
*/
|
|
424
423
|
responseFormat?: ResponseFormat;
|
|
425
424
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -350,7 +350,6 @@ interface ToolCall {
|
|
|
350
350
|
}
|
|
351
351
|
declare const ResponseFormatTypes: {
|
|
352
352
|
readonly Text: "text";
|
|
353
|
-
readonly JsonObject: "json_object";
|
|
354
353
|
readonly JsonSchema: "json_schema";
|
|
355
354
|
};
|
|
356
355
|
type ResponseFormatType = (typeof ResponseFormatTypes)[keyof typeof ResponseFormatTypes];
|
|
@@ -385,8 +384,8 @@ interface ChatCompletionCreateParams {
|
|
|
385
384
|
*/
|
|
386
385
|
toolChoice?: ToolChoice;
|
|
387
386
|
/**
|
|
388
|
-
* Structured outputs configuration. When set with type `
|
|
389
|
-
*
|
|
387
|
+
* Structured outputs configuration. When set with type `json_schema`,
|
|
388
|
+
* the backend validates and returns structured JSON.
|
|
390
389
|
*/
|
|
391
390
|
responseFormat?: ResponseFormat;
|
|
392
391
|
/**
|
|
@@ -418,8 +417,8 @@ interface CustomerChatParams {
|
|
|
418
417
|
*/
|
|
419
418
|
toolChoice?: ToolChoice;
|
|
420
419
|
/**
|
|
421
|
-
* Structured outputs configuration. When set with type `
|
|
422
|
-
*
|
|
420
|
+
* Structured outputs configuration. When set with type `json_schema`,
|
|
421
|
+
* the backend validates and returns structured JSON.
|
|
423
422
|
*/
|
|
424
423
|
responseFormat?: ResponseFormat;
|
|
425
424
|
/**
|
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.30.0",
|
|
344
344
|
description: "TypeScript SDK for the ModelRelay API",
|
|
345
345
|
type: "module",
|
|
346
346
|
main: "dist/index.cjs",
|
|
@@ -430,7 +430,6 @@ var ToolChoiceTypes = {
|
|
|
430
430
|
};
|
|
431
431
|
var ResponseFormatTypes = {
|
|
432
432
|
Text: "text",
|
|
433
|
-
JsonObject: "json_object",
|
|
434
433
|
JsonSchema: "json_schema"
|
|
435
434
|
};
|
|
436
435
|
function mergeMetrics(base, override) {
|
|
@@ -1235,7 +1234,7 @@ var ChatCompletionsClient = class {
|
|
|
1235
1234
|
headers,
|
|
1236
1235
|
apiKey: authHeaders.apiKey,
|
|
1237
1236
|
accessToken: authHeaders.accessToken,
|
|
1238
|
-
accept: stream ? "
|
|
1237
|
+
accept: stream ? "application/x-ndjson" : "application/json",
|
|
1239
1238
|
raw: true,
|
|
1240
1239
|
signal: options.signal,
|
|
1241
1240
|
timeoutMs: options.timeoutMs ?? (stream ? 0 : void 0),
|
|
@@ -1288,9 +1287,9 @@ var ChatCompletionsClient = class {
|
|
|
1288
1287
|
if (!hasUserMessage(params.messages)) {
|
|
1289
1288
|
throw new ConfigError("at least one user message is required");
|
|
1290
1289
|
}
|
|
1291
|
-
if (!params.responseFormat || params.responseFormat.type !== "
|
|
1290
|
+
if (!params.responseFormat || params.responseFormat.type !== "json_schema") {
|
|
1292
1291
|
throw new ConfigError(
|
|
1293
|
-
"responseFormat with type=
|
|
1292
|
+
"responseFormat with type=json_schema is required for structured streaming"
|
|
1294
1293
|
);
|
|
1295
1294
|
}
|
|
1296
1295
|
const authHeaders = await this.auth.authForChat();
|
|
@@ -1547,7 +1546,7 @@ var CustomerChatClient = class {
|
|
|
1547
1546
|
headers,
|
|
1548
1547
|
apiKey: authHeaders.apiKey,
|
|
1549
1548
|
accessToken: authHeaders.accessToken,
|
|
1550
|
-
accept: stream ? "
|
|
1549
|
+
accept: stream ? "application/x-ndjson" : "application/json",
|
|
1551
1550
|
raw: true,
|
|
1552
1551
|
signal: options.signal,
|
|
1553
1552
|
timeoutMs: options.timeoutMs ?? (stream ? 0 : void 0),
|
|
@@ -1600,9 +1599,9 @@ var CustomerChatClient = class {
|
|
|
1600
1599
|
if (!hasUserMessage(params.messages)) {
|
|
1601
1600
|
throw new ConfigError("at least one user message is required");
|
|
1602
1601
|
}
|
|
1603
|
-
if (!params.responseFormat || params.responseFormat.type !== "
|
|
1602
|
+
if (!params.responseFormat || params.responseFormat.type !== "json_schema") {
|
|
1604
1603
|
throw new ConfigError(
|
|
1605
|
-
"responseFormat with type=
|
|
1604
|
+
"responseFormat with type=json_schema is required for structured streaming"
|
|
1606
1605
|
);
|
|
1607
1606
|
}
|
|
1608
1607
|
const authHeaders = await this.auth.authForChat(this.customerId);
|
|
@@ -1829,9 +1828,9 @@ var ChatCompletionsStream = class {
|
|
|
1829
1828
|
}
|
|
1830
1829
|
const { value, done } = await reader.read();
|
|
1831
1830
|
if (done) {
|
|
1832
|
-
const {
|
|
1833
|
-
for (const
|
|
1834
|
-
const parsed =
|
|
1831
|
+
const { records: records2 } = consumeNDJSONBuffer(buffer, true);
|
|
1832
|
+
for (const line of records2) {
|
|
1833
|
+
const parsed = mapNDJSONChatEvent(line, this.requestId);
|
|
1835
1834
|
if (parsed) {
|
|
1836
1835
|
this.handleStreamEvent(parsed);
|
|
1837
1836
|
yield parsed;
|
|
@@ -1840,10 +1839,10 @@ var ChatCompletionsStream = class {
|
|
|
1840
1839
|
return;
|
|
1841
1840
|
}
|
|
1842
1841
|
buffer += decoder.decode(value, { stream: true });
|
|
1843
|
-
const {
|
|
1842
|
+
const { records, remainder } = consumeNDJSONBuffer(buffer);
|
|
1844
1843
|
buffer = remainder;
|
|
1845
|
-
for (const
|
|
1846
|
-
const parsed =
|
|
1844
|
+
for (const line of records) {
|
|
1845
|
+
const parsed = mapNDJSONChatEvent(line, this.requestId);
|
|
1847
1846
|
if (parsed) {
|
|
1848
1847
|
this.handleStreamEvent(parsed);
|
|
1849
1848
|
yield parsed;
|
|
@@ -2055,48 +2054,6 @@ var StructuredJSONStream = class {
|
|
|
2055
2054
|
this.trace.streamEvent({ context: this.context, event });
|
|
2056
2055
|
}
|
|
2057
2056
|
};
|
|
2058
|
-
function consumeSSEBuffer(buffer, flush = false) {
|
|
2059
|
-
const events = [];
|
|
2060
|
-
let eventName = "";
|
|
2061
|
-
let dataLines = [];
|
|
2062
|
-
let remainder = "";
|
|
2063
|
-
const lines = buffer.split(/\r?\n/);
|
|
2064
|
-
const lastIndex = lines.length - 1;
|
|
2065
|
-
const limit = flush ? lines.length : Math.max(0, lastIndex);
|
|
2066
|
-
const pushEvent = () => {
|
|
2067
|
-
if (!eventName && dataLines.length === 0) {
|
|
2068
|
-
return;
|
|
2069
|
-
}
|
|
2070
|
-
events.push({
|
|
2071
|
-
event: eventName || "message",
|
|
2072
|
-
data: dataLines.join("\n")
|
|
2073
|
-
});
|
|
2074
|
-
eventName = "";
|
|
2075
|
-
dataLines = [];
|
|
2076
|
-
};
|
|
2077
|
-
for (let i = 0; i < limit; i++) {
|
|
2078
|
-
const line = lines[i];
|
|
2079
|
-
if (line === "") {
|
|
2080
|
-
pushEvent();
|
|
2081
|
-
continue;
|
|
2082
|
-
}
|
|
2083
|
-
if (line.startsWith(":")) {
|
|
2084
|
-
continue;
|
|
2085
|
-
}
|
|
2086
|
-
if (line.startsWith("event:")) {
|
|
2087
|
-
eventName = line.slice(6).trim();
|
|
2088
|
-
} else if (line.startsWith("data:")) {
|
|
2089
|
-
dataLines.push(line.slice(5).trimStart());
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
if (flush) {
|
|
2093
|
-
pushEvent();
|
|
2094
|
-
remainder = "";
|
|
2095
|
-
} else {
|
|
2096
|
-
remainder = lines[lastIndex] ?? "";
|
|
2097
|
-
}
|
|
2098
|
-
return { events, remainder };
|
|
2099
|
-
}
|
|
2100
2057
|
function consumeNDJSONBuffer(buffer, flush = false) {
|
|
2101
2058
|
const lines = buffer.split(/\r?\n/);
|
|
2102
2059
|
const records = [];
|
|
@@ -2110,29 +2067,79 @@ function consumeNDJSONBuffer(buffer, flush = false) {
|
|
|
2110
2067
|
const remainder = flush ? "" : lines[lastIndex] ?? "";
|
|
2111
2068
|
return { records, remainder };
|
|
2112
2069
|
}
|
|
2113
|
-
function
|
|
2114
|
-
let parsed
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2070
|
+
function mapNDJSONChatEvent(line, requestId) {
|
|
2071
|
+
let parsed;
|
|
2072
|
+
try {
|
|
2073
|
+
parsed = JSON.parse(line);
|
|
2074
|
+
} catch (err) {
|
|
2075
|
+
console.warn(
|
|
2076
|
+
`[ModelRelay SDK] Failed to parse NDJSON line: ${err instanceof Error ? err.message : String(err)}`,
|
|
2077
|
+
{ line: line.substring(0, 200), requestId }
|
|
2078
|
+
);
|
|
2079
|
+
return null;
|
|
2080
|
+
}
|
|
2081
|
+
if (!parsed || typeof parsed !== "object") {
|
|
2082
|
+
console.warn("[ModelRelay SDK] NDJSON record is not an object", {
|
|
2083
|
+
parsed,
|
|
2084
|
+
requestId
|
|
2085
|
+
});
|
|
2086
|
+
return null;
|
|
2087
|
+
}
|
|
2088
|
+
const obj = parsed;
|
|
2089
|
+
const recordType = String(obj.type || "").trim().toLowerCase();
|
|
2090
|
+
if (recordType === "keepalive") {
|
|
2091
|
+
return null;
|
|
2092
|
+
}
|
|
2093
|
+
if (!recordType) {
|
|
2094
|
+
console.warn("[ModelRelay SDK] NDJSON record missing 'type' field", {
|
|
2095
|
+
obj,
|
|
2096
|
+
requestId
|
|
2097
|
+
});
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2100
|
+
let type;
|
|
2101
|
+
switch (recordType) {
|
|
2102
|
+
case "start":
|
|
2103
|
+
type = "message_start";
|
|
2104
|
+
break;
|
|
2105
|
+
case "update":
|
|
2106
|
+
type = "message_delta";
|
|
2107
|
+
break;
|
|
2108
|
+
case "completion":
|
|
2109
|
+
type = "message_stop";
|
|
2110
|
+
break;
|
|
2111
|
+
case "error":
|
|
2112
|
+
type = "custom";
|
|
2113
|
+
break;
|
|
2114
|
+
// Tool use event types
|
|
2115
|
+
case "tool_use_start":
|
|
2116
|
+
type = "tool_use_start";
|
|
2117
|
+
break;
|
|
2118
|
+
case "tool_use_delta":
|
|
2119
|
+
type = "tool_use_delta";
|
|
2120
|
+
break;
|
|
2121
|
+
case "tool_use_stop":
|
|
2122
|
+
type = "tool_use_stop";
|
|
2123
|
+
break;
|
|
2124
|
+
default:
|
|
2125
|
+
type = "custom";
|
|
2126
|
+
}
|
|
2127
|
+
const usage = normalizeUsage(obj.usage);
|
|
2128
|
+
const responseId = obj.request_id;
|
|
2129
|
+
const model = normalizeModelId(obj.model);
|
|
2130
|
+
const stopReason = normalizeStopReason(obj.stop_reason);
|
|
2131
|
+
let textDelta;
|
|
2132
|
+
if (obj.payload && typeof obj.payload === "object") {
|
|
2133
|
+
if (typeof obj.payload.content === "string") {
|
|
2134
|
+
textDelta = obj.payload.content;
|
|
2120
2135
|
}
|
|
2121
2136
|
}
|
|
2122
|
-
const
|
|
2123
|
-
const
|
|
2124
|
-
const type = normalizeEventType(raw.event, p);
|
|
2125
|
-
const usage = normalizeUsage(p.usage);
|
|
2126
|
-
const responseId = p.response_id || p.id || p?.message?.id;
|
|
2127
|
-
const model = normalizeModelId(p.model || p?.message?.model);
|
|
2128
|
-
const stopReason = normalizeStopReason(p.stop_reason);
|
|
2129
|
-
const textDelta = extractTextDelta(p);
|
|
2130
|
-
const toolCallDelta = extractToolCallDelta(p, type);
|
|
2131
|
-
const toolCalls = extractToolCalls(p, type);
|
|
2137
|
+
const toolCallDelta = extractToolCallDelta(obj, type);
|
|
2138
|
+
const toolCalls = extractToolCalls(obj, type);
|
|
2132
2139
|
return {
|
|
2133
2140
|
type,
|
|
2134
|
-
event:
|
|
2135
|
-
data:
|
|
2141
|
+
event: recordType,
|
|
2142
|
+
data: obj,
|
|
2136
2143
|
textDelta,
|
|
2137
2144
|
toolCallDelta,
|
|
2138
2145
|
toolCalls,
|
|
@@ -2141,52 +2148,9 @@ function mapChatEvent(raw, requestId) {
|
|
|
2141
2148
|
stopReason,
|
|
2142
2149
|
usage,
|
|
2143
2150
|
requestId,
|
|
2144
|
-
raw:
|
|
2151
|
+
raw: line
|
|
2145
2152
|
};
|
|
2146
2153
|
}
|
|
2147
|
-
function normalizeEventType(eventName, payload) {
|
|
2148
|
-
const hint = String(
|
|
2149
|
-
payload?.type || payload?.event || eventName || ""
|
|
2150
|
-
).trim();
|
|
2151
|
-
switch (hint) {
|
|
2152
|
-
case "message_start":
|
|
2153
|
-
return "message_start";
|
|
2154
|
-
case "message_delta":
|
|
2155
|
-
return "message_delta";
|
|
2156
|
-
case "message_stop":
|
|
2157
|
-
return "message_stop";
|
|
2158
|
-
case "tool_use_start":
|
|
2159
|
-
return "tool_use_start";
|
|
2160
|
-
case "tool_use_delta":
|
|
2161
|
-
return "tool_use_delta";
|
|
2162
|
-
case "tool_use_stop":
|
|
2163
|
-
return "tool_use_stop";
|
|
2164
|
-
case "ping":
|
|
2165
|
-
return "ping";
|
|
2166
|
-
default:
|
|
2167
|
-
return "custom";
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
function extractTextDelta(payload) {
|
|
2171
|
-
if (!payload || typeof payload !== "object") {
|
|
2172
|
-
return void 0;
|
|
2173
|
-
}
|
|
2174
|
-
if (typeof payload.text_delta === "string" && payload.text_delta !== "") {
|
|
2175
|
-
return payload.text_delta;
|
|
2176
|
-
}
|
|
2177
|
-
if (typeof payload.delta === "string") {
|
|
2178
|
-
return payload.delta;
|
|
2179
|
-
}
|
|
2180
|
-
if (payload.delta && typeof payload.delta === "object") {
|
|
2181
|
-
if (typeof payload.delta.text === "string") {
|
|
2182
|
-
return payload.delta.text;
|
|
2183
|
-
}
|
|
2184
|
-
if (typeof payload.delta.content === "string") {
|
|
2185
|
-
return payload.delta.content;
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
return void 0;
|
|
2189
|
-
}
|
|
2190
2154
|
function extractToolCallDelta(payload, type) {
|
|
2191
2155
|
if (!payload || typeof payload !== "object") {
|
|
2192
2156
|
return void 0;
|