@draht/ai 2026.7.30 → 2026.9.5-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/api/anthropic-messages.d.ts.map +1 -1
  2. package/dist/api/anthropic-messages.js +15 -8
  3. package/dist/api/anthropic-messages.js.map +1 -1
  4. package/dist/api/azure-openai-responses.d.ts.map +1 -1
  5. package/dist/api/azure-openai-responses.js +2 -1
  6. package/dist/api/azure-openai-responses.js.map +1 -1
  7. package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  8. package/dist/api/bedrock-converse-stream.js +16 -2
  9. package/dist/api/bedrock-converse-stream.js.map +1 -1
  10. package/dist/api/google-generative-ai.d.ts +2 -2
  11. package/dist/api/google-generative-ai.d.ts.map +1 -1
  12. package/dist/api/google-generative-ai.js +19 -15
  13. package/dist/api/google-generative-ai.js.map +1 -1
  14. package/dist/api/google-shared.d.ts +15 -2
  15. package/dist/api/google-shared.d.ts.map +1 -1
  16. package/dist/api/google-shared.js +60 -7
  17. package/dist/api/google-shared.js.map +1 -1
  18. package/dist/api/google-vertex.d.ts +2 -2
  19. package/dist/api/google-vertex.d.ts.map +1 -1
  20. package/dist/api/google-vertex.js +17 -13
  21. package/dist/api/google-vertex.js.map +1 -1
  22. package/dist/api/mistral-conversations.d.ts.map +1 -1
  23. package/dist/api/mistral-conversations.js +6 -2
  24. package/dist/api/mistral-conversations.js.map +1 -1
  25. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  26. package/dist/api/openai-codex-responses.js +51 -33
  27. package/dist/api/openai-codex-responses.js.map +1 -1
  28. package/dist/api/openai-completions.d.ts.map +1 -1
  29. package/dist/api/openai-completions.js +14 -8
  30. package/dist/api/openai-completions.js.map +1 -1
  31. package/dist/api/openai-responses.d.ts.map +1 -1
  32. package/dist/api/openai-responses.js +6 -2
  33. package/dist/api/openai-responses.js.map +1 -1
  34. package/dist/api/pi-messages.js +1 -1
  35. package/dist/api/pi-messages.js.map +1 -1
  36. package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  37. package/dist/auth/oauth/github-copilot.js +111 -35
  38. package/dist/auth/oauth/github-copilot.js.map +1 -1
  39. package/dist/auth/resolve.js +2 -1
  40. package/dist/auth/resolve.js.map +1 -1
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/providers/data/.manifest.json +1 -1
  45. package/dist/providers/data/amazon-bedrock.json +1 -1
  46. package/dist/providers/data/anthropic.json +1 -1
  47. package/dist/providers/data/azure-openai-responses.json +1 -1
  48. package/dist/providers/data/cerebras.json +1 -1
  49. package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  50. package/dist/providers/data/cloudflare-workers-ai.json +1 -1
  51. package/dist/providers/data/deepseek.json +1 -1
  52. package/dist/providers/data/fireworks.json +1 -1
  53. package/dist/providers/data/github-copilot.json +1 -1
  54. package/dist/providers/data/google-vertex.json +1 -1
  55. package/dist/providers/data/google.json +1 -1
  56. package/dist/providers/data/groq.json +1 -1
  57. package/dist/providers/data/huggingface.json +1 -1
  58. package/dist/providers/data/kimi-coding.json +1 -1
  59. package/dist/providers/data/mistral.json +1 -1
  60. package/dist/providers/data/nvidia.json +1 -1
  61. package/dist/providers/data/openai-codex.json +1 -1
  62. package/dist/providers/data/openai.json +1 -1
  63. package/dist/providers/data/opencode-go.json +1 -1
  64. package/dist/providers/data/opencode.json +1 -1
  65. package/dist/providers/data/openrouter.json +1 -1
  66. package/dist/providers/data/qwen-token-plan-cn.json +1 -1
  67. package/dist/providers/data/qwen-token-plan.json +1 -1
  68. package/dist/providers/data/together.json +1 -1
  69. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  70. package/dist/providers/data/xai.json +1 -1
  71. package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  72. package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  73. package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  74. package/dist/providers/data/xiaomi.json +1 -1
  75. package/dist/providers/data/zai-coding-cn.json +1 -1
  76. package/dist/providers/data/zai.json +1 -1
  77. package/dist/providers/xai.d.ts +1 -1
  78. package/dist/providers/xai.d.ts.map +1 -1
  79. package/dist/providers/xai.js +1 -5
  80. package/dist/providers/xai.js.map +1 -1
  81. package/dist/types.d.ts +3 -0
  82. package/dist/types.d.ts.map +1 -1
  83. package/dist/types.js.map +1 -1
  84. package/dist/utils/error-body.d.ts.map +1 -1
  85. package/dist/utils/error-body.js +23 -4
  86. package/dist/utils/error-body.js.map +1 -1
  87. package/dist/utils/node-http-proxy.d.ts.map +1 -1
  88. package/dist/utils/node-http-proxy.js +53 -12
  89. package/dist/utils/node-http-proxy.js.map +1 -1
  90. package/dist/utils/pi-user-agent.d.ts +2 -0
  91. package/dist/utils/pi-user-agent.d.ts.map +1 -0
  92. package/dist/utils/pi-user-agent.js +12 -0
  93. package/dist/utils/pi-user-agent.js.map +1 -0
  94. package/dist/utils/retry.d.ts.map +1 -1
  95. package/dist/utils/retry.js +1 -0
  96. package/dist/utils/retry.js.map +1 -1
  97. package/dist/utils/sleep.d.ts +2 -0
  98. package/dist/utils/sleep.d.ts.map +1 -0
  99. package/dist/utils/sleep.js +15 -0
  100. package/dist/utils/sleep.js.map +1 -0
  101. package/dist/utils/validation.d.ts.map +1 -1
  102. package/dist/utils/validation.js +6 -0
  103. package/dist/utils/validation.js.map +1 -1
  104. package/package.json +1 -1
