@x12i/openrouter-runtime 1.0.6 → 1.1.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.d.cts CHANGED
@@ -4,7 +4,8 @@ type ToolMode = "disabled" | "allowed" | "required";
4
4
  interface OpenRouterRuntime {
5
5
  run(request: RuntimeRequest): Promise<RuntimeResponse>;
6
6
  /**
7
- * Streaming chat entrypoint. Separate from `run()` by design.
7
+ * Explicit streaming chat API. Separate from `run()` by design — never an argument, never the default.
8
+ * Always sends OpenRouter Chat Completions with `stream: true` and yields typed SSE events.
8
9
  * The old `stream()` name was removed so mistaken/old clients break loudly.
9
10
  */
10
11
  executeStreamingChat(request: RuntimeRequest): AsyncIterable<RuntimeStreamEvent>;
@@ -364,9 +365,60 @@ interface RuntimePolicyViolation {
364
365
  details?: unknown;
365
366
  }
366
367
  interface RuntimeStreamEvent {
367
- type: string;
368
+ type: RuntimeStreamEventType;
369
+ requestId: string;
368
370
  data?: unknown;
369
371
  }
372
+ type RuntimeStreamEventType = "stream.start" | "stream.text.delta" | "stream.tool_call.delta" | "stream.usage" | "stream.warning" | "stream.error" | "stream.done";
373
+ interface RuntimeStreamStartEvent extends RuntimeStreamEvent {
374
+ type: "stream.start";
375
+ data: {
376
+ model: string;
377
+ apiMode: "chat";
378
+ entrypoint: "executeStreamingChat";
379
+ };
380
+ }
381
+ interface RuntimeStreamTextDeltaEvent extends RuntimeStreamEvent {
382
+ type: "stream.text.delta";
383
+ data: {
384
+ text: string;
385
+ };
386
+ }
387
+ interface RuntimeStreamToolCallDeltaEvent extends RuntimeStreamEvent {
388
+ type: "stream.tool_call.delta";
389
+ data: {
390
+ index: number;
391
+ id?: string;
392
+ name?: string;
393
+ argumentsDelta?: string;
394
+ };
395
+ }
396
+ interface RuntimeStreamUsageEvent extends RuntimeStreamEvent {
397
+ type: "stream.usage";
398
+ data: {
399
+ usage: RuntimeUsage;
400
+ };
401
+ }
402
+ interface RuntimeStreamWarningEvent extends RuntimeStreamEvent {
403
+ type: "stream.warning";
404
+ data: {
405
+ warning: RuntimeWarning;
406
+ };
407
+ }
408
+ interface RuntimeStreamErrorEvent extends RuntimeStreamEvent {
409
+ type: "stream.error";
410
+ data: {
411
+ error: RuntimeError;
412
+ };
413
+ }
414
+ interface RuntimeStreamDoneEvent extends RuntimeStreamEvent {
415
+ type: "stream.done";
416
+ data: {
417
+ text: string;
418
+ finishReason?: string;
419
+ model: string;
420
+ };
421
+ }
370
422
  type RuntimePatchApplier = (patch: RuntimePatchProposal) => Promise<unknown> | unknown;
371
423
 
372
424
  declare function createOpenRouterRuntime(options: OpenRouterRuntimeOptions): OpenRouterRuntime;
@@ -414,4 +466,4 @@ declare function buildOpenRouterServerTools(policy?: RuntimeServerToolsPolicy):
414
466
  declare function isRuntimeLoggingEnabled(env?: Record<string, string | undefined> | undefined): boolean;
415
467
  declare function createConsoleLogger(): RuntimeLogger;
416
468
 
417
- export { type AdvisorPolicy, type ApplyPatchPolicy, type CompiledOpenRouterRequest, type DatetimePolicy, type FusionPolicy, type ImageGenerationPolicy, OpenRouterHttpError, type OpenRouterRuntime, type OpenRouterRuntimeOptions, type RuntimeCitation, RuntimeConfigError, type RuntimeDefaults, type RuntimeError, type RuntimeFunctionToolDefinition, type RuntimeGeneratedImage, type RuntimeLogger, type RuntimeMessage, type RuntimePatchProposal, type RuntimePolicyViolation, type RuntimeRequest, type RuntimeResponse, type RuntimeServerToolsPolicy, type RuntimeStreamEvent, type RuntimeToolExecutor, type RuntimeToolUsage, type RuntimeUsage, type RuntimeWarning, type ServerToolKey, type ServerToolUsage, type SubagentPolicy, type WebFetchPolicy, type WebSearchPolicy, buildOpenRouterServerTools, compileRuntimeRequest, createConsoleLogger, createOpenRouterRuntime, isRuntimeLoggingEnabled };
469
+ export { type AdvisorPolicy, type ApplyPatchPolicy, type CompiledOpenRouterRequest, type DatetimePolicy, type FusionPolicy, type ImageGenerationPolicy, OpenRouterHttpError, type OpenRouterRuntime, type OpenRouterRuntimeOptions, type RuntimeCitation, RuntimeConfigError, type RuntimeDefaults, type RuntimeError, type RuntimeFunctionToolDefinition, type RuntimeGeneratedImage, type RuntimeLogger, type RuntimeMessage, type RuntimePatchProposal, type RuntimePolicyViolation, type RuntimeRequest, type RuntimeResponse, type RuntimeServerToolsPolicy, type RuntimeStreamDoneEvent, type RuntimeStreamErrorEvent, type RuntimeStreamEvent, type RuntimeStreamEventType, type RuntimeStreamStartEvent, type RuntimeStreamTextDeltaEvent, type RuntimeStreamToolCallDeltaEvent, type RuntimeStreamUsageEvent, type RuntimeStreamWarningEvent, type RuntimeToolExecutor, type RuntimeToolUsage, type RuntimeUsage, type RuntimeWarning, type ServerToolKey, type ServerToolUsage, type SubagentPolicy, type WebFetchPolicy, type WebSearchPolicy, buildOpenRouterServerTools, compileRuntimeRequest, createConsoleLogger, createOpenRouterRuntime, isRuntimeLoggingEnabled };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,8 @@ type ToolMode = "disabled" | "allowed" | "required";
4
4
  interface OpenRouterRuntime {
5
5
  run(request: RuntimeRequest): Promise<RuntimeResponse>;
6
6
  /**
7
- * Streaming chat entrypoint. Separate from `run()` by design.
7
+ * Explicit streaming chat API. Separate from `run()` by design — never an argument, never the default.
8
+ * Always sends OpenRouter Chat Completions with `stream: true` and yields typed SSE events.
8
9
  * The old `stream()` name was removed so mistaken/old clients break loudly.
9
10
  */
10
11
  executeStreamingChat(request: RuntimeRequest): AsyncIterable<RuntimeStreamEvent>;
@@ -364,9 +365,60 @@ interface RuntimePolicyViolation {
364
365
  details?: unknown;
365
366
  }
366
367
  interface RuntimeStreamEvent {
367
- type: string;
368
+ type: RuntimeStreamEventType;
369
+ requestId: string;
368
370
  data?: unknown;
369
371
  }
372
+ type RuntimeStreamEventType = "stream.start" | "stream.text.delta" | "stream.tool_call.delta" | "stream.usage" | "stream.warning" | "stream.error" | "stream.done";
373
+ interface RuntimeStreamStartEvent extends RuntimeStreamEvent {
374
+ type: "stream.start";
375
+ data: {
376
+ model: string;
377
+ apiMode: "chat";
378
+ entrypoint: "executeStreamingChat";
379
+ };
380
+ }
381
+ interface RuntimeStreamTextDeltaEvent extends RuntimeStreamEvent {
382
+ type: "stream.text.delta";
383
+ data: {
384
+ text: string;
385
+ };
386
+ }
387
+ interface RuntimeStreamToolCallDeltaEvent extends RuntimeStreamEvent {
388
+ type: "stream.tool_call.delta";
389
+ data: {
390
+ index: number;
391
+ id?: string;
392
+ name?: string;
393
+ argumentsDelta?: string;
394
+ };
395
+ }
396
+ interface RuntimeStreamUsageEvent extends RuntimeStreamEvent {
397
+ type: "stream.usage";
398
+ data: {
399
+ usage: RuntimeUsage;
400
+ };
401
+ }
402
+ interface RuntimeStreamWarningEvent extends RuntimeStreamEvent {
403
+ type: "stream.warning";
404
+ data: {
405
+ warning: RuntimeWarning;
406
+ };
407
+ }
408
+ interface RuntimeStreamErrorEvent extends RuntimeStreamEvent {
409
+ type: "stream.error";
410
+ data: {
411
+ error: RuntimeError;
412
+ };
413
+ }
414
+ interface RuntimeStreamDoneEvent extends RuntimeStreamEvent {
415
+ type: "stream.done";
416
+ data: {
417
+ text: string;
418
+ finishReason?: string;
419
+ model: string;
420
+ };
421
+ }
370
422
  type RuntimePatchApplier = (patch: RuntimePatchProposal) => Promise<unknown> | unknown;
371
423
 
372
424
  declare function createOpenRouterRuntime(options: OpenRouterRuntimeOptions): OpenRouterRuntime;
@@ -414,4 +466,4 @@ declare function buildOpenRouterServerTools(policy?: RuntimeServerToolsPolicy):
414
466
  declare function isRuntimeLoggingEnabled(env?: Record<string, string | undefined> | undefined): boolean;
415
467
  declare function createConsoleLogger(): RuntimeLogger;
416
468
 
417
- export { type AdvisorPolicy, type ApplyPatchPolicy, type CompiledOpenRouterRequest, type DatetimePolicy, type FusionPolicy, type ImageGenerationPolicy, OpenRouterHttpError, type OpenRouterRuntime, type OpenRouterRuntimeOptions, type RuntimeCitation, RuntimeConfigError, type RuntimeDefaults, type RuntimeError, type RuntimeFunctionToolDefinition, type RuntimeGeneratedImage, type RuntimeLogger, type RuntimeMessage, type RuntimePatchProposal, type RuntimePolicyViolation, type RuntimeRequest, type RuntimeResponse, type RuntimeServerToolsPolicy, type RuntimeStreamEvent, type RuntimeToolExecutor, type RuntimeToolUsage, type RuntimeUsage, type RuntimeWarning, type ServerToolKey, type ServerToolUsage, type SubagentPolicy, type WebFetchPolicy, type WebSearchPolicy, buildOpenRouterServerTools, compileRuntimeRequest, createConsoleLogger, createOpenRouterRuntime, isRuntimeLoggingEnabled };
469
+ export { type AdvisorPolicy, type ApplyPatchPolicy, type CompiledOpenRouterRequest, type DatetimePolicy, type FusionPolicy, type ImageGenerationPolicy, OpenRouterHttpError, type OpenRouterRuntime, type OpenRouterRuntimeOptions, type RuntimeCitation, RuntimeConfigError, type RuntimeDefaults, type RuntimeError, type RuntimeFunctionToolDefinition, type RuntimeGeneratedImage, type RuntimeLogger, type RuntimeMessage, type RuntimePatchProposal, type RuntimePolicyViolation, type RuntimeRequest, type RuntimeResponse, type RuntimeServerToolsPolicy, type RuntimeStreamDoneEvent, type RuntimeStreamErrorEvent, type RuntimeStreamEvent, type RuntimeStreamEventType, type RuntimeStreamStartEvent, type RuntimeStreamTextDeltaEvent, type RuntimeStreamToolCallDeltaEvent, type RuntimeStreamUsageEvent, type RuntimeStreamWarningEvent, type RuntimeToolExecutor, type RuntimeToolUsage, type RuntimeUsage, type RuntimeWarning, type ServerToolKey, type ServerToolUsage, type SubagentPolicy, type WebFetchPolicy, type WebSearchPolicy, buildOpenRouterServerTools, compileRuntimeRequest, createConsoleLogger, createOpenRouterRuntime, isRuntimeLoggingEnabled };
package/dist/index.js CHANGED
@@ -918,11 +918,14 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
918
918
  };
919
919
  }
