@gajae-code/ai 0.15.6 → 0.16.0

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 (39) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/types/adapter-internals/aws-region.d.ts +7 -0
  3. package/dist/types/core.d.ts +1 -0
  4. package/dist/types/index.d.ts +1 -0
  5. package/dist/types/providers/anthropic.d.ts +1 -1
  6. package/dist/types/providers/google-gemini-headers.d.ts +1 -1
  7. package/dist/types/providers/openai-codex-responses.d.ts +6 -0
  8. package/dist/types/utils/schema/normalize.d.ts +0 -5
  9. package/dist/types/utils/sqlite-errors.d.ts +4 -0
  10. package/package.json +3 -3
  11. package/src/adapter-internals/aws-region.d.ts +7 -0
  12. package/src/adapter-internals/aws-region.ts +14 -0
  13. package/src/auth-storage.ts +14 -14
  14. package/src/core.ts +1 -0
  15. package/src/index.ts +1 -0
  16. package/src/model-thinking.ts +8 -0
  17. package/src/models.json +201 -3
  18. package/src/provider-models/openai-compat.ts +61 -0
  19. package/src/providers/amazon-bedrock.ts +5 -1
  20. package/src/providers/anthropic.d.ts +1 -1
  21. package/src/providers/anthropic.ts +1 -1
  22. package/src/providers/aws-credentials.ts +6 -0
  23. package/src/providers/google-gemini-headers.d.ts +1 -1
  24. package/src/providers/google-gemini-headers.ts +1 -1
  25. package/src/providers/kiro-api-key.ts +33 -8
  26. package/src/providers/kiro-codewhisperer.ts +4 -1
  27. package/src/providers/openai-codex-responses.d.ts +6 -0
  28. package/src/providers/openai-codex-responses.ts +17 -2
  29. package/src/providers/pi-native-client.ts +24 -1
  30. package/src/utils/oauth/kiro.ts +91 -22
  31. package/src/utils/schema/dereference.ts +169 -49
  32. package/src/utils/schema/draft.ts +46 -23
  33. package/src/utils/schema/normalize.d.ts +0 -5
  34. package/src/utils/schema/normalize.ts +396 -119
  35. package/src/utils/schema/types.ts +3 -1
  36. package/src/utils/schema/zod-decontaminate.ts +83 -29
  37. package/src/utils/sqlite-errors.d.ts +4 -0
  38. package/src/utils/sqlite-errors.ts +13 -0
  39. package/src/utils/tool-choice-capability.ts +2 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.16.0] - 2026-09-02