@@ -1,11 +1,3 @@
1
- function loadNodeOs() {
2
- if (typeof process === "undefined" || !(process.versions?.node || process.versions?.bun)) {
3
- return null;
4
- }
5
- return process.getBuiltinModule?.("node:os") ?? null;
6
- }
7
- // NEVER convert to top-level runtime imports - breaks browser/Vite builds
8
- const _os = loadNodeOs();
9
1
  import { clampThinkingLevel } from "../models.js";
10
2
  import { registerSessionResourceCleanup } from "../session-resources.js";
11
3
  import { combineAbortSignals } from "../utils/abort-signals.js";
@@ -15,6 +7,7 @@ import { formatProviderError, normalizeProviderError } from "../utils/error-body
15
7
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
16
8
  import { headersToRecord } from "../utils/headers.js";
17
9
  import { resolveHttpProxyUrlForTarget } from "../utils/node-http-proxy.js";
10
+ import { getPiUserAgent } from "../utils/pi-user-agent.js";
18
11
  import { uuidv7 } from "../utils/uuid.js";
19
12
  import { createGrammarToolInputProperties } from "./constrained-sampling.js";
20
13
  import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
@@ -209,7 +202,7 @@ export const stream = (model, context, options) => {
209
202
  startEmitted = true;
210
203
  stream.push({ type: "start", partial: output });
211
204
  }
212
- }, httpTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, grammarToolInputProperties, options);
205
+ }, httpTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId, grammarToolInputProperties, options);
213
206
  if (options?.signal?.aborted) {
214
207
  throw new Error("Request was aborted");
215
208
  }
