@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
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Provider-resolved tool-call markers.
|
|
3
|
+
*
|
|
4
|
+
* A provider that executes a tool call itself (Cursor exec-owned calls, or an
|
|
5
|
+
* agent-level ACP provider such as Devin, whose agent runs its own tools) marks
|
|
6
|
+
* the emitted `toolCall` block with this symbol. The agent loop then treats the
|
|
7
|
+
* call as display-only and never dispatches it to a GJC tool. Symbols are used
|
|
8
|
+
* instead of a wire field so the marker exists only in-process and can never
|
|
9
|
+
* round-trip through a transcript or a provider payload.
|
|
10
|
+
*/
|
|
11
|
+
export declare const kProviderResolvedToolCall: unique symbol;
|
|
12
|
+
export type ProviderResolvedCarrier = object & {
|
|
13
|
+
[kProviderResolvedToolCall]?: true;
|
|
4
14
|
};
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
15
|
+
export declare function isProviderResolvedToolCall(block: ProviderResolvedCarrier | null | undefined): boolean;
|
|
16
|
+
export declare function copyProviderResolvedToolCall(target: ProviderResolvedCarrier, source: ProviderResolvedCarrier): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type FallbackTriggerClass = "rate_limit" | "quota" | "auth" | "server" | "unknown" | "other";
|
|
1
|
+
export type FallbackTriggerClass = "rate_limit" | "quota" | "auth" | "credential" | "server" | "unknown" | "other";
|
|
2
2
|
/**
|
|
3
3
|
* Refinement of an `auth` trigger.
|
|
4
4
|
*
|
|
@@ -50,6 +50,8 @@ export interface TransportFailureFacts {
|
|
|
50
50
|
anthropicErrorType?: string;
|
|
51
51
|
/** OpenAI's typed `error.code`, preserved separately at the transport boundary. */
|
|
52
52
|
openaiErrorCode?: string;
|
|
53
|
+
/** Provider-authoritative model rejection that is specific to the active credential. */
|
|
54
|
+
credentialModelUnavailable?: true;
|
|
53
55
|
headers?: Record<string, string>;
|
|
54
56
|
/** Safe request-size observation for retry amplification policy. Never contains body content. */
|
|
55
57
|
requestBytes?: number;
|
|
@@ -84,6 +86,7 @@ export interface FallbackTriggerInput {
|
|
|
84
86
|
status?: number;
|
|
85
87
|
providerCode?: string;
|
|
86
88
|
code?: string;
|
|
89
|
+
credentialModelUnavailable?: boolean;
|
|
87
90
|
headers?: TransportHeaders;
|
|
88
91
|
response?: {
|
|
89
92
|
status?: number;
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -7,6 +7,19 @@ export declare function toNumber(value: unknown): number | undefined;
|
|
|
7
7
|
export declare function toPositiveNumber(value: unknown, fallback: number): number;
|
|
8
8
|
export declare function toBoolean(value: unknown): boolean | undefined;
|
|
9
9
|
export declare function normalizeToolCallId(id: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Wire-facing tool call id for a canonical ToolCall served to a foreign client.
|
|
12
|
+
*
|
|
13
|
+
* Responses-backed upstreams (Codex, OpenAI Responses) encode the tool call as
|
|
14
|
+
* `${call_id}|${item_id}` in `ToolCall.id` so their own replay can recover the
|
|
15
|
+
* item id. That encoding is gjc-internal: a downstream OpenAI-format client
|
|
16
|
+
* (OpenCodex, another gjc) truncates the compound value at its own 64-char
|
|
17
|
+
* limit and can no longer pair its tool output with the call it echoed back,
|
|
18
|
+
* so the whole chained turn is rejected with "No tool output found". Emit only
|
|
19
|
+
* the `call_id` half on the wire; the item id travels separately as the item
|
|
20
|
+
* `id` where the wire format has one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wireToolCallId(id: string): string;
|
|
10
23
|
type ResponsesToolItemIdPrefix = "fc" | "ctc";
|
|
11
24
|
export declare function normalizeResponsesToolCallId(id: string, itemPrefix?: ResponsesToolItemIdPrefix): {
|
|
12
25
|
callId: string;
|
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.17.1",
|
|
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",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
"generate-models": "bun scripts/generate-models.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@agentclientprotocol/sdk": "1.3.0",
|
|
41
42
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
42
43
|
"@bufbuild/protobuf": "^2.12.0",
|
|
43
|
-
"@gajae-code/natives": "0.
|
|
44
|
-
"@gajae-code/utils": "0.
|
|
44
|
+
"@gajae-code/natives": "0.17.1",
|
|
45
|
+
"@gajae-code/utils": "0.17.1",
|
|
45
46
|
"openai": "^6.36.0",
|
|
46
47
|
"partial-json": "^0.1.7",
|
|
47
48
|
"zod": "4.4.3"
|
package/src/api-registry.ts
CHANGED
|
@@ -23,8 +23,16 @@ export function cleanReason(value: unknown): string | undefined {
|
|
|
23
23
|
return "Credential diagnostic unavailable.";
|
|
24
24
|
reason = reason.replace(/bearer\s+[^\s,;]+/gi, "Bearer [redacted]");
|
|
25
25
|
reason = reason.replace(/basic\s+[^\s,;]+/gi, "Basic [redacted]");
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// The scheme-character run is boundary anchored, so the unbounded suffix is
|
|
27
|
+
// attempted once per maximal run instead of once at every prefix. Keeping the
|
|
28
|
+
// leading non-letter characters in the capture preserves redaction for URLs
|
|
29
|
+
// embedded after digits or scheme punctuation without imposing an arbitrary
|
|
30
|
+
// scheme-length cap. Upstream failure text is remote-influenced.
|
|
31
|
+
reason = reason.replace(/(?<![A-Za-z0-9+.-])([0-9+.-]*[a-z][a-z0-9+.-]*:\/\/)[^\s/@]+@/gi, "$1[redacted]@");
|
|
32
|
+
// Apply the same maximal-run boundary to query and fragment stripping. A word
|
|
33
|
+
// boundary would skip underscore-wrapped URLs, while an unbounded scheme with
|
|
34
|
+
// no boundary would retry every prefix of a long scheme-character run.
|
|
35
|
+
reason = reason.replace(/(?<![A-Za-z0-9+.-])([0-9+.-]*[a-z][a-z0-9+.-]*:\/\/[^\s<>"']*?)(?:[?#][^\s<>"']*)/gi, "$1");
|
|
28
36
|
reason = reason.replace(
|
|
29
37
|
/((?:\\?["']?(?:key|api[_-]?key|client[_-]?secret|clientSecret|token|secret|authorization|password|access|refresh|cookie|credential)(?:[_-](?:token|key|secret|header|headers))?\\?["']?)\s*:\s*)\\?(["'])(?:\\.|(?!\2)[^\\])*\2/gi,
|
|
30
38
|
"$1$2[redacted]$2",
|
|
@@ -621,10 +621,9 @@ async function markManagedGatewayCredentialFailure(
|
|
|
621
621
|
}
|
|
622
622
|
if (trigger.class === "auth") {
|
|
623
623
|
await storage.invalidateCredentialMatching(model.provider, apiKey, signal);
|
|
624
|
-
} else if (trigger.class === "quota" || trigger.class === "rate_limit") {
|
|
625
|
-
await storage.
|
|
624
|
+
} else if (trigger.class === "quota" || trigger.class === "rate_limit" || trigger.class === "credential") {
|
|
625
|
+
await storage.markUsageLimitReachedMatching(model.provider, apiKey, {
|
|
626
626
|
retryAfterMs: trigger.retryAfterMs,
|
|
627
|
-
signal,
|
|
628
627
|
});
|
|
629
628
|
} else {
|
|
630
629
|
return;
|
|
@@ -647,6 +646,48 @@ async function markManagedGatewayCredentialFailure(
|
|
|
647
646
|
}
|
|
648
647
|
}
|
|
649
648
|
|
|
649
|
+
/**
|
|
650
|
+
* Records a provider-confirmed account-specific model rejection against the
|
|
651
|
+
* leased credential on the ordinary (non-managed) gateway path. The leased
|
|
652
|
+
* account is excluded from future selection so later requests stop picking the
|
|
653
|
+
* same model-incompatible account, but the credential is never invalidated: it
|
|
654
|
+
* may still serve other models. Never returns a replacement key — the current
|
|
655
|
+
* request surfaces the provider's own error and the next lease picks another
|
|
656
|
+
* credential.
|
|
657
|
+
*/
|
|
658
|
+
async function markUnmanagedGatewayCredentialModelFailure(
|
|
659
|
+
storage: AuthStorage,
|
|
660
|
+
model: Model<Api>,
|
|
661
|
+
apiKey: string,
|
|
662
|
+
error: unknown,
|
|
663
|
+
format: string,
|
|
664
|
+
peer: string,
|
|
665
|
+
): Promise<void> {
|
|
666
|
+
// Thrown errors may carry the typed facts on a `transportFailure` carrier;
|
|
667
|
+
// classify the carried facts so a synchronous custom-provider throw is
|
|
668
|
+
// recognized exactly like a mid-stream error event.
|
|
669
|
+
const carried = (error as { transportFailure?: unknown } | null | undefined)?.transportFailure;
|
|
670
|
+
const trigger = classifyFallbackTrigger(carried ?? error);
|
|
671
|
+
if (trigger.class !== "credential") return;
|
|
672
|
+
try {
|
|
673
|
+
await storage.markUsageLimitReachedMatching(model.provider, apiKey, {
|
|
674
|
+
retryAfterMs: trigger.retryAfterMs,
|
|
675
|
+
});
|
|
676
|
+
logger.debug("auth-gateway recorded credential model rejection", {
|
|
677
|
+
format,
|
|
678
|
+
provider: model.provider,
|
|
679
|
+
peer,
|
|
680
|
+
});
|
|
681
|
+
} catch (markError) {
|
|
682
|
+
logger.warn("auth-gateway failed to record credential model rejection", {
|
|
683
|
+
format,
|
|
684
|
+
provider: model.provider,
|
|
685
|
+
peer,
|
|
686
|
+
error: cleanReason(markError) ?? "Credential bookkeeping failed",
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
650
691
|
function observeManagedGatewayFailure(
|
|
651
692
|
events: AssistantMessageEventStream,
|
|
652
693
|
markFailure: (error: unknown) => Promise<void>,
|
|
@@ -831,6 +872,8 @@ async function handleFormatEndpoint(
|
|
|
831
872
|
route.label,
|
|
832
873
|
peer,
|
|
833
874
|
);
|
|
875
|
+
} else {
|
|
876
|
+
await markUnmanagedGatewayCredentialModelFailure(bootOpts.storage, model, apiKey, error, route.label, peer);
|
|
834
877
|
}
|
|
835
878
|
const classified = classifyGatewayError(error);
|
|
836
879
|
logger.warn("auth-gateway streamSimple threw", { format: route.label, error: classified.message, peer });
|
|
@@ -849,6 +892,10 @@ async function handleFormatEndpoint(
|
|
|
849
892
|
peer,
|
|
850
893
|
),
|
|
851
894
|
);
|
|
895
|
+
} else {
|
|
896
|
+
events = observeManagedGatewayFailure(events, error =>
|
|
897
|
+
markUnmanagedGatewayCredentialModelFailure(bootOpts.storage, model, apiKey, error, route.label, peer),
|
|
898
|
+
);
|
|
852
899
|
}
|
|
853
900
|
events = redactGatewayStream(events);
|
|
854
901
|
|
|
@@ -1041,6 +1088,8 @@ async function handlePiNative(
|
|
|
1041
1088
|
"pi-native",
|
|
1042
1089
|
peer,
|
|
1043
1090
|
);
|
|
1091
|
+
} else {
|
|
1092
|
+
await markUnmanagedGatewayCredentialModelFailure(bootOpts.storage, model, apiKey, error, "pi-native", peer);
|
|
1044
1093
|
}
|
|
1045
1094
|
const classified = classifyGatewayError(error);
|
|
1046
1095
|
logger.warn("auth-gateway streamSimple threw", { format: "pi-native", error: classified.message, peer });
|
|
@@ -1059,6 +1108,10 @@ async function handlePiNative(
|
|
|
1059
1108
|
peer,
|
|
1060
1109
|
),
|
|
1061
1110
|
);
|
|
1111
|
+
} else {
|
|
1112
|
+
events = observeManagedGatewayFailure(events, error =>
|
|
1113
|
+
markUnmanagedGatewayCredentialModelFailure(bootOpts.storage, model, apiKey, error, "pi-native", peer),
|
|
1114
|
+
);
|
|
1062
1115
|
}
|
|
1063
1116
|
events = redactGatewayStream(events);
|
|
1064
1117
|
|