@gajae-code/ai 0.4.5 → 0.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.
- package/CHANGELOG.md +31 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/providers/amazon-bedrock.d.ts +29 -5
- package/dist/types/providers/composer-discipline.d.ts +27 -0
- package/dist/types/providers/cursor.d.ts +1 -1
- package/dist/types/providers/google-gemini-cli.d.ts +1 -1
- package/dist/types/providers/google-shared.d.ts +11 -1
- package/dist/types/providers/ollama.d.ts +36 -1
- package/dist/types/providers/openai-completions-compat.d.ts +3 -1
- package/dist/types/providers/register-builtins.d.ts +3 -3
- package/dist/types/types.d.ts +25 -3
- package/dist/types/usage/grok-cli.d.ts +10 -0
- package/dist/types/utils/event-stream.d.ts +6 -1
- package/dist/types/utils/oauth/xai.d.ts +10 -3
- package/dist/types/utils/tool-choice-capability.d.ts +41 -0
- package/package.json +2 -2
- package/src/auth-storage.ts +3 -0
- package/src/index.ts +2 -0
- package/src/model-thinking.ts +9 -0
- package/src/models.json +116 -0
- package/src/models.ts +33 -7
- package/src/provider-models/descriptors.ts +1 -1
- package/src/provider-models/openai-compat.ts +9 -1
- package/src/providers/amazon-bedrock.ts +145 -60
- package/src/providers/anthropic.ts +85 -32
- package/src/providers/azure-openai-responses.ts +44 -3
- package/src/providers/composer-discipline.ts +38 -0
- package/src/providers/cursor.ts +10 -3
- package/src/providers/google-gemini-cli.ts +69 -10
- package/src/providers/google-shared.ts +61 -12
- package/src/providers/ollama.ts +60 -4
- package/src/providers/openai-codex-responses.ts +151 -2
- package/src/providers/openai-completions-compat.ts +9 -1
- package/src/providers/openai-completions.ts +46 -6
- package/src/providers/openai-request-transform.ts +1 -0
- package/src/providers/openai-responses.ts +54 -5
- package/src/providers/register-builtins.ts +5 -6
- package/src/rate-limit-utils.ts +11 -2
- package/src/types.ts +37 -3
- package/src/usage/grok-cli.ts +163 -0
- package/src/utils/event-stream.ts +35 -5
- package/src/utils/oauth/xai.ts +49 -13
- package/src/utils/tool-choice-capability.ts +220 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.5.1] - 2026-06-14
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Classified model/message limit exhaustion as persistent usage-limit errors so hosts fail fast or switch credentials instead of leaving sessions in an unbounded retry/working state.
|
|
10
|
+
|
|
11
|
+
## [0.5.0] - 2026-06-13
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added a generic tool-choice capability model: `toolChoiceSupport` compat enum (`none`/`auto`/`required`/`named`) available on every forced-choice-capable API, derived from the legacy `supportsToolChoice`/`supportsForcedToolChoice` booleans when absent, with a shared `resolveToolChoice` helper that clamps requested tool choices (`named` → `required` → omit) and returns structured degradation metadata.
|
|
16
|
+
- Added a transparent one-shot fallback for forced `tool_choice` 400s ("tool_choice forces tool use is not compatible with this model" and equivalents): transports retry once without the forced field at a pre-content streaming boundary, record the discovery in an in-memory per-process incapability registry, and emit an internal non-rendered `toolChoiceIncapability` event. Applies to Anthropic, OpenAI Completions/Responses, Azure Responses, OpenAI code Responses, Bedrock (including event-stream `validationException`), Ollama, Google, and Gemini CLI transports.
|
|
17
|
+
- Added bundled catalog entries for `kimi-code/kimi-k2.7-code`, `minimax-code/minimax-v3`, and `xai/grok-composer-2.5-fast`.
|
|
18
|
+
- Added composer-harness anchor/edit discipline injection for Cursor Composer and Grok Composer models so provider-specific coding harness priors do not override GJC hashline/edit contracts.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
- Removed the retired `anthropic/claude-fable-5` bundled catalog entry.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Moved the Claude Mythos forced-tool-use incapability knowledge out of Anthropic request code into catalog compat defaults (`toolChoiceSupport: "auto"`), applied during catalog generation, dynamic discovery, and bundled-model loading via a shared predicate.
|
|
27
|
+
- Google `toolConfig` mapping now sends `FunctionCallingConfig` mode `ANY` for both `required` and `any` requests instead of silently relaxing `required` to `AUTO`.
|
|
28
|
+
- Optimized `EventStream` queue draining with a head-indexed queue to avoid repeated array shifts in hot streaming paths.
|
|
29
|
+
- Clarified lazy builtin provider registration as the main provider loading path.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Stripped `OpenAI-Beta` in the `openai-proxy` request transform profile so OpenAI-compatible proxies do not receive SDK beta headers.
|
|
34
|
+
|
|
5
35
|
## [0.4.5] - 2026-06-12
|
|
6
36
|
|
|
7
37
|
### Changed
|
|
@@ -10,7 +40,7 @@
|
|
|
10
40
|
|
|
11
41
|
### Fixed
|
|
12
42
|
|
|
13
|
-
- Fixed direct Anthropic requests for Claude
|
|
43
|
+
- Fixed direct Anthropic requests for Claude Mythos-style models that support tools but reject forced tool use by omitting forced `tool_choice` while preserving `auto`/`none` choices.
|
|
14
44
|
- Preserved catalog transport metadata for opencode-go `qwen3.7-max` model resolution.
|
|
15
45
|
- Set SQLite auth-store `busy_timeout` before enabling WAL so initialization is reliable under contention.
|
|
16
46
|
- Resolved provider credentials from inherited or GJC-owned environment sources instead of trusting the caller project's `.env` overlays.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export * from "./usage/claude";
|
|
|
33
33
|
export * from "./usage/gemini";
|
|
34
34
|
export * from "./usage/github-copilot";
|
|
35
35
|
export * from "./usage/google-antigravity";
|
|
36
|
+
export * from "./usage/grok-cli";
|
|
36
37
|
export * from "./usage/kimi";
|
|
37
38
|
export * from "./usage/minimax-code";
|
|
38
39
|
export * from "./usage/openai-codex";
|
|
@@ -46,4 +47,5 @@ export type { OAuthCredentials, OAuthProvider, OAuthProviderId, OAuthProviderInf
|
|
|
46
47
|
export * from "./utils/overflow";
|
|
47
48
|
export * from "./utils/retry";
|
|
48
49
|
export * from "./utils/schema";
|
|
50
|
+
export * from "./utils/tool-choice-capability";
|
|
49
51
|
export * from "./utils/validation";
|
|
@@ -7,15 +7,12 @@
|
|
|
7
7
|
* Bun's native `HTTPS_PROXY` support.
|
|
8
8
|
*/
|
|
9
9
|
import type { Effort } from "../model-thinking";
|
|
10
|
-
import type { StreamFunction, StreamOptions, ThinkingBudgets } from "../types";
|
|
10
|
+
import type { StreamFunction, StreamOptions, ThinkingBudgets, Tool, ToolChoice } from "../types";
|
|
11
11
|
export type BedrockThinkingDisplay = "summarized" | "omitted";
|
|
12
12
|
export interface BedrockOptions extends StreamOptions {
|
|
13
13
|
region?: string;
|
|
14
14
|
profile?: string;
|
|
15
|
-
toolChoice?:
|
|
16
|
-
type: "tool";
|
|
17
|
-
name: string;
|
|
18
|
-
};
|
|
15
|
+
toolChoice?: ToolChoice;
|
|
19
16
|
reasoning?: Effort;
|
|
20
17
|
thinkingBudgets?: ThinkingBudgets;
|
|
21
18
|
interleavedThinking?: boolean;
|
|
@@ -33,4 +30,31 @@ export interface BedrockOptions extends StreamOptions {
|
|
|
33
30
|
*/
|
|
34
31
|
thinkingDisplay?: BedrockThinkingDisplay;
|
|
35
32
|
}
|
|
33
|
+
interface WireToolSpec {
|
|
34
|
+
toolSpec: {
|
|
35
|
+
name: string;
|
|
36
|
+
description: string;
|
|
37
|
+
inputSchema: {
|
|
38
|
+
json: unknown;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
interface WireToolChoice {
|
|
43
|
+
auto?: Record<string, never>;
|
|
44
|
+
any?: Record<string, never>;
|
|
45
|
+
tool?: {
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface WireToolConfig {
|
|
50
|
+
tools: WireToolSpec[];
|
|
51
|
+
toolChoice?: WireToolChoice;
|
|
52
|
+
}
|
|
36
53
|
export declare const streamBedrock: StreamFunction<"bedrock-converse-stream">;
|
|
54
|
+
export declare function stripBedrockForcedToolChoiceForRetry<T extends {
|
|
55
|
+
toolConfig?: {
|
|
56
|
+
toolChoice?: unknown;
|
|
57
|
+
};
|
|
58
|
+
}>(body: T): T;
|
|
59
|
+
export declare function convertToolConfig(tools: Tool[] | undefined, toolChoice: BedrockOptions["toolChoice"]): WireToolConfig | undefined;
|
|
60
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor/edit discipline for composer-harness models (xai grok-composer-*,
|
|
3
|
+
* cursor composer-*).
|
|
4
|
+
*
|
|
5
|
+
* Composer models are trained on a proprietary coding-agent harness
|
|
6
|
+
* (Cursor / Grok Build) and carry habits that break this agent's hashline
|
|
7
|
+
* edit workflow when driven through a generic provider. Observed in live
|
|
8
|
+
* sessions with grok-composer-2.5-fast:
|
|
9
|
+
*
|
|
10
|
+
* - they print files with shell commands (`sed -n`, `cat`, `grep -n`) or
|
|
11
|
+
* python heredocs whose output carries NO line anchors, then FABRICATE the
|
|
12
|
+
* 2-char anchor hash the edit tool requires (e.g. guessed "617hp" where
|
|
13
|
+
* the file had "617ca" → "Edit rejected: N anchors do not match");
|
|
14
|
+
* - they mutate files out-of-band via python heredocs (pathlib write_text /
|
|
15
|
+
* str.replace), which invalidates every previously seen anchor and defeats
|
|
16
|
+
* the read-cache snapshot that powers stale-anchor recovery;
|
|
17
|
+
* - they arithmetically renumber anchors after their own edits instead of
|
|
18
|
+
* copying them from the latest tool output;
|
|
19
|
+
* - they leak reasoning prose into heredoc bodies, producing shell/python
|
|
20
|
+
* syntax errors.
|
|
21
|
+
*
|
|
22
|
+
* This prompt is the per-request countermeasure, pinned ahead of the host
|
|
23
|
+
* system prompt on both the openai-completions path and the cursor RPC path.
|
|
24
|
+
*/
|
|
25
|
+
/** Matches composer-harness model ids on any provider (xai grok-composer-*, cursor composer-*). */
|
|
26
|
+
export declare function isComposerHarnessModel(modelId: string): boolean;
|
|
27
|
+
export declare const COMPOSER_EDIT_DISCIPLINE_PROMPT = "File-editing discipline for this harness (this OVERRIDES contrary habits from your training):\n\n- Read file contents ONLY with the provided read/search tools. NEVER print files through shell commands (sed, cat, awk, head, grep) or scripts \u2014 that output carries no line anchors, and the edit tool accepts ONLY anchors.\n- Modify files ONLY with the provided edit/write tools. NEVER mutate files through shell redirection, sed -i, or inline python scripts \u2014 out-of-band writes invalidate every known anchor and break edit recovery.\n- A line anchor (e.g. \"42sr\") is a line number plus a 2-char content hash. You CANNOT compute the hash yourself: copy anchors verbatim from the MOST RECENT read/search/edit output of that exact file. NEVER guess, renumber, or arithmetically shift an anchor.\n- After ANY edit to a file (including your own), anchors you saw earlier are stale. Re-read the edited region, or copy the fresh anchors printed in the edit result, before issuing the next edit.\n- If an edit is rejected with \"anchors do not match\", the rejection message prints the current lines WITH fresh anchors. Retry using exactly those printed anchors.\n- A shell command string must contain only the command itself. NEVER interleave reasoning or commentary into command strings or heredocs.";
|
|
@@ -34,7 +34,7 @@ export declare function resolveExecHandler<TArgs, TResult>(args: TArgs, handler:
|
|
|
34
34
|
* When no system prompts are provided, returns a single default greeting so we never emit
|
|
35
35
|
* an empty `rootPromptMessagesJson` head.
|
|
36
36
|
*/
|
|
37
|
-
export declare function buildCursorSystemPromptJsons(systemPrompt: readonly string[] | undefined): string[];
|
|
37
|
+
export declare function buildCursorSystemPromptJsons(systemPrompt: readonly string[] | undefined, modelId?: string): string[];
|
|
38
38
|
/** Exported for tests: decodes Cursor history blobs built from conversation messages. */
|
|
39
39
|
export declare function buildCursorHistoryForTest(messages: Message[]): {
|
|
40
40
|
rootPromptMessagesJson: unknown[];
|
|
@@ -7,7 +7,7 @@ import { type GoogleThinkingLevel } from "./google-shared";
|
|
|
7
7
|
*/
|
|
8
8
|
export type { GoogleThinkingLevel };
|
|
9
9
|
export interface GoogleGeminiCliOptions extends StreamOptions {
|
|
10
|
-
toolChoice?: "auto" | "none" | "any";
|
|
10
|
+
toolChoice?: "auto" | "none" | "any" | "required";
|
|
11
11
|
/**
|
|
12
12
|
* Thinking/reasoning configuration.
|
|
13
13
|
* - Gemini 2.x models: use `budgetTokens` to set the thinking budget
|
|
@@ -19,7 +19,7 @@ export type GoogleThinkingLevel = "THINKING_LEVEL_UNSPECIFIED" | "MINIMAL" | "LO
|
|
|
19
19
|
* `google-gemini-cli` uses a different transport and request shape — do not extend this for it.
|
|
20
20
|
*/
|
|
21
21
|
export interface GoogleSharedStreamOptions extends StreamOptions {
|
|
22
|
-
toolChoice?: "auto" | "none" | "any";
|
|
22
|
+
toolChoice?: "auto" | "none" | "any" | "required";
|
|
23
23
|
thinking?: {
|
|
24
24
|
enabled: boolean;
|
|
25
25
|
budgetTokens?: number;
|
|
@@ -161,3 +161,13 @@ export declare function streamGoogleGenAI<T extends "google-generative-ai" | "go
|
|
|
161
161
|
retainTextSignature?: boolean;
|
|
162
162
|
prepare: () => GoogleGenAIRequestPlan | Promise<GoogleGenAIRequestPlan>;
|
|
163
163
|
}): AssistantMessageEventStream;
|
|
164
|
+
/**
|
|
165
|
+
* Lift the SDK's `params.config` fields out of `config` and place them where the
|
|
166
|
+
* Gemini / Vertex AI REST API expects them on the request body. Mirrors the
|
|
167
|
+
* generateContentParametersTo{Mldev,Vertex} transformation in @google/genai
|
|
168
|
+
* for the subset of fields this codebase actually sets.
|
|
169
|
+
*
|
|
170
|
+
* `abortSignal` is intentionally dropped — the SDK propagates it via `fetch.signal`,
|
|
171
|
+
* which our caller already wires up through `options.signal`.
|
|
172
|
+
*/
|
|
173
|
+
export declare function paramsToWireBody(params: GenerateContentParameters): Record<string, unknown>;
|
|
@@ -1,6 +1,41 @@
|
|
|
1
|
-
import type { StreamFunction, StreamOptions, ToolChoice } from "../types";
|
|
1
|
+
import type { Context, Model, StreamFunction, StreamOptions, ToolChoice } from "../types";
|
|
2
2
|
export interface OllamaChatOptions extends StreamOptions {
|
|
3
3
|
reasoning?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
4
4
|
toolChoice?: ToolChoice;
|
|
5
5
|
}
|
|
6
|
+
type OllamaFunctionTool = {
|
|
7
|
+
type: "function";
|
|
8
|
+
function: {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
parameters: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
type OllamaMessage = {
|
|
15
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
16
|
+
content: string;
|
|
17
|
+
images?: string[];
|
|
18
|
+
thinking?: string;
|
|
19
|
+
tool_calls?: Array<{
|
|
20
|
+
type: "function";
|
|
21
|
+
function: {
|
|
22
|
+
index?: number;
|
|
23
|
+
name: string;
|
|
24
|
+
arguments: Record<string, unknown>;
|
|
25
|
+
};
|
|
26
|
+
}>;
|
|
27
|
+
tool_name?: string;
|
|
28
|
+
};
|
|
29
|
+
export declare function createChatBody(model: Model<"ollama-chat">, context: Context, options: OllamaChatOptions | undefined): {
|
|
30
|
+
model: string;
|
|
31
|
+
messages: OllamaMessage[];
|
|
32
|
+
tools?: OllamaFunctionTool[] | undefined;
|
|
33
|
+
think?: "high" | "low" | "medium" | boolean | undefined;
|
|
34
|
+
tool_choice?: "auto" | "none" | "required" | undefined;
|
|
35
|
+
options?: {
|
|
36
|
+
num_predict: number;
|
|
37
|
+
} | undefined;
|
|
38
|
+
stream: boolean;
|
|
39
|
+
};
|
|
6
40
|
export declare const streamOllama: StreamFunction<"ollama-chat">;
|
|
41
|
+
export {};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { Model, OpenAICompat } from "../types";
|
|
2
2
|
type ResolvedToolStrictMode = NonNullable<OpenAICompat["toolStrictMode"]> | "mixed";
|
|
3
|
-
export type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode">> & {
|
|
3
|
+
export type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolChoiceSupport">> & {
|
|
4
4
|
openRouterRouting?: OpenAICompat["openRouterRouting"];
|
|
5
5
|
vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
|
|
6
6
|
extraBody?: OpenAICompat["extraBody"];
|
|
7
7
|
toolStrictMode: ResolvedToolStrictMode;
|
|
8
|
+
/** Optional explicit capability override; resolved via deriveToolChoiceSupport. */
|
|
9
|
+
toolChoiceSupport?: OpenAICompat["toolChoiceSupport"];
|
|
8
10
|
};
|
|
9
11
|
/**
|
|
10
12
|
* Detect compatibility settings from provider and baseUrl for known providers.
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* openai) at startup. The loaded module promise is cached so subsequent calls
|
|
7
7
|
* reuse the same import.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* stream.ts imports its provider stream functions from this module (see the
|
|
10
|
+
* lazy wrappers below), so this file IS the main streaming path's provider
|
|
11
|
+
* loader: heavy SDKs stay out of the CLI startup parse graph.
|
|
12
12
|
*/
|
|
13
13
|
import type { AssistantMessageEventStream, Context, Model, OptionsForApi } from "../types";
|
|
14
14
|
import { AssistantMessageEventStream as EventStreamImpl } from "../utils/event-stream";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -68,6 +68,16 @@ export type ToolChoice = "auto" | "none" | "any" | "required" | {
|
|
|
68
68
|
type: "tool";
|
|
69
69
|
name: string;
|
|
70
70
|
};
|
|
71
|
+
export type ToolChoiceSupport = "none" | "auto" | "required" | "named";
|
|
72
|
+
export type ToolChoiceSupportSource = "static" | "derived" | "runtime";
|
|
73
|
+
export interface ToolChoiceCompat {
|
|
74
|
+
/** Maximum supported tool_choice level. */
|
|
75
|
+
toolChoiceSupport?: ToolChoiceSupport;
|
|
76
|
+
/** Legacy flag for accepting the tool_choice parameter. */
|
|
77
|
+
supportsToolChoice?: boolean;
|
|
78
|
+
/** Legacy flag for forced tool_choice support. */
|
|
79
|
+
supportsForcedToolChoice?: boolean;
|
|
80
|
+
}
|
|
71
81
|
export type CacheRetention = "none" | "short" | "long";
|
|
72
82
|
/**
|
|
73
83
|
* Service tier hint for processing priority / cost control.
|
|
@@ -576,12 +586,22 @@ export type AssistantMessageEvent = {
|
|
|
576
586
|
contentIndex?: undefined;
|
|
577
587
|
reason: Extract<StopReason, "aborted" | "error">;
|
|
578
588
|
error: AssistantMessage;
|
|
589
|
+
} | {
|
|
590
|
+
type: "toolChoiceIncapability";
|
|
591
|
+
contentIndex?: undefined;
|
|
592
|
+
api: string;
|
|
593
|
+
provider: string;
|
|
594
|
+
model: string;
|
|
595
|
+
requestedLevel: ToolChoiceSupport;
|
|
596
|
+
resolvedLevel: ToolChoiceSupport;
|
|
597
|
+
reason: string;
|
|
598
|
+
registryKey: string;
|
|
579
599
|
};
|
|
580
600
|
/**
|
|
581
601
|
* Compatibility settings for openai-completions API.
|
|
582
602
|
* Use this to override URL-based auto-detection for custom providers.
|
|
583
603
|
*/
|
|
584
|
-
export interface OpenAICompat {
|
|
604
|
+
export interface OpenAICompat extends ToolChoiceCompat {
|
|
585
605
|
/** Whether the provider supports the `store` field. Default: auto-detected from URL. */
|
|
586
606
|
supportsStore?: boolean;
|
|
587
607
|
/** Whether the provider supports the `developer` role (vs `system`). Default: auto-detected from URL. */
|
|
@@ -627,6 +647,8 @@ export interface OpenAICompat {
|
|
|
627
647
|
requiresAssistantContentForToolCalls?: boolean;
|
|
628
648
|
/** Whether the provider supports the `tool_choice` parameter. Default: true. */
|
|
629
649
|
supportsToolChoice?: boolean;
|
|
650
|
+
/** Whether `tool_choice` may force a tool (`required` / named tool). Default: true. */
|
|
651
|
+
supportsForcedToolChoice?: boolean;
|
|
630
652
|
/**
|
|
631
653
|
* Drop reasoning fields (`reasoning_effort`, OpenRouter `reasoning`) for
|
|
632
654
|
* the request when `tool_choice` forces a tool call. Mirrors the Anthropic
|
|
@@ -658,7 +680,7 @@ export interface OpenAICompat {
|
|
|
658
680
|
* Use this to disable features that strict-by-default Anthropic accepts but
|
|
659
681
|
* that proxy gateways (Vertex AI, AWS Bedrock-style fronts, etc.) reject.
|
|
660
682
|
*/
|
|
661
|
-
export interface AnthropicCompat {
|
|
683
|
+
export interface AnthropicCompat extends ToolChoiceCompat {
|
|
662
684
|
/**
|
|
663
685
|
* Drop the top-level `strict: true` field on tool definitions. Vertex AI's
|
|
664
686
|
* Anthropic-compatible endpoint rejects unknown tool fields with
|
|
@@ -770,7 +792,7 @@ export interface Model<TApi extends Api = any> {
|
|
|
770
792
|
/** Canonical thinking capability metadata for this model. */
|
|
771
793
|
thinking?: ThinkingConfig;
|
|
772
794
|
/** Compatibility overrides per API. If not set, auto-detected from baseUrl. */
|
|
773
|
-
compat?: TApi extends "openai-completions" | "openai-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : never;
|
|
795
|
+
compat?: TApi extends "openai-completions" | "openai-responses" ? OpenAICompat : TApi extends "anthropic-messages" ? AnthropicCompat : TApi extends "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex" | "ollama-chat" | "azure-openai-responses" | "openai-codex-responses" ? ToolChoiceCompat : never;
|
|
774
796
|
/**
|
|
775
797
|
* Which shape to use when exposing the OpenAI code backend `apply_patch` tool to this model.
|
|
776
798
|
* Generated catalog policy sets `"freeform"` for first-party GPT-5 Responses
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CredentialRankingStrategy, UsageProvider } from "../usage";
|
|
2
|
+
interface BillingUsage {
|
|
3
|
+
monthlyLimit: number;
|
|
4
|
+
used: number;
|
|
5
|
+
billingPeriodEnd: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseGrokCliBillingUsage(payload: unknown): BillingUsage;
|
|
8
|
+
export declare const grokCliUsageProvider: UsageProvider;
|
|
9
|
+
export declare const grokCliRankingStrategy: CredentialRankingStrategy;
|
|
10
|
+
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AssistantMessage, AssistantMessageEvent } from "../types";
|
|
2
2
|
export declare class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
3
3
|
#private;
|
|
4
|
-
queue: T[];
|
|
5
4
|
waiting: Array<{
|
|
6
5
|
resolve: (value: IteratorResult<T>) => void;
|
|
7
6
|
reject: (err: unknown) => void;
|
|
@@ -13,6 +12,12 @@ export declare class EventStream<T, R = T> implements AsyncIterable<T> {
|
|
|
13
12
|
isComplete: (event: T) => boolean;
|
|
14
13
|
extractResult: (event: T) => R;
|
|
15
14
|
constructor(isComplete: (event: T) => boolean, extractResult: (event: T) => R);
|
|
15
|
+
/**
|
|
16
|
+
* Read-only snapshot of the not-yet-consumed events. Always a fresh copy:
|
|
17
|
+
* external code can never mutate internal queue state or observe head-index
|
|
18
|
+
* tombstones, so the deque cannot desynchronize.
|
|
19
|
+
*/
|
|
20
|
+
get queue(): T[];
|
|
16
21
|
push(event: T): void;
|
|
17
22
|
deliver(event: T): void;
|
|
18
23
|
end(result?: R): void;
|
|
@@ -8,16 +8,23 @@ interface XaiDiscovery {
|
|
|
8
8
|
authorizationEndpoint: string;
|
|
9
9
|
tokenEndpoint: string;
|
|
10
10
|
}
|
|
11
|
+
export interface XaiOAuthFlowOptions {
|
|
12
|
+
extraAuthorizeParams?: Readonly<Record<string, string>>;
|
|
13
|
+
}
|
|
14
|
+
export interface XaiOAuthRefreshOptions {
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
extraTokenParams?: Readonly<Record<string, string>>;
|
|
17
|
+
}
|
|
11
18
|
export declare function discoverXaiOAuthEndpoints(signal?: AbortSignal): Promise<XaiDiscovery>;
|
|
12
19
|
export declare class XaiOAuthFlow extends OAuthCallbackFlow {
|
|
13
20
|
#private;
|
|
14
|
-
constructor(ctrl: OAuthController);
|
|
21
|
+
constructor(ctrl: OAuthController, options?: XaiOAuthFlowOptions);
|
|
15
22
|
generateAuthUrl(state: string, redirectUri: string): Promise<{
|
|
16
23
|
url: string;
|
|
17
24
|
instructions?: string;
|
|
18
25
|
}>;
|
|
19
26
|
exchangeToken(code: string, _state: string, redirectUri: string): Promise<OAuthCredentials>;
|
|
20
27
|
}
|
|
21
|
-
export declare function loginXai(ctrl: OAuthController): Promise<OAuthCredentials>;
|
|
22
|
-
export declare function refreshXaiToken(refreshToken: string,
|
|
28
|
+
export declare function loginXai(ctrl: OAuthController, options?: XaiOAuthFlowOptions): Promise<OAuthCredentials>;
|
|
29
|
+
export declare function refreshXaiToken(refreshToken: string, options?: AbortSignal | XaiOAuthRefreshOptions): Promise<OAuthCredentials>;
|
|
23
30
|
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Api, Model, ToolChoice, ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Mythos accepts tools but rejects forced tool use (Anthropic 400:
|
|
4
|
+
* "tool_choice forces tool use is not compatible with this model"). Catalog
|
|
5
|
+
* generation and dynamic discovery use this to default `toolChoiceSupport`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isClaudeForcedToolChoiceIncapableModelId(modelId: string): boolean;
|
|
8
|
+
/** Derives the effective static tool-choice support from compatibility flags. */
|
|
9
|
+
export declare function deriveToolChoiceSupport(compat: ToolChoiceCompat | undefined): {
|
|
10
|
+
support: ToolChoiceSupport;
|
|
11
|
+
source: "static" | "derived";
|
|
12
|
+
};
|
|
13
|
+
/** Returns the registry key used for runtime tool-choice capability overrides. */
|
|
14
|
+
export declare function toolChoiceRegistryKey(model: Model<Api>): string;
|
|
15
|
+
/** Returns the current runtime tool-choice capability override for a model. */
|
|
16
|
+
export declare function getToolChoiceCapabilityOverride(model: Model<Api>): ToolChoiceSupport | undefined;
|
|
17
|
+
/** Clears runtime tool-choice capability overrides for tests. */
|
|
18
|
+
export declare function clearToolChoiceIncapabilityRegistryForTests(): void;
|
|
19
|
+
/** Records a discovered maximum supported tool-choice level for a model. */
|
|
20
|
+
export declare function markToolChoiceIncapability(model: Model<Api>, maxSupport: ToolChoiceSupport, reason?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Resolves a requested tool_choice against static and runtime capability limits.
|
|
23
|
+
* `compat` overrides `model.compat` for transports that layer URL/provider
|
|
24
|
+
* detection on top of explicit model overrides (e.g. resolveOpenAICompat).
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveToolChoice(model: Model<Api>, requested: ToolChoice | undefined, compat?: ToolChoiceCompat): ResolveToolChoiceResult;
|
|
27
|
+
/** Detects provider errors indicating forced tool_choice is unsupported. */
|
|
28
|
+
export declare function isForcedToolChoiceUnsupportedError(error: unknown, sentForcedToolChoice: boolean): boolean;
|
|
29
|
+
export type { ToolChoiceCompat, ToolChoiceSupport, ToolChoiceSupportSource } from "../types";
|
|
30
|
+
export interface ResolveToolChoiceResult {
|
|
31
|
+
requestedChoice: ToolChoice | undefined;
|
|
32
|
+
requestedLevel: ToolChoiceSupport;
|
|
33
|
+
resolvedChoice: ToolChoice | undefined;
|
|
34
|
+
resolvedLevel: ToolChoiceSupport;
|
|
35
|
+
support: ToolChoiceSupport;
|
|
36
|
+
supportSource: ToolChoiceSupportSource;
|
|
37
|
+
degraded: boolean;
|
|
38
|
+
reason?: string;
|
|
39
|
+
registryKey: string;
|
|
40
|
+
targetToolName?: string;
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
45
45
|
"@bufbuild/protobuf": "^2.12.0",
|
|
46
|
-
"@gajae-code/utils": "0.
|
|
46
|
+
"@gajae-code/utils": "0.5.1",
|
|
47
47
|
"openai": "^6.36.0",
|
|
48
48
|
"partial-json": "^0.1.7",
|
|
49
49
|
"zod": "4.4.3"
|
package/src/auth-storage.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { claudeRankingStrategy, claudeUsageProvider } from "./usage/claude";
|
|
|
27
27
|
import { googleGeminiCliUsageProvider } from "./usage/gemini";
|
|
28
28
|
import { githubCopilotUsageProvider } from "./usage/github-copilot";
|
|
29
29
|
import { antigravityUsageProvider } from "./usage/google-antigravity";
|
|
30
|
+
import { grokCliRankingStrategy, grokCliUsageProvider } from "./usage/grok-cli";
|
|
30
31
|
import { kimiUsageProvider } from "./usage/kimi";
|
|
31
32
|
import { codexRankingStrategy, openaiCodexUsageProvider } from "./usage/openai-codex";
|
|
32
33
|
import { zaiUsageProvider } from "./usage/zai";
|
|
@@ -370,6 +371,7 @@ const DEFAULT_USAGE_PROVIDERS: UsageProvider[] = [
|
|
|
370
371
|
claudeUsageProvider,
|
|
371
372
|
zaiUsageProvider,
|
|
372
373
|
githubCopilotUsageProvider,
|
|
374
|
+
grokCliUsageProvider,
|
|
373
375
|
];
|
|
374
376
|
|
|
375
377
|
const DEFAULT_USAGE_PROVIDER_MAP = new Map<Provider, UsageProvider>(
|
|
@@ -498,6 +500,7 @@ function resolveDefaultUsageProvider(provider: Provider): UsageProvider | undefi
|
|
|
498
500
|
const DEFAULT_RANKING_STRATEGIES = new Map<Provider, CredentialRankingStrategy>([
|
|
499
501
|
["openai-codex", codexRankingStrategy],
|
|
500
502
|
["anthropic", claudeRankingStrategy],
|
|
503
|
+
["grok-build", grokCliRankingStrategy],
|
|
501
504
|
]);
|
|
502
505
|
|
|
503
506
|
function resolveDefaultRankingStrategy(provider: Provider): CredentialRankingStrategy | undefined {
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,7 @@ export * from "./usage/claude";
|
|
|
33
33
|
export * from "./usage/gemini";
|
|
34
34
|
export * from "./usage/github-copilot";
|
|
35
35
|
export * from "./usage/google-antigravity";
|
|
36
|
+
export * from "./usage/grok-cli";
|
|
36
37
|
export * from "./usage/kimi";
|
|
37
38
|
export * from "./usage/minimax-code";
|
|
38
39
|
export * from "./usage/openai-codex";
|
|
@@ -51,4 +52,5 @@ export type {
|
|
|
51
52
|
export * from "./utils/overflow";
|
|
52
53
|
export * from "./utils/retry";
|
|
53
54
|
export * from "./utils/schema";
|
|
55
|
+
export * from "./utils/tool-choice-capability";
|
|
54
56
|
export * from "./utils/validation";
|
package/src/model-thinking.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveOpenAICompat } from "./providers/openai-completions-compat";
|
|
2
2
|
import type { Api, Model as ApiModel, ThinkingConfig } from "./types";
|
|
3
|
+
import { isClaudeForcedToolChoiceIncapableModelId } from "./utils/tool-choice-capability";
|
|
3
4
|
|
|
4
5
|
/** User-facing thinking levels, ordered least to most intensive. */
|
|
5
6
|
export const enum Effort {
|
|
@@ -382,6 +383,14 @@ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
|
|
|
382
383
|
} else {
|
|
383
384
|
delete model.applyPatchToolType;
|
|
384
385
|
}
|
|
386
|
+
if (
|
|
387
|
+
(model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") &&
|
|
388
|
+
isClaudeForcedToolChoiceIncapableModelId(model.id)
|
|
389
|
+
) {
|
|
390
|
+
// Claude Mythos accepts tools but rejects forced tool use (Anthropic
|
|
391
|
+
// 400: "tool_choice forces tool use is not compatible with this model").
|
|
392
|
+
model.compat = { ...(model.compat ?? {}), toolChoiceSupport: "auto" } as typeof model.compat;
|
|
393
|
+
}
|
|
385
394
|
if (parsedModel.family === "anthropic") {
|
|
386
395
|
applyAnthropicCatalogPolicy(model, parsedModel);
|
|
387
396
|
}
|
package/src/models.json
CHANGED
|
@@ -18021,6 +18021,40 @@
|
|
|
18021
18021
|
"minLevel": "minimal",
|
|
18022
18022
|
"maxLevel": "high"
|
|
18023
18023
|
}
|
|
18024
|
+
},
|
|
18025
|
+
"kimi-k2.7-code": {
|
|
18026
|
+
"id": "kimi-k2.7-code",
|
|
18027
|
+
"name": "Kimi K2.7 Code",
|
|
18028
|
+
"api": "openai-completions",
|
|
18029
|
+
"provider": "kimi-code",
|
|
18030
|
+
"baseUrl": "https://api.kimi.com/coding/v1",
|
|
18031
|
+
"headers": {
|
|
18032
|
+
"User-Agent": "KimiCLI/1.0",
|
|
18033
|
+
"X-Msh-Platform": "kimi_cli"
|
|
18034
|
+
},
|
|
18035
|
+
"reasoning": true,
|
|
18036
|
+
"input": [
|
|
18037
|
+
"text",
|
|
18038
|
+
"image"
|
|
18039
|
+
],
|
|
18040
|
+
"cost": {
|
|
18041
|
+
"input": 0,
|
|
18042
|
+
"output": 0,
|
|
18043
|
+
"cacheRead": 0,
|
|
18044
|
+
"cacheWrite": 0
|
|
18045
|
+
},
|
|
18046
|
+
"contextWindow": 262144,
|
|
18047
|
+
"maxTokens": 65536,
|
|
18048
|
+
"compat": {
|
|
18049
|
+
"thinkingFormat": "zai",
|
|
18050
|
+
"reasoningContentField": "reasoning_content",
|
|
18051
|
+
"supportsDeveloperRole": false
|
|
18052
|
+
},
|
|
18053
|
+
"thinking": {
|
|
18054
|
+
"mode": "effort",
|
|
18055
|
+
"minLevel": "minimal",
|
|
18056
|
+
"maxLevel": "high"
|
|
18057
|
+
}
|
|
18024
18058
|
}
|
|
18025
18059
|
},
|
|
18026
18060
|
"litellm": {
|
|
@@ -35153,6 +35187,37 @@
|
|
|
35153
35187
|
"minLevel": "minimal",
|
|
35154
35188
|
"maxLevel": "high"
|
|
35155
35189
|
}
|
|
35190
|
+
},
|
|
35191
|
+
"minimax-v3": {
|
|
35192
|
+
"id": "minimax-v3",
|
|
35193
|
+
"name": "MiniMax-V3",
|
|
35194
|
+
"api": "openai-completions",
|
|
35195
|
+
"provider": "minimax-code",
|
|
35196
|
+
"baseUrl": "https://api.minimax.io/v1",
|
|
35197
|
+
"reasoning": true,
|
|
35198
|
+
"input": [
|
|
35199
|
+
"text",
|
|
35200
|
+
"image"
|
|
35201
|
+
],
|
|
35202
|
+
"cost": {
|
|
35203
|
+
"input": 0,
|
|
35204
|
+
"output": 0,
|
|
35205
|
+
"cacheRead": 0,
|
|
35206
|
+
"cacheWrite": 0
|
|
35207
|
+
},
|
|
35208
|
+
"contextWindow": 512000,
|
|
35209
|
+
"maxTokens": 128000,
|
|
35210
|
+
"compat": {
|
|
35211
|
+
"supportsStore": false,
|
|
35212
|
+
"supportsDeveloperRole": false,
|
|
35213
|
+
"supportsReasoningEffort": false,
|
|
35214
|
+
"reasoningContentField": "reasoning_content"
|
|
35215
|
+
},
|
|
35216
|
+
"thinking": {
|
|
35217
|
+
"mode": "effort",
|
|
35218
|
+
"minLevel": "minimal",
|
|
35219
|
+
"maxLevel": "high"
|
|
35220
|
+
}
|
|
35156
35221
|
}
|
|
35157
35222
|
},
|
|
35158
35223
|
"minimax-code-cn": {
|
|
@@ -70520,6 +70585,33 @@
|
|
|
70520
70585
|
"maxLevel": "high"
|
|
70521
70586
|
}
|
|
70522
70587
|
},
|
|
70588
|
+
"grok-composer-2.5-fast": {
|
|
70589
|
+
"id": "grok-composer-2.5-fast",
|
|
70590
|
+
"name": "Grok Composer 2.5 Fast",
|
|
70591
|
+
"api": "openai-completions",
|
|
70592
|
+
"provider": "xai",
|
|
70593
|
+
"baseUrl": "https://api.x.ai/v1",
|
|
70594
|
+
"reasoning": true,
|
|
70595
|
+
"input": [
|
|
70596
|
+
"text"
|
|
70597
|
+
],
|
|
70598
|
+
"cost": {
|
|
70599
|
+
"input": 0,
|
|
70600
|
+
"output": 0,
|
|
70601
|
+
"cacheRead": 0,
|
|
70602
|
+
"cacheWrite": 0
|
|
70603
|
+
},
|
|
70604
|
+
"contextWindow": 200000,
|
|
70605
|
+
"maxTokens": 64000,
|
|
70606
|
+
"compat": {
|
|
70607
|
+
"supportsReasoningEffort": false
|
|
70608
|
+
},
|
|
70609
|
+
"thinking": {
|
|
70610
|
+
"mode": "effort",
|
|
70611
|
+
"minLevel": "minimal",
|
|
70612
|
+
"maxLevel": "high"
|
|
70613
|
+
}
|
|
70614
|
+
},
|
|
70523
70615
|
"grok-vision-beta": {
|
|
70524
70616
|
"id": "grok-vision-beta",
|
|
70525
70617
|
"name": "Grok Vision Beta",
|
|
@@ -70956,6 +71048,30 @@
|
|
|
70956
71048
|
"maxLevel": "xhigh"
|
|
70957
71049
|
}
|
|
70958
71050
|
},
|
|
71051
|
+
"glm-5.2": {
|
|
71052
|
+
"id": "glm-5.2",
|
|
71053
|
+
"name": "GLM-5.2",
|
|
71054
|
+
"api": "anthropic-messages",
|
|
71055
|
+
"provider": "zai",
|
|
71056
|
+
"baseUrl": "https://api.z.ai/api/anthropic",
|
|
71057
|
+
"reasoning": true,
|
|
71058
|
+
"input": [
|
|
71059
|
+
"text"
|
|
71060
|
+
],
|
|
71061
|
+
"cost": {
|
|
71062
|
+
"input": 0,
|
|
71063
|
+
"output": 0,
|
|
71064
|
+
"cacheRead": 0,
|
|
71065
|
+
"cacheWrite": 0
|
|
71066
|
+
},
|
|
71067
|
+
"contextWindow": 200000,
|
|
71068
|
+
"maxTokens": 131072,
|
|
71069
|
+
"thinking": {
|
|
71070
|
+
"mode": "budget",
|
|
71071
|
+
"minLevel": "minimal",
|
|
71072
|
+
"maxLevel": "xhigh"
|
|
71073
|
+
}
|
|
71074
|
+
},
|
|
70959
71075
|
"glm-5v-turbo": {
|
|
70960
71076
|
"id": "glm-5v-turbo",
|
|
70961
71077
|
"name": "GLM-5V-Turbo",
|