@@ -365,7 +358,10 @@ export const streamSimple = (model, context, options) => {
365
358
  if (!apiKey) {
366
359
  throw new Error(`No API key for provider: ${model.provider}`);
367
360
  }
368
- const base = buildBaseOptions(model, context, options, apiKey);
361
+ const base = {
362
+ ...buildBaseOptions(model, context, options, apiKey),
363
+ toolChoice: options?.toolChoice,
364
+ };
369
365
  const clampedReasoning = options?.reasoning ? clampThinkingLevel(model, options.reasoning) : undefined;
370
366
  const reasoningEffort = clampedReasoning === "off" ? undefined : clampedReasoning;
371
367
  return stream(model, context, {
@@ -575,9 +571,10 @@ async function* parseSSE(response, signal) {
575
571
  if (signal?.aborted) {
576
572
  throw new Error("Request was aborted");
577
573
  }
578
- if (done)
579
- break;
580
- buffer += decoder.decode(value, { stream: true });
574
+ buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
575
+ // Treat EOF as terminating the residual SSE frame.
576
+ if (done && buffer.trim())
577
+ buffer += "\n\n";
581
578
  let idx = buffer.indexOf("\n\n");
582
579
  while (idx !== -1) {
583
580
  const chunk = buffer.slice(0, idx);
@@ -602,6 +599,8 @@ async function* parseSSE(response, signal) {
602
599
  }
603
600
  idx = buffer.indexOf("\n\n");
604
601
  }
602
+ if (done)
603
+ break;
605
604
  }
606
605
  }
607
606
  finally {
@@ -664,14 +663,14 @@ export function closeOpenAICodexWebSocketSessions(sessionId) {
664
663
  closeWebSocketSilently(entry.socket, 1000, "debug_close");
665
664
  };
666
665
  if (sessionId) {
667
- const entry = websocketSessionCache.get(sessionId);
668
- if (entry)
666
+ for (const entry of websocketSessionCache.get(sessionId)?.values() ?? [])
669
667
  closeEntry(entry);
670
668
  websocketSessionCache.delete(sessionId);
671
669
  return;
672
670
  }
673
- for (const entry of websocketSessionCache.values()) {
674
- closeEntry(entry);
671
+ for (const accountEntries of websocketSessionCache.values()) {
672
+ for (const entry of accountEntries.values())
673
+ closeEntry(entry);
675
674
  }
676
675
  websocketSessionCache.clear();
677
676
  }
@@ -752,7 +751,7 @@ function closeWebSocketSilently(socket, code = 1000, reason = "done") {
752
751
  }
753
752
  catch { }
754
753
  }
755
- function scheduleSessionWebSocketExpiry(sessionId, entry) {
754
+ function scheduleSessionWebSocketExpiry(sessionId, accountId, entry) {
756
755
  if (entry.idleTimer) {
757
756
  clearTimeout(entry.idleTimer);
758
757
  }
@@ -760,7 +759,11 @@ function scheduleSessionWebSocketExpiry(sessionId, entry) {
760
759
  if (entry.busy)
761
760
  return;
762
761
  closeWebSocketSilently(entry.socket, 1000, "idle_timeout");
763
- websocketSessionCache.delete(sessionId);
762
+ const accountEntries = websocketSessionCache.get(sessionId);
763
+ if (accountEntries?.get(accountId) === entry)
764
+ accountEntries.delete(accountId);
765
+ if (accountEntries?.size === 0)
766
+ websocketSessionCache.delete(sessionId);
764
767
  }, SESSION_WEBSOCKET_CACHE_TTL_MS);
765
768
  }
766
769
  async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS, env) {
@@ -831,7 +834,7 @@ async function connectWebSocket(url, headers, signal, connectTimeoutMs = DEFAULT
831
834
  }
832
835
  });
833
836
  }
834
- async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutMs, env) {
837
+ async function acquireWebSocket(url, headers, sessionId, accountId, signal, connectTimeoutMs, env) {
835
838
  if (!sessionId) {
836
839
  const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
837
840
  return {
@@ -840,7 +843,8 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
840
843
  release: () => closeWebSocketSilently(socket),
841
844
  };
842
845
  }
843
- const cached = websocketSessionCache.get(sessionId);
846
+ let accountEntries = websocketSessionCache.get(sessionId);
847
+ const cached = accountEntries?.get(accountId);
844
848
  if (cached) {
845
849
  if (cached.idleTimer) {
846
850
  clearTimeout(cached.idleTimer);
@@ -848,7 +852,9 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
848
852
  }
849
853
  if (!cached.busy && isWebSocketSessionExpired(cached)) {
850
854
  closeWebSocketSilently(cached.socket, 1000, "connection_age_limit");
851
- websocketSessionCache.delete(sessionId);
855
+ accountEntries?.delete(accountId);
856
+ if (accountEntries?.size === 0)
857
+ websocketSessionCache.delete(sessionId);
852
858
  }
853
859
  else if (!cached.busy && isWebSocketReusable(cached.socket)) {
854
860
  cached.busy = true;
@@ -859,11 +865,15 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
859
865
  release: ({ keep } = {}) => {
860
866
  if (!keep || !isWebSocketReusable(cached.socket)) {
861
867
  closeWebSocketSilently(cached.socket);
862
- websocketSessionCache.delete(sessionId);
868
+ const currentEntries = websocketSessionCache.get(sessionId);
869
+ if (currentEntries?.get(accountId) === cached)
870
+ currentEntries.delete(accountId);
871
+ if (currentEntries?.size === 0)
872
+ websocketSessionCache.delete(sessionId);
863
873
  return;
864
874
  }
865
875
  cached.busy = false;
866
- scheduleSessionWebSocketExpiry(sessionId, cached);
876
+ scheduleSessionWebSocketExpiry(sessionId, accountId, cached);
867
877
  },
868
878
  };
869
879
  }
@@ -879,12 +889,19 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
879
889
  }
880
890
  if (!isWebSocketReusable(cached.socket)) {
881
891
  closeWebSocketSilently(cached.socket);
882
- websocketSessionCache.delete(sessionId);
892
+ accountEntries?.delete(accountId);
893
+ if (accountEntries?.size === 0)
894
+ websocketSessionCache.delete(sessionId);
883
895
  }
884
896
  }
