@oh-my-pi/pi-ai 18.2.6 → 18.2.7

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 (49) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/THIRD-PARTY-NOTICES.txt +0 -37
  3. package/dist/types/auth-retry.d.ts +2 -0
  4. package/dist/types/auth-storage.d.ts +2 -2
  5. package/dist/types/error/classes.d.ts +4 -1
  6. package/dist/types/error/flags.d.ts +12 -4
  7. package/dist/types/index.d.ts +14 -12
  8. package/dist/types/judgment/types.d.ts +5 -2
  9. package/dist/types/judgment/typesafe.d.ts +16 -22
  10. package/dist/types/providers/anthropic-compaction.d.ts +10 -0
  11. package/dist/types/providers/anthropic-identity.d.ts +18 -0
  12. package/dist/types/providers/anthropic-state.d.ts +13 -0
  13. package/dist/types/providers/anthropic.d.ts +6 -59
  14. package/dist/types/providers/gitlab-duo.d.ts +0 -1
  15. package/dist/types/providers/kimi.d.ts +1 -5
  16. package/dist/types/providers/openai-codex-attestation.d.ts +6 -0
  17. package/dist/types/providers/openai-codex-compaction.d.ts +6 -0
  18. package/dist/types/providers/openai-codex-responses.d.ts +3 -27
  19. package/dist/types/providers/openai-codex-transport.d.ts +7 -0
  20. package/dist/types/providers/openai-shared.d.ts +0 -9
  21. package/dist/types/providers/register-builtins.d.ts +20 -22
  22. package/dist/types/providers/synthetic.d.ts +1 -5
  23. package/package.json +6 -6
  24. package/src/auth-retry.ts +3 -0
  25. package/src/auth-storage.ts +28 -22
  26. package/src/error/auth-classify.ts +10 -2
  27. package/src/error/classes.ts +23 -3
  28. package/src/error/flags.ts +51 -16
  29. package/src/index.ts +15 -12
  30. package/src/judgment/types.ts +6 -3
  31. package/src/judgment/typesafe.ts +53 -48
  32. package/src/provider-session-state.ts +1 -1
  33. package/src/providers/anthropic-compaction.ts +54 -0
  34. package/src/providers/anthropic-identity.ts +136 -0
  35. package/src/providers/anthropic-state.ts +55 -0
  36. package/src/providers/anthropic.ts +39 -296
  37. package/src/providers/bedrock-mantle.ts +1 -1
  38. package/src/providers/gitlab-duo.ts +0 -4
  39. package/src/providers/kimi.ts +1 -8
  40. package/src/providers/openai-codex-attestation.ts +19 -0
  41. package/src/providers/openai-codex-compaction.ts +18 -0
  42. package/src/providers/openai-codex-responses.ts +9 -68
  43. package/src/providers/openai-codex-transport.ts +18 -0
  44. package/src/providers/openai-shared.ts +1 -10
  45. package/src/providers/register-builtins.ts +113 -320
  46. package/src/providers/synthetic.ts +1 -8
  47. package/src/registry/cloudflare-ai-gateway.ts +1 -1
  48. package/src/stream.ts +7 -15
  49. package/src/utils/anthropic-auth.ts +3 -6
@@ -1,27 +1,10 @@
1
1
  /**
2
- * Lazy provider module loading.
3
- *
4
- * Each provider module is loaded only when its stream function is first called.
5
- * This avoids eagerly importing heavy SDK dependencies (e.g., openai) at
6
- * startup. The loaded module promise is cached so subsequent calls
7
- * reuse the same import.
8
- *
9
- * NOTE: stream.ts currently imports providers directly, so this file is not yet
10
- * wired into the main streaming path. It provides the infrastructure for lazy
11
- * loading that can be integrated when stream.ts is refactored.
2
+ * Built-in provider stream dispatch with shared error, cancellation, and timeout handling.
12
3
  */
13
4
 
14
5
  import type { CompatOf } from "@oh-my-pi/pi-catalog/types";
15
6
  import * as AIError from "../error";
16
- import type {
17
- Api,
18
- AssistantMessage,
19
- AssistantMessageEvent,
20
- AssistantMessageEventStream,
21
- Context,
22
- Model,
23
- OptionsForApi,
24
- } from "../types";
7
+ import type { Api, AssistantMessage, AssistantMessageEvent, Context, Model, OptionsForApi } from "../types";
25
8
  import { type AbortSourceTracker, createAbortSourceTracker } from "../utils/abort";
26
9
  import { AssistantMessageEventStream as EventStreamImpl } from "../utils/event-stream";
