@bitkyc08/opencodex 2.84.0 → 2.86.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.
- package/README.md +0 -4
- package/bin/ocx.mjs +61 -3
- package/gui/dist/assets/App-BjlttVLy.js +58 -0
- package/gui/dist/assets/{Tray-C9TGtwad.js → Tray-DyR9yBee.js} +1 -1
- package/gui/dist/assets/index-BMssP4k3.js +94 -0
- package/gui/dist/assets/quota-summary-D8M1bc_R.js +1 -0
- package/gui/dist/index.html +1 -1
- package/package.json +1 -2
- package/src/adapters/anthropic/beta-allowlist.ts +87 -8
- package/src/adapters/anthropic/client-identity.ts +1 -1
- package/src/adapters/anthropic/passthrough.ts +33 -4
- package/src/adapters/azure.ts +19 -1
- package/src/adapters/client-fingerprint.ts +24 -0
- package/src/adapters/coding-agent/turn.ts +22 -9
- package/src/adapters/cursor/arg-codec.ts +17 -5
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/freeform-args.ts +75 -0
- package/src/adapters/cursor/protobuf-events.ts +36 -23
- package/src/adapters/google-antigravity-wire.ts +22 -1
- package/src/adapters/google.ts +2 -2
- package/src/adapters/openai-chat/response-events.ts +59 -1
- package/src/adapters/openai-chat.ts +8 -5
- package/src/adapters/qoder/adapter.ts +40 -1
- package/src/advisor/consult.ts +220 -0
- package/src/advisor/context.ts +226 -0
- package/src/advisor/disclosure.ts +20 -0
- package/src/advisor/runtime.ts +305 -0
- package/src/advisor/settings.ts +135 -0
- package/src/advisor/state.ts +369 -0
- package/src/advisor/synthetic-tool.ts +33 -0
- package/src/bridge/errors.ts +5 -0
- package/src/chat/inbound.ts +30 -6
- package/src/chat/outbound.ts +5 -0
- package/src/claude/desktop-3p-library.ts +43 -3
- package/src/claude/desktop-3p.ts +22 -8
- package/src/claude/desktop-picker-profile.ts +11 -4
- package/src/claude/desktop-profile.ts +10 -1
- package/src/claude/desktop-remote-store-io.ts +5 -3
- package/src/claude/inbound.ts +121 -50
- package/src/claude/intercept/local-ca.ts +8 -1
- package/src/claude/model-default-settings.ts +154 -0
- package/src/claude/model-info.ts +7 -7
- package/src/claude/outbound.ts +13 -6
- package/src/cli/advisor.ts +151 -0
- package/src/cli/auxiliary-listener-preflight.ts +37 -0
- package/src/cli/capabilities-agents-routing.ts +18 -0
- package/src/cli/capabilities-base.ts +1 -1
- package/src/cli/chatgpt-command.ts +35 -14
- package/src/cli/claude.ts +46 -6
- package/src/cli/dispatch.ts +5 -1
- package/src/cli/doctor.ts +9 -0
- package/src/cli/ensure-desktop-cold-start.ts +329 -0
- package/src/cli/export-command.ts +1 -1
- package/src/cli/help.ts +2 -1
- package/src/cli/index.ts +13 -4
- package/src/cli/integration-plan-dto.ts +2 -0
- package/src/cli/registry.ts +15 -3
- package/src/cli/restart-scope.ts +3 -1
- package/src/clients/config-export/contracts.ts +1 -0
- package/src/clients/config-export/model-metadata.ts +3 -2
- package/src/clients/config-export/qoder.ts +93 -0
- package/src/clients/config-export.ts +17 -4
- package/src/codex/auth-api/pool-mode-gate.ts +5 -2
- package/src/codex/auth-context.ts +79 -5
- package/src/codex/autostart-health.ts +4 -0
- package/src/codex/catalog/build-entries.ts +11 -2
- package/src/codex/catalog/configured-tiers.ts +50 -0
- package/src/codex/catalog/effort.ts +4 -1
- package/src/codex/catalog/model-hints.ts +21 -3
- package/src/codex/catalog/native-ultrafast.ts +106 -0
- package/src/codex/catalog/parsing.ts +5 -0
- package/src/codex/catalog/provider-models.ts +4 -0
- package/src/codex/catalog/retained-sync.ts +2 -0
- package/src/codex/catalog/routed-gather.ts +22 -4
- package/src/codex/catalog/vendor-context.ts +82 -0
- package/src/codex/config-write-lock.ts +40 -2
- package/src/codex/convergence.ts +2 -0
- package/src/codex/desktop-app/types.ts +2 -0
- package/src/codex/desktop-app/windows.ts +29 -16
- package/src/codex/desktop-app-restart.ts +4 -2
- package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
- package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
- package/src/codex/desktop-compatibility/connection-store.ts +87 -0
- package/src/codex/desktop-compatibility/installed-build.ts +55 -0
- package/src/codex/desktop-compatibility/json-body.ts +29 -0
- package/src/codex/desktop-compatibility/native-identity.ts +62 -0
- package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
- package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
- package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
- package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
- package/src/codex/desktop-compatibility/runtime.ts +173 -0
- package/src/codex/desktop-compatibility/service.ts +30 -0
- package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
- package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
- package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
- package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
- package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
- package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
- package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
- package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
- package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
- package/src/codex/desktop-compatibility/windows-key-protection.ts +59 -0
- package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
- package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
- package/src/codex/history-provider.ts +1 -1
- package/src/codex/inject/config-write-section.ts +4 -1
- package/src/codex/inject/remove.ts +18 -6
- package/src/codex/journal.ts +16 -1
- package/src/codex/main-account.ts +99 -15
- package/src/codex/native-main-refresh-mode.ts +217 -0
- package/src/codex/routing/health-store.ts +1 -1
- package/src/codex/routing/pool-recovery.ts +79 -0
- package/src/codex/shim-diagnostics.ts +6 -0
- package/src/codex/shim-overlay.ts +7 -2
- package/src/config/diagnostics.ts +2 -1
- package/src/config/live-reconcile.ts +13 -0
- package/src/config/load-degrade.ts +6 -1
- package/src/config/paths.ts +10 -3
- package/src/config/schema/config-schema.ts +17 -0
- package/src/config/schema/desktop-compatibility.ts +9 -0
- package/src/config/schema/leaf-validators.ts +1 -0
- package/src/generated/compatibility-version.json +451 -163
- package/src/generated/model-metadata.ts +1 -1
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/config-io.ts +20 -2
- package/src/integrations/journal.ts +15 -1
- package/src/integrations/mutation-plan.ts +1 -0
- package/src/integrations/registry.ts +7 -0
- package/src/integrations/store.ts +3 -0
- package/src/integrations/writer.ts +10 -1
- package/src/lib/advisor-activation.ts +16 -0
- package/src/lib/background-work.ts +65 -0
- package/src/lib/bounded-file-read.ts +58 -0
- package/src/lib/bun-path-runtime.d.mts +10 -1
- package/src/lib/bun-path-runtime.mjs +62 -3
- package/src/lib/desktop-proxy-route.ts +30 -0
- package/src/lib/desktop-upstream-tunnel.ts +107 -0
- package/src/lib/errors.ts +7 -0
- package/src/lib/local-internal-call-capability.ts +55 -0
- package/src/lib/package-tree-integrity.ts +2 -2
- package/src/lib/socks5-fetch.ts +48 -71
- package/src/lib/socks5-handshake.ts +112 -0
- package/src/lib/translator-budget.ts +7 -1
- package/src/oauth/generic-account-failover.ts +29 -5
- package/src/oauth/index.ts +4 -2
- package/src/oauth/kiro-device-login.ts +2 -1
- package/src/oauth/kiro.ts +7 -1
- package/src/protocols/codecs/chat-ir.ts +467 -0
- package/src/protocols/codecs/chat.ts +10 -1
- package/src/protocols/codecs/messages-ir.ts +500 -0
- package/src/protocols/features.ts +10 -2
- package/src/protocols/path.ts +11 -1
- package/src/protocols/plan-snapshot.ts +39 -16
- package/src/protocols/plan.ts +9 -1
- package/src/protocols/settings.ts +8 -0
- package/src/providers/antigravity-account-roster.ts +102 -0
- package/src/providers/antigravity-models.ts +85 -7
- package/src/providers/model-rename-fields.ts +2 -0
- package/src/providers/model-rename-migration.ts +5 -3
- package/src/providers/registry/entries-core.ts +7 -6
- package/src/providers/registry/entries-extended.ts +19 -0
- package/src/responses/parser.ts +30 -19
- package/src/responses/state.ts +32 -29
- package/src/routing/history/build-file.ts +92 -0
- package/src/routing/history/indexer.ts +248 -216
- package/src/routing/history/ingest.ts +238 -0
- package/src/routing/history/rebuild-job.ts +111 -0
- package/src/routing/history/rebuild-protocol.ts +15 -0
- package/src/routing/history/rebuild-worker.ts +34 -0
- package/src/server/admission-model-scope.ts +4 -1
- package/src/server/antigravity-direct-eligibility.ts +208 -0
- package/src/server/auth-cors.ts +4 -0
- package/src/server/chat-completions.ts +75 -9
- package/src/server/claude-messages.ts +110 -20
- package/src/server/index/desktop-compatibility-startup.ts +56 -0
- package/src/server/index/serve-options.ts +2 -2
- package/src/server/index/startup-warnings.ts +9 -0
- package/src/server/index/websocket-handler.ts +9 -0
- package/src/server/index.ts +13 -10
- package/src/server/inference/client-encoder-delivery.ts +6 -5
- package/src/server/login-shell-path.ts +146 -0
- package/src/server/management/advisor-routes.ts +191 -0
- package/src/server/management/agent-settings-routes.ts +22 -4
- package/src/server/management/companion-routes.ts +4 -0
- package/src/server/management/config-routes.ts +2 -2
- package/src/server/management/context.ts +4 -0
- package/src/server/management/desktop-compatibility-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
- package/src/server/management/model-routes.ts +2 -2
- package/src/server/management/protocol-settings-patch.ts +1 -0
- package/src/server/management/route-registry.ts +11 -0
- package/src/server/management/sibling-guard.ts +1 -0
- package/src/server/management-api.ts +6 -0
- package/src/server/messages-antigravity-direct.ts +195 -0
- package/src/server/messages-native.ts +5 -1
- package/src/server/request-log.ts +7 -0
- package/src/server/responses/adapter-continuation.ts +35 -18
- package/src/server/responses/adapter-delivery.ts +24 -2
- package/src/server/responses/adapter-dispatch.ts +29 -2
- package/src/server/responses/advisor-plan-slot.ts +27 -0
- package/src/server/responses/advisor-slot.ts +336 -0
- package/src/server/responses/code-mode-collab-surface.ts +116 -8
- package/src/server/responses/core-combo-failure.ts +10 -1
- package/src/server/responses/core-combo.ts +21 -0
- package/src/server/responses/core-lifetime.ts +2 -0
- package/src/server/responses/core-normalize.ts +11 -0
- package/src/server/responses/core-options.ts +46 -0
- package/src/server/responses/core-replay.ts +7 -4
- package/src/server/responses/core.ts +1 -1
- package/src/server/responses/passthrough-delivery.ts +16 -10
- package/src/server/responses/passthrough-dispatch.ts +14 -3
- package/src/server/responses/request-prepare.ts +68 -5
- package/src/server/responses/request-transport.ts +16 -0
- package/src/server/responses/run-turn-execution.ts +70 -8
- package/src/server/responses/sidecar-execution.ts +78 -3
- package/src/server/responses/terminal-guard.ts +2 -1
- package/src/server/responses-undeclared-tool-guard.ts +30 -9
- package/src/server/startup-action-control.ts +16 -2
- package/src/server/startup-health-cache.ts +1 -0
- package/src/service/desktop-startup.ts +14 -0
- package/src/service/health-sentinel-main.ts +23 -4
- package/src/service/health-sentinel-probe.ts +24 -7
- package/src/service/logging.ts +72 -0
- package/src/tray/windows-tray.ps1 +43 -24
- package/src/types/config.ts +63 -6
- package/src/types/provider.ts +7 -0
- package/src/types/request.ts +15 -0
- package/src/types/tools.ts +2 -0
- package/src/update/async-check.ts +1 -1
- package/src/update/badge.ts +2 -2
- package/src/update/index.ts +88 -15
- package/src/update/job-supervised-restart.ts +107 -0
- package/src/update/job.ts +32 -32
- package/src/update/notify.ts +1 -1
- package/src/update/refresh-scheduler.ts +2 -2
- package/src/update/supervised-recovery.d.mts +27 -0
- package/src/update/supervised-recovery.mjs +157 -0
- package/src/usage/cache-diagnostic.ts +2 -0
- package/src/usage/expected-prices.ts +12 -0
- package/src/web-search/gemini-executor.ts +2 -2
- package/assets/sponsors/packycode.png +0 -0
- package/gui/dist/assets/App-CZtqiGcw.js +0 -56
- package/gui/dist/assets/index-CTm4l-HQ.js +0 -94
- package/gui/dist/assets/quota-summary-BbEeRfPY.js +0 -1
|
@@ -64,6 +64,7 @@ export interface ProtocolRolloutSettings {
|
|
|
64
64
|
managedMessagesNative: boolean;
|
|
65
65
|
managedMessagesNativeOAuth: boolean;
|
|
66
66
|
directEncoders: boolean;
|
|
67
|
+
antigravityDirect: boolean;
|
|
67
68
|
shadowPlan: boolean;
|
|
68
69
|
}
|
|
69
70
|
|
|
@@ -101,6 +102,12 @@ export function resolveProtocolSettings(config: ProtocolConfig, providerName?: s
|
|
|
101
102
|
// OAuth extension is meaningless without the key-auth path it extends.
|
|
102
103
|
managedMessagesNativeOAuth: managedMessagesNative && nativeOn("managedMessagesNativeOAuth"),
|
|
103
104
|
directEncoders: on("directEncoders"),
|
|
105
|
+
// Default on: an absent switch takes the Antigravity direct lane, which falls back to the
|
|
106
|
+
// bridge per request whenever its eligibility rule declines. Only an explicit `false` turns
|
|
107
|
+
// it off; a non-boolean value or a malformed container fails closed like every other switch.
|
|
108
|
+
antigravityDirect: validContainers && (Object.hasOwn(rollout, "antigravityDirect")
|
|
109
|
+
? rollout.antigravityDirect === true
|
|
110
|
+
: true),
|
|
104
111
|
shadowPlan: on("shadowPlan"),
|
|
105
112
|
}),
|
|
106
113
|
});
|
|
@@ -145,6 +152,7 @@ export function protocolPolicyRevision(config: ProtocolConfig & Pick<OcxConfig,
|
|
|
145
152
|
secondarySettings.rollout.managedMessagesNative,
|
|
146
153
|
secondarySettings.rollout.managedMessagesNativeOAuth,
|
|
147
154
|
settings.rollout.directEncoders,
|
|
155
|
+
settings.rollout.antigravityDirect,
|
|
148
156
|
settings.rollout.shadowPlan,
|
|
149
157
|
],
|
|
150
158
|
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { getConfigDir } from "../config/paths";
|
|
2
|
+
import { ANTIGRAVITY_MODEL_ALIASES, canonicalAntigravityUsageModel, type AntigravityAvailableModel } from "./antigravity-models";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Per-account Antigravity model rosters, taken from each account's own live
|
|
6
|
+
* `:fetchAvailableModels` discovery.
|
|
7
|
+
*
|
|
8
|
+
* Google gates models per account, not per client. Measured 2026-10-14: one account lists
|
|
9
|
+
* `claude-sonnet-4-6` / `claude-opus-4-6-thinking` and answers 404 "Requested entity was not
|
|
10
|
+
* found" for every `claude-{opus,sonnet}-5-5-*` id, while other accounts list only the 5.5
|
|
11
|
+
* families. Gemini 4 Argon is likewise Ultra / Enterprise only. Google documents Claude 5.5 as
|
|
12
|
+
* needing a directly billed, non-trial Pro or Ultra plan and rolls it out gradually, so the static
|
|
13
|
+
* lineup is a superset and only discovery says what one account can actually call.
|
|
14
|
+
*
|
|
15
|
+
* The catalog already exposes only the ACTIVE account's discovered rows (an authoritative live
|
|
16
|
+
* roster drops static rows it did not return). This store keeps every account's last roster so
|
|
17
|
+
* that account selection can prefer an account that lists the requested model, instead of
|
|
18
|
+
* landing a 5.5 request on a 4.6-only account. Absence of a roster is "unknown", never "no":
|
|
19
|
+
* an account that was never active during discovery stays fully usable.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** A roster older than this is treated as unknown; entitlements change with plan and rollout. */
|
|
23
|
+
export const ANTIGRAVITY_ACCOUNT_ROSTER_TTL_MS = 6 * 60 * 60 * 1000;
|
|
24
|
+
|
|
25
|
+
interface AccountRoster {
|
|
26
|
+
readonly ids: ReadonlySet<string>;
|
|
27
|
+
readonly modelIds: readonly string[];
|
|
28
|
+
readonly observedAt: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const rosters = new Map<string, AccountRoster>();
|
|
32
|
+
|
|
33
|
+
function rosterKey(providerName: string, accountId: string): string {
|
|
34
|
+
return `${getConfigDir()}\0${providerName}\0${accountId}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Record one account's discovered roster: picker ids, representative wire ids, and tier wire ids. */
|
|
38
|
+
export function recordAntigravityAccountRoster(
|
|
39
|
+
providerName: string,
|
|
40
|
+
accountId: string,
|
|
41
|
+
models: readonly AntigravityAvailableModel[],
|
|
42
|
+
now = Date.now(),
|
|
43
|
+
): void {
|
|
44
|
+
if (!providerName || !accountId) return;
|
|
45
|
+
const ids = new Set<string>();
|
|
46
|
+
for (const model of models) {
|
|
47
|
+
ids.add(model.id);
|
|
48
|
+
ids.add(model.wireModelId);
|
|
49
|
+
for (const wire of Object.values(model.effortWireModelIds ?? {})) if (wire) ids.add(wire);
|
|
50
|
+
}
|
|
51
|
+
rosters.set(rosterKey(providerName, accountId), {
|
|
52
|
+
ids,
|
|
53
|
+
modelIds: models.map(model => model.id),
|
|
54
|
+
observedAt: now,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function freshRoster(providerName: string, accountId: string, now: number): AccountRoster | undefined {
|
|
59
|
+
const roster = rosters.get(rosterKey(providerName, accountId));
|
|
60
|
+
if (!roster || now - roster.observedAt > ANTIGRAVITY_ACCOUNT_ROSTER_TTL_MS) return undefined;
|
|
61
|
+
return roster;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The picker ids one account's last discovery returned, or `undefined` when unknown. */
|
|
65
|
+
export function antigravityAccountRosterModelIds(
|
|
66
|
+
providerName: string,
|
|
67
|
+
accountId: string,
|
|
68
|
+
now = Date.now(),
|
|
69
|
+
): readonly string[] | undefined {
|
|
70
|
+
return freshRoster(providerName, accountId, now)?.modelIds;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether one account's roster lists `modelId`: `true` / `false` from its last discovery,
|
|
75
|
+
* `undefined` when that account has no fresh roster. A picker id, one of its tier wire ids, or a
|
|
76
|
+
* compatibility alias of either all count as listed.
|
|
77
|
+
*/
|
|
78
|
+
export function antigravityAccountSupportsModel(
|
|
79
|
+
providerName: string,
|
|
80
|
+
accountId: string,
|
|
81
|
+
modelId: string,
|
|
82
|
+
now = Date.now(),
|
|
83
|
+
): boolean | undefined {
|
|
84
|
+
const roster = freshRoster(providerName, accountId, now);
|
|
85
|
+
if (!roster) return undefined;
|
|
86
|
+
const id = modelId.trim();
|
|
87
|
+
if (!id) return undefined;
|
|
88
|
+
if (roster.ids.has(id)) return true;
|
|
89
|
+
const canonical = canonicalAntigravityUsageModel(id);
|
|
90
|
+
if (roster.ids.has(canonical)) return true;
|
|
91
|
+
const alias = Object.hasOwn(ANTIGRAVITY_MODEL_ALIASES, id) ? ANTIGRAVITY_MODEL_ALIASES[id] : undefined;
|
|
92
|
+
return alias !== undefined && roster.ids.has(alias);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Forget rosters (one account, or all). For account removal and tests. */
|
|
96
|
+
export function clearAntigravityAccountRosters(providerName?: string, accountId?: string): void {
|
|
97
|
+
if (providerName && accountId) {
|
|
98
|
+
rosters.delete(rosterKey(providerName, accountId));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
rosters.clear();
|
|
102
|
+
}
|
|
@@ -17,6 +17,21 @@ import { readAntigravityWireSnapshot, writeAntigravityWireSnapshot, type Antigra
|
|
|
17
17
|
/** Current Antigravity Flash generation. */
|
|
18
18
|
const GEMINI_FLASH_CURRENT = "gemini-3.8-flash";
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Gemini 4 Argon. Like 3.8 it publishes one wire id per tier (`-low/-medium/-high`) and no
|
|
22
|
+
* `-tiered` row, verified 2026-10-14 against live CCA. CCA serves these ids only to the CLI
|
|
23
|
+
* User-Agent (see antigravityUserAgentForWireModel), and only to AI Ultra / Enterprise accounts.
|
|
24
|
+
*/
|
|
25
|
+
const GEMINI_ARGON = "gemini-4-argon";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Claude 5.5 on Antigravity: one wire id per tier (`-low/-medium/-high`), each 1,000,000 tokens
|
|
29
|
+
* with image input, observed in live CCA discovery on 2026-10-03
|
|
30
|
+
* (devlog/_fin/261003_release_lane_c). They ride the IDE User-Agent like every non-Argon model.
|
|
31
|
+
*/
|
|
32
|
+
const CLAUDE_OPUS_55 = "claude-opus-5-5";
|
|
33
|
+
const CLAUDE_SONNET_55 = "claude-sonnet-5-5";
|
|
34
|
+
|
|
20
35
|
/**
|
|
21
36
|
* Previous Flash generation — still served, still picker-visible.
|
|
22
37
|
*
|
|
@@ -75,6 +90,15 @@ const ANTIGRAVITY_WIRE_MODELS = [
|
|
|
75
90
|
];
|
|
76
91
|
|
|
77
92
|
const ANTIGRAVITY_PICKER_MODEL_BY_WIRE_ID: Record<string, string> = {
|
|
93
|
+
"claude-opus-5-5-low": CLAUDE_OPUS_55,
|
|
94
|
+
"claude-opus-5-5-medium": CLAUDE_OPUS_55,
|
|
95
|
+
"claude-opus-5-5-high": CLAUDE_OPUS_55,
|
|
96
|
+
"claude-sonnet-5-5-low": CLAUDE_SONNET_55,
|
|
97
|
+
"claude-sonnet-5-5-medium": CLAUDE_SONNET_55,
|
|
98
|
+
"claude-sonnet-5-5-high": CLAUDE_SONNET_55,
|
|
99
|
+
"gemini-4-argon-low": GEMINI_ARGON,
|
|
100
|
+
"gemini-4-argon-medium": GEMINI_ARGON,
|
|
101
|
+
"gemini-4-argon-high": GEMINI_ARGON,
|
|
78
102
|
"gemini-3.8-flash-low": "gemini-3.8-flash",
|
|
79
103
|
"gemini-3.8-flash-medium": "gemini-3.8-flash",
|
|
80
104
|
"gemini-3.8-flash-high": "gemini-3.8-flash",
|
|
@@ -164,8 +188,11 @@ function collapsesIntoKnownPickerModel(candidateId: string): boolean {
|
|
|
164
188
|
// Claude Opus: effort → thinkingConfig.thinkingLevel (CLIProxyAPI proven pattern).
|
|
165
189
|
export const ANTIGRAVITY_MODEL_EFFORTS: Record<string, string[]> = {
|
|
166
190
|
// No `minimal`: Google documents it as an error for this generation, and CCA exposes only
|
|
167
|
-
// the three tiers.
|
|
191
|
+
// the three tiers. Argon documents the same ladder (`minimal` is an HTTP 400).
|
|
192
|
+
[GEMINI_ARGON]: ["low", "medium", "high"],
|
|
168
193
|
"gemini-3.8-flash": ["low", "medium", "high"],
|
|
194
|
+
[CLAUDE_OPUS_55]: ["low", "medium", "high"],
|
|
195
|
+
[CLAUDE_SONNET_55]: ["low", "medium", "high"],
|
|
169
196
|
"gemini-3.7-flash": ["low", "medium", "high"],
|
|
170
197
|
"gemini-3.1-pro": ["low", "high"],
|
|
171
198
|
"claude-sonnet-4-6": ["low", "medium", "high", "max"],
|
|
@@ -175,7 +202,23 @@ export const ANTIGRAVITY_MODEL_EFFORTS: Record<string, string[]> = {
|
|
|
175
202
|
// ── Effort → wire model map for Gemini base models ──
|
|
176
203
|
const ANTIGRAVITY_EFFORT_WIRE_MAP: Record<string, Record<string, string>> = {
|
|
177
204
|
// 3.8 publishes one wire id per tier and no `-tiered` row, so its efforts ride the suffix.
|
|
178
|
-
// This is the 3.6 shape, not the 3.7 one.
|
|
205
|
+
// This is the 3.6 shape, not the 3.7 one. Argon has the same shape.
|
|
206
|
+
[GEMINI_ARGON]: {
|
|
207
|
+
low: "gemini-4-argon-low",
|
|
208
|
+
medium: "gemini-4-argon-medium",
|
|
209
|
+
high: "gemini-4-argon-high",
|
|
210
|
+
},
|
|
211
|
+
// Claude 5.5 publishes the same per-tier suffix family.
|
|
212
|
+
[CLAUDE_OPUS_55]: {
|
|
213
|
+
low: "claude-opus-5-5-low",
|
|
214
|
+
medium: "claude-opus-5-5-medium",
|
|
215
|
+
high: "claude-opus-5-5-high",
|
|
216
|
+
},
|
|
217
|
+
[CLAUDE_SONNET_55]: {
|
|
218
|
+
low: "claude-sonnet-5-5-low",
|
|
219
|
+
medium: "claude-sonnet-5-5-medium",
|
|
220
|
+
high: "claude-sonnet-5-5-high",
|
|
221
|
+
},
|
|
179
222
|
"gemini-3.8-flash": {
|
|
180
223
|
low: "gemini-3.8-flash-low",
|
|
181
224
|
medium: "gemini-3.8-flash-medium",
|
|
@@ -198,7 +241,7 @@ const ANTIGRAVITY_EFFORT_WIRE_MAP: Record<string, Record<string, string>> = {
|
|
|
198
241
|
* `gemini-3.1-pro` is deliberately absent: its `high` rung is `gemini-pro-agent`, which carries
|
|
199
242
|
* no tier suffix, so there the level is the only thing naming the effort.
|
|
200
243
|
*/
|
|
201
|
-
const ANTIGRAVITY_SUFFIX_TIER_MODELS = new Set(["gemini-3.8-flash"]);
|
|
244
|
+
const ANTIGRAVITY_SUFFIX_TIER_MODELS = new Set([GEMINI_ARGON, "gemini-3.8-flash", CLAUDE_OPUS_55, CLAUDE_SONNET_55]);
|
|
202
245
|
|
|
203
246
|
function completeDiscoveredEffortWireModelIds(
|
|
204
247
|
pickerId: string,
|
|
@@ -223,7 +266,11 @@ function completeDiscoveredEffortWireModelIds(
|
|
|
223
266
|
// ── Default effort per Gemini base model ──
|
|
224
267
|
const ANTIGRAVITY_DEFAULT_EFFORT: Record<string, string> = {
|
|
225
268
|
// Google's documented thinking_level default, and the tier CCA marks `recommended`.
|
|
269
|
+
[GEMINI_ARGON]: "medium",
|
|
226
270
|
"gemini-3.8-flash": "medium",
|
|
271
|
+
// Matches the discovered-family default (medium), so static and live resolution agree.
|
|
272
|
+
[CLAUDE_OPUS_55]: "medium",
|
|
273
|
+
[CLAUDE_SONNET_55]: "medium",
|
|
227
274
|
"gemini-3.1-pro": "high",
|
|
228
275
|
};
|
|
229
276
|
|
|
@@ -285,9 +332,25 @@ export const ANTIGRAVITY_MODEL_ALIASES: Record<string, string> = {
|
|
|
285
332
|
...ANTIGRAVITY_COMPATIBILITY_MODEL_ALIASES,
|
|
286
333
|
};
|
|
287
334
|
|
|
288
|
-
//
|
|
335
|
+
// Static picker lineup: collapsed base models only, exactly "3.8 / 4 / 5.5 / 5.5" (2026-10-14).
|
|
336
|
+
// Anything else reaches the picker only when live discovery returns it.
|
|
289
337
|
export const ANTIGRAVITY_MODELS = [
|
|
290
338
|
GEMINI_FLASH_CURRENT,
|
|
339
|
+
GEMINI_ARGON,
|
|
340
|
+
CLAUDE_OPUS_55,
|
|
341
|
+
CLAUDE_SONNET_55,
|
|
342
|
+
];
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Every base id the routing and discovery rules recognise: the static lineup plus models that
|
|
346
|
+
* left it. Removing a model from the picker must not change how a saved selection routes or how
|
|
347
|
+
* a discovered row collapses, so these legacy bases stay known here. Live discovery on
|
|
348
|
+
* 2026-10-14 no longer returns gemini-3.7-flash(-tiered) or the gemini-3.1-pro wire ids (both
|
|
349
|
+
* 404), but still returns the Claude 4.6 rows and gpt-oss-120b-medium, which therefore keep
|
|
350
|
+
* appearing through discovery.
|
|
351
|
+
*/
|
|
352
|
+
export const ANTIGRAVITY_KNOWN_PICKER_MODELS: readonly string[] = [
|
|
353
|
+
...ANTIGRAVITY_MODELS,
|
|
291
354
|
GEMINI_FLASH_PREVIOUS,
|
|
292
355
|
"gemini-3.1-pro",
|
|
293
356
|
"gemini-3.1-flash-image",
|
|
@@ -297,11 +360,20 @@ export const ANTIGRAVITY_MODELS = [
|
|
|
297
360
|
];
|
|
298
361
|
|
|
299
362
|
function isKnownAntigravityPickerModelId(value: string): boolean {
|
|
300
|
-
return isValidModelDiscoveryModelId(value) &&
|
|
363
|
+
return isValidModelDiscoveryModelId(value) && ANTIGRAVITY_KNOWN_PICKER_MODELS.includes(value);
|
|
301
364
|
}
|
|
302
365
|
|
|
303
366
|
// Context windows from the upstream `:fetchAvailableModels` maxTokens per model.
|
|
304
367
|
const ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
368
|
+
"claude-opus-5-5-low": 1_000_000,
|
|
369
|
+
"claude-opus-5-5-medium": 1_000_000,
|
|
370
|
+
"claude-opus-5-5-high": 1_000_000,
|
|
371
|
+
"claude-sonnet-5-5-low": 1_000_000,
|
|
372
|
+
"claude-sonnet-5-5-medium": 1_000_000,
|
|
373
|
+
"claude-sonnet-5-5-high": 1_000_000,
|
|
374
|
+
"gemini-4-argon-low": 1_048_576,
|
|
375
|
+
"gemini-4-argon-medium": 1_048_576,
|
|
376
|
+
"gemini-4-argon-high": 1_048_576,
|
|
305
377
|
"gemini-3.8-flash-low": 1_048_576,
|
|
306
378
|
"gemini-3.8-flash-medium": 1_048_576,
|
|
307
379
|
"gemini-3.8-flash-high": 1_048_576,
|
|
@@ -316,7 +388,10 @@ const ANTIGRAVITY_WIRE_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
316
388
|
|
|
317
389
|
export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
318
390
|
// Collapsed base IDs — explicit entries for the picker.
|
|
391
|
+
[GEMINI_ARGON]: 1_048_576,
|
|
319
392
|
"gemini-3.8-flash": 1_048_576,
|
|
393
|
+
[CLAUDE_OPUS_55]: 1_000_000,
|
|
394
|
+
[CLAUDE_SONNET_55]: 1_000_000,
|
|
320
395
|
"gemini-3.7-flash": 1_048_576,
|
|
321
396
|
"gemini-3.1-pro": 1_048_576,
|
|
322
397
|
// Wire IDs and aliases via derivation.
|
|
@@ -330,6 +405,9 @@ export const ANTIGRAVITY_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
|
330
405
|
};
|
|
331
406
|
|
|
332
407
|
export const ANTIGRAVITY_MODEL_INPUT_MODALITIES: Record<string, string[]> = {
|
|
408
|
+
[GEMINI_ARGON]: ["text", "image"],
|
|
409
|
+
[CLAUDE_OPUS_55]: ["text", "image"],
|
|
410
|
+
[CLAUDE_SONNET_55]: ["text", "image"],
|
|
333
411
|
// Google documents 3.7 Flash as also accepting video, audio and PDF, but this proxy
|
|
334
412
|
// carries only text and image parts (`OcxImageContent`, src/types.ts) and the Codex
|
|
335
413
|
// catalog normalizes `input_modalities` against a closed enum. Advertising a modality
|
|
@@ -641,7 +719,7 @@ export function resolveAntigravityWireModelId(modelId: string, baseUrl?: string)
|
|
|
641
719
|
* IS the effort, and sending both creates a contradictory request.
|
|
642
720
|
*/
|
|
643
721
|
export function isAntigravitySuffixModelId(modelId: string): boolean {
|
|
644
|
-
return !
|
|
722
|
+
return !ANTIGRAVITY_KNOWN_PICKER_MODELS.includes(modelId);
|
|
645
723
|
}
|
|
646
724
|
|
|
647
725
|
/** The reasoning tier a retired Flash id used to encode, if it is one. */
|
|
@@ -753,7 +831,7 @@ export function resolveAntigravityEffortWireModel(
|
|
|
753
831
|
// summary aggregation consults this reverse map so one call model = one usage row.
|
|
754
832
|
const ANTIGRAVITY_USAGE_BASE_BY_ID: Record<string, string> = (() => {
|
|
755
833
|
const rev: Record<string, string> = {};
|
|
756
|
-
for (const base of
|
|
834
|
+
for (const base of ANTIGRAVITY_KNOWN_PICKER_MODELS) rev[base] = base;
|
|
757
835
|
for (const [base, effortMap] of Object.entries(ANTIGRAVITY_EFFORT_WIRE_MAP)) {
|
|
758
836
|
rev[base] = base;
|
|
759
837
|
for (const wire of Object.values(effortMap)) rev[wire] = base;
|
|
@@ -59,6 +59,7 @@ export const PROVIDER_MODEL_RENAME_ROLES = {
|
|
|
59
59
|
newModelPolicy: "none",
|
|
60
60
|
modelPreset: "none",
|
|
61
61
|
contextWindow: "none",
|
|
62
|
+
inferContextWindow: "none",
|
|
62
63
|
modelContextWindows: "record",
|
|
63
64
|
modelContextTiers: "record",
|
|
64
65
|
modelInputModalities: "record",
|
|
@@ -66,6 +67,7 @@ export const PROVIDER_MODEL_RENAME_ROLES = {
|
|
|
66
67
|
modelMaxInputTokens: "record",
|
|
67
68
|
modelAutoCompactTokenLimits: "record",
|
|
68
69
|
defaultMaxOutputTokens: "none",
|
|
70
|
+
minMaxOutputTokens: "none",
|
|
69
71
|
modelMaxOutputTokens: "record",
|
|
70
72
|
modelCosts: "record",
|
|
71
73
|
autoReviewModel: "none",
|
|
@@ -124,16 +124,18 @@ export const MODEL_RENAMES: readonly ModelRename[] = [
|
|
|
124
124
|
// Assist almost immediately when the next ships, so a saved 3.6 (or older 3.5) id is a
|
|
125
125
|
// dead selection rather than a merely outdated one. Routing already redirects these ids
|
|
126
126
|
// at request time; this migration repairs the saved config so the picker, the allowlist
|
|
127
|
-
// and the capability maps stop naming a model the backend no longer serves.
|
|
127
|
+
// and the capability maps stop naming a model the backend no longer serves. The target is
|
|
128
|
+
// the live 3.8 base: 3.7 left the static lineup on 2026-10-14 (CCA 404s its wire id), and
|
|
129
|
+
// registrySeedsTarget refuses to write an id the registry no longer seeds.
|
|
128
130
|
...(["gemini-3.6-flash", "gemini-3.6-flash-low", "gemini-3.6-flash-medium", "gemini-3.6-flash-high",
|
|
129
131
|
"gemini-3.5-flash-extra-low", "gemini-3.5-flash-low", "gemini-3.5-flash-mid", "gemini-3.5-flash-high",
|
|
130
132
|
"gemini-3-flash-agent"] as const).map(from => ({
|
|
131
133
|
provider: "google-antigravity",
|
|
132
134
|
from,
|
|
133
|
-
to: "gemini-3.
|
|
135
|
+
to: "gemini-3.8-flash",
|
|
134
136
|
reason: "Google retires the previous Antigravity Flash generation from Cloud Code Assist when its successor ships, so the saved id no longer resolves to a live model",
|
|
135
137
|
// The retired Flash tiers were wire ids, so any saved per-model record keyed by one
|
|
136
|
-
// may also hold one as a value. 3.
|
|
138
|
+
// may also hold one as a value. 3.8 resolves tiers from its own suffix ladder instead.
|
|
137
139
|
dropReasoningEffortMap: true,
|
|
138
140
|
})),
|
|
139
141
|
];
|
|
@@ -1140,10 +1140,8 @@ export const PROVIDER_REGISTRY_CORE: readonly ProviderRegistryEntry[] = [
|
|
|
1140
1140
|
// https://cf.api.fan/v1 — GET /v1/models answers 401 without a key, so the host is live and
|
|
1141
1141
|
// discovery narrows to what the key's token group allows. Model ids are bare OpenAI-style
|
|
1142
1142
|
// ids (the Codex token group lists gpt-5.5 / gpt-5.1-codex).
|
|
1143
|
-
// Standard sponsor under SPONSORS.md; the dashboardUrl carries their affiliate code.
|
|
1144
1143
|
id: "packycode", label: "PackyCode", adapter: "openai-chat", baseUrl: "https://cf.api.fan/v1",
|
|
1145
|
-
authKind: "key", dashboardUrl: "https://www.packyapi.com
|
|
1146
|
-
sponsor: { tier: "standard", url: "https://www.packyapi.com/register?aff=k5KT" },
|
|
1144
|
+
authKind: "key", dashboardUrl: "https://www.packyapi.com",
|
|
1147
1145
|
defaultModel: "gpt-5.5",
|
|
1148
1146
|
models: ["gpt-5.5", "gpt-5.1-codex"],
|
|
1149
1147
|
liveModels: true,
|
|
@@ -1170,13 +1168,16 @@ export const PROVIDER_REGISTRY_CORE: readonly ProviderRegistryEntry[] = [
|
|
|
1170
1168
|
// devlog/_plan/260710_provider_hardening/001_research_frontier.md.
|
|
1171
1169
|
{
|
|
1172
1170
|
id: "google", label: "Google Gemini", adapter: "google", baseUrl: "https://generativelanguage.googleapis.com", authKind: "key", featured: true,
|
|
1173
|
-
dashboardUrl: "https://aistudio.google.com/apikey", defaultModel: "gemini-3.5-flash", models: ["gemini-3.8-flash", "gemini-3.6-flash", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.1-pro-preview", "gemini-3.7-flash"],
|
|
1174
|
-
modelContextWindows: { "gemini-3.8-flash": 1_048_576, "gemini-3.6-flash": 1_048_576, "gemini-3.5-flash": 1_000_000, "gemini-3.5-flash-lite": 1_048_576, "gemini-3.7-flash": 1_048_576 },
|
|
1175
|
-
modelInputModalities: { "gemini-3.8-flash": ["text", "image"], "gemini-3.6-flash": ["text", "image"], "gemini-3.5-flash-lite": ["text", "image"], "gemini-3.7-flash": ["text", "image"] },
|
|
1171
|
+
dashboardUrl: "https://aistudio.google.com/apikey", defaultModel: "gemini-3.5-flash", models: ["gemini-4-argon", "gemini-3.8-flash", "gemini-3.6-flash", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.1-pro-preview", "gemini-3.7-flash"],
|
|
1172
|
+
modelContextWindows: { "gemini-4-argon": 1_048_576, "gemini-3.8-flash": 1_048_576, "gemini-3.6-flash": 1_048_576, "gemini-3.5-flash": 1_000_000, "gemini-3.5-flash-lite": 1_048_576, "gemini-3.7-flash": 1_048_576 },
|
|
1173
|
+
modelInputModalities: { "gemini-4-argon": ["text", "image"], "gemini-3.8-flash": ["text", "image"], "gemini-3.6-flash": ["text", "image"], "gemini-3.5-flash-lite": ["text", "image"], "gemini-3.7-flash": ["text", "image"] },
|
|
1176
1174
|
modelReasoningEfforts: {
|
|
1177
1175
|
// 3.7 and 3.8 omit `minimal`: Google documents it as a validation error on both model
|
|
1178
1176
|
// pages, so advertising it hands the user a rung the API rejects. 3.5/3.6 keep theirs —
|
|
1179
1177
|
// their pages still list it, and this unit has no evidence to change them.
|
|
1178
|
+
// Gemini 4 Argon (GA 2026-10-13): low/medium(default)/high; `minimal` and thinking_budget
|
|
1179
|
+
// return HTTP 400 per ai.google.dev/gemini-api/docs/models/gemini-4-argon.
|
|
1180
|
+
"gemini-4-argon": ["low", "medium", "high"],
|
|
1180
1181
|
"gemini-3.8-flash": ["low", "medium", "high"],
|
|
1181
1182
|
"gemini-3.7-flash": ["low", "medium", "high"],
|
|
1182
1183
|
"gemini-3.6-flash": ["minimal", "low", "medium", "high"],
|
|
@@ -1247,6 +1247,25 @@ export const PROVIDER_REGISTRY_EXTENDED: readonly ProviderRegistryEntry[] = [
|
|
|
1247
1247
|
},
|
|
1248
1248
|
note: "OpenAI-compatible API gateway. Create a workspace API key at tokenlab.sh. Live discovery lists tool-capable chat models available to your key and delivery policy.",
|
|
1249
1249
|
},
|
|
1250
|
+
{
|
|
1251
|
+
// Modelflare: OpenAI-compatible relay at https://modelflare.dev/v1 (an Anthropic Messages
|
|
1252
|
+
// surface also answers at https://modelflare.dev/v1/messages). Live-checked 2026-10-13 through
|
|
1253
|
+
// the proxy: chat, streaming and tool calls succeed on Chat for all four seeded models, and a
|
|
1254
|
+
// real `codex exec` turn completed on glm-5.3-flash. GET /v1/models lists ~77 rows mixing chat,
|
|
1255
|
+
// image and video models, and includes deepseek-v4.1-flash, which answers 503 on every call,
|
|
1256
|
+
// so the preset seeds the verified chat models statically instead of trusting live discovery.
|
|
1257
|
+
// The conventional env reference derived from the id is ${MODELFLARE_API_KEY}.
|
|
1258
|
+
id: "modelflare",
|
|
1259
|
+
label: "Modelflare",
|
|
1260
|
+
adapter: "openai-chat",
|
|
1261
|
+
baseUrl: "https://modelflare.dev/v1",
|
|
1262
|
+
authKind: "key",
|
|
1263
|
+
dashboardUrl: "https://modelflare.dev",
|
|
1264
|
+
preserveCustomDestination: true,
|
|
1265
|
+
defaultModel: "glm-5.3-flash",
|
|
1266
|
+
models: ["glm-5.3-flash", "claude-sonnet-5-5", "gpt-6.1-sol", "deepseek-v4-flash"],
|
|
1267
|
+
note: "OpenAI-compatible relay for Claude, GPT, GLM and DeepSeek chat models. The seeded models were verified with chat, streaming and tool calls; deepseek-v4.1-flash is listed upstream but currently answers 503 and is left out. An ordinary key only reaches its own routing group's models; a Smart key reaches all seeded models. Image and video models are not served through this Chat preset. Upstream latency varies widely (a few seconds to about 30 s) with occasional transient 503s.",
|
|
1268
|
+
},
|
|
1250
1269
|
{
|
|
1251
1270
|
id: "opencode-free",
|
|
1252
1271
|
label: "OpenCode Free",
|
package/src/responses/parser.ts
CHANGED
|
@@ -66,6 +66,35 @@ function repairJsonObjectEnvelope(text: string): Record<string, unknown> | undef
|
|
|
66
66
|
return undefined;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Decode a function call's serialized arguments the way history replay tolerates them: empty
|
|
71
|
+
* or non-JSON text becomes `{}` instead of failing every later turn, and the one bounded
|
|
72
|
+
* lost-brace corruption above is repaired. Shared with the direct Chat decoder
|
|
73
|
+
* (`src/protocols/codecs/chat-ir.ts`) so both decode the same call to the same object.
|
|
74
|
+
*/
|
|
75
|
+
export function functionCallArgumentsFromText(callId: string, rawArguments: string | undefined): Record<string, unknown> {
|
|
76
|
+
let args: Record<string, unknown> = {};
|
|
77
|
+
const rawArgs = rawArguments?.trim();
|
|
78
|
+
if (rawArgs) {
|
|
79
|
+
try {
|
|
80
|
+
const parsed: unknown = JSON.parse(rawArgs);
|
|
81
|
+
if (isObj(parsed)) args = parsed;
|
|
82
|
+
} catch {
|
|
83
|
+
// One observed serialization corruption loses exactly the JSON object's opening
|
|
84
|
+
// brace; the closed envelope is tight enough to repair back into a call the
|
|
85
|
+
// routed model can still see and retry, instead of replaying {} forever.
|
|
86
|
+
const repaired = repairJsonObjectEnvelope(rawArgs);
|
|
87
|
+
if (repaired === undefined) {
|
|
88
|
+
console.warn(`[parser] function_call ${callId} has non-JSON arguments; defaulting to {}`);
|
|
89
|
+
} else {
|
|
90
|
+
args = repaired;
|
|
91
|
+
console.warn(`[parser] function_call ${callId} arguments lost the JSON opening brace; repaired from history`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return args;
|
|
96
|
+
}
|
|
97
|
+
|
|
69
98
|
|
|
70
99
|
|
|
71
100
|
function ensureAssistantPlaceholder(messages: OcxMessage[], modelId: string, now: number): OcxAssistantMessage {
|
|
@@ -397,25 +426,7 @@ export function parseRequest(
|
|
|
397
426
|
const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string; extra_content?: unknown };
|
|
398
427
|
// Tolerate empty/non-JSON arguments (e.g. a no-arg tool call serialized as "") instead of
|
|
399
428
|
// throwing — a single poisoned history item would otherwise 400 every subsequent turn.
|
|
400
|
-
|
|
401
|
-
const rawArgs = call.arguments?.trim();
|
|
402
|
-
if (rawArgs) {
|
|
403
|
-
try {
|
|
404
|
-
const parsed: unknown = JSON.parse(rawArgs);
|
|
405
|
-
if (isObj(parsed)) args = parsed;
|
|
406
|
-
} catch {
|
|
407
|
-
// One observed serialization corruption loses exactly the JSON object's opening
|
|
408
|
-
// brace; the closed envelope is tight enough to repair back into a call the
|
|
409
|
-
// routed model can still see and retry, instead of replaying {} forever.
|
|
410
|
-
const repaired = repairJsonObjectEnvelope(rawArgs);
|
|
411
|
-
if (repaired === undefined) {
|
|
412
|
-
console.warn(`[parser] function_call ${call.call_id} has non-JSON arguments; defaulting to {}`);
|
|
413
|
-
} else {
|
|
414
|
-
args = repaired;
|
|
415
|
-
console.warn(`[parser] function_call ${call.call_id} arguments lost the JSON opening brace; repaired from history`);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
429
|
+
const args = functionCallArgumentsFromText(call.call_id, call.arguments);
|
|
419
430
|
// Do NOT map Responses item `id` (fc_/ctc_/…) onto `thoughtSignature`. That field is
|
|
420
431
|
// reserved for Gemini/Antigravity opaque thought tokens; forwarding item ids as
|
|
421
432
|
// thoughtSignature 400s Antigravity (Base64 / TYPE_BYTES). Continuity for CCA comes from
|
package/src/responses/state.ts
CHANGED
|
@@ -710,11 +710,6 @@ export function sweepOrphanedResponseSpills(): number {
|
|
|
710
710
|
type SnapshotWriteOutcome = "stable" | "unstable" | "failed";
|
|
711
711
|
|
|
712
712
|
async function writeBoundedSnapshot(path: string, attemptLimit: number): Promise<SnapshotWriteOutcome> {
|
|
713
|
-
// Serialize writers so concurrent flush + debounce cannot race on temps / ACL (#612).
|
|
714
|
-
const previous = persistGate;
|
|
715
|
-
let release!: () => void;
|
|
716
|
-
persistGate = new Promise<void>(resolve => { release = resolve; });
|
|
717
|
-
await previous;
|
|
718
713
|
try {
|
|
719
714
|
for (let attempt = 0; attempt < attemptLimit; attempt += 1) {
|
|
720
715
|
const revision = stateRevision;
|
|
@@ -751,13 +746,19 @@ async function writeBoundedSnapshot(path: string, attemptLimit: number): Promise
|
|
|
751
746
|
lastSnapshotTarget = resolveWriteTarget(path);
|
|
752
747
|
}
|
|
753
748
|
persistAttemptHookForTests?.();
|
|
754
|
-
if (revision === stateRevision)
|
|
749
|
+
if (revision === stateRevision) {
|
|
750
|
+
// Cancel only the timer whose mutation this stable revision includes,
|
|
751
|
+
// before an awaiting caller's microtask can record a newer revision.
|
|
752
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
753
|
+
persistTimer = null;
|
|
754
|
+
pendingPersistPath = null;
|
|
755
|
+
drainPendingSpillUnlinks();
|
|
756
|
+
return "stable";
|
|
757
|
+
}
|
|
755
758
|
}
|
|
756
759
|
return "unstable";
|
|
757
760
|
} catch {
|
|
758
761
|
return "failed";
|
|
759
|
-
} finally {
|
|
760
|
-
release();
|
|
761
762
|
}
|
|
762
763
|
}
|
|
763
764
|
|
|
@@ -792,21 +793,30 @@ function schedulePersistAt(path: string, replace = false): void {
|
|
|
792
793
|
}
|
|
793
794
|
|
|
794
795
|
async function persistNow(path: string, awaitFollowUp = false): Promise<void> {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
796
|
+
// Include follow-up scheduling in the gate: releasing after only the disk write
|
|
797
|
+
// lets shutdown observe an empty timer before the background pass re-arms it.
|
|
798
|
+
const previous = persistGate;
|
|
799
|
+
let release!: () => void;
|
|
800
|
+
persistGate = new Promise<void>(resolve => { release = resolve; });
|
|
801
|
+
await previous;
|
|
802
|
+
try {
|
|
803
|
+
if (persistTimer) {
|
|
804
|
+
clearTimeout(persistTimer);
|
|
805
|
+
persistTimer = null;
|
|
806
|
+
}
|
|
805
807
|
pendingPersistPath = null;
|
|
806
|
-
|
|
808
|
+
const attemptLimit = awaitFollowUp ? MAX_SNAPSHOT_REWRITE_ATTEMPTS : 1;
|
|
809
|
+
let outcome = await writeBoundedSnapshot(path, attemptLimit);
|
|
810
|
+
if (outcome === "unstable" && awaitFollowUp) {
|
|
811
|
+
if (persistTimer) clearTimeout(persistTimer);
|
|
812
|
+
persistTimer = null;
|
|
813
|
+
pendingPersistPath = null;
|
|
814
|
+
outcome = await writeBoundedSnapshot(path, attemptLimit);
|
|
815
|
+
}
|
|
816
|
+
if (outcome === "unstable" && !awaitFollowUp) schedulePersistAt(path, true);
|
|
817
|
+
} finally {
|
|
818
|
+
release();
|
|
807
819
|
}
|
|
808
|
-
if (outcome === "stable") drainPendingSpillUnlinks();
|
|
809
|
-
else if (outcome === "unstable" && !awaitFollowUp) schedulePersistAt(path, true);
|
|
810
820
|
}
|
|
811
821
|
|
|
812
822
|
function schedulePersist(): void {
|
|
@@ -816,15 +826,8 @@ function schedulePersist(): void {
|
|
|
816
826
|
}
|
|
817
827
|
|
|
818
828
|
async function flushResponseSnapshot(): Promise<void> {
|
|
819
|
-
|
|
820
|
-
await persistNow(pendingPersistPath ?? snapshotPath(), true);
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
// No pending timer: still await any in-flight write so shutdown does not race (#612).
|
|
829
|
+
// The gate includes the background pass's timer decision, not just its write.
|
|
824
830
|
await persistGate;
|
|
825
|
-
// A bounded background pass may have scheduled its same-path follow-up while
|
|
826
|
-
// this flush was waiting on the single-flight gate. Shutdown owns one awaited
|
|
827
|
-
// bounded follow-up rather than returning behind that unref'd timer.
|
|
828
831
|
if (persistTimer) await persistNow(pendingPersistPath ?? snapshotPath(), true);
|
|
829
832
|
}
|
|
830
833
|
|