6
+
7
+ ### Added
8
+
9
+ - Bundled `anthropic/claude-fable-5-1` (Claude Fable 5.1): 1M context, 128K output, `anthropic-adaptive` thinking clamped to `xhigh` on the Messages API, matching the Fable 5 effort ladder exactly. The model is served only by Anthropic's first-party API and requires a Claude Code compatibility version of at least `2.1.251`; older fingerprints are answered with an HTTP 400 `claude_code_version_too_old`, which the `2.1.257` attribution bump clears. Verified live: `2.1.219` returns the 400, `2.1.257` returns 200, `low`/`high`/`xhigh` all stream, and adaptive thinking returns visible summarized content rather than signature-only billed thinking.
10
+
11
+ ### Fixed
12
+
13
+ - Cursor's `kimi-k3-low`, `kimi-k3-high`, and `kimi-k3-max` now declare their real 1,048,576-token context window instead of 200,000. The bundled value was understated by 5.2x, so context management compacted these models at roughly a fifth of their usable window. The same underlying model already declares 1,048,576 elsewhere in this catalog (`openrouter/moonshotai/kimi-k3`, `kilo/moonshotai/kimi-k3`, and `opencode-go/kimi-k3` in `provider-models/openai-compat.ts`), so the cursor entries were the inconsistent ones. Measured against the live `cursor-agent` transport, which reports `usage.inputTokens` per request: 1,026,459 input tokens were accepted and answered correctly, while 1,161,948 tokens were silently summarized down to 20,552 and lost the answer. Output `maxTokens` is unchanged at 64,000, which this change did not measure.
14
+
15
+ - The Cursor Kimi K3 context correction is now enforced by the deterministic model-generation policy, so a future catalog regeneration cannot reintroduce the stale 200,000-token fallback.
16
+
17
+ - OpenCode Go's bundled catalog now contains all 33 models advertised by its live provider list, including the seven newly published models. Canonical endpoint metadata supplies their transport, multimodal input, limits, pricing, and reasoning capabilities, while generated output remains deterministic and preserves fail-closed selection when a live catalog is unavailable (#5144).
18
+
19
+ - SQLite corruption detection is now shared by credential and capability-cache surfaces, so callers can recognize `SQLITE_CORRUPT` and `SQLITE_NOTADB` without inspecting provider-specific error details.
20
+
21
+ - OpenAI Codex WebSockets are now opt-in on Windows. Bun 1.4.0 can segfault in its Windows TLS WebSocket handshake, so the automatic model preference uses SSE on Windows while the explicit WebSocket setting remains available for operators who have a newer safe runtime.
22
+ - MCP dispatcher tools now preserve dynamic nested `args` and `params` objects when a server declares them as propertyless JSON Schema objects. `normalizeSchemaForMCP` makes the implicit open-map semantics explicit with `additionalProperties: true` without loosening objects that declare properties or an explicit closure, so provider tool schemas no longer collapse valid nested arguments to `{}`.
23
+ - Schema normalization now copies `default`, `const`, `enum`, and `examples` payloads verbatim. These keywords carry instance data, not subschemas, so the previous recursive walk rewrote user payloads as if they were schemas (a `default` of `{"type":"object","nullable":true}` lost `nullable`, and literal `anyOf`/`const` branches collapsed into `enum`).
24
+ - Schema copies now write property names as own data properties. A `JSON.parse`d tool schema carries `__proto__` as an ordinary key, and plain assignment routed it to `Object.prototype`'s `__proto__` setter, dropping that valid property from the normalized schema.
25
+ - Schema-valued maps now remain maps even when dispatcher argument names collide with JSON Schema keywords (`type`, `default`, `const`, `enum`, or `examples`), and prototype-colliding names survive draft-upgrade, dereference, and Zod cleanup copies without polluting `Object.prototype`.
26
+ - Claude Code compatibility attribution moved from `2.1.219` to `2.1.257`, and the Gemini CLI spoofed version from `0.52.0` to `0.58.0`. Anthropic gates newer models behind a minimum client version, so a stale `claude-cli/<version>` fingerprint surfaces as an HTTP 400 on a model the account can otherwise reach. `scripts/check-spoofed-versions.ts` now covers `claudeCodeVersion` (resolved from Anthropic's `latest` native-installer release channel, with the `@anthropic-ai/claude-code` npm dist-tag as a second source and the higher of the two winning so one lagging channel cannot pin us back), spans multiple source files, and compares by semver instead of string equality. Both constants had only ever been bumped by hand and the check was never scheduled, so the new read-only daily `spoofed-version-sync` workflow now runs it and fails with a one-command remediation on drift.
27
+ - Bedrock and both Kiro credential transports now reject malformed project-aware AWS regions before interpolating them into authenticated service authorities. Valid lowercase ASCII region labels and explicit Kiro model `baseUrl` overrides are unchanged.
28
+ - Kiro Builder ID device-code login no longer aborts on the first poll. AWS SSO OIDC `CreateToken` reports the in-progress states (`authorization_pending`, `slow_down`) as HTTP 400 responses whose body carries the error code, but the poll loop went through the shared `fetchOidc` helper that throws on any non-2xx status, so the `authorization_pending` branch it already implemented was unreachable and every login failed within one interval of printing the verification URL. The poll now reads the JSON payload before classifying the response; non-2xx responses without an `error` field still fail closed.
29
+
5
30
  ## [0.15.6] - 2026-08-30
6
31
 
7
32
  ### Added
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Fail closed before an AWS region is interpolated into a credential-bearing
3
+ * service authority. Region names are one lowercase ASCII DNS label; dots,
4
+ * URL delimiters, Unicode, whitespace, and controls must never reach URL
5
+ * parsing as part of that label.
6
+ */
7
+ export declare function assertAwsRegionLabel(region: unknown): asserts region is string;
@@ -31,5 +31,6 @@ export type { OAuthCredentials, OAuthProvider, OAuthProviderId, OAuthProviderInf
31
31
  export * from "./utils/overflow";
32
32
  export * from "./utils/retry";
33
33
  export * from "./utils/schema";
34
+ export * from "./utils/sqlite-errors";
34
35
  export * from "./utils/tool-choice-capability";
35
36
  export * from "./utils/validation";
@@ -51,5 +51,6 @@ export * from "./utils/overflow";
51
51
  export * from "./utils/provider-safety-stop";
52
52
  export * from "./utils/retry";
53
53
  export * from "./utils/schema";
54
+ export * from "./utils/sqlite-errors";
54
55
  export * from "./utils/tool-choice-capability";
55
56
  export * from "./utils/validation";
@@ -107,7 +107,7 @@ export interface CpaToolAliasRestoreFailure {
107
107
  */
108
108
  export declare function parseCpaToolAliasRestoreFailure(error: unknown): CpaToolAliasRestoreFailure | undefined;
109
109
  export declare function isCpaToolAliasRestoreFailure(error: unknown): boolean;
110
- export declare const claudeCodeVersion = "2.1.219";
110
+ export declare const claudeCodeVersion = "2.1.257";
111
111
  export declare const claudeCodeEntrypoint = "sdk-cli";
112
112
  export declare const claudeToolPrefix: string;
113
113
  export declare const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
@@ -5,7 +5,7 @@
5
5
  */
6
6
  export declare const GEMINI_CLI_VERSION_ENV = "GJC_AI_GEMINI_CLI_VERSION";
7
7
  export declare const LEGACY_GEMINI_CLI_VERSION_ENV = "PI_AI_GEMINI_CLI_VERSION";
8
- export declare const DEFAULT_GEMINI_CLI_VERSION = "0.52.0";
8
+ export declare const DEFAULT_GEMINI_CLI_VERSION = "0.58.0";
9
9
  export declare function getGeminiCliUserAgent(modelId?: string): string;
10
10
  export declare const getGeminiCliHeaders: (modelId?: string) => {
11
11
  "User-Agent": string;
@@ -25,6 +25,12 @@ export declare function normalizeCodexToolChoice(choice: ToolChoice | undefined,
25
25
  export declare function formatCodexUserAgent(platform: string, release: string, arch: string): string;
26
26
  export declare const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses">;
27
27
  export declare function prewarmOpenAICodexResponses(model: Model<"openai-codex-responses">, options?: Pick<OpenAICodexResponsesOptions, "apiKey" | "headers" | "sessionId" | "signal" | "preferWebsockets" | "providerSessionState">): Promise<void>;
28
+ /**
29
+ * Bun 1.4.0's Windows WebSocket client can segfault during TLS handshakes.
30
+ * Keep the model's websocket preference available on other platforms, while
31
+ * requiring an explicit opt-in on Windows until the bundled runtime is fixed.
32
+ */
33
+ export declare function isCodexWebSocketSafeByDefault(platform?: NodeJS.Platform): boolean;
28
34
  export interface OpenAICodexTransportDetails {
29
35
  websocketPreferred: boolean;
30
36
  lastTransport?: CodexTransport;
@@ -25,11 +25,6 @@ export interface NormalizeSchemaOptions {
25
25
  }
26
26
  /** Copy all keys from a schema except the specified combiner key. */
27
27
  export declare function copySchemaWithout(schema: JsonObject, combiner: string): JsonObject;
28
- /**
29
- * Recursively strip any remaining anyOf/oneOf that same-type or mixed-type
30
- * collapse can handle. This is needed because object-combiner merging can
31
- * create new anyOf in merged subtrees after child normalization already ran.
32
- */
33
28
  export declare function stripResidualCombiners(value: unknown, epoch?: number): unknown;
34
29
  export declare function normalizeSchema(value: unknown, options: NormalizeSchemaOptions): unknown;
35
30
  export declare function normalizeSchemaForGoogle(value: unknown): unknown;
@@ -0,0 +1,4 @@
1
+ /** Return whether an error carries a SQLite result code. */
2
+ export declare function isSqliteError(error: unknown): boolean;
3
+ /** Return whether an error is one of SQLite's explicit database-corruption classes. */
4
+ export declare function isSqliteCorruptionError(error: unknown): boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/ai",
4
- "version": "0.15.6",
4
+ "version": "0.16.0",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -40,8 +40,8 @@
40
40
  "dependencies": {
41
41
  "@anthropic-ai/sdk": "^0.94.0",
42
42
  "@bufbuild/protobuf": "^2.12.0",
43
- "@gajae-code/natives": "0.15.6",
44
- "@gajae-code/utils": "0.15.6",
43
+ "@gajae-code/natives": "0.16.0",
44
+ "@gajae-code/utils": "0.16.0",
45
45
  "openai": "^6.36.0",
46
46
  "partial-json": "^0.1.7",
47
47
  "zod": "4.4.3"
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Fail closed before an AWS region is interpolated into a credential-bearing
3
+ * service authority. Region names are one lowercase ASCII DNS label; dots,
4
+ * URL delimiters, Unicode, whitespace, and controls must never reach URL
5
+ * parsing as part of that label.
6
+ */
7
+ export declare function assertAwsRegionLabel(region: unknown): asserts region is string;
@@ -0,0 +1,14 @@
1
+ const AWS_REGION_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
2
+
3
+ /**
4
+ * Fail closed before an AWS region is interpolated into a credential-bearing
5
+ * service authority. Region names are one lowercase ASCII DNS label; dots,
6
+ * URL delimiters, Unicode, whitespace, and controls must never reach URL
7
+ * parsing as part of that label.
8
+ */
9
+ export function assertAwsRegionLabel(region: unknown): asserts region is string {
10
+ const match = typeof region === "string" ? AWS_REGION_LABEL.exec(region) : undefined;
11
+ if (!match || match[0] !== region) {
12
+ throw new Error("Invalid AWS region: expected a lowercase ASCII DNS label.");
13
+ }
14
+ }
@@ -37,6 +37,7 @@ import type {
37
37
  OAuthProvider,
38
38
  OAuthProviderId,
39
39
  } from "./utils/oauth/types";
40
+ import { isSqliteError } from "./utils/sqlite-errors";
40
41
 
41
42
  // ─────────────────────────────────────────────────────────────────────────────
42
43
  // Credential Types
@@ -4944,7 +4945,9 @@ export class AuthStorage {
4944
4945
  !refreshedCredentials.persistedByLease,
4945
4946
  credentialId,
4946
4947
  );
4947
- } catch {}
4948
+ } catch (error) {
4949
+ if (isSqliteError(error)) throw error;
4950
+ }
4948
4951
  }),
4949
4952
  );
4950
4953
 
@@ -5408,6 +5411,7 @@ export class AuthStorage {
5408
5411
  this.#recordSessionCredential(provider, sessionId, "oauth", selection.index);
5409
5412
  return { apiKey: result.apiKey, credential: updated };
5410
5413
  } catch (error) {
5414
+ if (isSqliteError(error)) throw error;
5411
5415
  // Auth-broker errors retain the sanitized upstream body separately from
5412
5416
  // their transport message. Include that body for failure classification
5413
5417
  // (the broker's 500 envelope otherwise hides `invalid_grant`) while
@@ -7116,19 +7120,15 @@ export class SqliteAuthCredentialStore implements AuthCredentialStore {
7116
7120
  }
7117
7121
 
7118
7122
  updateAuthCredential(id: number, credential: AuthCredential): void {
7119
- try {
7120
- const providerRow = this.#db.prepare("SELECT provider FROM auth_credentials WHERE id = ?").get(id) as
7121
- | { provider?: string }
7122
- | undefined;
7123
- const provider = providerRow?.provider ?? "";
7124
- const serialized = serializeCredential(provider, credential);
7125
- if (!serialized) return;
7126
- this.#updateStmt.run(serialized.credentialType, serialized.data, serialized.identityKey, id);
7127
- if (provider) {
7128
- this.#purgeSupersededDisabledRows(provider, this.listAuthCredentials(provider));
7129
- }
7130
- } catch {
7131
- // Ignore update failures
7123
+ const providerRow = this.#db.prepare("SELECT provider FROM auth_credentials WHERE id = ?").get(id) as
7124
+ | { provider?: string }
7125
+ | undefined;
7126
+ const provider = providerRow?.provider ?? "";
7127
+ const serialized = serializeCredential(provider, credential);
7128
+ if (!serialized) return;
7129
+ this.#updateStmt.run(serialized.credentialType, serialized.data, serialized.identityKey, id);
7130
+ if (provider) {
7131
+ this.#purgeSupersededDisabledRows(provider, this.listAuthCredentials(provider));
7132
7132
  }
7133
7133
  }
7134
7134
 
package/src/core.ts CHANGED
@@ -40,5 +40,6 @@ export type {
40
40
  export * from "./utils/overflow";
41
41
  export * from "./utils/retry";
42
42
  export * from "./utils/schema";
43
+ export * from "./utils/sqlite-errors";
43
44
  export * from "./utils/tool-choice-capability";
44
45
  export * from "./utils/validation";
package/src/index.ts CHANGED
@@ -57,5 +57,6 @@ export * from "./utils/overflow";
57
57
  export * from "./utils/provider-safety-stop";
58
58
  export * from "./utils/retry";
59
59
  export * from "./utils/schema";
60
+ export * from "./utils/sqlite-errors";
60
61
  export * from "./utils/tool-choice-capability";
61
62
  export * from "./utils/validation";
@@ -278,6 +278,14 @@ export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
278
278
  if (source.provider === "omlx") {
279
279
  source.reasoning = true;
280
280
  }
281
+ if (
282
+ source.provider === "cursor" &&
283
+ (source.id === "kimi-k3-low" || source.id === "kimi-k3-high" || source.id === "kimi-k3-max")
284
+ ) {
285
+ // Cursor's GetUsableModels metadata omits numeric context limits for
286
+ // this family. Keep the measured 1M fallback across regeneration.
287
+ source.contextWindow = 1_048_576;
288
+ }
281
289
  const model = refreshModelThinking(source);
282
290
  applyGeneratedModelPolicy(model);
283
291
  models[index] = model;
package/src/models.json CHANGED
@@ -3853,6 +3853,31 @@
3853
3853
  "maxLevel": "xhigh"
3854
3854
  }
3855
3855
  },
3856
+ "claude-fable-5-1": {
3857
+ "id": "claude-fable-5-1",
3858
+ "name": "Anthropic Fable 5.1",
3859
+ "api": "anthropic-messages",
3860
+ "provider": "anthropic",
3861
+ "baseUrl": "https://api.anthropic.com",
3862
+ "reasoning": true,
3863
+ "input": [
3864
+ "text",
3865
+ "image"
3866
+ ],
3867
+ "cost": {
3868
+ "input": 10,
3869
+ "output": 50,
3870
+ "cacheRead": 0.25,
3871
+ "cacheWrite": 12.5
3872
+ },
3873
+ "contextWindow": 1000000,
3874
+ "maxTokens": 128000,
3875
+ "thinking": {
3876
+ "mode": "anthropic-adaptive",
3877
+ "minLevel": "minimal",
3878
+ "maxLevel": "xhigh"
3879
+ }
3880
+ },
3856
3881
  "claude-haiku-4-5": {
3857
3882
  "id": "claude-haiku-4-5",
3858
3883
  "name": "Anthropic Haiku 4.5 (latest)",
@@ -10900,7 +10925,7 @@
10900
10925
  "cacheRead": 0,
10901
10926
  "cacheWrite": 0
10902
10927
  },
10903
- "contextWindow": 200000,
10928
+ "contextWindow": 1048576,
10904
10929
  "maxTokens": 64000
10905
10930
  },
10906
10931
  "kimi-k3-low": {
@@ -10919,7 +10944,7 @@
10919
10944
  "cacheRead": 0,
10920
10945
  "cacheWrite": 0
10921
10946
  },
10922
- "contextWindow": 200000,
10947
+ "contextWindow": 1048576,
10923
10948
  "maxTokens": 64000
10924
10949
  },
10925
10950
  "kimi-k3-max": {
@@ -10938,7 +10963,7 @@
10938
10963
  "cacheRead": 0,
10939
10964
  "cacheWrite": 0
10940
10965
  },
10941
- "contextWindow": 200000,
10966
+ "contextWindow": 1048576,
10942
10967
  "maxTokens": 64000
10943
10968
  }
