@deslop/workbench 0.0.396 → 0.0.407

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.
Files changed (53) hide show
  1. package/dist/{anthropic-DcE0yHBZ.mjs → anthropic-messages--JAnb97W.mjs} +38 -51
  2. package/dist/{azure-openai-responses-ecGypQVA.mjs → azure-openai-responses-g-awH_uA.mjs} +9 -16
  3. package/dist/client/assets/{-workbench-terminal-Af-sz4R6.js → -workbench-terminal-C3m5o50g.js} +8 -8
  4. package/dist/client/assets/agent-BXm8Dnfe.js +2 -0
  5. package/dist/client/assets/agent-DWi_bAGy.js +1 -0
  6. package/dist/client/assets/{dialog-CTIcy8Vy.js → dialog-CpMhdP-y.js} +1 -1
  7. package/dist/client/assets/{diff-MiGOu0DY.js → diff-BDdajfz3.js} +2 -2
  8. package/dist/client/assets/{diff-_Gk9o1mg.js → diff-mRZ3PeyD.js} +9 -9
  9. package/dist/client/assets/{external-link-BxixiKaa.js → external-link-Bw3Ptvfw.js} +1 -1
  10. package/dist/client/assets/{fallbacks-D21cBTdH.js → fallbacks-f8E4aL2c.js} +3 -3
  11. package/dist/client/assets/{index-DW7dKhgZ.js → index-D53pFEJY.js} +1 -1
  12. package/dist/client/assets/index-YmJ_EbaF.css +2 -0
  13. package/dist/client/assets/{input-DW9ssWUO.js → input-BVvU6Eiy.js} +1 -1
  14. package/dist/client/assets/portless-BYTEgoik.js +1 -0
  15. package/dist/client/assets/portless-Cke08ZHX.js +2 -0
  16. package/dist/client/assets/{resizable-CZjAW7-J.js → resizable-CYsJ6Kg2.js} +1 -1
  17. package/dist/client/assets/{route-DwWgYFyk.js → route-BzHtbTaZ.js} +2 -2
  18. package/dist/client/assets/route-DD4r__Zm.js +45 -0
  19. package/dist/client/assets/{run-CeqkWWtZ.js → run-C8QYJmux.js} +1 -1
  20. package/dist/client/assets/run-CW5YhyWI.js +2 -0
  21. package/dist/client/assets/{sonner-BKURESHO.js → sonner-CrB5PaMX.js} +1 -1
  22. package/dist/client/assets/state-CvX-YRlC.js +2 -0
  23. package/dist/client/assets/terminal-DJzGIrES.js +2 -0
  24. package/dist/client/assets/{terminal-CcfbU9tU.js → terminal-Dj-VWVHI.js} +1 -1
  25. package/dist/client/assets/{triangle-alert-DLHVemGQ.js → triangle-alert-llGGn6BK.js} +1 -1
  26. package/dist/client/index.html +11 -11
  27. package/dist/github-copilot-headers-BB6z1RAk.mjs +23 -0
  28. package/dist/{google-Jzn1v4-q.mjs → google-generative-ai-r4Wb8Eaq.mjs} +15 -20
  29. package/dist/{google-shared-DNNqX1gf.mjs → google-shared-DN1OvwJM.mjs} +4 -4
  30. package/dist/{google-vertex-z0Cbw7eq.mjs → google-vertex-Clcq7cAd.mjs} +15 -20
  31. package/dist/{hash-CScAQ-b_.mjs → hash-wSEYO-QF.mjs} +1 -1
  32. package/dist/headers-SFoLwUHv.mjs +15 -0
  33. package/dist/{mistral-CxEIkz4y.mjs → mistral-conversations-Bnpuiv3e.mjs} +12 -19
  34. package/dist/{openai-codex-responses-7ZUsVcbT.mjs → openai-codex-responses-4Te8RbRb.mjs} +62 -46
  35. package/dist/{openai-completions-CaGFVr3X.mjs → openai-completions-B4nInzTS.mjs} +69 -96
  36. package/dist/{openai-responses-Vjw8-3qm.mjs → openai-responses-GeDULmTh.mjs} +28 -31
  37. package/dist/{openai-responses-shared-DtEshy-7.mjs → openai-responses-shared-CG93Thoy.mjs} +37 -32
  38. package/dist/{openrouter-CZ-H_QwG.mjs → openrouter-images-CgbIytYQ.mjs} +7 -14
  39. package/dist/{sanitize-unicode-BbVojtka.mjs → sanitize-unicode-Ga8nHda1.mjs} +1 -1
  40. package/dist/server.js +27722 -24346
  41. package/dist/{transform-messages-CLmkH5Gu.mjs → transform-messages-D9fZ7fnU.mjs} +2 -2
  42. package/package.json +3 -2
  43. package/dist/client/assets/agent-BnkD1Glf.js +0 -2
  44. package/dist/client/assets/agent-DQPX2IZb.js +0 -1
  45. package/dist/client/assets/index-B2S_w1d1.css +0 -2
  46. package/dist/client/assets/portless-3KC81g42.js +0 -2
  47. package/dist/client/assets/portless-CxovsEbp.js +0 -1
  48. package/dist/client/assets/route-te6-VkZE.js +0 -45
  49. package/dist/client/assets/run-B-qmimXV.js +0 -2
  50. package/dist/client/assets/state-a4d_PikB.js +0 -2
  51. package/dist/client/assets/terminal-BHNxWKc6.js +0 -2
  52. package/dist/github-copilot-headers-P0xZolzq.mjs +0 -39
  53. package/dist/headers-oksLmLNC.mjs +0 -9
