@gajae-code/ai 0.16.7 → 0.17.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 +44 -1
- package/dist/types/auth-storage.d.ts +23 -4
- package/dist/types/models.d.ts +14 -0
- package/dist/types/provider-models/special.d.ts +12 -0
- package/dist/types/providers/anthropic.d.ts +1 -1
- package/dist/types/providers/cursor.d.ts +33 -21
- package/dist/types/providers/devin-acp.d.ts +157 -0
- package/dist/types/providers/google-gemini-headers.d.ts +1 -1
- package/dist/types/providers/mock.d.ts +2 -0
- package/dist/types/providers/openai-responses-shared.d.ts +21 -1
- package/dist/types/providers/register-builtins.d.ts +1 -0
- package/dist/types/types.d.ts +52 -11
- package/dist/types/utils/block-symbols.d.ts +15 -5
- package/dist/types/utils/fallback-transport.d.ts +4 -1
- package/dist/types/utils.d.ts +13 -0
- package/package.json +4 -3
- package/src/api-registry.ts +1 -0
- package/src/auth-broker/redact.ts +10 -2
- package/src/auth-gateway/server.ts +56 -3
- package/src/auth-storage.ts +330 -116
- package/src/model-manager.ts +21 -2
- package/src/models.d.ts +14 -0
- package/src/models.json +117 -0
- package/src/models.ts +18 -0
- package/src/provider-models/descriptors.ts +7 -0
- package/src/provider-models/openai-compat.ts +14 -0
- package/src/provider-models/special.ts +39 -0
- package/src/providers/anthropic.d.ts +1 -1
- package/src/providers/anthropic.ts +1 -1
- package/src/providers/azure-openai-responses.ts +10 -1
- package/src/providers/cursor.d.ts +33 -21
- package/src/providers/cursor.ts +2024 -508
- package/src/providers/devin-acp.d.ts +157 -0
- package/src/providers/devin-acp.ts +1103 -0
- package/src/providers/google-gemini-headers.d.ts +1 -1
- package/src/providers/google-gemini-headers.ts +1 -1
- package/src/providers/mock.ts +16 -1
- package/src/providers/openai-chat-server.ts +3 -3
- package/src/providers/openai-codex-responses.ts +27 -17
- package/src/providers/openai-responses-server.ts +5 -5
- package/src/providers/openai-responses-shared.d.ts +21 -1
- package/src/providers/openai-responses-shared.ts +60 -6
- package/src/providers/openai-responses.ts +10 -1
- package/src/providers/register-builtins.d.ts +1 -0
- package/src/providers/register-builtins.ts +21 -1
- package/src/stream.ts +14 -0
- package/src/types.d.ts +52 -11
- package/src/types.ts +70 -8
- package/src/utils/block-symbols.d.ts +15 -5
- package/src/utils/block-symbols.ts +16 -6
- package/src/utils/discovery/cursor.ts +3 -2
- package/src/utils/fallback-transport.d.ts +4 -1
- package/src/utils/fallback-transport.ts +12 -5
- package/src/utils.d.ts +13 -0
- package/src/utils.ts +17 -0
- package/dist/types/utils/codex-entitlement.d.ts +0 -22
- package/src/utils/codex-entitlement.d.ts +0 -22
- package/src/utils/codex-entitlement.ts +0 -57
package/src/model-manager.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { insertModelCacheIfAbsent, readModelCache, updateModelCacheIfUnchanged,
|
|
|
4
4
|
import { isRetiredModel, isRetiredModelKey } from "./model-retirements";
|
|
5
5
|
import { applyGeneratedModelPolicies, enrichModelThinking } from "./model-thinking";
|
|
6
6
|
import { type GeneratedProvider, getBundledModels } from "./models";
|
|
7
|
+
import { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "./provider-models/openai-compat";
|
|
7
8
|
import type { Api, Model, Provider } from "./types";
|
|
8
9
|
import { isSafeCatalogModelId } from "./utils/discovery/openai-compatible";
|
|
9
10
|
|
|
@@ -552,6 +553,20 @@ function fingerprintStatic<TApi extends Api>(models: readonly Model<TApi>[]): st
|
|
|
552
553
|
|
|
553
554
|
function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamicModel: Model<TApi>): Model<TApi> {
|
|
554
555
|
const supportsImage = existingModel.input.includes("image") || dynamicModel.input.includes("image");
|
|
556
|
+
// Before this exact Go model was curated, ID-only discovery cached the
|
|
557
|
+
// non-reasoning Completions defaults. A fresh authoritative cache can skip
|
|
558
|
+
// discovery after an upgrade, so recover its limits from reviewed static
|
|
559
|
+
// Responses metadata here. Do not reinterpret individual numeric limits or
|
|
560
|
+
// apply this correction to reviewed discovery rows or other model IDs.
|
|
561
|
+
const hasPreReviewMuseLimits =
|
|
562
|
+
existingModel.provider === "opencode-go" &&
|
|
563
|
+
existingModel.id === "muse-spark-1.3-contributor" &&
|
|
564
|
+
existingModel.api === "openai-responses" &&
|
|
565
|
+
existingModel.reasoning &&
|
|
566
|
+
dynamicModel.api === "openai-completions" &&
|
|
567
|
+
!dynamicModel.reasoning &&
|
|
568
|
+
dynamicModel.contextWindow === UNK_CONTEXT_WINDOW &&
|
|
569
|
+
dynamicModel.maxTokens === UNK_MAX_TOKENS;
|
|
555
570
|
// The static catalog is authoritative for transport: `api` (and its
|
|
556
571
|
// api-specific `baseUrl`). Dynamic discovery enumerates ids via a single
|
|
557
572
|
// hardcoded api (e.g. fetchOpenAICompatibleModels always tags
|
|
@@ -579,8 +594,12 @@ function mergeDynamicModel<TApi extends Api>(existingModel: Model<TApi>, dynamic
|
|
|
579
594
|
cacheRead: preferDiscoveryCost(dynamicModel.cost.cacheRead, existingModel.cost.cacheRead),
|
|
580
595
|
cacheWrite: preferDiscoveryCost(dynamicModel.cost.cacheWrite, existingModel.cost.cacheWrite),
|
|
581
596
|
},
|
|
582
|
-
contextWindow:
|
|
583
|
-
|
|
597
|
+
contextWindow: hasPreReviewMuseLimits
|
|
598
|
+
? existingModel.contextWindow
|
|
599
|
+
: preferDiscoveryLimit(dynamicModel.contextWindow, existingModel.contextWindow),
|
|
600
|
+
maxTokens: hasPreReviewMuseLimits
|
|
601
|
+
? existingModel.maxTokens
|
|
602
|
+
: preferDiscoveryLimit(dynamicModel.maxTokens, existingModel.maxTokens),
|
|
584
603
|
headers: dynamicModel.headers ? { ...existingModel.headers, ...dynamicModel.headers } : existingModel.headers,
|
|
585
604
|
compat: dynamicModel.compat ?? existingModel.compat,
|
|
586
605
|
contextPromotionTarget: dynamicModel.contextPromotionTarget ?? existingModel.contextPromotionTarget,
|
package/src/models.d.ts
CHANGED
|
@@ -18,4 +18,18 @@ export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usag
|
|
|
18
18
|
* Returns false if either model is null or undefined.
|
|
19
19
|
*/
|
|
20
20
|
export declare function modelsAreEqual<TApi extends Api>(a: Model<TApi> | null | undefined, b: Model<TApi> | null | undefined): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* APIs backed by agent-level providers — currently Devin over ACP. An
|
|
23
|
+
* agent-level provider runs its own agent loop and owns the conversation
|
|
24
|
+
* history, so it refuses GJC maintenance calls (`maintenanceCall` requests such
|
|
25
|
+
* as compaction summaries, handoff generation, and branch summaries) instead of
|
|
26
|
+
* spending billed agent quota on work it cannot answer as a text model.
|
|
27
|
+
*/
|
|
28
|
+
export declare const AGENT_LEVEL_PROVIDER_APIS: ReadonlySet<Api>;
|
|
29
|
+
/**
|
|
30
|
+
* Whether a model's provider can serve GJC maintenance calls at all. When this
|
|
31
|
+
* is false for every model a maintenance action can reach, the call can only
|
|
32
|
+
* report a guaranteed refusal, so callers should skip rather than surface it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function modelSupportsMaintenanceCalls(model: Model<Api>): boolean;
|
|
21
35
|
export {};
|
package/src/models.json
CHANGED
|
@@ -64677,6 +64677,52 @@
|
|
|
64677
64677
|
"provider": "openai",
|
|
64678
64678
|
"baseUrl": ""
|
|
64679
64679
|
},
|
|
64680
|
+
"gpt-image-2.5-flare": {
|
|
64681
|
+
"id": "gpt-image-2.5-flare",
|
|
64682
|
+
"name": "GPT Image 2.5 Flare",
|
|
64683
|
+
"reasoning": false,
|
|
64684
|
+
"input": [
|
|
64685
|
+
"text"
|
|
64686
|
+
],
|
|
64687
|
+
"output": [
|
|
64688
|
+
"text",
|
|
64689
|
+
"image"
|
|
64690
|
+
],
|
|
64691
|
+
"cost": {
|
|
64692
|
+
"input": 0,
|
|
64693
|
+
"output": 0,
|
|
64694
|
+
"cacheRead": 0,
|
|
64695
|
+
"cacheWrite": 0
|
|
64696
|
+
},
|
|
64697
|
+
"contextWindow": 128000,
|
|
64698
|
+
"maxTokens": 16384,
|
|
64699
|
+
"api": "openai-responses",
|
|
64700
|
+
"provider": "openai",
|
|
64701
|
+
"baseUrl": ""
|
|
64702
|
+
},
|
|
64703
|
+
"gpt-image-2.5-sunburst": {
|
|
64704
|
+
"id": "gpt-image-2.5-sunburst",
|
|
64705
|
+
"name": "GPT Image 2.5 Sunburst",
|
|
64706
|
+
"reasoning": false,
|
|
64707
|
+
"input": [
|
|
64708
|
+
"text"
|
|
64709
|
+
],
|
|
64710
|
+
"output": [
|
|
64711
|
+
"text",
|
|
64712
|
+
"image"
|
|
64713
|
+
],
|
|
64714
|
+
"cost": {
|
|
64715
|
+
"input": 0,
|
|
64716
|
+
"output": 0,
|
|
64717
|
+
"cacheRead": 0,
|
|
64718
|
+
"cacheWrite": 0
|
|
64719
|
+
},
|
|
64720
|
+
"contextWindow": 128000,
|
|
64721
|
+
"maxTokens": 16384,
|
|
64722
|
+
"api": "openai-responses",
|
|
64723
|
+
"provider": "openai",
|
|
64724
|
+
"baseUrl": ""
|
|
64725
|
+
},
|
|
64680
64726
|
"gpt-realtime-2.1": {
|
|
64681
64727
|
"id": "gpt-realtime-2.1",
|
|
64682
64728
|
"name": "GPT-Realtime-2.1",
|
|
@@ -65547,6 +65593,52 @@
|
|
|
65547
65593
|
"api": "openai-codex-responses",
|
|
65548
65594
|
"provider": "openai-codex",
|
|
65549
65595
|
"baseUrl": ""
|
|
65596
|
+
},
|
|
65597
|
+
"gpt-image-2.5-flare": {
|
|
65598
|
+
"id": "gpt-image-2.5-flare",
|
|
65599
|
+
"name": "GPT Image 2.5 Flare",
|
|
65600
|
+
"reasoning": false,
|
|
65601
|
+
"input": [
|
|
65602
|
+
"text"
|
|
65603
|
+
],
|
|
65604
|
+
"output": [
|
|
65605
|
+
"text",
|
|
65606
|
+
"image"
|
|
65607
|
+
],
|
|
65608
|
+
"cost": {
|
|
65609
|
+
"input": 0,
|
|
65610
|
+
"output": 0,
|
|
65611
|
+
"cacheRead": 0,
|
|
65612
|
+
"cacheWrite": 0
|
|
65613
|
+
},
|
|
65614
|
+
"contextWindow": 128000,
|
|
65615
|
+
"maxTokens": 16384,
|
|
65616
|
+
"api": "openai-codex-responses",
|
|
65617
|
+
"provider": "openai-codex",
|
|
65618
|
+
"baseUrl": ""
|
|
65619
|
+
},
|
|
65620
|
+
"gpt-image-2.5-sunburst": {
|
|
65621
|
+
"id": "gpt-image-2.5-sunburst",
|
|
65622
|
+
"name": "GPT Image 2.5 Sunburst",
|
|
65623
|
+
"reasoning": false,
|
|
65624
|
+
"input": [
|
|
65625
|
+
"text"
|
|
65626
|
+
],
|
|
65627
|
+
"output": [
|
|
65628
|
+
"text",
|
|
65629
|
+
"image"
|
|
65630
|
+
],
|
|
65631
|
+
"cost": {
|
|
65632
|
+
"input": 0,
|
|
65633
|
+
"output": 0,
|
|
65634
|
+
"cacheRead": 0,
|
|
65635
|
+
"cacheWrite": 0
|
|
65636
|
+
},
|
|
65637
|
+
"contextWindow": 128000,
|
|
65638
|
+
"maxTokens": 16384,
|
|
65639
|
+
"api": "openai-codex-responses",
|
|
65640
|
+
"provider": "openai-codex",
|
|
65641
|
+
"baseUrl": ""
|
|
65550
65642
|
}
|
|
65551
65643
|
},
|
|
65552
65644
|
"opencode": {
|
|
@@ -66470,6 +66562,31 @@
|
|
|
66470
66562
|
"maxLevel": "xhigh"
|
|
66471
66563
|
}
|
|
66472
66564
|
},
|
|
66565
|
+
"muse-spark-1.3-contributor": {
|
|
66566
|
+
"id": "muse-spark-1.3-contributor",
|
|
66567
|
+
"name": "Muse Spark 1.3 Contributor",
|
|
66568
|
+
"api": "openai-responses",
|
|
66569
|
+
"provider": "opencode-go",
|
|
66570
|
+
"baseUrl": "https://opencode.ai/zen/go/v1",
|
|
66571
|
+
"reasoning": true,
|
|
66572
|
+
"input": [
|
|
66573
|
+
"text",
|
|
66574
|
+
"image"
|
|
66575
|
+
],
|
|
66576
|
+
"cost": {
|
|
66577
|
+
"input": 0.1,
|
|
66578
|
+
"output": 0.2,
|
|
66579
|
+
"cacheRead": 0.002,
|
|
66580
|
+
"cacheWrite": 0
|
|
66581
|
+
},
|
|
66582
|
+
"contextWindow": 1048576,
|
|
66583
|
+
"maxTokens": 131072,
|
|
66584
|
+
"thinking": {
|
|
66585
|
+
"mode": "effort",
|
|
66586
|
+
"minLevel": "minimal",
|
|
66587
|
+
"maxLevel": "xhigh"
|
|
66588
|
+
}
|
|
66589
|
+
},
|
|
66473
66590
|
"qwen3.8-flash": {
|
|
66474
66591
|
"id": "qwen3.8-flash",
|
|
66475
66592
|
"name": "Qwen3.8 Flash",
|
package/src/models.ts
CHANGED
|
@@ -124,3 +124,21 @@ export function modelsAreEqual<TApi extends Api>(
|
|
|
124
124
|
if (!a || !b) return false;
|
|
125
125
|
return a.id === b.id && a.provider === b.provider;
|
|
126
126
|
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* APIs backed by agent-level providers — currently Devin over ACP. An
|
|
130
|
+
* agent-level provider runs its own agent loop and owns the conversation
|
|
131
|
+
* history, so it refuses GJC maintenance calls (`maintenanceCall` requests such
|
|
132
|
+
* as compaction summaries, handoff generation, and branch summaries) instead of
|
|
133
|
+
* spending billed agent quota on work it cannot answer as a text model.
|
|
134
|
+
*/
|
|
135
|
+
export const AGENT_LEVEL_PROVIDER_APIS: ReadonlySet<Api> = new Set<Api>(["devin-acp"]);
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Whether a model's provider can serve GJC maintenance calls at all. When this
|
|
139
|
+
* is false for every model a maintenance action can reach, the call can only
|
|
140
|
+
* report a guaranteed refusal, so callers should skip rather than surface it.
|
|
141
|
+
*/
|
|
142
|
+
export function modelSupportsMaintenanceCalls(model: Model<Api>): boolean {
|
|
143
|
+
return !AGENT_LEVEL_PROVIDER_APIS.has(model.api);
|
|
144
|
+
}
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
} from "./openai-compat";
|
|
54
54
|
import {
|
|
55
55
|
cursorModelManagerOptions,
|
|
56
|
+
devinModelManagerOptions,
|
|
56
57
|
glmZcodeModelManagerOptions,
|
|
57
58
|
jetbrainsJunieModelManagerOptions,
|
|
58
59
|
kiroModelManagerOptions,
|
|
@@ -364,6 +365,12 @@ export const PROVIDER_DESCRIPTORS: readonly ProviderDescriptor[] = [
|
|
|
364
365
|
catalog("GLM ZCode (unofficial)", ["GLM_ZCODE_API_KEY"], { oauthProvider: "glm-zcode" }),
|
|
365
366
|
),
|
|
366
367
|
descriptor("jetbrains-junie", "claude-sonnet-4-6", config => jetbrainsJunieModelManagerOptions(config)),
|
|
368
|
+
// `adaptive` is Devin's documented recommended default (docs.devin.ai/cli/adaptive).
|
|
369
|
+
// Enterprise organizations may disable it; the account's real model list comes from
|
|
370
|
+
// the ACP session's model config option.
|
|
371
|
+
descriptor("devin", "adaptive", () => devinModelManagerOptions(), {
|
|
372
|
+
allowUnauthenticated: true,
|
|
373
|
+
}),
|
|
367
374
|
descriptor("github-copilot", "gpt-4o", config => githubCopilotModelManagerOptions(config)),
|
|
368
375
|
descriptor("google", "gemini-2.5-pro", config => googleModelManagerOptions(config)),
|
|
369
376
|
catalogDescriptor(
|
|
@@ -2405,6 +2405,7 @@ const OPENCODE_GO_MESSAGES_MODEL_IDS = [
|
|
|
2405
2405
|
const OPENCODE_GO_API_OVERRIDES: Readonly<Record<string, Api>> = {
|
|
2406
2406
|
...Object.fromEntries(OPENCODE_GO_CHAT_COMPLETIONS_MODEL_IDS.map(id => [id, "openai-completions"])),
|
|
2407
2407
|
...Object.fromEntries(OPENCODE_GO_MESSAGES_MODEL_IDS.map(id => [id, "anthropic-messages"])),
|
|
2408
|
+
"muse-spark-1.3-contributor": "openai-responses",
|
|
2408
2409
|
} as Record<string, Api>;
|
|
2409
2410
|
// OpenCode Go has a provider-specific endpoint table at
|
|
2410
2411
|
// https://opencode.ai/docs/go/#endpoints. Keep routing aligned with that table:
|
|
@@ -2873,6 +2874,19 @@ const OPENCODE_GO_OFFICIAL_MODELS: Readonly<Record<string, OpenCodeGoOfficialMod
|
|
|
2873
2874
|
reasoning: true,
|
|
2874
2875
|
cost: { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 },
|
|
2875
2876
|
},
|
|
2877
|
+
// Provisional models.dev contract, not a published Meta 1.3 specification:
|
|
2878
|
+
// providers/opencode-go/models/muse-spark-1.3-contributor.toml
|
|
2879
|
+
// blob df9405a4823feeaa5705558807515bdd2d930da2 explicitly inherits 1.2 capabilities.
|
|
2880
|
+
// Its minimal..xhigh efforts match existing Responses inference. Advertise
|
|
2881
|
+
// only GJC's supported text/image inputs; pricing is from opencode.ai/docs/go.
|
|
2882
|
+
"muse-spark-1.3-contributor": {
|
|
2883
|
+
name: "Muse Spark 1.3 Contributor",
|
|
2884
|
+
contextWindow: 1_048_576,
|
|
2885
|
+
maxTokens: 131_072,
|
|
2886
|
+
input: ["text", "image"],
|
|
2887
|
+
reasoning: true,
|
|
2888
|
+
cost: { input: 0.1, output: 0.2, cacheRead: 0.002, cacheWrite: 0 },
|
|
2889
|
+
},
|
|
2876
2890
|
"qwen3.8-flash": {
|
|
2877
2891
|
name: "Qwen3.8 Flash",
|
|
2878
2892
|
contextWindow: 1_000_000,
|
|
@@ -5,6 +5,7 @@ import type { ModelManagerOptions } from "../model-manager";
|
|
|
5
5
|
import { buildZCodeSourceHeaders, resolveGlmZcodeAnthropicBaseUrl } from "../providers/anthropic";
|
|
6
6
|
import { fetchKiroApiModels, isKiroApiKey, kiroApiStaticModels } from "../providers/kiro-api-key";
|
|
7
7
|
import { fetchOpenCodexModels, OPENCODEX_MODEL_CACHE_TTL_MS } from "../providers/openai-opencodex-responses";
|
|
8
|
+
import type { Model } from "../types";
|
|
8
9
|
import { fetchCodexModels } from "../utils/discovery/codex";
|
|
9
10
|
import { fetchOpenAICompatibleModels } from "../utils/discovery/openai-compatible";
|
|
10
11
|
import { createBundledReferenceMap } from "./bundled-references";
|
|
@@ -16,6 +17,44 @@ export function openCodexModelManagerOptions(): ModelManagerOptions<"openai-resp
|
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Devin CLI (ACP)
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Lazy handle to the ACP provider module. The ACP SDK must stay out of the
|
|
26
|
+
* catalog/startup import graph, so it is only required when Devin model
|
|
27
|
+
* discovery actually runs.
|
|
28
|
+
*/
|
|
29
|
+
interface DevinAcpDiscoveryModule {
|
|
30
|
+
fetchDevinAcpModels: (config?: {
|
|
31
|
+
cliPath?: string;
|
|
32
|
+
cliArgs?: readonly string[];
|
|
33
|
+
cwd?: string;
|
|
34
|
+
}) => Promise<Model<"devin-acp">[] | null>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const devinAcpDiscovery = once(() => require("../providers/devin-acp") as DevinAcpDiscoveryModule);
|
|
38
|
+
|
|
39
|
+
export interface DevinModelManagerConfig {
|
|
40
|
+
cliPath?: string;
|
|
41
|
+
cliArgs?: readonly string[];
|
|
42
|
+
cwd?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Devin models come from the ACP session's own `model` config option: the
|
|
47
|
+
* account and enterprise allowlists are authoritative there, and ACP is the
|
|
48
|
+
* documented programmatic surface (`devin acp`). Discovery fails closed to "no
|
|
49
|
+
* models" when the CLI is missing or unauthenticated.
|
|
50
|
+
*/
|
|
51
|
+
export function devinModelManagerOptions(config: DevinModelManagerConfig = {}): ModelManagerOptions<"devin-acp"> {
|
|
52
|
+
return {
|
|
53
|
+
providerId: "devin",
|
|
54
|
+
fetchDynamicModels: () => devinAcpDiscovery().fetchDevinAcpModels(config),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
19
58
|
// ---------------------------------------------------------------------------
|
|
20
59
|
// OpenAI code provider
|
|
21
60
|
// ---------------------------------------------------------------------------
|
|
@@ -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.
|
|
110
|
+
export declare const claudeCodeVersion = "2.1.273";
|
|
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.";
|
|
@@ -833,7 +833,7 @@ function getCacheControl(
|
|
|
833
833
|
}
|
|
834
834
|
|
|
835
835
|
// Stealth mode: Mimic Anthropic Code headers and tool prefixing.
|
|
836
|
-
export const claudeCodeVersion = "2.1.
|
|
836
|
+
export const claudeCodeVersion = "2.1.273";
|
|
837
837
|
export const claudeCodeEntrypoint = "sdk-cli";
|
|
838
838
|
export const claudeToolPrefix: string = "proxy_";
|
|
839
839
|
export const claudeCodeSystemInstruction = "You are a Claude agent, built on Anthropic's Claude Agent SDK.";
|
|
@@ -50,6 +50,8 @@ import {
|
|
|
50
50
|
isOpenAIResponsesProgressEvent,
|
|
51
51
|
normalizeResponsesToolCallIdForTransform,
|
|
52
52
|
processResponsesStream,
|
|
53
|
+
responsesStreamFailureCode,
|
|
54
|
+
unexpectedResponsesStreamEndError,
|
|
53
55
|
} from "./openai-responses-shared";
|
|
54
56
|
import { transformMessages } from "./transform-messages";
|
|
55
57
|
|
|
@@ -177,7 +179,7 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
|
|
177
179
|
const firstEventTimeoutMs = options?.streamFirstEventTimeoutMs ?? getStreamFirstEventTimeoutMs(idleTimeoutMs);
|
|
178
180
|
stream.push({ type: "start", partial: output });
|
|
179
181
|
|
|
180
|
-
await processResponsesStream(
|
|
182
|
+
const sawTerminalEvent = await processResponsesStream(
|
|
181
183
|
iterateWithIdleTimeout(openaiStream, {
|
|
182
184
|
firstItemTimeoutMs: firstEventTimeoutMs,
|
|
183
185
|
firstItemErrorMessage: AZURE_OPENAI_RESPONSES_FIRST_EVENT_TIMEOUT_MESSAGE,
|
|
@@ -210,6 +212,11 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
|
|
210
212
|
throw new Error(output.errorMessage ?? "An unknown error occurred");
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
// The Responses SSE contract always ends with a terminal event. A stream
|
|
216
|
+
// that closes without one is an interrupted upstream, not a completed
|
|
217
|
+
// turn, and must not surface as a content-free success.
|
|
218
|
+
if (!sawTerminalEvent) throw unexpectedResponsesStreamEndError();
|
|
219
|
+
|
|
213
220
|
output.duration = Date.now() - startTime;
|
|
214
221
|
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
215
222
|
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
@@ -224,6 +231,8 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
|
|
|
224
231
|
output.stopReason = abortTracker.wasCallerAbort() ? "aborted" : "error";
|
|
225
232
|
output.errorStatus = extractHttpStatusFromError(firstEventTimeoutError ?? normalizedError);
|
|
226
233
|
output.transportFailure = transportFailureFacts(firstEventTimeoutError ?? normalizedError);
|
|
234
|
+
const streamFailureCode = responsesStreamFailureCode(firstEventTimeoutError ?? normalizedError);
|
|
235
|
+
if (streamFailureCode !== undefined) output.errorCode = streamFailureCode;
|
|
227
236
|
output.errorMessage =
|
|
228
237
|
firstEventTimeoutError?.message ?? (await finalizeErrorMessage(normalizedError, rawRequestDump));
|
|
229
238
|
output.duration = Date.now() - startTime;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import http2 from "node:http2";
|
|
1
2
|
import { type JsonValue } from "@bufbuild/protobuf";
|
|
2
|
-
import type { AssistantMessage, CursorExecHandlerResult, CursorExecHandlers, CursorToolResultHandler, Message, Model, StreamFunction, StreamOptions, ToolCall, ToolResultMessage, Usage } from "../types";
|
|
3
|
-
import {
|
|
3
|
+
import type { AssistantMessage, CursorExecHandlerResult, CursorExecHandlers, CursorToolResultHandler, Message, Model, StreamFunction, StreamOptions, Tool, ToolCall, ToolResultMessage, Usage } from "../types";
|
|
4
|
+
import { kProviderResolvedToolCall } from "../utils/block-symbols";
|
|
4
5
|
import { CURSOR_CLIENT_VERSION } from "./cursor/client-version";
|
|
5
6
|
import type { CursorRule, RequestedModel_ModelParameterbytes } from "./cursor/gen/agent_pb";
|
|
6
|
-
import { type ConversationStateStructure } from "./cursor/gen/agent_pb";
|
|
7
7
|
export declare const CURSOR_API_URL = "https://api2.cursor.sh";
|
|
8
8
|
export { CURSOR_CLIENT_VERSION };
|
|
9
9
|
/** Drop all cached state + blob bytes for a conversation (F15 bound + session-teardown hook). */
|
|
@@ -14,6 +14,24 @@ export interface CursorOptions extends StreamOptions {
|
|
|
14
14
|
execHandlers?: CursorExecHandlers;
|
|
15
15
|
onToolResult?: CursorToolResultHandler;
|
|
16
16
|
}
|
|
17
|
+
/** Exported for deterministic validation of fragmented Connect progress. */
|
|
18
|
+
export declare function isPlausibleCursorConnectProgressForTest(bufferedLength: number, flags: number, messageLength?: number): boolean;
|
|
19
|
+
/** Exported for deterministic coverage of the Cursor exec-budget derivation. */
|
|
20
|
+
export declare function cursorExecDeadlineMsForTest(idleTimeoutMs: number | undefined): number;
|
|
21
|
+
/** Settlement proof for a started non-abortable Cursor exec. */
|
|
22
|
+
export interface CursorNonAbortableSettlement {
|
|
23
|
+
/** Resolves when the marked mutation settles; never rejects. */
|
|
24
|
+
settled: Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** Exported for production-bridge coverage of non-abortable terminal ordering. */
|
|
27
|
+
export declare function runWithCursorExecDeadlineForTest<T>(operation: (signal: AbortSignal, markNonAbortable: () => void) => Promise<T>, signal: AbortSignal | undefined, deadlineMs: number): Promise<T>;
|
|
28
|
+
/** Await request-side END_STREAM under the same bounded teardown contract used by Cursor streams. */
|
|
29
|
+
export declare function endCursorRequestForTest(request: Pick<http2.ClientHttp2Stream, "end">, timeoutMs?: number): Promise<boolean>;
|
|
30
|
+
/** Exported for deterministic coverage of successful writer teardown ordering. */
|
|
31
|
+
export declare function waitForCursorWritesForTest(request: http2.ClientHttp2Stream | null, timeoutMs?: number): Promise<void>;
|
|
32
|
+
export declare function waitForCursorWriteDrainForTest(request: http2.ClientHttp2Stream, timeoutMs?: number): Promise<void>;
|
|
33
|
+
/** Exported for deterministic coverage of the post-fence write race. */
|
|
34
|
+
export declare function writeCursorFrameForTest(request: http2.ClientHttp2Stream, frame: Uint8Array): boolean;
|
|
17
35
|
/** Build the ordered global USER rules Cursor expects for the current system prompt. */
|
|
18
36
|
export declare function buildCursorRequestContextRules(systemPrompt: readonly string[] | undefined): CursorRule[];
|
|
19
37
|
export interface CursorWireModelResolution {
|
|
@@ -30,42 +48,34 @@ type ToolCallState = ToolCall & {
|
|
|
30
48
|
index: number;
|
|
31
49
|
partialJson?: string;
|
|
32
50
|
kind: "mcp" | "todo_write" | "native" | "cursor-exec";
|
|
33
|
-
[
|
|
51
|
+
[kProviderResolvedToolCall]?: true;
|
|
34
52
|
};
|
|
35
53
|
interface UsageState {
|
|
36
54
|
sawTokenDelta: boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Latest `ConversationTokenDetails.used_tokens`: the whole conversation's
|
|
39
|
-
* token consumption as counted by Cursor, not this turn's output.
|
|
40
|
-
*/
|
|
41
55
|
conversationUsedTokens: number;
|
|
42
|
-
/** Output tokens already included in the latest checkpoint snapshot. */
|
|
43
56
|
checkpointOutputTokens: number;
|
|
44
|
-
/** Whether the current stream received a checkpoint, including an explicit zero. */
|
|
45
57
|
hasConversationCheckpoint: boolean;
|
|
46
|
-
pendingCheckpoint?: ConversationStateStructure;
|
|
47
58
|
}
|
|
59
|
+
export declare function storeCursorBlobForTest(blobStore: Map<string, Uint8Array>, blobId: Uint8Array, blobData: Uint8Array, limits: {
|
|
60
|
+
maxBytes: number;
|
|
61
|
+
}): boolean;
|
|
48
62
|
/** Exported for tests: verifies handler is invoked with correct `this` when passed as bound. */
|
|
49
|
-
export declare function resolveExecHandler<TArgs, TResult>(args: TArgs, handler: ((args: TArgs) => Promise<CursorExecHandlerResult<TResult>>) | undefined, onToolResult: CursorToolResultHandler | undefined, buildFromToolResult: (toolResult: ToolResultMessage) => TResult, buildRejected: (reason: string) => TResult, buildError: (error: string) => TResult): Promise<{
|
|
63
|
+
export declare function resolveExecHandler<TArgs, TResult>(args: TArgs, handler: ((args: TArgs, signal?: AbortSignal, markNonAbortable?: () => void) => Promise<CursorExecHandlerResult<TResult>>) | undefined, onToolResult: CursorToolResultHandler | undefined, buildFromToolResult: (toolResult: ToolResultMessage) => TResult, buildRejected: (reason: string) => TResult, buildError: (error: string) => TResult, signal?: AbortSignal, markNonAbortable?: () => void): Promise<{
|
|
50
64
|
execResult: TResult;
|
|
51
65
|
toolResult?: ToolResultMessage;
|
|
52
66
|
}>;
|
|
53
67
|
/** Exported for deterministic coverage of ordered server-message handling. */
|
|
54
|
-
export declare function createCursorMessageQueueForTest(onError?: (error: unknown) => void): {
|
|
55
|
-
enqueue(handler: () => void | Promise<void
|
|
68
|
+
export declare function createCursorMessageQueueForTest(onError?: (error: unknown) => void, maxPendingBytes?: number): {
|
|
69
|
+
enqueue(handler: () => void | Promise<void>, byteSize?: number): Promise<void>;
|
|
56
70
|
drain(): Promise<void>;
|
|
71
|
+
pending(): number;
|
|
72
|
+
pendingBytes(): number;
|
|
57
73
|
};
|
|
58
74
|
/** Exported for direct regression coverage of the JSON-safety boundary. */
|
|
59
75
|
export declare function cursorJsonSafeValueForTest(value: unknown): unknown;
|
|
60
76
|
export declare function buildNativeToolCallBlock(toolCall: Record<string, unknown>, callId: string, index: number): ToolCallState | null;
|
|
61
|
-
/**
|
|
62
|
-
* Cursor streams output tokens as deltas and reports whole-conversation
|
|
63
|
-
* consumption separately as `ConversationTokenDetails.used_tokens`. Derive
|
|
64
|
-
* prompt tokens from the difference so context accounting and compaction see a
|
|
65
|
-
* real prompt size instead of zero.
|
|
66
|
-
*/
|
|
77
|
+
/** Derive prompt usage from Cursor's whole-conversation checkpoint total. */
|
|
67
78
|
export declare function finalizeCursorUsage(output: AssistantMessage, usageState: UsageState): void;
|
|
68
|
-
/** Exposes {@link finalizeCursorUsage} for tests without a live HTTP/2 stream. */
|
|
69
79
|
export declare function finalizeCursorUsageForTest(usedTokens: number, outputTokens: number, options?: {
|
|
70
80
|
checkpointOutputTokens?: number;
|
|
71
81
|
hasConversationCheckpoint?: boolean;
|
|
@@ -91,6 +101,8 @@ export declare function finalizeCursorUsageForTest(usedTokens: number, outputTok
|
|
|
91
101
|
* an empty `rootPromptMessagesJson` head.
|
|
92
102
|
*/
|
|
93
103
|
export declare function buildCursorSystemPromptJsons(systemPrompt: readonly string[] | undefined, modelId?: string): string[];
|
|
104
|
+
/** Exported for regression coverage of the tool usage-cache identity boundary. */
|
|
105
|
+
export declare function buildCursorUsageToolsKeyForTest(tools: Tool[]): string;
|
|
94
106
|
/** Exported for tests: decodes Cursor history blobs built from conversation messages. */
|
|
95
107
|
export declare function buildCursorHistoryForTest(messages: Message[]): {
|
|
96
108
|
rootPromptMessagesJson: unknown[];
|