10944
10969
  },
@@ -66259,6 +66284,179 @@
66259
66284
  "minLevel": "minimal",
66260
66285
  "maxLevel": "xhigh"
66261
66286
  }
66287
+ },
66288
+ "deepseek-v4-flash-vision-exp": {
66289
+ "id": "deepseek-v4-flash-vision-exp",
66290
+ "name": "DeepSeek V4 Flash Vision Exp",
66291
+ "api": "openai-completions",
66292
+ "provider": "opencode-go",
66293
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66294
+ "reasoning": true,
66295
+ "input": [
66296
+ "text",
66297
+ "image"
66298
+ ],
66299
+ "cost": {
66300
+ "input": 0.22,
66301
+ "output": 0.66,
66302
+ "cacheRead": 0.007,
66303
+ "cacheWrite": 0
66304
+ },
66305
+ "contextWindow": 1000000,
66306
+ "maxTokens": 384000,
66307
+ "thinking": {
66308
+ "mode": "effort",
66309
+ "minLevel": "minimal",
66310
+ "maxLevel": "xhigh"
66311
+ }
66312
+ },
66313
+ "glm-5.3-flash": {
66314
+ "id": "glm-5.3-flash",
66315
+ "name": "GLM-5.3-Flash (2x usage)",
66316
+ "api": "openai-completions",
66317
+ "provider": "opencode-go",
66318
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66319
+ "reasoning": true,
66320
+ "input": [
66321
+ "text",
66322
+ "image"
66323
+ ],
66324
+ "cost": {
66325
+ "input": 0.075,
66326
+ "output": 0.25,
66327
+ "cacheRead": 0.015,
66328
+ "cacheWrite": 0
66329
+ },
66330
+ "contextWindow": 1000000,
66331
+ "maxTokens": 131072,
66332
+ "thinking": {
66333
+ "mode": "effort",
66334
+ "minLevel": "minimal",
66335
+ "maxLevel": "xhigh"
66336
+ }
66337
+ },
66338
+ "grok-4.6": {
66339
+ "id": "grok-4.6",
66340
+ "name": "Grok 4.6",
66341
+ "api": "openai-responses",
66342
+ "provider": "opencode-go",
66343
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66344
+ "reasoning": true,
66345
+ "input": [
66346
+ "text",
66347
+ "image"
66348
+ ],
66349
+ "cost": {
66350
+ "input": 2,
66351
+ "output": 6,
66352
+ "cacheRead": 0.5,
66353
+ "cacheWrite": 0
66354
+ },
66355
+ "contextWindow": 500000,
66356
+ "maxTokens": 500000,
66357
+ "thinking": {
66358
+ "mode": "effort",
66359
+ "minLevel": "minimal",
66360
+ "maxLevel": "xhigh"
66361
+ }
66362
+ },
66363
+ "hy4-preview": {
66364
+ "id": "hy4-preview",
66365
+ "name": "Hy4 preview",
66366
+ "api": "openai-completions",
66367
+ "provider": "opencode-go",
66368
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66369
+ "reasoning": true,
66370
+ "input": [
66371
+ "text"
66372
+ ],
66373
+ "cost": {
66374
+ "input": 0.834,
66375
+ "output": 2.501,
66376
+ "cacheRead": 0.042,
66377
+ "cacheWrite": 0
66378
+ },
66379
+ "contextWindow": 1024000,
66380
+ "maxTokens": 64000,
66381
+ "thinking": {
66382
+ "mode": "effort",
66383
+ "minLevel": "minimal",
66384
+ "maxLevel": "xhigh"
66385
+ }
66386
+ },
66387
+ "longcat-2.0": {
66388
+ "id": "longcat-2.0",
66389
+ "name": "LongCat-2.0",
66390
+ "api": "openai-completions",
66391
+ "provider": "opencode-go",
66392
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66393
+ "reasoning": true,
66394
+ "input": [
66395
+ "text"
66396
+ ],
66397
+ "cost": {
66398
+ "input": 0.3,
66399
+ "output": 1.2,
66400
+ "cacheRead": 0.006,
66401
+ "cacheWrite": 0
66402
+ },
66403
+ "contextWindow": 1000000,
66404
+ "maxTokens": 131072,
66405
+ "thinking": {
66406
+ "mode": "effort",
66407
+ "minLevel": "minimal",
66408
+ "maxLevel": "xhigh"
66409
+ }
66410
+ },
66411
+ "muse-spark-1.2-contributor": {
66412
+ "id": "muse-spark-1.2-contributor",
66413
+ "name": "Muse Spark 1.2 Contributor",
66414
+ "api": "openai-responses",
66415
+ "provider": "opencode-go",
66416
+ "baseUrl": "https://opencode.ai/zen/go/v1",
66417
+ "reasoning": true,
66418
+ "input": [
66419
+ "text",
66420
+ "image"
66421
+ ],
66422
+ "cost": {
66423
+ "input": 0.1,
66424
+ "output": 0.2,
66425
+ "cacheRead": 0.002,
66426
+ "cacheWrite": 0
66427
+ },
66428
+ "contextWindow": 1048576,
66429
+ "maxTokens": 131072,
66430
+ "thinking": {
66431
+ "mode": "effort",
66432
+ "minLevel": "minimal",
66433
+ "maxLevel": "xhigh"
66434
+ }
66435
+ },
66436
+ "qwen3.8-flash": {
66437
+ "id": "qwen3.8-flash",
66438
+ "name": "Qwen3.8 Flash",
66439
+ "api": "anthropic-messages",
66440
+ "provider": "opencode-go",
66441
+ "baseUrl": "https://opencode.ai/zen/go",
66442
+ "reasoning": true,
66443
+ "input": [
66444
+ "text",
66445
+ "image"
66446
+ ],
66447
+ "cost": {
66448
+ "input": 0.15,
66449
+ "output": 0.47,
66450
+ "cacheRead": 0.016,
66451
+ "cacheWrite": 0.2
66452
+ },
66453
+ "contextWindow": 1000000,
66454
+ "maxTokens": 131072,
66455
+ "thinking": {
66456
+ "mode": "budget",
66457
+ "minLevel": "minimal",
66458
+ "maxLevel": "xhigh"
66459
+ }
66262
66460
  }
