@gajae-code/ai 0.13.1 → 0.13.3
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 +18 -0
- package/dist/types/provider-models/special.d.ts +3 -0
- package/dist/types/providers/kiro-codewhisperer.d.ts +8 -0
- package/dist/types/providers/mock.d.ts +2 -0
- package/dist/types/providers/register-builtins.d.ts +1 -0
- package/dist/types/types.d.ts +14 -2
- package/dist/types/utils/json-parse.d.ts +19 -0
- package/dist/types/utils/oauth/kiro.d.ts +71 -0
- package/dist/types/utils/oauth/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/model-thinking.ts +24 -0
- package/src/models.json +7753 -1422
- package/src/openai-completions-compat.ts +2 -1
- package/src/provider-models/descriptors.ts +2 -0
- package/src/provider-models/special.ts +12 -0
- package/src/providers/anthropic.ts +17 -5
- package/src/providers/kiro-codewhisperer.ts +572 -0
- package/src/providers/mock.ts +3 -0
- package/src/providers/openai-completions.ts +4 -1
- package/src/providers/openai-responses-shared.ts +12 -4
- package/src/providers/register-builtins.ts +19 -0
- package/src/providers/transform-messages.ts +9 -2
- package/src/stream.ts +13 -0
- package/src/types.ts +15 -1
- package/src/utils/json-parse.ts +80 -0
- package/src/utils/oauth/index.ts +14 -1
- package/src/utils/oauth/kiro.ts +448 -0
- package/src/utils/oauth/synthetic.ts +2 -3
- package/src/utils/oauth/types.ts +1 -0
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
iterateWithIdleTimeout,
|
|
55
55
|
resolveOpenAISdkRequestTimeoutMs,
|
|
56
56
|
} from "../utils/idle-iterator";
|
|
57
|
-
import { isCompleteJson, parseStreamingJson } from "../utils/json-parse";
|
|
57
|
+
import { findUnnecessaryUnicodeEscape, isCompleteJson, parseStreamingJson } from "../utils/json-parse";
|
|
58
58
|
import { parseGitHubCopilotApiKey } from "../utils/oauth/github-copilot";
|
|
59
59
|
import { getKimiCommonHeaders } from "../utils/oauth/kimi";
|
|
60
60
|
import { notifyProviderResponse } from "../utils/provider-response";
|
|
@@ -676,6 +676,8 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
|
|
|
676
676
|
return;
|
|
677
677
|
}
|
|
678
678
|
block.arguments = parseStreamingJson(block.partialArgs);
|
|
679
|
+
// Raw-wire check: after decode the escape is invisible.
|
|
680
|
+
if (findUnnecessaryUnicodeEscape(block.partialArgs)) block.escapedNonAsciiArguments = true;
|
|
679
681
|
delete (block as { partialArgs?: string }).partialArgs;
|
|
680
682
|
stream.push({ type: "toolcall_end", contentIndex, toolCall: block, partial: output });
|
|
681
683
|
};
|
|
@@ -804,6 +806,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
|
|
|
804
806
|
partialArgs: call.arguments,
|
|
805
807
|
};
|
|
806
808
|
block.arguments = parseStreamingJson(call.arguments);
|
|
809
|
+
if (findUnnecessaryUnicodeEscape(call.arguments)) block.escapedNonAsciiArguments = true;
|
|
807
810
|
currentBlock = block;
|
|
808
811
|
output.content.push(block);
|
|
809
812
|
stream.push({ type: "toolcall_start", contentIndex: blockIndex(block), partial: output });
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
} from "../types";
|
|
31
31
|
import { normalizeResponsesToolCallId, sanitizeJsonStrings } from "../utils";
|
|
32
32
|
import type { AssistantMessageEventStream } from "../utils/event-stream";
|
|
33
|
-
import { isCompleteJson, parseStreamingJson } from "../utils/json-parse";
|
|
33
|
+
import { findUnnecessaryUnicodeEscape, isCompleteJson, parseStreamingJson } from "../utils/json-parse";
|
|
34
34
|
import { joinTextWithImagePlaceholder, NON_VISION_IMAGE_PLACEHOLDER, partitionVisionContent } from "./vision-guard";
|
|
35
35
|
|
|
36
36
|
const OPENAI_RESPONSES_PROGRESS_EVENT_TYPES = new Set([
|
|
@@ -735,20 +735,28 @@ export async function processResponsesStream<TApi extends Api>(
|
|
|
735
735
|
// Finalize onto the same block object stored in output.content, reading
|
|
736
736
|
// the matching entry's buffered partialJson first and only then the done
|
|
737
737
|
// item's arguments — never an adjacent item's buffer.
|
|
738
|
-
const
|
|
738
|
+
const rawArguments =
|
|
739
739
|
entry?.block.type === "toolCall" && entry.block.partialJson
|
|
740
|
-
?
|
|
741
|
-
:
|
|
740
|
+
? entry.block.partialJson
|
|
741
|
+
: item.arguments || "{}";
|
|
742
|
+
const args = parseStreamingJson(rawArguments);
|
|
743
|
+
// Detected on the raw wire text: after JSON decode an unnecessary
|
|
744
|
+
// `\uXXXX` escape is indistinguishable from legitimate literal UTF-8,
|
|
745
|
+
// so this is the only point where the defect is still observable.
|
|
746
|
+
const escapedNonAscii = findUnnecessaryUnicodeEscape(rawArguments) !== undefined;
|
|
742
747
|
const toolCall: ToolCall = {
|
|
743
748
|
type: "toolCall",
|
|
744
749
|
id: encodeResponsesToolCallId(item.call_id, item.id),
|
|
745
750
|
name: item.name,
|
|
746
751
|
arguments: args,
|
|
752
|
+
...(escapedNonAscii ? { escapedNonAsciiArguments: true } : {}),
|
|
747
753
|
};
|
|
748
754
|
if (entry?.block.type === "toolCall") {
|
|
749
755
|
entry.block.id = toolCall.id;
|
|
750
756
|
entry.block.name = toolCall.name;
|
|
751
757
|
entry.block.arguments = args;
|
|
758
|
+
if (escapedNonAscii) entry.block.escapedNonAsciiArguments = true;
|
|
759
|
+
else delete entry.block.escapedNonAsciiArguments;
|
|
752
760
|
}
|
|
753
761
|
const contentIndex = entry?.blockContentIndex ?? output.content.length - 1;
|
|
754
762
|
dropEntry(item.id, event.output_index);
|
|
@@ -37,6 +37,7 @@ import type { CursorOptions } from "./cursor";
|
|
|
37
37
|
import type { GoogleOptions } from "./google";
|
|
38
38
|
import type { GoogleGeminiCliOptions } from "./google-gemini-cli";
|
|
39
39
|
import type { GoogleVertexOptions } from "./google-vertex";
|
|
40
|
+
import type { KiroCodeWhispererOptions } from "./kiro-codewhisperer";
|
|
40
41
|
import type { OllamaChatOptions } from "./ollama";
|
|
41
42
|
import type { OpenAICodexResponsesOptions } from "./openai-codex-responses";
|
|
42
43
|
import type { OpenAICompletionsOptions } from "./openai-completions";
|
|
@@ -153,6 +154,14 @@ interface BedrockProviderModule {
|
|
|
153
154
|
) => AssistantMessageEventStream;
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
interface KiroCodeWhispererProviderModule {
|
|
158
|
+
streamKiroCodeWhisperer: (
|
|
159
|
+
model: Model<"kiro-codewhisperer-stream">,
|
|
160
|
+
context: Context,
|
|
161
|
+
options: KiroCodeWhispererOptions,
|
|
162
|
+
) => AssistantMessageEventStream;
|
|
163
|
+
}
|
|
164
|
+
|
|
156
165
|
// ---------------------------------------------------------------------------
|
|
157
166
|
// Module-level lazy promise caches
|
|
158
167
|
// ---------------------------------------------------------------------------
|
|
@@ -168,6 +177,7 @@ let openAIResponsesProviderModulePromise: Promise<LazyProviderModule<"openai-res
|
|
|
168
177
|
let ollamaProviderModulePromise: Promise<LazyProviderModule<"ollama-chat">> | undefined;
|
|
169
178
|
let cursorProviderModulePromise: Promise<LazyProviderModule<"cursor-agent">> | undefined;
|
|
170
179
|
let bedrockProviderModuleOverride: LazyProviderModule<"bedrock-converse-stream"> | undefined;
|
|
180
|
+
let kiroCodeWhispererProviderModulePromise: Promise<LazyProviderModule<"kiro-codewhisperer-stream">> | undefined;
|
|
171
181
|
let bedrockProviderModulePromise: Promise<LazyProviderModule<"bedrock-converse-stream">> | undefined;
|
|
172
182
|
|
|
173
183
|
export function setBedrockProviderModule(module: BedrockProviderModule): void {
|
|
@@ -443,6 +453,13 @@ function loadBedrockProviderModule(): Promise<LazyProviderModule<"bedrock-conver
|
|
|
443
453
|
});
|
|
444
454
|
return bedrockProviderModulePromise;
|
|
445
455
|
}
|
|
456
|
+
function loadKiroCodeWhispererProviderModule(): Promise<LazyProviderModule<"kiro-codewhisperer-stream">> {
|
|
457
|
+
kiroCodeWhispererProviderModulePromise ||= Promise.resolve().then(() => {
|
|
458
|
+
const provider = require("./kiro-codewhisperer") as KiroCodeWhispererProviderModule;
|
|
459
|
+
return { stream: provider.streamKiroCodeWhisperer };
|
|
460
|
+
});
|
|
461
|
+
return kiroCodeWhispererProviderModulePromise;
|
|
462
|
+
}
|
|
446
463
|
|
|
447
464
|
/**
|
|
448
465
|
* Lazy provider descriptors used by core consumers that need to inspect or
|
|
@@ -459,6 +476,7 @@ export const PROVIDER_RUNTIME_DESCRIPTORS: readonly ProviderRuntimeDescriptor<Ap
|
|
|
459
476
|
{ api: "openai-responses", load: loadOpenAIResponsesProviderModule },
|
|
460
477
|
{ api: "ollama-chat", load: loadOllamaProviderModule },
|
|
461
478
|
{ api: "cursor-agent", load: loadCursorProviderModule },
|
|
479
|
+
{ api: "kiro-codewhisperer-stream", load: loadKiroCodeWhispererProviderModule },
|
|
462
480
|
{ api: "bedrock-converse-stream", load: loadBedrockProviderModule },
|
|
463
481
|
] as readonly ErasedProviderRuntimeDescriptor[];
|
|
464
482
|
|
|
@@ -507,3 +525,4 @@ export const streamCursor = createLazyStream(loadCursorProviderModule);
|
|
|
507
525
|
export const streamOllama = createLazyStream(loadOllamaProviderModule);
|
|
508
526
|
|
|
509
527
|
export const streamBedrock = createLazyStream(loadBedrockProviderModule);
|
|
528
|
+
export const streamKiroCodeWhisperer = createLazyStream(loadKiroCodeWhispererProviderModule);
|
|
@@ -98,8 +98,15 @@ export function transformMessages<TApi extends Api>(
|
|
|
98
98
|
if (dropAssistantThinkingForRepair && replaysAsNativeThinking) return [];
|
|
99
99
|
if (mustPreserveLatestAnthropicThinking) return sanitized;
|
|
100
100
|
// For same model: keep thinking blocks with signatures (needed for replay)
|
|
101
|
-
// even if the thinking text is empty
|
|
102
|
-
|
|
101
|
+
// even if the thinking text is empty — but only for non-Anthropic APIs where
|
|
102
|
+
// the signature represents OpenAI encrypted reasoning. For anthropic-messages,
|
|
103
|
+
// a signed block with empty text means clear_thinking_20251015 stripped the
|
|
104
|
+
// content server-side while the stale signature remained; replaying it
|
|
105
|
+
// produces `thinking ... cannot be modified` 400s on every turn (#4247).
|
|
106
|
+
if (isSameModel && sanitized.thinkingSignature) {
|
|
107
|
+
if (sanitized.thinking.trim() === "" && model.api === "anthropic-messages") return [];
|
|
108
|
+
return sanitized;
|
|
109
|
+
}
|
|
103
110
|
// Skip empty thinking blocks, convert others to plain text
|
|
104
111
|
if (!sanitized.thinking || sanitized.thinking.trim() === "") return [];
|
|
105
112
|
if (isSameModel) return sanitized;
|
package/src/stream.ts
CHANGED
|
@@ -32,6 +32,7 @@ import type { CursorOptions } from "./providers/cursor";
|
|
|
32
32
|
import type { GoogleOptions } from "./providers/google";
|
|
33
33
|
import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
|
|
34
34
|
import type { GoogleVertexOptions } from "./providers/google-vertex";
|
|
35
|
+
import type { KiroCodeWhispererOptions } from "./providers/kiro-codewhisperer";
|
|
35
36
|
import type { OllamaChatOptions } from "./providers/ollama";
|
|
36
37
|
import type { OpenAICompletionsOptions } from "./providers/openai-completions";
|
|
37
38
|
// Heavy provider stream functions are imported lazily via register-builtins,
|
|
@@ -46,6 +47,7 @@ import {
|
|
|
46
47
|
streamGoogle,
|
|
47
48
|
streamGoogleGeminiCli,
|
|
48
49
|
streamGoogleVertex,
|
|
50
|
+
streamKiroCodeWhisperer,
|
|
49
51
|
streamOllama,
|
|
50
52
|
streamOpenAICodexResponses,
|
|
51
53
|
streamOpenAICompletions,
|
|
@@ -119,6 +121,11 @@ const serviceProviderMap: Record<string, KeyResolver> = {
|
|
|
119
121
|
tavily: "TAVILY_API_KEY",
|
|
120
122
|
parallel: "PARALLEL_API_KEY",
|
|
121
123
|
kagi: "KAGI_API_KEY",
|
|
124
|
+
// Kiro uses AWS SSO OIDC OAuth flow; bearer token is stored as the OAuth access token.
|
|
125
|
+
kiro: () => {
|
|
126
|
+
const bearerToken = $credentialEnv("AWS_BEARER_TOKEN_KIRO");
|
|
127
|
+
if (bearerToken) return bearerToken;
|
|
128
|
+
},
|
|
122
129
|
// GitHub Copilot uses GitHub personal access token
|
|
123
130
|
"github-copilot": () => $pickCredentialEnv("COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"),
|
|
124
131
|
// Foundry mode optionally switches Anthropic auth to enterprise gateway credentials.
|
|
@@ -330,6 +337,12 @@ export function stream<TApi extends Api>(
|
|
|
330
337
|
} else if (model.api === "bedrock-converse-stream") {
|
|
331
338
|
// Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
|
|
332
339
|
return streamBedrock(model as Model<"bedrock-converse-stream">, context, (options || {}) as BedrockOptions);
|
|
340
|
+
} else if (model.api === "kiro-codewhisperer-stream") {
|
|
341
|
+
return streamKiroCodeWhisperer(
|
|
342
|
+
model as Model<"kiro-codewhisperer-stream">,
|
|
343
|
+
context,
|
|
344
|
+
(options || {}) as KiroCodeWhispererOptions,
|
|
345
|
+
);
|
|
333
346
|
}
|
|
334
347
|
|
|
335
348
|
const apiKey = options?.apiKey || (model.provider === "opencodex" ? "local" : getEnvApiKey(model.provider));
|
package/src/types.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
import type { GoogleOptions } from "./providers/google";
|
|
24
24
|
import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
|
|
25
25
|
import type { GoogleVertexOptions } from "./providers/google-vertex";
|
|
26
|
+
import type { KiroCodeWhispererOptions } from "./providers/kiro-codewhisperer";
|
|
26
27
|
import type { OllamaChatOptions } from "./providers/ollama";
|
|
27
28
|
import type { OpenAICodexResponsesOptions } from "./providers/openai-codex-responses";
|
|
28
29
|
import type { OpenAICompletionsOptions } from "./providers/openai-completions";
|
|
@@ -43,7 +44,8 @@ export type KnownApi =
|
|
|
43
44
|
| "google-gemini-cli"
|
|
44
45
|
| "google-vertex"
|
|
45
46
|
| "ollama-chat"
|
|
46
|
-
| "cursor-agent"
|
|
47
|
+
| "cursor-agent"
|
|
48
|
+
| "kiro-codewhisperer-stream";
|
|
47
49
|
export type Api = KnownApi | (string & {});
|
|
48
50
|
export interface ApiOptionsMap {
|
|
49
51
|
"anthropic-messages": AnthropicOptions;
|
|
@@ -57,6 +59,7 @@ export interface ApiOptionsMap {
|
|
|
57
59
|
"google-vertex": GoogleVertexOptions;
|
|
58
60
|
"ollama-chat": OllamaChatOptions;
|
|
59
61
|
"cursor-agent": CursorOptions;
|
|
62
|
+
"kiro-codewhisperer-stream": KiroCodeWhispererOptions;
|
|
60
63
|
}
|
|
61
64
|
// Compile-time exhaustiveness check - this will fail if ApiOptionsMap doesn't have all KnownApi keys
|
|
62
65
|
type _CheckExhaustive =
|
|
@@ -116,6 +119,7 @@ export interface ThinkingConfig {
|
|
|
116
119
|
export const KNOWN_PROVIDERS = [
|
|
117
120
|
"alibaba-token-plan",
|
|
118
121
|
"amazon-bedrock",
|
|
122
|
+
"kiro",
|
|
119
123
|
"azure-openai",
|
|
120
124
|
"anthropic",
|
|
121
125
|
"google",
|
|
@@ -584,6 +588,16 @@ export interface ToolCall {
|
|
|
584
588
|
* rejects the call with a retryable error instead.
|
|
585
589
|
*/
|
|
586
590
|
incompleteArguments?: boolean;
|
|
591
|
+
/**
|
|
592
|
+
* Set when the provider saw the argument JSON spell a printable non-ASCII
|
|
593
|
+
* character as a `\uXXXX` escape instead of literal UTF-8. Hand-written hex
|
|
594
|
+
* is where models mistype digits, and a mistyped nibble decodes to a
|
|
595
|
+
* different but equally valid character, so the decoded arguments cannot be
|
|
596
|
+
* verified or repaired after parsing. The agent loop treats such a turn as a
|
|
597
|
+
* sampling accident: managed runs discard and re-request it, and execution
|
|
598
|
+
* rejects the call rather than running on silently corrupted text.
|
|
599
|
+
*/
|
|
600
|
+
escapedNonAsciiArguments?: boolean;
|
|
587
601
|
}
|
|
588
602
|
|
|
589
603
|
export interface Usage {
|
package/src/utils/json-parse.ts
CHANGED
|
@@ -110,6 +110,86 @@ export function repairJson(json: string): string {
|
|
|
110
110
|
return parts.join("");
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* First unnecessary `\uXXXX` escape in a JSON document, or `undefined` when the
|
|
115
|
+
* document contains none.
|
|
116
|
+
*
|
|
117
|
+
* "Unnecessary" means the escape encodes a character JSON can carry literally:
|
|
118
|
+
* any non-ASCII printable character. Control characters (< U+0020) MUST be
|
|
119
|
+
* escaped, and an unpaired surrogate CANNOT be written literally, so neither
|
|
120
|
+
* counts. A `\\uXXXX` sequence is a literal backslash followed by `u` — the
|
|
121
|
+
* intended source syntax when the model is writing code or a nested JSON
|
|
122
|
+
* document — and is skipped, which is why this scans the raw text with the same
|
|
123
|
+
* string/escape state machine as {@link repairJson} instead of using a regex.
|
|
124
|
+
*
|
|
125
|
+
* Models that spell non-ASCII text as hand-written hex instead of literal UTF-8
|
|
126
|
+
* mistype the digits, and every mistyped nibble silently decodes to a different
|
|
127
|
+
* but perfectly valid character (`\uc7a5` vs `\uc7a4`). The resulting arguments
|
|
128
|
+
* parse cleanly and cannot be repaired after the fact, so the escape itself is
|
|
129
|
+
* the only observable evidence that the payload is untrustworthy.
|
|
130
|
+
*/
|
|
131
|
+
export function findUnnecessaryUnicodeEscape(json: string): string | undefined {
|
|
132
|
+
const len = json.length;
|
|
133
|
+
let inString = false;
|
|
134
|
+
let i = 0;
|
|
135
|
+
|
|
136
|
+
const hexAt = (start: number): number | undefined => {
|
|
137
|
+
if (start + 3 >= len) return undefined;
|
|
138
|
+
for (let k = start; k <= start + 3; k++) if (!isHexDigit(json.charCodeAt(k))) return undefined;
|
|
139
|
+
return Number.parseInt(json.slice(start, start + 4), 16);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
while (i < len) {
|
|
143
|
+
if (!inString) {
|
|
144
|
+
const open = json.indexOf('"', i);
|
|
145
|
+
if (open === -1) return undefined;
|
|
146
|
+
inString = true;
|
|
147
|
+
i = open + 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Jump straight to the next quote or backslash. A per-character walk costs
|
|
152
|
+
// ~40ms on a 1MB literal-UTF-8 payload (a large `write`), and every byte in
|
|
153
|
+
// between is by definition uninteresting.
|
|
154
|
+
const nextQuote = json.indexOf('"', i);
|
|
155
|
+
const nextBackslash = json.indexOf("\\", i);
|
|
156
|
+
if (nextQuote === -1 && nextBackslash === -1) return undefined;
|
|
157
|
+
i = nextBackslash === -1 || (nextQuote !== -1 && nextQuote < nextBackslash) ? nextQuote : nextBackslash;
|
|
158
|
+
|
|
159
|
+
if (json.charCodeAt(i) === QUOTE) {
|
|
160
|
+
inString = false;
|
|
161
|
+
i++;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (json.charCodeAt(i + 1) !== U) {
|
|
165
|
+
// Any other escape (including `\\`) consumes its own second character,
|
|
166
|
+
// so a literal `\uXXXX` in the decoded value is never misread as one.
|
|
167
|
+
i += 2;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const first = hexAt(i + 2);
|
|
172
|
+
if (first === undefined) {
|
|
173
|
+
i += 2;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (first >= 0xd800 && first <= 0xdbff) {
|
|
177
|
+
// High surrogate: only a completed pair denotes a real character.
|
|
178
|
+
const low = json.charCodeAt(i + 6) === BACKSLASH && json.charCodeAt(i + 7) === U ? hexAt(i + 8) : undefined;
|
|
179
|
+
if (low !== undefined && low >= 0xdc00 && low <= 0xdfff) {
|
|
180
|
+
return json.slice(i, i + 12);
|
|
181
|
+
}
|
|
182
|
+
i += 6;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (first >= 0x80 && !(first >= 0xdc00 && first <= 0xdfff)) {
|
|
186
|
+
return json.slice(i, i + 6);
|
|
187
|
+
}
|
|
188
|
+
i += 6;
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
113
193
|
export function parseJsonWithRepair<T>(json: string): T {
|
|
114
194
|
try {
|
|
115
195
|
return JSON.parse(json) as T;
|
package/src/utils/oauth/index.ts
CHANGED
|
@@ -275,6 +275,11 @@ const builtInOAuthProviders: OAuthProviderInfo[] = [
|
|
|
275
275
|
name: "Vercel AI Gateway",
|
|
276
276
|
available: true,
|
|
277
277
|
},
|
|
278
|
+
{
|
|
279
|
+
id: "kiro",
|
|
280
|
+
name: "Kiro (Amazon Q Developer / CodeWhisperer)",
|
|
281
|
+
available: true,
|
|
282
|
+
},
|
|
278
283
|
];
|
|
279
284
|
|
|
280
285
|
const customOAuthProviders = new Map<string, OAuthProviderInterface>();
|
|
@@ -375,6 +380,11 @@ export async function refreshOAuthToken(
|
|
|
375
380
|
newCredentials = await refreshGlmZcodeToken(credentials);
|
|
376
381
|
break;
|
|
377
382
|
}
|
|
383
|
+
case "kiro": {
|
|
384
|
+
const { refreshKiroToken } = await import("./kiro");
|
|
385
|
+
newCredentials = await refreshKiroToken(credentials);
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
378
388
|
case "kilo":
|
|
379
389
|
case "perplexity":
|
|
380
390
|
case "huggingface":
|
|
@@ -487,7 +497,10 @@ export async function getOAuthApiKey(
|
|
|
487
497
|
}
|
|
488
498
|
// For providers that need request-time credential metadata, return JSON.
|
|
489
499
|
const needsStructuredApiKey =
|
|
490
|
-
provider === "github-copilot" ||
|
|
500
|
+
provider === "github-copilot" ||
|
|
501
|
+
provider === "google-gemini-cli" ||
|
|
502
|
+
provider === "google-antigravity" ||
|
|
503
|
+
provider === "kiro";
|
|
491
504
|
const apiKey = needsStructuredApiKey
|
|
492
505
|
? JSON.stringify({
|
|
493
506
|
token: creds.access,
|