920
920
  function enforceStreamingPolicyForRun(body, warnings, context) {
921
- if (context.streaming) return;
921
+ if (context.streaming) {
922
+ body.stream = true;
923
+ return;
924
+ }
922
925
  if (body.stream !== void 0 && body.stream !== false) {
923
926
  warnings.push({
924
927
  code: "STREAMING_OVERRIDE_IGNORED_FOR_RUN",
925
- message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() when streaming is implemented.",
928
+ message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() for streaming.",
926
929
  details: { ignoredStreamValue: body.stream }
927
930
  });
928
931
  }
@@ -1325,12 +1328,333 @@ function optional6(key, value) {
1325
1328
  return value === void 0 ? {} : { [key]: value };
1326
1329
  }
1327
1330
 
1331
+ // src/openrouter/stream-client.ts
1332
+ async function openOpenRouterStream(compiled, options, timeoutMs) {
1333
+ const controller = new AbortController();
1334
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
1335
+ const cleanup = () => clearTimeout(timeout);
1336
+ try {
1337
+ const response = await options.fetch(compiled.url, {
1338
+ method: "POST",
1339
+ headers: {
1340
+ ...compiled.headers,
1341
+ Accept: "text/event-stream"
1342
+ },
1343
+ body: JSON.stringify(compiled.body),
1344
+ signal: controller.signal
1345
+ });
1346
+ if (!response.ok) {
1347
+ const text = await response.text();
1348
+ cleanup();
1349
+ const body = text ? parseBody2(text) : void 0;
1350
+ const message = extractMessage2(body) ?? `OpenRouter stream failed with status ${response.status}.`;
1351
+ throw new OpenRouterHttpError(
1352
+ response.status,
1353
+ classifyProviderFailure2(response.status, message, body),
1354
+ message,
1355
+ body,
1356
+ isRetryableStatus2(response.status)
1357
+ );
1358
+ }
1359
+ return { response, cleanup };
1360
+ } catch (error) {
1361
+ cleanup();
1362
+ if (error instanceof OpenRouterHttpError) throw error;
1363
+ if (error instanceof Error && error.name === "AbortError") {
1364
+ throw new OpenRouterHttpError(408, "PROVIDER_GATEWAY_UNREACHABLE", "OpenRouter stream timed out.", void 0, true);
1365
+ }
1366
+ throw new OpenRouterHttpError(
1367
+ 503,
1368
+ "PROVIDER_GATEWAY_UNREACHABLE",
1369
+ error instanceof Error ? error.message : "OpenRouter stream failed before receiving a response.",
1370
+ void 0,
1371
+ true
1372
+ );
1373
+ }
1374
+ }
1375
+ async function* parseSseStream(response) {
1376
+ const body = response.body;
1377
+ if (!body) {
1378
+ throw new OpenRouterHttpError(
1379
+ 503,
1380
+ "PROVIDER_GATEWAY_UNREACHABLE",
1381
+ "OpenRouter stream response had no body.",
1382
+ void 0,
1383
+ true
1384
+ );
1385
+ }
1386
+ const reader = body.getReader();
1387
+ const decoder = new TextDecoder();
1388
+ let buffer = "";
1389
+ while (true) {
1390
+ const { done, value } = await reader.read();
1391
+ if (done) break;
1392
+ buffer += decoder.decode(value, { stream: true });
1393
+ const parts = buffer.split(/\r?\n/);
1394
+ buffer = parts.pop() ?? "";
1395
+ for (const part of parts) {
1396
+ const line = part.trim();
1397
+ if (!line || line.startsWith(":")) continue;
1398
+ if (!line.startsWith("data:")) continue;
1399
+ const data = line.slice(5).trim();
1400
+ if (!data) continue;
1401
+ if (data === "[DONE]") return;
1402
+ try {
1403
+ yield JSON.parse(data);
1404
+ } catch {
1405
+ }
1406
+ }
1407
+ }
1408
+ const trailing = buffer.trim();
1409
+ if (trailing.startsWith("data:")) {
1410
+ const data = trailing.slice(5).trim();
1411
+ if (data && data !== "[DONE]") {
1412
+ try {
1413
+ yield JSON.parse(data);
1414
+ } catch {
1415
+ }
1416
+ }
1417
+ }
1418
+ }
1419
+ function parseBody2(text) {
1420
+ try {
1421
+ return JSON.parse(text);
1422
+ } catch {
1423
+ return text;
1424
+ }
1425
+ }
1426
+ function extractMessage2(body) {
1427
+ if (typeof body !== "object" || body === null) return void 0;
1428
+ const record = body;
1429
+ const error = record.error;
1430
+ if (typeof error === "object" && error !== null && typeof error.message === "string") {
1431
+ return error.message;
1432
+ }
1433
+ return typeof record.message === "string" ? record.message : void 0;
1434
+ }
1435
+ function classifyProviderFailure2(status, message, body) {
1436
+ const haystack = `${message} ${JSON.stringify(body ?? "")}`.toLowerCase();
1437
+ if (status === 401 || status === 403) return "PROVIDER_AUTH_FAILED";
1438
+ if (status === 402 || /\b(quota|credit|credits|billing|balance|insufficient funds|insufficient credit)\b/.test(haystack)) {
1439
+ return "PROVIDER_QUOTA_EXCEEDED";
1440
+ }
1441
+ if (status === 404 || /\bmodel\b.*\b(not found|not a valid|invalid|unavailable)\b/.test(haystack) || /\b(no endpoints found|not a valid model id)\b/.test(haystack)) {
1442
+ return "PROVIDER_MODEL_NOT_FOUND";
1443
+ }
1444
+ if (status === 429) return "PROVIDER_RATE_LIMITED";
1445
+ if (status === 408 || status >= 500) return "PROVIDER_GATEWAY_UNREACHABLE";
1446
+ return "PROVIDER_REQUEST_FAILED";
1447
+ }
1448
+ function isRetryableStatus2(status) {
1449
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
1450
+ }
1451
+
1328
1452
  // src/runtime/streaming.ts
1329
- async function* executeStreamingChatNotImplemented() {
1330
- throw new RuntimeConfigError(
1331
- "STREAMING_NOT_IMPLEMENTED",
1332
- "executeStreamingChat() is reserved and not implemented yet. Use runtime.run() for non-streaming execution."
1333
- );
1453
+ async function* executeStreamingChat(request, context) {
1454
+ const requestId = request.id ?? "unknown";
1455
+ const options = context.options;
1456
+ const defaults = context.defaults;
1457
+ options.logger?.info?.("runtime.executeStreamingChat.started", {
1458
+ requestId,
1459
+ streaming: true,
1460
+ entrypoint: "executeStreamingChat"
1461
+ });
1462
+ try {
1463
+ assertStreamingChatRequest(request, defaults);
1464
+ const streamingRequest = {
1465
+ ...request,
1466
+ apiMode: "chat"
1467
+ };
1468
+ const compiled = compileRuntimeRequest(streamingRequest, defaults, options, { streaming: true });
1469
+ if (compiled.body.stream !== true) {
1470
+ throw new RuntimeConfigError(
1471
+ "STREAMING_CHAT_MISCONFIGURED",
1472
+ "executeStreamingChat() requires stream=true on the compiled OpenRouter body."
1473
+ );
1474
+ }
1475
+ for (const warning of compiled.warnings) {
1476
+ yield warningEvent(requestId, warning);
1477
+ }
1478
+ const model = typeof compiled.body.model === "string" ? compiled.body.model : "";
1479
+ yield startEvent(requestId, model);
1480
+ await options.hooks?.beforeOpenRouterRequest?.(compiled);
1481
+ const timeoutMs = request.execution?.timeoutMs ?? defaults.timeoutMs;
1482
+ const session = await openOpenRouterStream(compiled, options, timeoutMs);
1483
+ let text = "";
1484
+ let finishReason;
1485
+ let resolvedModel = model;
1486
+ try {
1487
+ for await (const chunk of parseSseStream(session.response)) {
1488
+ if (!isRecord(chunk)) continue;
1489
+ if (chunk.error) {
1490
+ const message = isRecord(chunk.error) && typeof chunk.error.message === "string" ? chunk.error.message : "OpenRouter stream returned an error chunk.";
1491
+ const error = {
1492
+ code: "PROVIDER_REQUEST_FAILED",
1493
+ message,
1494
+ source: "openrouter",
1495
+ details: chunk.error
1496
+ };
1497
+ yield errorEvent(requestId, error);
1498
+ throw new OpenRouterHttpError(500, "PROVIDER_REQUEST_FAILED", message, chunk, false);
1499
+ }
1500
+ if (typeof chunk.model === "string") resolvedModel = chunk.model;
1501
+ const choice = Array.isArray(chunk.choices) && isRecord(chunk.choices[0]) ? chunk.choices[0] : void 0;
1502
+ const delta = choice && isRecord(choice.delta) ? choice.delta : void 0;
1503
+ if (delta && typeof delta.content === "string" && delta.content.length > 0) {
1504
+ text += delta.content;
1505
+ yield textDeltaEvent(requestId, delta.content);
1506
+ }
1507
+ if (delta && Array.isArray(delta.tool_calls)) {
1508
+ for (const toolCall of delta.tool_calls) {
1509
+ if (!isRecord(toolCall)) continue;
1510
+ const index = typeof toolCall.index === "number" ? toolCall.index : 0;
1511
+ const fn = isRecord(toolCall.function) ? toolCall.function : {};
1512
+ yield toolCallDeltaEvent(requestId, {
1513
+ index,
1514
+ ...typeof toolCall.id === "string" ? { id: toolCall.id } : {},
1515
+ ...typeof fn.name === "string" ? { name: fn.name } : {},
1516
+ ...typeof fn.arguments === "string" ? { argumentsDelta: fn.arguments } : {}
1517
+ });
1518
+ }
1519
+ }
1520
+ if (choice && typeof choice.finish_reason === "string") {
1521
+ finishReason = choice.finish_reason;
1522
+ }
1523
+ if (chunk.usage) {
1524
+ const usage = normalizeUsage(chunk.usage);
1525
+ if (usage) yield usageEvent(requestId, usage);
1526
+ }
1527
+ }
1528
+ } finally {
1529
+ session.cleanup();
1530
+ }
1531
+ await options.hooks?.afterOpenRouterResponse?.({ streamed: true, text, finishReason, model: resolvedModel });
1532
+ yield doneEvent(requestId, {
1533
+ text,
1534
+ model: resolvedModel,
1535
+ ...finishReason ? { finishReason } : {}
1536
+ });
1537
+ options.logger?.info?.("runtime.executeStreamingChat.completed", {
1538
+ requestId,
1539
+ streaming: true,
1540
+ entrypoint: "executeStreamingChat",
1541
+ finishReason,
1542
+ textLength: text.length
1543
+ });
1544
+ } catch (error) {
1545
+ const runtimeError = toRuntimeError(error);
1546
+ yield errorEvent(requestId, runtimeError);
1547
+ options.logger?.error?.("runtime.executeStreamingChat.failed", {
1548
+ requestId,
1549
+ streaming: true,
1550
+ code: runtimeError.code,
1551
+ message: runtimeError.message
1552
+ });
1553
+ throw error instanceof Error ? error : new Error(runtimeError.message);
1554
+ }
1555
+ }
1556
+ function assertStreamingChatRequest(request, defaults) {
1557
+ if (request.apiMode === "responses") {
1558
+ throw new RuntimeConfigError(
1559
+ "STREAMING_CHAT_REQUIRES_CHAT_API",
1560
+ "executeStreamingChat() only supports Chat Completions. Use runtime.run() for Responses API requests."
1561
+ );
1562
+ }
1563
+ if (request.serverTools?.applyPatch?.mode && request.serverTools.applyPatch.mode !== "disabled") {
1564
+ throw new RuntimeConfigError(
1565
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1566
+ "executeStreamingChat() does not support applyPatch. Use runtime.run() instead."
1567
+ );
1568
+ }
1569
+ if (defaults.serverTools?.applyPatch?.mode && defaults.serverTools.applyPatch.mode !== "disabled") {
1570
+ const requestPatch = request.serverTools?.applyPatch;
1571
+ if (!requestPatch || requestPatch.mode !== "disabled") {
1572
+ throw new RuntimeConfigError(
1573
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1574
+ "executeStreamingChat() does not support applyPatch defaults. Use runtime.run() instead."
1575
+ );
1576
+ }
1577
+ }
1578
+ }
1579
+ function startEvent(requestId, model) {
1580
+ return {
1581
+ type: "stream.start",
1582
+ requestId,
1583
+ data: {
1584
+ model,
1585
+ apiMode: "chat",
1586
+ entrypoint: "executeStreamingChat"
1587
+ }
1588
+ };
1589
+ }
1590
+ function textDeltaEvent(requestId, text) {
1591
+ return {
1592
+ type: "stream.text.delta",
1593
+ requestId,
1594
+ data: { text }
1595
+ };
1596
+ }
1597
+ function toolCallDeltaEvent(requestId, data) {
1598
+ return {
1599
+ type: "stream.tool_call.delta",
1600
+ requestId,
1601
+ data
1602
+ };
1603
+ }
1604
+ function usageEvent(requestId, usage) {
1605
+ return {
1606
+ type: "stream.usage",
1607
+ requestId,
1608
+ data: { usage }
1609
+ };
1610
+ }
1611
+ function warningEvent(requestId, warning) {
1612
+ return {
1613
+ type: "stream.warning",
1614
+ requestId,
1615
+ data: { warning }
1616
+ };
1617
+ }
1618
+ function errorEvent(requestId, error) {
1619
+ return {
1620
+ type: "stream.error",
1621
+ requestId,
1622
+ data: { error }
1623
+ };
1624
+ }
1625
+ function doneEvent(requestId, data) {
1626
+ return {
1627
+ type: "stream.done",
1628
+ requestId,
1629
+ data
1630
+ };
1631
+ }
1632
+ function toRuntimeError(error) {
1633
+ if (error instanceof RuntimeConfigError) {
1634
+ return {
1635
+ code: error.code,
1636
+ message: error.message,
1637
+ source: "validation",
1638
+ details: error.details
1639
+ };
1640
+ }
1641
+ if (error instanceof OpenRouterHttpError) {
1642
+ return {
1643
+ code: error.code,
1644
+ message: error.message,
1645
+ source: "openrouter",
1646
+ retryable: error.retryable,
1647
+ details: {
1648
+ providerAttempts: error.providerAttempts,
1649
+ ...error.body === void 0 ? {} : { response: error.body }
1650
+ }
1651
+ };
1652
+ }
1653
+ return {
1654
+ code: "RUNTIME_ERROR",
1655
+ message: error instanceof Error ? error.message : String(error),
1656
+ source: "runtime"
1657
+ };
1334
1658
  }
1335
1659
 
1336
1660
  // src/runtime/create-runtime.ts
@@ -1371,13 +1695,8 @@ function createOpenRouterRuntime(options) {
1371
1695
  }
1372
1696
  },
1373
1697
  executeStreamingChat(request) {
1374
- resolvedOptions.logger?.warn?.("runtime.executeStreamingChat.called", {
1375
- requestId: request.id,
1376
- streaming: true,
1377
- entrypoint: "executeStreamingChat",
1378
- implemented: false
1379
- });
1380
- return executeStreamingChatNotImplemented();
1698
+ const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
1699
+ return executeStreamingChat(requestWithId, context);
1381
1700
  }
1382
1701
  };
1383
1702
  function errorResponse(request, error) {