66263
66461
  },
66264
66462
  "opencode-zen": {
@@ -2357,11 +2357,15 @@ const OPENCODE_GO_BASE_PATH = "https://opencode.ai/zen/go";
2357
2357
  const OPENCODE_ZEN_API_RESOLUTION = createOpenCodeApiResolution("https://opencode.ai/zen");
2358
2358
  const OPENCODE_GO_CHAT_COMPLETIONS_MODEL_IDS = [
2359
2359
  "deepseek-v4-flash",
2360
+ "deepseek-v4-flash-vision-exp",
2360
2361
  "deepseek-v4-pro",
2361
2362
  "glm-5.1",
2362
2363
  "glm-5.2",
2364
+ "glm-5.3-flash",
2363
2365
  "kimi-k2.6",
2364
2366
  "kimi-k2.7-code",
2367
+ "hy4-preview",
2368
+ "longcat-2.0",
2365
2369
  "mimo-v2.5",
2366
2370
  "mimo-v2.5-pro",
2367
2371
  ] as const;
@@ -2372,6 +2376,7 @@ const OPENCODE_GO_MESSAGES_MODEL_IDS = [
2372
2376
  "qwen3.6-plus",
2373
2377
  "qwen3.7-max",
2374
2378
  "qwen3.7-plus",
2379
+ "qwen3.8-flash",
2375
2380
  ] as const;
2376
2381
  const OPENCODE_GO_API_OVERRIDES: Readonly<Record<string, Api>> = {
2377
2382
  ...Object.fromEntries(OPENCODE_GO_CHAT_COMPLETIONS_MODEL_IDS.map(id => [id, "openai-completions"])),
@@ -2796,6 +2801,62 @@ const OPENCODE_GO_OFFICIAL_MODELS: Readonly<Record<string, OpenCodeGoOfficialMod
2796
2801
  reasoning: true,
2797
2802
  cost: { input: 0.066, output: 0.26, cacheRead: 0.029, cacheWrite: 0 },
2798
2803
  },
2804
+ "deepseek-v4-flash-vision-exp": {
2805
+ name: "DeepSeek V4 Flash Vision Exp",
2806
+ contextWindow: 1_000_000,
2807
+ maxTokens: 384_000,
2808
+ input: ["text", "image"],
2809
+ reasoning: true,
2810
+ cost: { input: 0.22, output: 0.66, cacheRead: 0.007, cacheWrite: 0 },
2811
+ },
2812
+ "glm-5.3-flash": {
2813
+ name: "GLM-5.3-Flash (2x usage)",
2814
+ contextWindow: 1_000_000,
2815
+ maxTokens: 131_072,
2816
+ input: ["text", "image"],
2817
+ reasoning: true,
2818
+ cost: { input: 0.075, output: 0.25, cacheRead: 0.015, cacheWrite: 0 },
2819
+ },
2820
+ "grok-4.6": {
2821
+ name: "Grok 4.6",
2822
+ contextWindow: 500_000,
2823
+ maxTokens: 500_000,
2824
+ input: ["text", "image"],
2825
+ reasoning: true,
2826
+ cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 },
2827
+ },
2828
+ "hy4-preview": {
2829
+ name: "Hy4 preview",
2830
+ contextWindow: 1_024_000,
2831
+ maxTokens: 64_000,
2832
+ input: ["text"],
2833
+ reasoning: true,
2834
+ cost: { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 },
2835
+ },
2836
+ "longcat-2.0": {
2837
+ name: "LongCat-2.0",
2838
+ contextWindow: 1_000_000,
2839
+ maxTokens: 131_072,
2840
+ input: ["text"],
2841
+ reasoning: true,
2842
+ cost: { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 },
2843
+ },
2844
+ "muse-spark-1.2-contributor": {
2845
+ name: "Muse Spark 1.2 Contributor",
2846
+ contextWindow: 1_048_576,
2847
+ maxTokens: 131_072,
2848
+ input: ["text", "image"],
2849
+ reasoning: true,
2850
+ cost: { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 },
2851
+ },
2852
+ "qwen3.8-flash": {
2853
+ name: "Qwen3.8 Flash",
2854
+ contextWindow: 1_000_000,
2855
+ maxTokens: 131_072,
2856
+ input: ["text", "image"],
2857
+ reasoning: true,
2858
+ cost: { input: 0.15, output: 0.47, cacheRead: 0.016, cacheWrite: 0.2 },
2859
+ },
2799
2860
  };