885
897
  const socket = await connectWebSocket(url, headers, signal, connectTimeoutMs, env);
886
898
  const entry = { socket, busy: true, createdAt: Date.now() };
887
- websocketSessionCache.set(sessionId, entry);
899
+ accountEntries = websocketSessionCache.get(sessionId);
900
+ if (!accountEntries) {
901
+ accountEntries = new Map();
902
+ websocketSessionCache.set(sessionId, accountEntries);
903
+ }
904
+ accountEntries.set(accountId, entry);
888
905
  return {
889
906
  socket,
890
907
  entry,
@@ -894,13 +911,15 @@ async function acquireWebSocket(url, headers, sessionId, signal, connectTimeoutM
894
911
  closeWebSocketSilently(entry.socket);
895
912
  if (entry.idleTimer)
896
913
  clearTimeout(entry.idleTimer);
897
- if (websocketSessionCache.get(sessionId) === entry) {
914
+ const currentEntries = websocketSessionCache.get(sessionId);
915
+ if (currentEntries?.get(accountId) === entry)
916
+ currentEntries.delete(accountId);
917
+ if (currentEntries?.size === 0)
898
918
  websocketSessionCache.delete(sessionId);
899
- }
900
919
  return;
901
920
  }
902
921
  entry.busy = false;
903
- scheduleSessionWebSocketExpiry(sessionId, entry);
922
+ scheduleSessionWebSocketExpiry(sessionId, accountId, entry);
904
923
  },
905
924
  };
906
925
  }
@@ -1120,8 +1139,8 @@ async function* startWebSocketOutputOnFirstEvent(events, onStart) {
1120
1139
  yield event;
1121
1140
  }
1122
1141
  }
1123
- async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, grammarToolInputProperties, options) {
1124
- const { socket, entry, reused, release } = await acquireWebSocket(url, headers, cacheSessionId, options?.signal, websocketConnectTimeoutMs, options?.env);
1142
+ async function processWebSocketStream(url, body, headers, output, stream, model, onStart, idleTimeoutMs, websocketConnectTimeoutMs, cacheSessionId, accountId, grammarToolInputProperties, options) {
1143
+ const { socket, entry, reused, release } = await acquireWebSocket(url, headers, cacheSessionId, accountId, options?.signal, websocketConnectTimeoutMs, options?.env);
1125
1144
  let keepConnection = true;
1126
1145
  const useCachedContext = options?.transport === "websocket-cached" || options?.transport === "auto";
1127
1146
  // ChatGPT Codex Responses rejects `store: true` ("Store must be set to false").
@@ -1242,8 +1261,7 @@ function buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token)
1242
1261
  headers.set("Authorization", `Bearer ${token}`);
1243
1262
  headers.set("chatgpt-account-id", accountId);
1244
1263
  headers.set("originator", "pi");
1245
- const userAgent = _os ? `pi (${_os.platform()} ${_os.release()}; ${_os.arch()})` : "pi (browser)";
1246
- headers.set("User-Agent", userAgent);
1264
+ headers.set("User-Agent", getPiUserAgent());
1247
1265
  return headers;
1248
1266
  }
1249
1267
  function buildSSEHeaders(initHeaders, additionalHeaders, accountId, token, sessionId) {