@gajae-code/ai 0.15.4 → 0.15.6
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/CHANGELOG.md +27 -1
- package/dist/types/auth-broker/client.d.ts +6 -2
- package/dist/types/auth-broker/remote-store.d.ts +14 -2
- package/dist/types/auth-broker/types.d.ts +6 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +19 -0
- package/dist/types/auth-gateway/server.d.ts +39 -5
- package/dist/types/auth-gateway/types.d.ts +16 -2
- package/dist/types/auth-storage.d.ts +116 -34
- package/dist/types/provider-models/openai-compat.d.ts +1 -0
- package/dist/types/provider-models/special.d.ts +2 -1
- package/dist/types/providers/kiro-api-key.d.ts +50 -0
- package/dist/types/providers/kiro-codewhisperer.d.ts +3 -0
- package/dist/types/providers/register-builtins.d.ts +12 -12
- package/dist/types/stream.d.ts +2 -1
- package/dist/types/types.d.ts +35 -24
- package/dist/types/utils/fallback-transport.d.ts +7 -0
- package/dist/types/utils/json-parse.d.ts +5 -3
- package/dist/types/utils/oauth/api-key-login.d.ts +4 -1
- package/dist/types/utils/oauth/api-key-validation.d.ts +12 -6
- package/dist/types/utils/oauth/commandcode.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/dist/types/utils/retry.d.ts +2 -0
- package/dist/types/utils/tool-call-healing.d.ts +4 -4
- package/package.json +3 -3
- package/src/auth-broker/client.ts +41 -13
- package/src/auth-broker/redact.ts +25 -1
- package/src/auth-broker/remote-store.ts +374 -115
- package/src/auth-broker/server.ts +131 -91
- package/src/auth-broker/types.ts +6 -0
- package/src/auth-broker/wire-schemas.ts +6 -0
- package/src/auth-gateway/server.ts +447 -79
- package/src/auth-gateway/types.ts +28 -2
- package/src/auth-storage.ts +742 -157
- package/src/cli.ts +1 -0
- package/src/model-thinking.ts +16 -0
- package/src/models.json +1054 -0
- package/src/models.ts +9 -1
- package/src/provider-models/descriptors.ts +3 -1
- package/src/provider-models/openai-compat.ts +41 -1
- package/src/provider-models/special.ts +15 -3
- package/src/providers/anthropic.ts +7 -1
- package/src/providers/azure-openai-responses.ts +4 -1
- package/src/providers/cursor.ts +256 -101
- package/src/providers/gitlab-duo.ts +18 -1
- package/src/providers/google-gemini-cli.ts +3 -0
- package/src/providers/google-shared.ts +3 -0
- package/src/providers/kiro-api-key.d.ts +50 -0
- package/src/providers/kiro-api-key.ts +786 -0
- package/src/providers/kiro-codewhisperer.d.ts +3 -0
- package/src/providers/kiro-codewhisperer.ts +34 -9
- package/src/providers/ollama.ts +3 -0
- package/src/providers/openai-codex-responses.ts +24 -6
- package/src/providers/openai-completions.ts +11 -1
- package/src/providers/openai-responses-shared.ts +23 -2
- package/src/providers/openai-responses.ts +10 -1
- package/src/providers/pi-native-client.ts +1 -0
- package/src/providers/pi-native-server.ts +24 -0
- package/src/providers/register-builtins.d.ts +12 -12
- package/src/providers/register-builtins.ts +16 -3
- package/src/stream.d.ts +2 -1
- package/src/stream.ts +180 -70
- package/src/types.d.ts +35 -24
- package/src/types.ts +40 -23
- package/src/utils/fallback-transport.d.ts +7 -0
- package/src/utils/fallback-transport.ts +21 -4
- package/src/utils/json-parse.d.ts +5 -3
- package/src/utils/json-parse.ts +6 -6
- package/src/utils/oauth/api-key-login.ts +13 -2
- package/src/utils/oauth/api-key-validation.ts +242 -41
- package/src/utils/oauth/commandcode.ts +17 -0
- package/src/utils/oauth/index.ts +20 -5
- package/src/utils/oauth/types.d.ts +1 -1
- package/src/utils/oauth/types.ts +1 -0
- package/src/utils/retry.d.ts +2 -0
- package/src/utils/retry.ts +15 -2
- package/src/utils/tool-call-healing.d.ts +4 -4
- package/src/utils/tool-call-healing.ts +4 -4
package/src/stream.ts
CHANGED
|
@@ -67,6 +67,7 @@ import type {
|
|
|
67
67
|
Api,
|
|
68
68
|
AssistantMessage,
|
|
69
69
|
AssistantMessageEvent,
|
|
70
|
+
AuthRetryCredential,
|
|
70
71
|
Context,
|
|
71
72
|
Model,
|
|
72
73
|
OptionsForApi,
|
|
@@ -115,6 +116,7 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
115
116
|
mistral: "MISTRAL_API_KEY",
|
|
116
117
|
minimax: "MINIMAX_API_KEY",
|
|
117
118
|
"minimax-code": "MINIMAX_CODE_API_KEY",
|
|
119
|
+
"commandcode-goat": "CMD_API_KEY",
|
|
118
120
|
"minimax-code-cn": "MINIMAX_CODE_CN_API_KEY",
|
|
119
121
|
"opencode-go": "OPENCODE_API_KEY",
|
|
120
122
|
"opencode-zen": "OPENCODE_API_KEY",
|
|
@@ -131,10 +133,12 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
131
133
|
tavily: "TAVILY_API_KEY",
|
|
132
134
|
parallel: "PARALLEL_API_KEY",
|
|
133
135
|
kagi: "KAGI_API_KEY",
|
|
134
|
-
// Kiro
|
|
136
|
+
// Kiro API keys use the ksk_ prefix; preserve the AWS bearer fallback for OAuth.
|
|
135
137
|
kiro: () => {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
+
const apiKey = $credentialEnv("KIRO_API_KEY");
|
|
139
|
+
return apiKey?.trim().startsWith("ksk_") && !/[\x00-\x1f\x7f]/.test(apiKey)
|
|
140
|
+
? apiKey
|
|
141
|
+
: $credentialEnv("AWS_BEARER_TOKEN_KIRO");
|
|
138
142
|
},
|
|
139
143
|
// GitHub Copilot uses GitHub personal access token
|
|
140
144
|
"github-copilot": () => $pickCredentialEnv("COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"),
|
|
@@ -219,6 +223,7 @@ export function listProvidersWithEnvKey(): string[] {
|
|
|
219
223
|
* Used to give OpenCode users an accurate headless auth diagnostic (#755).
|
|
220
224
|
*/
|
|
221
225
|
const OPENCODE_SUBSCRIPTION_PROVIDERS = new Set(["opencode-go", "opencode-zen"]);
|
|
226
|
+
const API_KEY_LOGIN_PROVIDERS = new Set(["commandcode-goat"]);
|
|
222
227
|
|
|
223
228
|
/**
|
|
224
229
|
* Provider-specific credential guidance appended to "no credential" errors.
|
|
@@ -237,12 +242,16 @@ export function formatProviderCredentialHint(provider: string): string {
|
|
|
237
242
|
const resolver = serviceProviderMap[provider];
|
|
238
243
|
const envVar = typeof resolver === "string" ? resolver : undefined;
|
|
239
244
|
const isOpenCodeSubscription = OPENCODE_SUBSCRIPTION_PROVIDERS.has(provider);
|
|
245
|
+
const isApiKeyLoginProvider = API_KEY_LOGIN_PROVIDERS.has(provider);
|
|
240
246
|
const parts: string[] = [];
|
|
241
247
|
if (isOpenCodeSubscription) {
|
|
242
248
|
parts.push(
|
|
243
249
|
"OpenCode subscriptions authenticate with an API key (created at https://opencode.ai/auth), not a separate session/OAuth token.",
|
|
244
250
|
);
|
|
245
251
|
}
|
|
252
|
+
if (isApiKeyLoginProvider) {
|
|
253
|
+
parts.push("Command Code GOAT uses an API key from https://commandcode.ai/studio/#api-keys.");
|
|
254
|
+
}
|
|
246
255
|
if (provider === "jetbrains-junie") {
|
|
247
256
|
parts.push(
|
|
248
257
|
"JetBrains AI (Junie) authenticates with an access token generated at https://junie.jetbrains.com/cli; there is no OAuth login for this provider.",
|
|
@@ -265,10 +274,18 @@ function pipeAssistantStream(
|
|
|
265
274
|
outer: AssistantMessageEventStream,
|
|
266
275
|
inner: AssistantMessageEventStream,
|
|
267
276
|
signal?: AbortSignal,
|
|
277
|
+
onStreamCreated?: () => void,
|
|
268
278
|
): void {
|
|
269
279
|
void (async () => {
|
|
270
280
|
try {
|
|
281
|
+
let admitted = false;
|
|
282
|
+
const markAdmission = (): void => {
|
|
283
|
+
if (admitted) return;
|
|
284
|
+
admitted = true;
|
|
285
|
+
onStreamCreated?.();
|
|
286
|
+
};
|
|
271
287
|
for await (const event of inner) {
|
|
288
|
+
if (event.type !== "start") markAdmission();
|
|
272
289
|
outer.push(event);
|
|
273
290
|
// The inner provider stream owns abort semantics (it receives the
|
|
274
291
|
// same signal), but stop forwarding as soon as the consumer
|
|
@@ -286,14 +303,16 @@ function pipeAssistantStream(
|
|
|
286
303
|
})();
|
|
287
304
|
}
|
|
288
305
|
|
|
289
|
-
function streamFromLazyImport(
|
|
306
|
+
export function streamFromLazyImport(
|
|
290
307
|
createInner: () => Promise<AssistantMessageEventStream>,
|
|
291
308
|
signal?: AbortSignal,
|
|
309
|
+
onStreamCreated?: () => void,
|
|
292
310
|
): AssistantMessageEventStream {
|
|
293
311
|
const outer = new AssistantMessageEventStream();
|
|
294
312
|
void (async () => {
|
|
295
313
|
try {
|
|
296
|
-
|
|
314
|
+
const inner = await createInner();
|
|
315
|
+
pipeAssistantStream(outer, inner, signal, onStreamCreated);
|
|
297
316
|
} catch (error) {
|
|
298
317
|
outer.fail(error);
|
|
299
318
|
}
|
|
@@ -315,6 +334,7 @@ export function stream<TApi extends Api>(
|
|
|
315
334
|
model: Model<TApi>,
|
|
316
335
|
context: Context,
|
|
317
336
|
options?: OptionsForApi<TApi>,
|
|
337
|
+
onStreamCreated?: () => void,
|
|
318
338
|
): AssistantMessageEventStream {
|
|
319
339
|
if (!hasValidatedManagedAttempt(options)) assertManagedAttempt(options);
|
|
320
340
|
if (options?.fallbackManaged) {
|
|
@@ -348,6 +368,7 @@ export function stream<TApi extends Api>(
|
|
|
348
368
|
return streamGitLabDuo(model, context, adapterOptions);
|
|
349
369
|
},
|
|
350
370
|
(options as StreamOptions | undefined)?.signal,
|
|
371
|
+
onStreamCreated,
|
|
351
372
|
);
|
|
352
373
|
}
|
|
353
374
|
|
|
@@ -360,15 +381,22 @@ export function stream<TApi extends Api>(
|
|
|
360
381
|
isProviderSafetyStopModelTrusted(model)
|
|
361
382
|
? withProviderSafetyStopAdapterInvocation(vertexOptions)
|
|
362
383
|
: vertexOptions,
|
|
384
|
+
onStreamCreated,
|
|
363
385
|
);
|
|
364
386
|
} else if (model.api === "bedrock-converse-stream") {
|
|
365
387
|
// Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
|
|
366
|
-
return streamBedrock(
|
|
388
|
+
return streamBedrock(
|
|
389
|
+
model as Model<"bedrock-converse-stream">,
|
|
390
|
+
context,
|
|
391
|
+
(options || {}) as BedrockOptions,
|
|
392
|
+
onStreamCreated,
|
|
393
|
+
);
|
|
367
394
|
} else if (model.api === "kiro-codewhisperer-stream") {
|
|
368
395
|
return streamKiroCodeWhisperer(
|
|
369
396
|
model as Model<"kiro-codewhisperer-stream">,
|
|
370
397
|
context,
|
|
371
398
|
(options || {}) as KiroCodeWhispererOptions,
|
|
399
|
+
onStreamCreated,
|
|
372
400
|
);
|
|
373
401
|
}
|
|
374
402
|
|
|
@@ -385,23 +413,39 @@ export function stream<TApi extends Api>(
|
|
|
385
413
|
switch (api) {
|
|
386
414
|
case "anthropic-messages": {
|
|
387
415
|
const anthropicOptions = adapterProviderOptions as AnthropicOptions;
|
|
388
|
-
return streamAnthropic(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
416
|
+
return streamAnthropic(
|
|
417
|
+
model as Model<"anthropic-messages">,
|
|
418
|
+
context,
|
|
419
|
+
{
|
|
420
|
+
...anthropicOptions,
|
|
421
|
+
isOAuth: anthropicOptions.isOAuth ?? model.isOAuth,
|
|
422
|
+
},
|
|
423
|
+
onStreamCreated,
|
|
424
|
+
);
|
|
392
425
|
}
|
|
393
426
|
|
|
394
427
|
case "openai-completions":
|
|
395
|
-
return streamOpenAICompletions(
|
|
428
|
+
return streamOpenAICompletions(
|
|
429
|
+
model as Model<"openai-completions">,
|
|
430
|
+
context,
|
|
431
|
+
adapterProviderOptions as any,
|
|
432
|
+
onStreamCreated,
|
|
433
|
+
);
|
|
396
434
|
|
|
397
435
|
case "openai-responses":
|
|
398
|
-
return streamOpenAIResponses(
|
|
436
|
+
return streamOpenAIResponses(
|
|
437
|
+
model as Model<"openai-responses">,
|
|
438
|
+
context,
|
|
439
|
+
adapterProviderOptions as any,
|
|
440
|
+
onStreamCreated,
|
|
441
|
+
);
|
|
399
442
|
|
|
400
443
|
case "azure-openai-responses":
|
|
401
444
|
return streamAzureOpenAIResponses(
|
|
402
445
|
model as Model<"azure-openai-responses">,
|
|
403
446
|
context,
|
|
404
447
|
adapterProviderOptions as any,
|
|
448
|
+
onStreamCreated,
|
|
405
449
|
);
|
|
406
450
|
|
|
407
451
|
case "openai-codex-responses":
|
|
@@ -409,23 +453,35 @@ export function stream<TApi extends Api>(
|
|
|
409
453
|
model as Model<"openai-codex-responses">,
|
|
410
454
|
context,
|
|
411
455
|
adapterProviderOptions as any,
|
|
456
|
+
onStreamCreated,
|
|
412
457
|
);
|
|
413
458
|
|
|
414
459
|
case "google-generative-ai":
|
|
415
|
-
return streamGoogle(model as Model<"google-generative-ai">, context, adapterProviderOptions);
|
|
460
|
+
return streamGoogle(model as Model<"google-generative-ai">, context, adapterProviderOptions, onStreamCreated);
|
|
416
461
|
|
|
417
462
|
case "google-gemini-cli":
|
|
418
463
|
return streamGoogleGeminiCli(
|
|
419
464
|
model as Model<"google-gemini-cli">,
|
|
420
465
|
context,
|
|
421
466
|
adapterProviderOptions as GoogleGeminiCliOptions,
|
|
467
|
+
onStreamCreated,
|
|
422
468
|
);
|
|
423
469
|
|
|
424
470
|
case "ollama-chat":
|
|
425
|
-
return streamOllama(
|
|
471
|
+
return streamOllama(
|
|
472
|
+
model as Model<"ollama-chat">,
|
|
473
|
+
context,
|
|
474
|
+
adapterProviderOptions as OllamaChatOptions,
|
|
475
|
+
onStreamCreated,
|
|
476
|
+
);
|
|
426
477
|
|
|
427
478
|
case "cursor-agent":
|
|
428
|
-
return streamCursor(
|
|
479
|
+
return streamCursor(
|
|
480
|
+
model as Model<"cursor-agent">,
|
|
481
|
+
context,
|
|
482
|
+
adapterProviderOptions as CursorOptions,
|
|
483
|
+
onStreamCreated,
|
|
484
|
+
);
|
|
429
485
|
|
|
430
486
|
default:
|
|
431
487
|
throw new Error(`Unhandled API: ${api}`);
|
|
@@ -537,9 +593,19 @@ export function streamSimple<TApi extends Api>(
|
|
|
537
593
|
? AbortSignal.any([options.signal, consumerAbortController.signal])
|
|
538
594
|
: consumerAbortController.signal;
|
|
539
595
|
const onAuthError = options!.onAuthError!;
|
|
540
|
-
const runAttempt = async (
|
|
596
|
+
const runAttempt = async (
|
|
597
|
+
apiKey: string,
|
|
598
|
+
captureAuthFailure: boolean,
|
|
599
|
+
onStreamCreated?: () => void,
|
|
600
|
+
): Promise<AuthRetryFailure | undefined> => {
|
|
541
601
|
const bufferedEvents: AssistantMessageEvent[] = [];
|
|
542
602
|
let emittedReplayUnsafeEvent = false;
|
|
603
|
+
let admitted = false;
|
|
604
|
+
const markAdmission = (): void => {
|
|
605
|
+
if (admitted) return;
|
|
606
|
+
admitted = true;
|
|
607
|
+
onStreamCreated?.();
|
|
608
|
+
};
|
|
543
609
|
const flushBuffered = (): void => {
|
|
544
610
|
emitBufferedEvents(outer, bufferedEvents);
|
|
545
611
|
bufferedEvents.length = 0;
|
|
@@ -550,6 +616,7 @@ export function streamSimple<TApi extends Api>(
|
|
|
550
616
|
...options,
|
|
551
617
|
apiKey,
|
|
552
618
|
onAuthError: undefined,
|
|
619
|
+
onStreamCreated: markAdmission,
|
|
553
620
|
signal: requestSignal,
|
|
554
621
|
});
|
|
555
622
|
for await (const event of inner) {
|
|
@@ -585,6 +652,12 @@ export function streamSimple<TApi extends Api>(
|
|
|
585
652
|
}
|
|
586
653
|
flushBuffered();
|
|
587
654
|
outer.fail(error);
|
|
655
|
+
} finally {
|
|
656
|
+
// A lazy import or a synchronous provider failure can happen before
|
|
657
|
+
// the admission hook is reached. Release that attempt's lease in
|
|
658
|
+
// the failure path without extending a successful request's lease
|
|
659
|
+
// through the response lifetime.
|
|
660
|
+
if (!admitted) markAdmission();
|
|
588
661
|
}
|
|
589
662
|
return undefined;
|
|
590
663
|
};
|
|
@@ -598,19 +671,22 @@ export function streamSimple<TApi extends Api>(
|
|
|
598
671
|
};
|
|
599
672
|
|
|
600
673
|
void (async () => {
|
|
601
|
-
const failure = await runAttempt(retryApiKey, true);
|
|
674
|
+
const failure = await runAttempt(retryApiKey, true, options?.onStreamCreated);
|
|
602
675
|
if (!failure) return;
|
|
603
|
-
let
|
|
676
|
+
let nextCredential: string | AuthRetryCredential | undefined;
|
|
604
677
|
try {
|
|
605
|
-
|
|
678
|
+
nextCredential = await onAuthError(model.provider, retryApiKey, failure.error);
|
|
606
679
|
} catch {
|
|
607
|
-
|
|
680
|
+
nextCredential = undefined;
|
|
608
681
|
}
|
|
609
|
-
|
|
682
|
+
const retryCredential: AuthRetryCredential | undefined =
|
|
683
|
+
typeof nextCredential === "string" ? { apiKey: nextCredential } : nextCredential;
|
|
684
|
+
if (!retryCredential?.apiKey || retryCredential.apiKey === retryApiKey) {
|
|
685
|
+
if (retryCredential) retryCredential.onStreamCreated?.();
|
|
610
686
|
emitFailure(failure);
|
|
611
687
|
return;
|
|
612
688
|
}
|
|
613
|
-
await runAttempt(
|
|
689
|
+
await runAttempt(retryCredential.apiKey, false, retryCredential.onStreamCreated);
|
|
614
690
|
})();
|
|
615
691
|
return outer;
|
|
616
692
|
}
|
|
@@ -623,26 +699,39 @@ export function streamSimple<TApi extends Api>(
|
|
|
623
699
|
// pi-native transport.
|
|
624
700
|
const resolvedRequestMaxTokens = resolveDefaultRequestMaxTokens(model, options?.maxTokens);
|
|
625
701
|
if (model.transport === "pi-native") {
|
|
626
|
-
return streamFromLazyImport(
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
702
|
+
return streamFromLazyImport(
|
|
703
|
+
async () => {
|
|
704
|
+
const { streamPiNative } = await import("./providers/pi-native-client");
|
|
705
|
+
return streamPiNative(model, context, { ...options, maxTokens: resolvedRequestMaxTokens });
|
|
706
|
+
},
|
|
707
|
+
options?.signal,
|
|
708
|
+
options?.onStreamCreated,
|
|
709
|
+
);
|
|
630
710
|
}
|
|
631
711
|
|
|
632
712
|
// Check custom API registry (extension-provided APIs)
|
|
633
713
|
const customApiProvider = getCustomApi(model.api);
|
|
634
714
|
if (customApiProvider) {
|
|
635
|
-
|
|
715
|
+
const events = customApiProvider.streamSimple(model, context, {
|
|
716
|
+
...options,
|
|
717
|
+
maxTokens: resolvedRequestMaxTokens,
|
|
718
|
+
});
|
|
719
|
+
if (!options?.onStreamCreated) return events;
|
|
720
|
+
const forwarded = new AssistantMessageEventStream();
|
|
721
|
+
pipeAssistantStream(forwarded, events, options.signal, options.onStreamCreated);
|
|
722
|
+
return forwarded;
|
|
636
723
|
}
|
|
637
724
|
|
|
638
725
|
// Vertex AI uses Application Default Credentials, not API keys
|
|
639
726
|
if (model.api === "google-vertex") {
|
|
640
727
|
const providerOptions = mapOptionsForApi(model, options, undefined);
|
|
641
|
-
|
|
728
|
+
const events = stream(model, context, providerOptions, options?.onStreamCreated);
|
|
729
|
+
return events;
|
|
642
730
|
} else if (model.api === "bedrock-converse-stream") {
|
|
643
731
|
// Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
|
|
644
732
|
const providerOptions = mapOptionsForApi(model, options, undefined);
|
|
645
|
-
|
|
733
|
+
const events = stream(model, context, providerOptions, options?.onStreamCreated);
|
|
734
|
+
return events;
|
|
646
735
|
}
|
|
647
736
|
|
|
648
737
|
const apiKey = options?.apiKey || getEnvApiKey(model.provider);
|
|
@@ -656,58 +745,71 @@ export function streamSimple<TApi extends Api>(
|
|
|
656
745
|
|
|
657
746
|
// GitLab Duo - wraps Anthropic/OpenAI behind GitLab AI Gateway direct access tokens
|
|
658
747
|
if (model.provider === "gitlab-duo") {
|
|
659
|
-
return streamFromLazyImport(
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
748
|
+
return streamFromLazyImport(
|
|
749
|
+
async () => {
|
|
750
|
+
const { streamGitLabDuo } = await import("./providers/gitlab-duo");
|
|
751
|
+
return streamGitLabDuo(
|
|
752
|
+
model,
|
|
753
|
+
context,
|
|
754
|
+
copyProviderSafetyStopAdapterInvocation(adapterOptions, {
|
|
755
|
+
...adapterOptions,
|
|
756
|
+
apiKey,
|
|
757
|
+
maxTokens: resolvedSpecialProviderMaxTokens,
|
|
758
|
+
}),
|
|
759
|
+
);
|
|
760
|
+
},
|
|
761
|
+
options?.signal,
|
|
762
|
+
options?.onStreamCreated,
|
|
763
|
+
);
|
|
671
764
|
}
|
|
672
765
|
|
|
673
766
|
// Kimi Code - route to dedicated handler that wraps OpenAI or Anthropic API
|
|
674
767
|
if (model.provider === "kimi-code") {
|
|
675
|
-
return streamFromLazyImport(
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
768
|
+
return streamFromLazyImport(
|
|
769
|
+
async () => {
|
|
770
|
+
const { streamKimi } = await import("./providers/kimi");
|
|
771
|
+
// Pass raw SimpleStreamOptions - streamKimi handles mapping internally
|
|
772
|
+
return streamKimi(
|
|
773
|
+
model as Model<"openai-completions">,
|
|
774
|
+
context,
|
|
775
|
+
copyProviderSafetyStopAdapterInvocation(adapterOptions, {
|
|
776
|
+
...adapterOptions,
|
|
777
|
+
apiKey,
|
|
778
|
+
maxTokens: resolvedSpecialProviderMaxTokens,
|
|
779
|
+
format: options?.kimiApiFormat ?? "anthropic",
|
|
780
|
+
}),
|
|
781
|
+
);
|
|
782
|
+
},
|
|
783
|
+
options?.signal,
|
|
784
|
+
options?.onStreamCreated,
|
|
785
|
+
);
|
|
689
786
|
}
|
|
690
787
|
|
|
691
788
|
// Synthetic - route to dedicated handler that wraps OpenAI or Anthropic API
|
|
692
789
|
if (model.provider === "synthetic") {
|
|
693
|
-
return streamFromLazyImport(
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
790
|
+
return streamFromLazyImport(
|
|
791
|
+
async () => {
|
|
792
|
+
const { streamSynthetic } = await import("./providers/synthetic");
|
|
793
|
+
// Pass raw SimpleStreamOptions - streamSynthetic handles mapping internally
|
|
794
|
+
return streamSynthetic(
|
|
795
|
+
model as Model<"openai-completions">,
|
|
796
|
+
context,
|
|
797
|
+
copyProviderSafetyStopAdapterInvocation(adapterOptions, {
|
|
798
|
+
...adapterOptions,
|
|
799
|
+
apiKey,
|
|
800
|
+
maxTokens: resolvedSpecialProviderMaxTokens,
|
|
801
|
+
format: options?.syntheticApiFormat ?? "openai", // Default to OpenAI format
|
|
802
|
+
}),
|
|
803
|
+
);
|
|
804
|
+
},
|
|
805
|
+
options?.signal,
|
|
806
|
+
options?.onStreamCreated,
|
|
807
|
+
);
|
|
707
808
|
}
|
|
708
809
|
|
|
709
810
|
const providerOptions = mapOptionsForApi(model, options, apiKey);
|
|
710
|
-
|
|
811
|
+
const events = stream(model, context, providerOptions, options?.onStreamCreated);
|
|
812
|
+
return events;
|
|
711
813
|
}
|
|
712
814
|
|
|
713
815
|
export async function completeSimple<TApi extends Api>(
|
|
@@ -856,6 +958,8 @@ function mapOptionsForApi<TApi extends Api>(
|
|
|
856
958
|
providerSessionState: options?.providerSessionState,
|
|
857
959
|
onPayload: options?.onPayload,
|
|
858
960
|
onResponse: options?.onResponse,
|
|
961
|
+
onStreamCreated: options?.onStreamCreated,
|
|
962
|
+
disableProviderRetries: options?.disableProviderRetries,
|
|
859
963
|
onSseEvent: options?.onSseEvent,
|
|
860
964
|
attemptScope: options?.attemptScope,
|
|
861
965
|
execHandlers: options?.execHandlers,
|
|
@@ -1160,6 +1264,12 @@ function mapOptionsForApi<TApi extends Api>(
|
|
|
1160
1264
|
});
|
|
1161
1265
|
}
|
|
1162
1266
|
|
|
1267
|
+
case "kiro-codewhisperer-stream":
|
|
1268
|
+
return castApi<"kiro-codewhisperer-stream">({
|
|
1269
|
+
...base,
|
|
1270
|
+
reasoning: options?.reasoning,
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1163
1273
|
default:
|
|
1164
1274
|
throw new Error(`Unhandled API in mapOptionsForApi: ${model.api}`);
|
|
1165
1275
|
}
|
package/src/types.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface ThinkingConfig {
|
|
|
54
54
|
/** Provider-specific transport used to encode the selected effort. */
|
|
55
55
|
mode: ThinkingControlMode;
|
|
56
56
|
}
|
|
57
|
-
export declare const KNOWN_PROVIDERS: readonly ["alibaba-token-plan", "amazon-bedrock", "kiro", "azure-openai", "anthropic", "google", "google-gemini-cli", "google-antigravity", "google-vertex", "openai", "openai-codex", "opencodex", "kimi-code", "minimax-code", "minimax-code-cn", "github-copilot", "fireworks", "firepass", "fugu", "gitlab-duo", "cursor", "jetbrains-junie", "deepseek", "deepinfra", "xai", "groq", "cerebras", "openrouter", "kilo", "vercel-ai-gateway", "zai", "glm-zcode", "mistral", "minimax", "opencode-go", "opencode-zen", "opengateway", "bizrouter", "mara", "synthetic", "cloudflare-ai-gateway", "huggingface", "litellm", "moonshot", "nvidia", "nanogpt", "ollama", "ollama-cloud", "qianfan", "qwen-portal", "sglang", "together", "venice", "vllm", "xiaomi", "xiaomi-token-plan-sgp", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "zenmux", "lm-studio", "omlx"];
|
|
57
|
+
export declare const KNOWN_PROVIDERS: readonly ["alibaba-token-plan", "amazon-bedrock", "kiro", "azure-openai", "anthropic", "google", "google-gemini-cli", "google-antigravity", "google-vertex", "openai", "openai-codex", "opencodex", "kimi-code", "minimax-code", "minimax-code-cn", "github-copilot", "fireworks", "firepass", "fugu", "gitlab-duo", "cursor", "jetbrains-junie", "deepseek", "deepinfra", "xai", "groq", "cerebras", "openrouter", "kilo", "vercel-ai-gateway", "zai", "glm-zcode", "mistral", "minimax", "opencode-go", "commandcode-goat", "opencode-zen", "opengateway", "bizrouter", "mara", "synthetic", "cloudflare-ai-gateway", "huggingface", "litellm", "moonshot", "nvidia", "nanogpt", "ollama", "ollama-cloud", "qianfan", "qwen-portal", "sglang", "together", "venice", "vllm", "xiaomi", "xiaomi-token-plan-sgp", "xiaomi-token-plan-ams", "xiaomi-token-plan-cn", "zenmux", "lm-studio", "omlx"];
|
|
58
58
|
export type KnownProvider = (typeof KNOWN_PROVIDERS)[number];
|
|
59
59
|
export declare function isKnownProvider(provider: string): provider is KnownProvider;
|
|
60
60
|
export type Provider = KnownProvider | string;
|
|
@@ -155,6 +155,18 @@ export interface RawSseEvent {
|
|
|
155
155
|
export type FetchImpl = ((input: string | URL | Request, init?: RequestInit) => Promise<Response>) & {
|
|
156
156
|
preconnect?: typeof globalThis.fetch.preconnect;
|
|
157
157
|
};
|
|
158
|
+
/**
|
|
159
|
+
* Credential returned by an auth retry resolver.
|
|
160
|
+
*
|
|
161
|
+
* The optional admission callback lets an authority-bearing caller retain a
|
|
162
|
+
* credential lease until the replacement provider request is actually
|
|
163
|
+
* admitted. Ordinary callers can continue returning a string from
|
|
164
|
+
* {@link StreamOptions.onAuthError}.
|
|
165
|
+
*/
|
|
166
|
+
export interface AuthRetryCredential {
|
|
167
|
+
apiKey: string;
|
|
168
|
+
onStreamCreated?: () => void;
|
|
169
|
+
}
|
|
158
170
|
export interface StreamOptions {
|
|
159
171
|
temperature?: number;
|
|
160
172
|
topP?: number;
|
|
@@ -186,7 +198,7 @@ export interface StreamOptions {
|
|
|
186
198
|
* event has been emitted. Returning a different key retries the provider
|
|
187
199
|
* request once.
|
|
188
200
|
*/
|
|
189
|
-
onAuthError?: (provider: string, apiKey: string, error: unknown) => Promise<string | undefined>;
|
|
201
|
+
onAuthError?: (provider: string, apiKey: string, error: unknown) => Promise<string | AuthRetryCredential | undefined>;
|
|
190
202
|
cacheRetention?: CacheRetention;
|
|
191
203
|
/**
|
|
192
204
|
* Additional headers to include in provider requests.
|
|
@@ -243,6 +255,14 @@ export interface StreamOptions {
|
|
|
243
255
|
* The `scope` parameter carries the per-attempt identity for execution attribution.
|
|
244
256
|
*/
|
|
245
257
|
onResponse?: (response: ProviderResponseMetadata, model?: Model<Api>, scope?: AttemptScopeRef) => void | Promise<void>;
|
|
258
|
+
/**
|
|
259
|
+
* Internal dispatch-admission hook. Providers invoke this immediately before
|
|
260
|
+
* submitting an outbound request; stream forwarding retains a first-response
|
|
261
|
+
* fallback for custom providers that do not expose a transport seam.
|
|
262
|
+
*/
|
|
263
|
+
onStreamCreated?: () => void;
|
|
264
|
+
/** Internal authority policy: disable provider-owned retries and corrective replays. */
|
|
265
|
+
disableProviderRetries?: boolean;
|
|
246
266
|
/**
|
|
247
267
|
* Optional callback for raw Server-Sent Events as they arrive from HTTP streaming providers.
|
|
248
268
|
*
|
|
@@ -399,31 +419,22 @@ export interface ToolCall {
|
|
|
399
419
|
*/
|
|
400
420
|
incompleteArgumentsReason?: "truncated" | "malformed" | "conflicting" | "ambiguous";
|
|
401
421
|
/**
|
|
402
|
-
* Set when
|
|
403
|
-
*
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* The agent loop
|
|
409
|
-
*
|
|
410
|
-
* is a tool that enumerated its display-only fields
|
|
411
|
-
* (`displaySafeEscapedArgFields`): when every escaped scalar corroborates
|
|
412
|
-
* a decoded non-ASCII character inside those fields, the call executes
|
|
413
|
-
* with a warning instead — rendered question text, never executable
|
|
414
|
-
* content, ids, or durable metadata.
|
|
415
|
-
* Escapes that are required (control characters) or unavoidable (lone
|
|
416
|
-
* surrogates) never set this.
|
|
422
|
+
* Set by current producers when raw argument JSON carries unsafe Unicode
|
|
423
|
+
* data, such as malformed escape evidence or a decoded unpaired surrogate.
|
|
424
|
+
* Valid JSON `\uXXXX` escapes are canonical spellings of the decoded string
|
|
425
|
+
* and current producers do not set this flag for them.
|
|
426
|
+
*
|
|
427
|
+
* Legacy producers may still set the flag for any escaped non-ASCII spelling.
|
|
428
|
+
* The agent loop keeps its bounded legacy resample/display-safe behavior for
|
|
429
|
+
* those calls while consuming the transient evidence below.
|
|
417
430
|
*/
|
|
418
431
|
escapedNonAsciiArguments?: boolean;
|
|
419
432
|
/**
|
|
420
|
-
* Bounded, payload-free evidence for
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
* `escapedNonAsciiArguments`. The agent consumes and removes this transient
|
|
426
|
-
* field before the tool-call message can become durable.
|
|
433
|
+
* Bounded, payload-free evidence for raw Unicode argument data. Current
|
|
434
|
+
* producers attach it only for unsafe data; legacy producers may attach
|
|
435
|
+
* non-malformed positional evidence used by the display-safe compatibility
|
|
436
|
+
* path. The agent consumes and removes this transient field before the
|
|
437
|
+
* tool-call message can become durable.
|
|
427
438
|
*/
|
|
428
439
|
escapedUnicodeArgumentEvidence?: UnicodeEscapeEvidence;
|
|
429
440
|
}
|