2800
2861
 
2801
2862
  function applyOpenCodeGoOfficialMetadata<TApi extends Api>(model: Model<TApi>): Model<TApi> {
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import { $credentialEnv, $env, $flag, extractHttpStatusFromError, fetchWithRetry } from "@gajae-code/utils";
11
+ import { assertAwsRegionLabel } from "../adapter-internals/aws-region";
11
12
  import type { Effort } from "../model-thinking";
12
13
  import {
13
14
  mapEffortToAnthropicAdaptiveEffort,
@@ -202,9 +203,10 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
202
203
 
203
204
  const blocks = output.content as Block[];
204
205
  let rawRequestDump: RawHttpRequestDump | undefined;
205
- const region = options.region || $env.AWS_REGION || $env.AWS_DEFAULT_REGION || "us-east-1";
206
+ const region = options.region ?? $env.AWS_REGION ?? $env.AWS_DEFAULT_REGION ?? "us-east-1";
206
207
 
207
208
  try {
209
+ assertAwsRegionLabel(region);
208
210
  const cacheRetention = resolveCacheRetention(options.cacheRetention);
209
211
  const resolvedToolChoice = resolveToolChoice(model, options.toolChoice);
210
212
  const toolConfig = convertToolConfig(context.tools, resolvedToolChoice.resolvedChoice);
@@ -303,6 +305,7 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
303
305
  method: "POST",
304
306
  headers: await buildRequestHeaders(retryBody),
305
307
  body: retryBody,
308
+ redirect: "error",
306
309
  signal: options.signal,
307
310
  maxAttempts: 1,
308
311
  });
@@ -312,6 +315,7 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
312
315
  method: "POST",
313
316
  headers: requestHeaders,
314
317
  body,
318
+ redirect: "error",
315
319
  signal: options.signal,
316
320
  maxAttempts: resolveRetryBudget(options.requestMaxRetries, 4) + 1,
317
321
  });
@@ -107,7 +107,7 @@ export interface CpaToolAliasRestoreFailure {
107
107
  */
108
108
  export declare function parseCpaToolAliasRestoreFailure(error: unknown): CpaToolAliasRestoreFailure | undefined;
109
109
  export declare function isCpaToolAliasRestoreFailure(error: unknown): boolean;
110
- export declare const claudeCodeVersion = "2.1.219";
110
+ export declare const claudeCodeVersion = "2.1.257";
111
111
  export declare const claudeCodeEntrypoint = "sdk-cli";
112
112
  export declare const claudeToolPrefix: string;
113
113
  export declare const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
@@ -828,7 +828,7 @@ function getCacheControl(
828
828
  }
829
829
 
830
830
  // Stealth mode: Mimic Anthropic Code headers and tool prefixing.
831
- export const claudeCodeVersion = "2.1.219";
831
+ export const claudeCodeVersion = "2.1.257";
832
832
  export const claudeCodeEntrypoint = "sdk-cli";
833
833
  export const claudeToolPrefix: string = "proxy_";
834
834
  export const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";