@@ -1,17 +1,28 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { Ir as calculateCost, Lr as clampThinkingLevel, Rr as getProviderEnvValue, Vr as registerApiProvider, jr as parseStreamingJson, zr as AssistantMessageEventStream } from "./server.js";
3
- import { t as headersToRecord } from "./headers-oksLmLNC.mjs";
4
- import { t as sanitizeSurrogates } from "./sanitize-unicode-BbVojtka.mjs";
5
- import { i as resolveCloudflareBaseUrl, n as hasCopilotVisionInput, r as isCloudflareProvider, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-P0xZolzq.mjs";
6
- import { r as buildBaseOptions, t as transformMessages } from "./transform-messages-CLmkH5Gu.mjs";
2
+ import { Ir as calculateCost, Lr as clampThinkingLevel, Rr as getProviderEnvValue, jr as parseStreamingJson, zr as AssistantMessageEventStream } from "./server.js";
3
+ import { t as headersToRecord } from "./headers-SFoLwUHv.mjs";
4
+ import { t as sanitizeSurrogates } from "./sanitize-unicode-Ga8nHda1.mjs";
5
+ import { n as hasCopilotVisionInput, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-BB6z1RAk.mjs";
6
+ import { r as buildBaseOptions, t as transformMessages } from "./transform-messages-D9fZ7fnU.mjs";
7
7
  import { n as OpenAI } from "./openai-CUH8rb7p.mjs";
8
8
  import { t as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-6hf3xB_x.mjs";
9
- //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.79.10_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js
9
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.80.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js
10
10
  /**
11
11
  * Check if conversation messages contain tool calls or tool results.
12
12
  * This is needed because Anthropic (via proxy) requires the tools param
13
13
  * to be present when messages include tool_calls or tool role messages.
14
14
  */
15
+ function hasHeader(headers, name) {
16
+ if (!headers) return false;
17
+ const expected = name.toLowerCase();
18
+ for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;
19
+ return false;
20
+ }
21
+ function getClientApiKey(provider, apiKey, headers) {
22
+ if (apiKey) return apiKey;
23
+ if (hasHeader(headers, "authorization") || hasHeader(headers, "cf-aig-authorization")) return "unused";
24
+ throw new Error(`No API key for provider: ${provider}`);
25
+ }
15
26
  function hasToolHistory(messages) {
16
27
  for (const msg of messages) {
17
28
  if (msg.role === "toolResult") return true;
@@ -43,7 +54,7 @@ function resolveCacheRetention(cacheRetention, env) {
43
54
  if (getProviderEnvValue("PI_CACHE_RETENTION", env) === "long") return "long";
44
55
  return "short";
45
56
  }
46
- const streamOpenAICompletions = (model, context, options) => {
57
+ const stream = (model, context, options) => {
47
58
  const stream = new AssistantMessageEventStream();
48
59
  (async () => {
49
60
  const output = {
@@ -70,12 +81,11 @@ const streamOpenAICompletions = (model, context, options) => {
70
81
  timestamp: Date.now()
71
82
  };
72
83
  try {
73
- const apiKey = options?.apiKey;
74
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
84
+ const apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);
75
85
  const compat = getCompat(model);
76
86
  const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
77
87
  const cacheSessionId = cacheRetention === "none" ? void 0 : options?.sessionId;
78
- const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat, options?.env);
88
+ const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, compat);
79
89
  let params = buildParams(model, context, options, compat, cacheRetention);
80
90
  const nextParams = await options?.onPayload?.(params, model);
81
91
  if (nextParams !== void 0) params = nextParams;
@@ -311,27 +321,19 @@ const streamOpenAICompletions = (model, context, options) => {
311
321
  })();
312
322
  return stream;
313
323
  };
314
- const streamSimpleOpenAICompletions = (model, context, options) => {
315
- const apiKey = options?.apiKey;
316
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
317
- const base = buildBaseOptions(model, options, apiKey);
324
+ const streamSimple = (model, context, options) => {
325
+ getClientApiKey(model.provider, options?.apiKey, options?.headers);
326
+ const base = buildBaseOptions(model, options, options?.apiKey);
318
327
  const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;
319
328
  const reasoningEffort = clampedReasoning === "off" ? void 0 : clampedReasoning;
320
329
  const toolChoice = options?.toolChoice;
321
- return streamOpenAICompletions(model, context, {
330
+ return stream(model, context, {
322
331
  ...base,
323
332
  reasoningEffort,
324
333
  toolChoice
325
334
  });
326
335
  };
327
- function register() {
328
- registerApiProvider({
329
- api: "openai-completions",
330
- stream: streamOpenAICompletions,
331
- streamSimple: streamSimpleOpenAICompletions
332
- });
333
- }
334
- function createClient(model, context, apiKey, optionsHeaders, sessionId, compat = getCompat(model), env) {
336
+ function createClient(model, context, apiKey, optionsHeaders, sessionId, compat = getCompat(model)) {
335
337
  const headers = { ...model.headers };
336
338
  if (model.provider === "github-copilot") {
337
339
  const hasImages = hasCopilotVisionInput(context.messages);
@@ -347,16 +349,11 @@ function createClient(model, context, apiKey, optionsHeaders, sessionId, compat
347
349
  headers["x-session-affinity"] = sessionId;
348
350
  }
349
351
  if (optionsHeaders) Object.assign(headers, optionsHeaders);
350
- const defaultHeaders = model.provider === "cloudflare-ai-gateway" ? {
351
- ...headers,
352
- Authorization: headers.Authorization ?? null,
353
- "cf-aig-authorization": `Bearer ${apiKey}`
354
- } : headers;
355
352
  return new OpenAI({
356
353
  apiKey,
357
- baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,
354
+ baseURL: model.baseUrl,
358
355
  dangerouslyAllowBrowser: true,
359
- defaultHeaders
356
+ defaultHeaders: headers
360
357
  });
361
358
  }
362
359
  function buildParams(model, context, options, compat = getCompat(model), cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env)) {
@@ -421,7 +418,7 @@ function buildParams(model, context, options, compat = getCompat(model), cacheRe
421
418
  if (typeof offValue === "string") params.reasoning_effort = offValue;
422
419
  }
423
420
  if (model.compat?.openRouterRouting) params.provider = model.compat.openRouterRouting;
424
- if (model.baseUrl.includes("ai-gateway.vercel.sh") && model.compat?.vercelGatewayRouting) {
421
+ if (model.compat?.vercelGatewayRouting) {
425
422
  const routing = model.compat.vercelGatewayRouting;
426
423
  if (routing.only || routing.order) {
427
424
  const gatewayOptions = {};
@@ -698,76 +695,52 @@ function mapStopReason(reason) {
698
695
  };
699
696
  }
700
697
  }
701
- /**
702
- * Detect compatibility settings from provider and baseUrl for known providers.
703
- * Provider takes precedence over URL-based detection since it's explicitly configured.
704
- * Returns a fully resolved OpenAICompletionsCompat object with all fields set.
705
- */
706
- function detectCompat(model) {
707
- const provider = model.provider;
708
- const baseUrl = model.baseUrl;
709
- const isZai = provider === "zai" || provider === "zai-coding-cn" || baseUrl.includes("api.z.ai") || baseUrl.includes("open.bigmodel.cn");
710
- const isTogether = provider === "together" || baseUrl.includes("api.together.ai") || baseUrl.includes("api.together.xyz");
711
- const isMoonshot = provider === "moonshotai" || provider === "moonshotai-cn" || baseUrl.includes("api.moonshot.");
712
- const isOpenRouter = provider === "openrouter" || baseUrl.includes("openrouter.ai");
713
- const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com");
714
- const isCloudflareAiGateway = provider === "cloudflare-ai-gateway" || baseUrl.includes("gateway.ai.cloudflare.com");
715
- const isNvidia = provider === "nvidia" || baseUrl.includes("integrate.api.nvidia.com");
716
- const isAntLing = provider === "ant-ling" || baseUrl.includes("api.ant-ling.com");
717
- const isNonStandard = isNvidia || provider === "cerebras" || baseUrl.includes("cerebras.ai") || provider === "xai" || baseUrl.includes("api.x.ai") || isTogether || baseUrl.includes("chutes.ai") || baseUrl.includes("deepseek.com") || isZai || isMoonshot || provider === "opencode" || baseUrl.includes("opencode.ai") || isCloudflareWorkersAI || isCloudflareAiGateway || isAntLing;
718
- const useMaxTokens = baseUrl.includes("chutes.ai") || isMoonshot || isCloudflareAiGateway || isTogether || isNvidia || isAntLing;
719
- const isGrok = provider === "xai" || baseUrl.includes("api.x.ai");
720
- const isDeepSeek = provider === "deepseek" || baseUrl.includes("deepseek.com");
721
- const isOpenRouterDeveloperRoleModel = isOpenRouter && (model.id.startsWith("anthropic/") || model.id.startsWith("openai/"));
722
- const cacheControlFormat = provider === "openrouter" && model.id.startsWith("anthropic/") ? "anthropic" : void 0;
723
- return {
724
- supportsStore: !isNonStandard,
725
- supportsDeveloperRole: isOpenRouterDeveloperRoleModel || !isNonStandard && !isOpenRouter,
726
- supportsReasoningEffort: !isGrok && !isZai && !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia && !isAntLing,
727
- supportsUsageInStreaming: true,
728
- maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
729
- requiresToolResultName: false,
730
- requiresAssistantAfterToolResult: false,
731
- requiresThinkingAsText: false,
732
- requiresReasoningContentOnAssistantMessages: isDeepSeek,
733
- thinkingFormat: isDeepSeek ? "deepseek" : isZai ? "zai" : isTogether ? "together" : isAntLing ? "ant-ling" : isOpenRouter ? "openrouter" : "openai",
734
- openRouterRouting: {},
735
- vercelGatewayRouting: {},
736
- chatTemplateKwargs: {},
737
- zaiToolStream: false,
738
- supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
739
- cacheControlFormat,
740
- sendSessionAffinityHeaders: false,
741
- supportsLongCacheRetention: !(isTogether || isCloudflareWorkersAI || isCloudflareAiGateway || isNvidia || isAntLing)
742
- };
743
- }
698
+ const DEFAULT_COMPAT = {
699
+ supportsStore: true,
700
+ supportsDeveloperRole: true,
701
+ supportsReasoningEffort: true,
702
+ supportsUsageInStreaming: true,
703
+ maxTokensField: "max_completion_tokens",
704
+ requiresToolResultName: false,
705
+ requiresAssistantAfterToolResult: false,
706
+ requiresThinkingAsText: false,
707
+ requiresReasoningContentOnAssistantMessages: false,
708
+ thinkingFormat: "openai",
709
+ openRouterRouting: {},
710
+ vercelGatewayRouting: {},
711
+ chatTemplateKwargs: {},
712
+ zaiToolStream: false,
713
+ supportsStrictMode: true,
714
+ cacheControlFormat: void 0,
715
+ sendSessionAffinityHeaders: false,
716
+ supportsLongCacheRetention: true
717
+ };
744
718
  /**
745
719
  * Get resolved compatibility settings for a model.
746
- * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL.
720
+ * Uses explicit generated/custom model.compat over OpenAI-standard defaults.
747
721
  */
748
722
  function getCompat(model) {
749
- const detected = detectCompat(model);
750
- if (!model.compat) return detected;
723
+ if (!model.compat) return DEFAULT_COMPAT;
751
724
  return {
752
- supportsStore: model.compat.supportsStore ?? detected.supportsStore,
753
- supportsDeveloperRole: model.compat.supportsDeveloperRole ?? detected.supportsDeveloperRole,
754
- supportsReasoningEffort: model.compat.supportsReasoningEffort ?? detected.supportsReasoningEffort,
755
- supportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? detected.supportsUsageInStreaming,
756
- maxTokensField: model.compat.maxTokensField ?? detected.maxTokensField,
757
- requiresToolResultName: model.compat.requiresToolResultName ?? detected.requiresToolResultName,
758
- requiresAssistantAfterToolResult: model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
759
- requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
760
- requiresReasoningContentOnAssistantMessages: model.compat.requiresReasoningContentOnAssistantMessages ?? detected.requiresReasoningContentOnAssistantMessages,
761
- thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
762
- openRouterRouting: model.compat.openRouterRouting ?? {},
763
- vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
764
- chatTemplateKwargs: model.compat.chatTemplateKwargs ?? detected.chatTemplateKwargs,
765
- zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,
766
- supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,
767
- cacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,
768
- sendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? detected.sendSessionAffinityHeaders,
769
- supportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? detected.supportsLongCacheRetention
725
+ supportsStore: model.compat.supportsStore ?? DEFAULT_COMPAT.supportsStore,
726
+ supportsDeveloperRole: model.compat.supportsDeveloperRole ?? DEFAULT_COMPAT.supportsDeveloperRole,
727
+ supportsReasoningEffort: model.compat.supportsReasoningEffort ?? DEFAULT_COMPAT.supportsReasoningEffort,
728
+ supportsUsageInStreaming: model.compat.supportsUsageInStreaming ?? DEFAULT_COMPAT.supportsUsageInStreaming,
729
+ maxTokensField: model.compat.maxTokensField ?? DEFAULT_COMPAT.maxTokensField,
730
+ requiresToolResultName: model.compat.requiresToolResultName ?? DEFAULT_COMPAT.requiresToolResultName,
731
+ requiresAssistantAfterToolResult: model.compat.requiresAssistantAfterToolResult ?? DEFAULT_COMPAT.requiresAssistantAfterToolResult,
732
+ requiresThinkingAsText: model.compat.requiresThinkingAsText ?? DEFAULT_COMPAT.requiresThinkingAsText,
733
+ requiresReasoningContentOnAssistantMessages: model.compat.requiresReasoningContentOnAssistantMessages ?? DEFAULT_COMPAT.requiresReasoningContentOnAssistantMessages,
734
+ thinkingFormat: model.compat.thinkingFormat ?? DEFAULT_COMPAT.thinkingFormat,
735
+ openRouterRouting: model.compat.openRouterRouting ?? DEFAULT_COMPAT.openRouterRouting,
736
+ vercelGatewayRouting: model.compat.vercelGatewayRouting ?? DEFAULT_COMPAT.vercelGatewayRouting,
737
+ chatTemplateKwargs: model.compat.chatTemplateKwargs ?? DEFAULT_COMPAT.chatTemplateKwargs,
738
+ zaiToolStream: model.compat.zaiToolStream ?? DEFAULT_COMPAT.zaiToolStream,
739
+ supportsStrictMode: model.compat.supportsStrictMode ?? DEFAULT_COMPAT.supportsStrictMode,
740
+ cacheControlFormat: model.compat.cacheControlFormat ?? DEFAULT_COMPAT.cacheControlFormat,
741
+ sendSessionAffinityHeaders: model.compat.sendSessionAffinityHeaders ?? DEFAULT_COMPAT.sendSessionAffinityHeaders,
742
+ supportsLongCacheRetention: model.compat.supportsLongCacheRetention ?? DEFAULT_COMPAT.supportsLongCacheRetention
770
743
  };
771
744
  }
772
745
  //#endregion
773
- export { convertMessages, register, streamOpenAICompletions, streamSimpleOpenAICompletions };
746
+ export { convertMessages, stream, streamSimple };
@@ -1,17 +1,28 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { Lr as clampThinkingLevel, Rr as getProviderEnvValue, Vr as registerApiProvider, zr as AssistantMessageEventStream } from "./server.js";
3
- import { t as headersToRecord } from "./headers-oksLmLNC.mjs";
4
- import { i as resolveCloudflareBaseUrl, n as hasCopilotVisionInput, r as isCloudflareProvider, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-P0xZolzq.mjs";
5
- import { r as buildBaseOptions } from "./transform-messages-CLmkH5Gu.mjs";
2
+ import { Lr as clampThinkingLevel, Rr as getProviderEnvValue, zr as AssistantMessageEventStream } from "./server.js";
3
+ import { t as headersToRecord } from "./headers-SFoLwUHv.mjs";
4
+ import { n as hasCopilotVisionInput, t as buildCopilotDynamicHeaders } from "./github-copilot-headers-BB6z1RAk.mjs";
5
+ import { r as buildBaseOptions } from "./transform-messages-D9fZ7fnU.mjs";
6
6
  import { n as OpenAI } from "./openai-CUH8rb7p.mjs";
7
7
  import { t as clampOpenAIPromptCacheKey } from "./openai-prompt-cache-6hf3xB_x.mjs";
8
- import { n as convertResponsesTools, r as processResponsesStream, t as convertResponsesMessages } from "./openai-responses-shared-DtEshy-7.mjs";
9
- //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.79.10_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js
8
+ import { n as convertResponsesTools, r as processResponsesStream, t as convertResponsesMessages } from "./openai-responses-shared-CG93Thoy.mjs";
9
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.80.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js
10
10
  const OPENAI_TOOL_CALL_PROVIDERS = new Set([
11
11
  "openai",
12
12
  "openai-codex",
13
13
  "opencode"
14
14
  ]);
15
+ function hasHeader(headers, name) {
16
+ if (!headers) return false;
17
+ const expected = name.toLowerCase();
18
+ for (const [key, value] of Object.entries(headers)) if (key.toLowerCase() === expected && value !== null && value.trim().length > 0) return true;
19
+ return false;
20
+ }
21
+ function getClientApiKey(provider, apiKey, headers) {
22
+ if (apiKey) return apiKey;
23
+ if (hasHeader(headers, "authorization") || hasHeader(headers, "cf-aig-authorization")) return "unused";
24
+ throw new Error(`No API key for provider: ${provider}`);
25
+ }
15
26
  /**
16
27
  * Resolve cache retention preference.
17
28
  * Defaults to "short" and uses PI_CACHE_RETENTION for backward compatibility.
@@ -47,7 +58,7 @@ function formatOpenAIResponsesError(error) {
47
58
  /**
48
59
  * Generate function for OpenAI Responses API
49
60
  */
50
- const streamOpenAIResponses = (model, context, options) => {
61
+ const stream = (model, context, options) => {
51
62
  const stream = new AssistantMessageEventStream();
52
63
  (async () => {
53
64
  const output = {
@@ -74,10 +85,9 @@ const streamOpenAIResponses = (model, context, options) => {
74
85
  timestamp: Date.now()
75
86
  };
76
87
  try {
77
- const apiKey = options?.apiKey;
78
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
88
+ const apiKey = getClientApiKey(model.provider, options?.apiKey, options?.headers);
79
89
  const cacheSessionId = resolveCacheRetention(options?.cacheRetention, options?.env) === "none" ? void 0 : options?.sessionId;
80
- const client = createClient(model, context, apiKey, options?.headers, cacheSessionId, options?.env);
90
+ const client = createClient(model, context, apiKey, options?.headers, cacheSessionId);
81
91
  let params = buildParams(model, context, options);
82
92
  const nextParams = await options?.onPayload?.(params, model);
83
93
  if (nextParams !== void 0) params = nextParams;
@@ -124,25 +134,17 @@ const streamOpenAIResponses = (model, context, options) => {
124
134
  })();
125
135
  return stream;
126
136
  };
127
- const streamSimpleOpenAIResponses = (model, context, options) => {
128
- const apiKey = options?.apiKey;
129
- if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`);
130
- const base = buildBaseOptions(model, options, apiKey);
137
+ const streamSimple = (model, context, options) => {
138
+ getClientApiKey(model.provider, options?.apiKey, options?.headers);
139
+ const base = buildBaseOptions(model, options, options?.apiKey);
131
140
  const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : void 0;
132
141
  const reasoningEffort = clampedReasoning === "off" ? void 0 : clampedReasoning;
133
- return streamOpenAIResponses(model, context, {
142
+ return stream(model, context, {
134
143
  ...base,
135
144
  reasoningEffort
136
145
  });
137
146
  };
138
- function register() {
139
- registerApiProvider({
140
- api: "openai-responses",
141
- stream: streamOpenAIResponses,
142
- streamSimple: streamSimpleOpenAIResponses
143
- });
144
- }
145
- function createClient(model, context, apiKey, optionsHeaders, sessionId, env) {
147
+ function createClient(model, context, apiKey, optionsHeaders, sessionId) {
146
148
  const compat = getCompat(model);
147
149
  const headers = { ...model.headers };
148
150
  if (model.provider === "github-copilot") {
@@ -158,16 +160,11 @@ function createClient(model, context, apiKey, optionsHeaders, sessionId, env) {
158
160
  headers["x-client-request-id"] = sessionId;
159
161
  }
160
162
  if (optionsHeaders) Object.assign(headers, optionsHeaders);
161
- const defaultHeaders = model.provider === "cloudflare-ai-gateway" ? {
162
- ...headers,
163
- Authorization: headers.Authorization ?? null,
164
- "cf-aig-authorization": `Bearer ${apiKey}`
165
- } : headers;
166
163
  return new OpenAI({
167
164
  apiKey,
168
- baseURL: isCloudflareProvider(model.provider) ? resolveCloudflareBaseUrl(model, env) : model.baseUrl,
165
+ baseURL: model.baseUrl,
169
166
  dangerouslyAllowBrowser: true,
170
- defaultHeaders
167
+ defaultHeaders: headers
171
168
  });
172
169
  }
173
170
  function buildParams(model, context, options) {
@@ -214,4 +211,4 @@ function applyServiceTierPricing(usage, serviceTier, model) {
214
211
  usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
215
212
  }
216
213
  //#endregion
217
- export { register, streamOpenAIResponses, streamSimpleOpenAIResponses };
214
+ export { stream, streamSimple };
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
2
  import { Ir as calculateCost, jr as parseStreamingJson } from "./server.js";
3
- import { t as sanitizeSurrogates } from "./sanitize-unicode-BbVojtka.mjs";
4
- import { t as transformMessages } from "./transform-messages-CLmkH5Gu.mjs";
5
- import { t as shortHash } from "./hash-CScAQ-b_.mjs";
6
- //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.79.10_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js
3
+ import { t as sanitizeSurrogates } from "./sanitize-unicode-Ga8nHda1.mjs";
4
+ import { t as transformMessages } from "./transform-messages-D9fZ7fnU.mjs";
5
+ import { t as shortHash } from "./hash-wSEYO-QF.mjs";
6
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.80.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js
7
7
  function encodeTextSignatureV1(id, phase) {
8
8
  const payload = {
9
9
  v: 1,
@@ -168,8 +168,37 @@ function convertResponsesTools(tools, options) {
168
168
  async function processResponsesStream(openaiStream, output, stream, model, options) {
169
169
  let currentItem = null;
170
170
  let currentBlock = null;
171
+ let sawTerminalResponseEvent = false;
171
172
  const blocks = output.content;
172
173
  const blockIndex = () => blocks.length - 1;
174
+ const finalizeResponse = (response) => {
175
+ sawTerminalResponseEvent = true;
176
+ if (response?.id) output.responseId = response.id;
177
+ if (response?.usage) {
178
+ const cachedTokens = response.usage.input_tokens_details?.cached_tokens || 0;
179
+ output.usage = {
180
+ input: (response.usage.input_tokens || 0) - cachedTokens,
181
+ output: response.usage.output_tokens || 0,
182
+ cacheRead: cachedTokens,
183
+ cacheWrite: 0,
184
+ totalTokens: response.usage.total_tokens || 0,
185
+ cost: {
186
+ input: 0,
187
+ output: 0,
188
+ cacheRead: 0,
189
+ cacheWrite: 0,
190
+ total: 0
191
+ }
192
+ };
193
+ }
194
+ calculateCost(model, output.usage);
195
+ if (options?.applyServiceTierPricing) {
196
+ const serviceTier = options.resolveServiceTier ? options.resolveServiceTier(response?.service_tier, options.serviceTier) : response?.service_tier ?? options.serviceTier;
197
+ options.applyServiceTierPricing(output.usage, serviceTier);
198
+ }
199
+ output.stopReason = mapStopReason(response?.status);
200
+ if (output.content.some((b) => b.type === "toolCall") && output.stopReason === "stop") output.stopReason = "toolUse";
201
+ };
173
202
  for await (const event of openaiStream) if (event.type === "response.created") output.responseId = event.response.id;
174
203
  else if (event.type === "response.output_item.added") {
175
204
  const item = event.item;
@@ -364,40 +393,16 @@ async function processResponsesStream(openaiStream, output, stream, model, optio
364
393
  partial: output
365
394
  });
366
395
  }
367
- } else if (event.type === "response.completed") {
368
- const response = event.response;
369
- if (response?.id) output.responseId = response.id;
370
- if (response?.usage) {
371
- const cachedTokens = response.usage.input_tokens_details?.cached_tokens || 0;
372
- output.usage = {
373
- input: (response.usage.input_tokens || 0) - cachedTokens,
374
- output: response.usage.output_tokens || 0,
375
- cacheRead: cachedTokens,
376
- cacheWrite: 0,
377
- totalTokens: response.usage.total_tokens || 0,
378
- cost: {
379
- input: 0,
380
- output: 0,
381
- cacheRead: 0,
382
- cacheWrite: 0,
383
- total: 0
384
- }
385
- };
386
- }
387
- calculateCost(model, output.usage);
388
- if (options?.applyServiceTierPricing) {
389
- const serviceTier = options.resolveServiceTier ? options.resolveServiceTier(response?.service_tier, options.serviceTier) : response?.service_tier ?? options.serviceTier;
390
- options.applyServiceTierPricing(output.usage, serviceTier);
391
- }
392
- output.stopReason = mapStopReason(response?.status);
393
- if (output.content.some((b) => b.type === "toolCall") && output.stopReason === "stop") output.stopReason = "toolUse";
394
- } else if (event.type === "error") throw new Error(`Error Code ${event.code}: ${event.message}` || "Unknown error");
396
+ } else if (event.type === "response.completed" || event.type === "response.incomplete") finalizeResponse(event.response);
397
+ else if (event.type === "error") throw new Error(`Error Code ${event.code}: ${event.message}` || "Unknown error");
395
398
  else if (event.type === "response.failed") {
399
+ sawTerminalResponseEvent = true;
396
400
  const error = event.response?.error;
397
401
  const details = event.response?.incomplete_details;
398
402
  const msg = error ? `${error.code || "unknown"}: ${error.message || "no message"}` : details?.reason ? `incomplete: ${details.reason}` : "Unknown error (no error details in response)";
399
403
  throw new Error(msg);
400
404
  }
405
+ if (!sawTerminalResponseEvent) throw new Error("OpenAI Responses stream ended before a terminal response event");
401
406
  }
402
407
  function mapStopReason(status) {
403
408
  if (!status) return "stop";
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- import { Br as registerImagesApiProvider } from "./server.js";
3
- import { t as headersToRecord } from "./headers-oksLmLNC.mjs";
4
- import { t as sanitizeSurrogates } from "./sanitize-unicode-BbVojtka.mjs";
2
+ import { n as providerHeadersToRecord, t as headersToRecord } from "./headers-SFoLwUHv.mjs";
3
+ import { t as sanitizeSurrogates } from "./sanitize-unicode-Ga8nHda1.mjs";
5
4
  import { n as OpenAI } from "./openai-CUH8rb7p.mjs";
6
- //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.79.10_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js
7
- const generateImagesOpenRouter = async (model, context, options) => {
5
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.80.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js
6
+ const generateImages = async (model, context, options) => {
8
7
  const output = {
9
8
  api: model.api,
10
9
  provider: model.provider,
@@ -59,21 +58,15 @@ const generateImagesOpenRouter = async (model, context, options) => {
59
58
  return output;
60
59
  }
61
60
  };
62
- function register() {
63
- registerImagesApiProvider({
64
- api: "openrouter-images",
65
- generateImages: generateImagesOpenRouter
66
- });
67
- }
68
61
  function createClient(model, apiKey, optionsHeaders) {
69
62
  return new OpenAI({
70
63
  apiKey,
71
64
  baseURL: model.baseUrl,
72
65
  dangerouslyAllowBrowser: true,
73
- defaultHeaders: {
66
+ defaultHeaders: providerHeadersToRecord({
74
67
  ...model.headers,
75
68
  ...optionsHeaders
76
- }
69
+ })
77
70
  });
78
71
  }
79
72
  function buildParams(model, context) {
@@ -122,4 +115,4 @@ function parseUsage(rawUsage, model) {
122
115
  return usage;
123
116
  }
124
117
  //#endregion
125
- export { generateImagesOpenRouter, register };
118
+ export { generateImages };
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env -S node --max-old-space-size=16384 --heapsnapshot-near-heap-limit=3 --report-on-fatalerror
2
- //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.79.10_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/sanitize-unicode.js
2
+ //#region ../../node_modules/.pnpm/@earendil-works+pi-ai@0.80.1_@modelcontextprotocol+sdk@1.29.0_zod@4.4.3__ws@8.21.0_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/utils/sanitize-unicode.js
3
3
  /**
4
4
  * Removes unpaired Unicode surrogate characters from a string.
5
5
  *