27
10
  import {
@@ -31,156 +14,44 @@ import {
31
14
  getStreamIdleTimeoutMs,
32
15
  iterateWithIdleTimeout,
33
16
  } from "../utils/idle-iterator";
34
- import type { BedrockOptions } from "./amazon-bedrock";
35
- import type { AnthropicOptions } from "./anthropic";
36
- import type { AzureOpenAIResponsesOptions } from "./azure-openai-responses";
37
- import type { CursorOptions } from "./cursor";
38
- import type { DevinOptions } from "./devin";
39
- import type { GoogleOptions } from "./google";
40
- import type { GoogleGeminiCliOptions } from "./google-gemini-cli";
41
- import type { GoogleVertexOptions } from "./google-vertex";
42
- import type { OllamaChatOptions } from "./ollama";
43
- import type { OpenAICodexResponsesOptions } from "./openai-codex-responses";
44
- import type { OpenAICompletionsOptions } from "./openai-completions";
45
- import type { OpenAIResponsesOptions } from "./openai-responses";
46
-
47
- // ---------------------------------------------------------------------------
48
- // Lazy provider module shape
49
- // ---------------------------------------------------------------------------
50
-
51
- interface LazyProviderModule<TApi extends Api> {
52
- stream: (model: Model<TApi>, context: Context, options: OptionsForApi<TApi>) => AsyncIterable<AssistantMessageEvent>;
53
- }
54
-
55
- interface AnthropicProviderModule {
56
- streamAnthropic: (
57
- model: Model<"anthropic-messages">,
58
- context: Context,
59
- options: AnthropicOptions,
60
- ) => AssistantMessageEventStream;
61
- }
62
-
63
- interface AzureOpenAIResponsesProviderModule {
64
- streamAzureOpenAIResponses: (
65
- model: Model<"azure-openai-responses">,
66
- context: Context,
67
- options: AzureOpenAIResponsesOptions,
68
- ) => AssistantMessageEventStream;
69
- }
70
-
71
- interface GoogleProviderModule {
72
- streamGoogle: (
73
- model: Model<"google-generative-ai">,
74
- context: Context,
75
- options: GoogleOptions,
76
- ) => AssistantMessageEventStream;
77
- }
78
-
79
- interface GoogleGeminiCliProviderModule {
80
- streamGoogleGeminiCli: (
81
- model: Model<"google-gemini-cli">,
82
- context: Context,
83
- options: GoogleGeminiCliOptions,
84
- ) => AssistantMessageEventStream;
85
- }
86
-
87
- interface GoogleVertexProviderModule {
88
- streamGoogleVertex: (
89
- model: Model<"google-vertex">,
90
- context: Context,
91
- options: GoogleVertexOptions,
92
- ) => AssistantMessageEventStream;
93
- }
94
-
95
- interface OpenAICodexResponsesProviderModule {
96
- streamOpenAICodexResponses: (
97
- model: Model<"openai-codex-responses">,
98
- context: Context,
99
- options: OpenAICodexResponsesOptions,
100
- ) => AssistantMessageEventStream;
101
- }
102
-
103
- interface OpenAICompletionsProviderModule {
104
- streamOpenAICompletions: (
105
- model: Model<"openai-completions">,
106
- context: Context,
107
- options: OpenAICompletionsOptions,
108
- ) => AssistantMessageEventStream;
109
- }
110
-
111
- interface OpenAIResponsesProviderModule {
112
- streamOpenAIResponses: (
113
- model: Model<"openai-responses">,
114
- context: Context,
115
- options: OpenAIResponsesOptions,
116
- ) => AssistantMessageEventStream;
117
- }
118
-
119
- interface OllamaProviderModule {
120
- streamOllama: (
121
- model: Model<"ollama-chat">,
122
- context: Context,
123
- options: OllamaChatOptions,
124
- ) => AssistantMessageEventStream;
125
- }
126
-
127
- interface CursorProviderModule {
128
- streamCursor: (
129
- model: Model<"cursor-agent">,
130
- context: Context,
131
- options: CursorOptions,
132
- ) => AssistantMessageEventStream;
133
- }
134
-
135
- interface DevinProviderModule {
136
- streamDevin: (model: Model<"devin-agent">, context: Context, options: DevinOptions) => AssistantMessageEventStream;
137
- }
138
-
139
- interface BedrockProviderModule {
140
- streamBedrock: (
141
- model: Model<"bedrock-converse-stream">,
142
- context: Context,
143
- options: BedrockOptions,
144
- ) => AssistantMessageEventStream;
145
- }
146
-
147
- // ---------------------------------------------------------------------------
148
- // Module-level lazy promise caches
149
- // ---------------------------------------------------------------------------
17
+ import * as AnthropicProvider from "./anthropic";
18
+ import * as AzureOpenAIResponsesProvider from "./azure-openai-responses";
19
+ import * as BedrockProvider from "./amazon-bedrock";
20
+ import * as CursorProvider from "./cursor";
21
+ import * as DevinProvider from "./devin";
22
+ import * as GoogleProvider from "./google";
23
+ import * as GoogleGeminiCliProvider from "./google-gemini-cli";
24
+ import * as GoogleVertexProvider from "./google-vertex";
25
+ import * as OllamaProvider from "./ollama";
26
+ import * as OpenAICodexResponsesProvider from "./openai-codex-responses";
27
+ import * as OpenAICompletionsProvider from "./openai-completions";
28
+ import * as OpenAIResponsesProvider from "./openai-responses";
29
+
30
+ type ProviderStream<TApi extends Api> = (
31
+ model: Model<TApi>,
32
+ context: Context,
33
+ options: OptionsForApi<TApi>,
34
+ ) => AsyncIterable<AssistantMessageEvent>;
150
35
 
151
- let anthropicProviderModulePromise: Promise<LazyProviderModule<"anthropic-messages">> | undefined;
152
- let azureOpenAIResponsesProviderModulePromise: Promise<LazyProviderModule<"azure-openai-responses">> | undefined;
153
- let googleProviderModulePromise: Promise<LazyProviderModule<"google-generative-ai">> | undefined;
154
- let googleGeminiCliProviderModulePromise: Promise<LazyProviderModule<"google-gemini-cli">> | undefined;
155
- let googleVertexProviderModulePromise: Promise<LazyProviderModule<"google-vertex">> | undefined;
156
- let openAICodexResponsesProviderModulePromise: Promise<LazyProviderModule<"openai-codex-responses">> | undefined;
157
- let openAICompletionsProviderModulePromise: Promise<LazyProviderModule<"openai-completions">> | undefined;
158
- let openAIResponsesProviderModulePromise: Promise<LazyProviderModule<"openai-responses">> | undefined;
159
- let ollamaProviderModulePromise: Promise<LazyProviderModule<"ollama-chat">> | undefined;
160
- let cursorProviderModulePromise: Promise<LazyProviderModule<"cursor-agent">> | undefined;
161
- let cursorProviderModuleOverride: LazyProviderModule<"cursor-agent"> | undefined;
162
- let devinProviderModulePromise: Promise<LazyProviderModule<"devin-agent">> | undefined;
163
- let bedrockProviderModuleOverride: LazyProviderModule<"bedrock-converse-stream"> | undefined;
164
- let bedrockProviderModulePromise: Promise<LazyProviderModule<"bedrock-converse-stream">> | undefined;
36
+ let cursorStreamOverride: typeof CursorProvider.streamCursor | undefined;
37
+ let bedrockStreamOverride: typeof BedrockProvider.streamBedrock | undefined;
165
38
 
166
- export function setBedrockProviderModule(module: BedrockProviderModule): void {
167
- bedrockProviderModuleOverride = {
168
- stream: module.streamBedrock,
169
- };
39
+ /** Install a host-supplied Bedrock transport in place of the built-in provider. */
40
+ export function setBedrockProviderModule(module: Pick<typeof BedrockProvider, "streamBedrock">): void {
41
+ bedrockStreamOverride = module.streamBedrock;
170
42
  }
171
43
 
172
- export function setCursorProviderModule(module: CursorProviderModule): void {
173
- cursorProviderModuleOverride = {
174
- stream: module.streamCursor,
175
- };
44
+ /** Install a host-supplied Cursor transport in place of the built-in provider. */
45
+ export function setCursorProviderModule(module: Pick<typeof CursorProvider, "streamCursor">): void {
46
+ cursorStreamOverride = module.streamCursor;
176
47
  }
177
48
 
178
49
  // ---------------------------------------------------------------------------
179
50
  // Stream forwarding / error helpers
180
51
  // ---------------------------------------------------------------------------
181
52
 
182
- const LAZY_STREAM_IDLE_TIMEOUT_ERROR = "Provider stream stalled while waiting for the next event";
183
- const LAZY_STREAM_FIRST_EVENT_TIMEOUT_ERROR = "Provider stream timed out while waiting for the first event";
53
+ const STREAM_IDLE_TIMEOUT_ERROR = "Provider stream stalled while waiting for the next event";
54
+ const STREAM_FIRST_EVENT_TIMEOUT_ERROR = "Provider stream timed out while waiting for the first event";
184
55
 
185
56
  function hasFinalResult(
186
57
  source: AsyncIterable<AssistantMessageEvent>,
@@ -194,21 +65,21 @@ function hasFinalResult(
194
65
  * take precedence unless a provider opts into OpenAI-family idle flooring for
195
66
  * local backends that users historically tuned with `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS`.
196
67
  */
197
- interface LazyStreamLimits {
68
+ interface StreamLimits {
198
69
  defaultFirstEventTimeoutMs?: number;
199
70
  defaultIdleTimeoutMs?: number;
200
71
  /**
201
72
  * The provider implementation already wraps its upstream transport with
202
- * stream timeouts. Keep the lazy loader from racing it with generic errors.
73
+ * stream timeouts. Keep the shared watchdog from racing it with generic errors.
203
74
  */
204
75
  providerHandlesStreamTimeouts?: boolean;
205
76
  /**
206
77
  * The provider retries or fails over when no first event arrives, while the
207
- * lazy wrapper continues to own steady-state idle detection.
78
+ * shared wrapper continues to own steady-state idle detection.
208
79
  */
209
80
  providerHandlesFirstEventTimeouts?: boolean;
210
81
  /**
211
- * Apply OpenAI-family idle timeout precedence in the lazy wrapper. Used by
82
+ * Apply OpenAI-family idle timeout precedence in the shared wrapper. Used by
212
83
  * local backends whose users historically tune slow prompt-processing gaps
213
84
  * with `PI_OPENAI_STREAM_IDLE_TIMEOUT_MS`.
214
85
  */
@@ -217,18 +88,18 @@ interface LazyStreamLimits {
217
88
  /**
218
89
  * Cloud Code Assist owns first-event detection because Antigravity can return
219
90
  * successful headers and then never emit an SSE event. Keeping the watchdog in
220
- * the provider lets it fail over before surfacing an error; the lazy wrapper
91
+ * the provider lets it fail over before surfacing an error; the shared wrapper
221
92
  * still catches post-first-event stalls.
222
93
  */
223
- const GOOGLE_GEMINI_CLI_LAZY_STREAM_LIMITS: LazyStreamLimits = {
94
+ const GOOGLE_GEMINI_CLI_STREAM_LIMITS: StreamLimits = {
224
95
  providerHandlesFirstEventTimeouts: true,
225
96
  };
226
97
 
227
- const PROVIDER_HANDLED_STREAM_TIMEOUTS: LazyStreamLimits = {
98
+ const PROVIDER_HANDLED_STREAM_TIMEOUTS: StreamLimits = {
228
99
  providerHandlesStreamTimeouts: true,
229
100
  };
230
101
 
231
- const OPENAI_IDLE_FLOORED_LAZY_STREAM_LIMITS: LazyStreamLimits = {
102
+ const OPENAI_IDLE_FLOORED_STREAM_LIMITS: StreamLimits = {
232
103
  openAIIdleEnvFloorsFirstEvent: true,
233
104
  };
234
105
 
@@ -238,7 +109,7 @@ function forwardStream<TApi extends Api>(
238
109
  model: Model<TApi>,
239
110
  options: OptionsForApi<TApi>,
240
111
  abortTracker: AbortSourceTracker,
241
- limits?: LazyStreamLimits,
112
+ limits?: StreamLimits,
242
113
  ): void {
243
114
  (async () => {
244
115
  try {
@@ -275,11 +146,11 @@ function forwardStream<TApi extends Api>(
275
146
  const watchedSource = iterateWithIdleTimeout(source, {
276
147
  idleTimeoutMs,
277
148
  firstItemTimeoutMs,
278
- errorMessage: LAZY_STREAM_IDLE_TIMEOUT_ERROR,
279
- firstItemErrorMessage: LAZY_STREAM_FIRST_EVENT_TIMEOUT_ERROR,
280
- onIdle: () => abortTracker.abortLocally(new AIError.StreamTimeoutError(LAZY_STREAM_IDLE_TIMEOUT_ERROR)),
149
+ errorMessage: STREAM_IDLE_TIMEOUT_ERROR,
150
+ firstItemErrorMessage: STREAM_FIRST_EVENT_TIMEOUT_ERROR,
151
+ onIdle: () => abortTracker.abortLocally(new AIError.StreamTimeoutError(STREAM_IDLE_TIMEOUT_ERROR)),
281
152
  onFirstItemTimeout: () =>
282
- abortTracker.abortLocally(new AIError.StreamTimeoutError(LAZY_STREAM_FIRST_EVENT_TIMEOUT_ERROR)),
153
+ abortTracker.abortLocally(new AIError.StreamTimeoutError(STREAM_FIRST_EVENT_TIMEOUT_ERROR)),
283
154
  abortSignal: options.signal,
284
155
  // The synthetic `start` event is yielded immediately by every provider before
285
156
  // the upstream model has emitted any tokens. Treating it as the first "real"
@@ -300,14 +171,14 @@ function forwardStream<TApi extends Api>(
300
171
  }
301
172
  } catch (error) {
302
173
  const stopReason = abortTracker.wasCallerAbort() ? "aborted" : "error";
303
- const message = createLazyLoadErrorMessage(model, error, stopReason);
174
+ const message = createProviderStreamError(model, error, stopReason);
304
175
  target.push({ type: "error", reason: stopReason, error: message });
305
176
  target.end(message);
306
177
  }
307
178
  })();
308
179
  }
309
180
 
310
- function createLazyLoadErrorMessage<TApi extends Api>(
181
+ function createProviderStreamError<TApi extends Api>(
311
182
  model: Model<TApi>,
312
183
  error: unknown,
313
184
  stopReason: Extract<AssistantMessage["stopReason"], "aborted" | "error"> = "error",
@@ -335,173 +206,95 @@ function createLazyLoadErrorMessage<TApi extends Api>(
335
206
  }
336
207
 
337
208
  // ---------------------------------------------------------------------------
338
- // Generic lazy stream factory
209
+ // Provider stream wrapper
339
210
  // ---------------------------------------------------------------------------
340
211
 
341
- function createLazyStream<TApi extends Api>(
342
- loadModule: () => Promise<LazyProviderModule<TApi>>,
343
- limits?: LazyStreamLimits,
212
+ function createProviderStream<TApi extends Api>(
213
+ stream: ProviderStream<TApi>,
214
+ limits?: StreamLimits,
344
215
  ): (model: Model<TApi>, context: Context, options: OptionsForApi<TApi>) => EventStreamImpl {
345
216
  return (model, context, options) => {
346
217
  const outer = new EventStreamImpl();
347
- const streamOptions = (options ?? {}) as OptionsForApi<TApi>;
218
+ const streamOptions: OptionsForApi<TApi> = options ?? {};
348
219
 
349
- loadModule()
350
- .then(module => {
351
- const abortTracker = createAbortSourceTracker(streamOptions.signal);
352
- const providerOptions = { ...streamOptions, signal: abortTracker.requestSignal } as OptionsForApi<TApi>;
353
- const inner = module.stream(model, context, providerOptions);
354
- forwardStream(outer, inner, model, streamOptions, abortTracker, limits);
355
- })
356
- .catch(error => {
357
- const message = createLazyLoadErrorMessage(model, error);
358
- outer.push({ type: "error", reason: "error", error: message });
359
- outer.end(message);
360
- });
220
+ try {
221
+ const abortTracker = createAbortSourceTracker(streamOptions.signal);
222
+ const providerOptions: OptionsForApi<TApi> = { ...streamOptions, signal: abortTracker.requestSignal };
223
+ const inner = stream(model, context, providerOptions);
224
+ forwardStream(outer, inner, model, streamOptions, abortTracker, limits);
225
+ } catch (error) {
226
+ const message = createProviderStreamError(model, error);
227
+ outer.push({ type: "error", reason: "error", error: message });
228
+ outer.end(message);
229
+ }
361
230
 
362
231
  return outer;
363
232
  };
364
233
  }
365
234
 
366
- // ---------------------------------------------------------------------------
367
- // Module loaders (one per provider, cached via ||=)
368
- // ---------------------------------------------------------------------------
369
-
370
- function loadAnthropicProviderModule(): Promise<LazyProviderModule<"anthropic-messages">> {
371
- anthropicProviderModulePromise ||= import("./anthropic").then(module => {
372
- const provider = module as AnthropicProviderModule;
373
- return { stream: provider.streamAnthropic };
374
- });
375
- return anthropicProviderModulePromise;
376
- }
377
-
378
- function loadAzureOpenAIResponsesProviderModule(): Promise<LazyProviderModule<"azure-openai-responses">> {
379
- azureOpenAIResponsesProviderModulePromise ||= import("./azure-openai-responses").then(module => {
380
- const provider = module as AzureOpenAIResponsesProviderModule;
381
- return { stream: provider.streamAzureOpenAIResponses };
382
- });
383
- return azureOpenAIResponsesProviderModulePromise;
384
- }
385
-
386
- function loadGoogleProviderModule(): Promise<LazyProviderModule<"google-generative-ai">> {
387
- googleProviderModulePromise ||= import("./google").then(module => {
388
- const provider = module as GoogleProviderModule;
389
- return { stream: provider.streamGoogle };
390
- });
391
- return googleProviderModulePromise;
392
- }
393
-
394
- function loadGoogleGeminiCliProviderModule(): Promise<LazyProviderModule<"google-gemini-cli">> {
395
- googleGeminiCliProviderModulePromise ||= import("./google-gemini-cli").then(module => {
396
- const provider = module as GoogleGeminiCliProviderModule;
397
- return { stream: provider.streamGoogleGeminiCli };
398
- });
399
- return googleGeminiCliProviderModulePromise;
400
- }
401
-
402
- function loadGoogleVertexProviderModule(): Promise<LazyProviderModule<"google-vertex">> {
403
- googleVertexProviderModulePromise ||= import("./google-vertex").then(module => {
404
- const provider = module as GoogleVertexProviderModule;
405
- return { stream: provider.streamGoogleVertex };
406
- });
407
- return googleVertexProviderModulePromise;
408
- }
409
-
410
- function loadOpenAICodexResponsesProviderModule(): Promise<LazyProviderModule<"openai-codex-responses">> {
411
- openAICodexResponsesProviderModulePromise ||= import("./openai-codex-responses").then(module => {
412
- const provider = module as OpenAICodexResponsesProviderModule;
413
- return { stream: provider.streamOpenAICodexResponses };
414
- });
415
- return openAICodexResponsesProviderModulePromise;
416
- }
417
-
418
- function loadOpenAICompletionsProviderModule(): Promise<LazyProviderModule<"openai-completions">> {
419
- openAICompletionsProviderModulePromise ||= import("./openai-completions").then(module => {
420
- const provider = module as OpenAICompletionsProviderModule;
421
- return { stream: provider.streamOpenAICompletions };
422
- });
423
- return openAICompletionsProviderModulePromise;
424
- }
425
-
426
- function loadOpenAIResponsesProviderModule(): Promise<LazyProviderModule<"openai-responses">> {
427
- openAIResponsesProviderModulePromise ||= import("./openai-responses").then(module => {
428
- const provider = module as OpenAIResponsesProviderModule;
429
- return { stream: provider.streamOpenAIResponses };
430
- });
431
- return openAIResponsesProviderModulePromise;
432
- }
433
-
434
- function loadOllamaProviderModule(): Promise<LazyProviderModule<"ollama-chat">> {
435
- ollamaProviderModulePromise ||= import("./ollama").then(module => {
436
- const provider = module as OllamaProviderModule;
437
- return { stream: provider.streamOllama };
438
- });
439
- return ollamaProviderModulePromise;
440
- }
235
+ /** Stream Anthropic responses with provider-owned timeout handling. */
236
+ export const streamAnthropic = createProviderStream<"anthropic-messages">(
237
+ (model, context, options) => AnthropicProvider.streamAnthropic(model, context, options),
238
+ PROVIDER_HANDLED_STREAM_TIMEOUTS,
239
+ );
441
240
 
442
- function loadCursorProviderModule(): Promise<LazyProviderModule<"cursor-agent">> {
443
- if (cursorProviderModuleOverride) {
444
- return Promise.resolve(cursorProviderModuleOverride);
445
- }
446
- cursorProviderModulePromise ||= import("./cursor").then(module => {
447
- const provider = module as CursorProviderModule;
448
- return { stream: provider.streamCursor };
449
- });
450
- return cursorProviderModulePromise;
451
- }
241
+ /** Stream Azure Responses with provider-owned timeout handling. */
242
+ export const streamAzureOpenAIResponses = createProviderStream<"azure-openai-responses">(
243
+ (model, context, options) => AzureOpenAIResponsesProvider.streamAzureOpenAIResponses(model, context, options),
244
+ PROVIDER_HANDLED_STREAM_TIMEOUTS,
245
+ );
452
246
 
453
- function loadDevinProviderModule(): Promise<LazyProviderModule<"devin-agent">> {
454
- devinProviderModulePromise ||= import("./devin").then(module => {
455
- const provider = module as DevinProviderModule;
456
- return { stream: provider.streamDevin };
457
- });
458
- return devinProviderModulePromise;
459
- }
247
+ /** Stream Google's direct API through the shared watchdog. */
248
+ export const streamGoogle = createProviderStream<"google-generative-ai">((model, context, options) =>
249
+ GoogleProvider.streamGoogle(model, context, options),
250
+ );
460
251
 
461
- function loadBedrockProviderModule(): Promise<LazyProviderModule<"bedrock-converse-stream">> {
462
- if (bedrockProviderModuleOverride) {
463
- return Promise.resolve(bedrockProviderModuleOverride);
464
- }
465
- bedrockProviderModulePromise ||= import("./amazon-bedrock").then(module => {
466
- const provider = module as BedrockProviderModule;
467
- return { stream: provider.streamBedrock };
468
- });
469
- return bedrockProviderModulePromise;
470
- }
252
+ /** Stream Cloud Code Assist while retaining its first-event watchdog. */
253
+ export const streamGoogleGeminiCli = createProviderStream<"google-gemini-cli">(
254
+ (model, context, options) => GoogleGeminiCliProvider.streamGoogleGeminiCli(model, context, options),
255
+ GOOGLE_GEMINI_CLI_STREAM_LIMITS,
256
+ );
471
257
 
472
- // ---------------------------------------------------------------------------
473
- // Lazy stream function exports
474
- //
475
- // These use the same names as the direct provider stream functions. When
476
- // stream.ts is updated to import from this module instead of individual
477
- // providers, the lazy loading will take effect on the main code path.
478
- // ---------------------------------------------------------------------------
258
+ /** Stream the Vertex API through the shared watchdog. */
259
+ export const streamGoogleVertex = createProviderStream<"google-vertex">((model, context, options) =>
260
+ GoogleVertexProvider.streamGoogleVertex(model, context, options),
261
+ );
479
262
 
480
- export const streamAnthropic = createLazyStream(loadAnthropicProviderModule, PROVIDER_HANDLED_STREAM_TIMEOUTS);
481
- export const streamAzureOpenAIResponses = createLazyStream(
482
- loadAzureOpenAIResponsesProviderModule,
263
+ /** Stream Codex with provider-owned timeout handling. */
264
+ export const streamOpenAICodexResponses = createProviderStream<"openai-codex-responses">(
265
+ (model, context, options) => OpenAICodexResponsesProvider.streamOpenAICodexResponses(model, context, options),
483
266
  PROVIDER_HANDLED_STREAM_TIMEOUTS,
484
267
  );
485
- export const streamGoogle = createLazyStream(loadGoogleProviderModule);
486
- export const streamGoogleGeminiCli = createLazyStream(
487
- loadGoogleGeminiCliProviderModule,
488
- GOOGLE_GEMINI_CLI_LAZY_STREAM_LIMITS,
489
- );
490
- export const streamGoogleVertex = createLazyStream(loadGoogleVertexProviderModule);
491
- export const streamOpenAICodexResponses = createLazyStream(
492
- loadOpenAICodexResponsesProviderModule,
268
+
269
+ /** Stream Chat Completions with provider-owned timeout handling. */
270
+ export const streamOpenAICompletions = createProviderStream<"openai-completions">(
271
+ (model, context, options) => OpenAICompletionsProvider.streamOpenAICompletions(model, context, options),
493
272
  PROVIDER_HANDLED_STREAM_TIMEOUTS,
494
273
  );
495
- export const streamOpenAICompletions = createLazyStream(
496
- loadOpenAICompletionsProviderModule,
274
+
275
+ /** Stream Responses with provider-owned timeout handling. */
276
+ export const streamOpenAIResponses = createProviderStream<"openai-responses">(
277
+ (model, context, options) => OpenAIResponsesProvider.streamOpenAIResponses(model, context, options),
497
278
  PROVIDER_HANDLED_STREAM_TIMEOUTS,
498
279
  );
499
- export const streamOpenAIResponses = createLazyStream(
500
- loadOpenAIResponsesProviderModule,
501
- PROVIDER_HANDLED_STREAM_TIMEOUTS,
280
+
281
+ /** Stream through the host Cursor transport when installed, otherwise the built-in transport. */
282
+ export const streamCursor = createProviderStream<"cursor-agent">((model, context, options) =>
283
+ (cursorStreamOverride ?? CursorProvider.streamCursor)(model, context, options),
502
284
  );
503
- export const streamCursor = createLazyStream(loadCursorProviderModule);
504
- export const streamDevin = createLazyStream(loadDevinProviderModule);
505
- export const streamOllama = createLazyStream(loadOllamaProviderModule, OPENAI_IDLE_FLOORED_LAZY_STREAM_LIMITS);
506
285
 
507
- export const streamBedrock = createLazyStream(loadBedrockProviderModule);
286
+ /** Stream Devin through the shared watchdog. */
287
+ export const streamDevin = createProviderStream<"devin-agent">((model, context, options) =>
288
+ DevinProvider.streamDevin(model, context, options),
289
+ );
290
+
291
+ /** Stream Ollama with OpenAI-compatible idle timeout precedence. */
292
+ export const streamOllama = createProviderStream<"ollama-chat">(
293
+ (model, context, options) => OllamaProvider.streamOllama(model, context, options),
294
+ OPENAI_IDLE_FLOORED_STREAM_LIMITS,
295
+ );
296
+
297
+ /** Stream through the host Bedrock transport when installed, otherwise the built-in transport. */
298
+ export const streamBedrock = createProviderStream<"bedrock-converse-stream">((model, context, options) =>
299
+ (bedrockStreamOverride ?? BedrockProvider.streamBedrock)(model, context, options),
300
+ );
@@ -8,7 +8,7 @@
8
8
  * @see https://dev.synthetic.new/docs/api/overview
9
9
  */
10
10
 
11
- import type { Api, Context, Model } from "../types";
11
+ import type { Context, Model } from "../types";
12
12
  import type { AssistantMessageEventStream } from "../utils/event-stream";
13
13
  import {
14
14
  type OpenAIAnthropicApiFormat,
@@ -41,10 +41,3 @@ export function streamSynthetic(
41
41
  defaultFormat: "openai",
42
42
  });
43
43
  }
44
-
45
- /**
46
- * Check if a model is a Synthetic model.
47
- */
48
- export function isSyntheticModel(model: Model<Api>): boolean {
49
- return model.provider === "synthetic";
50
- }
@@ -8,8 +8,8 @@ import {
8
8
  parseCloudflareAiGatewayCredential,
9
9
  } from "@oh-my-pi/pi-catalog/wire/cloudflare-ai-gateway";
10
10
  import { $env } from "@oh-my-pi/pi-utils";
11
+ import { NO_AUTH_SENTINEL } from "../auth-retry";
11
12
  import * as AIError from "../error";
12
- import { NO_AUTH_SENTINEL } from "../providers/openai-shared";
13
13
  import type { ProviderTransport } from "./build";
14
14
 
15
15
  /** Cloudflare AI Gateway model/request shaping; login lives in `oauth/cloudflare-ai-gateway.ts` + its auth rule. */
package/src/stream.ts CHANGED
@@ -26,24 +26,17 @@ import type { AnthropicOptions } from "./providers/anthropic";
26
26
  import type { MessageCreateParamsStreaming } from "./providers/anthropic-wire";
27
27
  import type { CursorOptions } from "./providers/cursor";
28
28
  import type { DevinOptions } from "./providers/devin";
29
- import { isGitLabDuoModel, streamGitLabDuo } from "./providers/gitlab-duo";
29
+ import { streamGitLabDuo } from "./providers/gitlab-duo";
30
30
  import { type GitLabDuoWorkflowOptions, streamGitLabDuoWorkflow } from "./providers/gitlab-duo-workflow";
31
31
  import type { GoogleOptions } from "./providers/google";
32
32
  import { getVertexAccessToken } from "./providers/google-auth";
33
33
  import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
34
34
  import type { GoogleVertexOptions } from "./providers/google-vertex";
35
- import { isKimiModel, streamKimi } from "./providers/kimi";
35
+ import { streamKimi } from "./providers/kimi";
36
36
  import type { OllamaChatOptions } from "./providers/ollama";
37
37
  import type { OpenAICompletionsOptions } from "./providers/openai-completions";
38
38
  import { streamPiNative } from "./providers/pi-native-client";
39
- // Heavy provider stream functions are imported lazily via register-builtins,
40
- // which wraps each provider module in a dynamic import. This keeps the
41
- // AWS SDK, google-auth-library, @google/genai, and
42
- // other provider SDKs out of the CLI startup parse graph. The
43
- // gitlab-duo / kimi / synthetic providers stay eager because their modules
44
- // export routing predicates (isGitLabDuoModel, isKimiModel, isSyntheticModel)
45
- // that must be callable synchronously before streaming begins, and their
46
- // modules are thin wrappers with no heavy SDK dependencies.
39
+ import { streamSynthetic } from "./providers/synthetic";
47
40
  import {
48
41
  streamAnthropic,
49
42
  streamAzureOpenAIResponses,
@@ -58,7 +51,6 @@ import {
58
51
  streamOpenAICompletions,
59
52
  streamOpenAIResponses,
60
53
  } from "./providers/register-builtins";
61
- import { isSyntheticModel, streamSynthetic } from "./providers/synthetic";
62
54
  import { getProviderDefinition, PROVIDER_REGISTRY } from "./registry";
63
55
  import type {
64
56
  Api,
@@ -953,7 +945,7 @@ function streamDispatch<TApi extends Api>(
953
945
  return customApiProvider.stream(model, context, requestOptions as StreamOptions);
954
946
  }
955
947
 
956
- if (isGitLabDuoModel(model)) {
948
+ if (model.provider === "gitlab-duo") {
957
949
  const apiKey = requestOptions.apiKey || getEnvApiKey(model.provider);
958
950
  if (!apiKey) {
959
951
  throw new AIError.MissingApiKeyError(model.provider);
@@ -1725,7 +1717,7 @@ function streamSimpleRequest<TApi extends Api>(
1725
1717
  }
1726
1718
 
1727
1719
  // GitLab Duo - wraps Anthropic/OpenAI behind GitLab AI Gateway direct access tokens
1728
- if (isGitLabDuoModel(model)) {
1720
+ if (model.provider === "gitlab-duo") {
1729
1721
  return withThinkingLoopGuard(model, requestOptions, opts =>
1730
1722
  withProviderInFlightLimit(model, opts, () =>
1731
1723
  streamGitLabDuo(model, context, {
@@ -1751,7 +1743,7 @@ function streamSimpleRequest<TApi extends Api>(
1751
1743
  }
1752
1744
 
1753
1745
  // Kimi Code - route to dedicated handler that wraps OpenAI or Anthropic API
1754
- if (isKimiModel(model)) {
1746
+ if (model.provider === "kimi-code") {
1755
1747
  // streamKimi handles openai/anthropic format mapping internally, but the
1756
1748
  // mandatory-reasoning clamp is a request-shaping concern owned here: K3's
1757
1749
  // `supports_thinking_type: "only"` endpoint rejects disabled/omitted
@@ -1770,7 +1762,7 @@ function streamSimpleRequest<TApi extends Api>(
1770
1762
  }
1771
1763
 
1772
1764
  // Synthetic - route to dedicated handler that wraps OpenAI or Anthropic API
1773
- if (isSyntheticModel(model)) {
1765
+ if (model.provider === "synthetic") {
1774
1766
  // Pass raw SimpleStreamOptions - streamSynthetic handles mapping internally.
1775
1767
  return withThinkingLoopGuard(model, requestOptions, opts =>
1776
1768
  withProviderInFlightLimit(model, opts, () =>