@golba98/codexa 1.0.4 → 1.0.5
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/package.json +1 -1
- package/src/app.tsx +128 -47
- package/src/commands/handler.ts +5 -16
- package/src/config/buildInfo.ts +2 -2
- package/src/core/models/codexModelCapabilities.ts +57 -4
- package/src/core/models/codexModelsCacheSeed.ts +153 -0
- package/src/core/models/providerModelCache.ts +106 -0
- package/src/core/process/CommandRunner.ts +12 -1
- package/src/core/providerLauncher/registry.ts +37 -7
- package/src/core/providerLauncher/types.ts +2 -1
- package/src/core/providerRuntime/anthropic.ts +3 -5
- package/src/core/providerRuntime/antigravity.ts +246 -90
- package/src/core/providerRuntime/claudeCodeDiscovery.ts +724 -692
- package/src/core/providerRuntime/mistralVibe.ts +663 -0
- package/src/core/providerRuntime/models.ts +18 -4
- package/src/core/providerRuntime/reasoning.ts +9 -6
- package/src/core/providerRuntime/registry.ts +94 -49
- package/src/core/providerRuntime/types.ts +1 -0
- package/src/index.tsx +23 -9
- package/src/test/runtimeTestUtils.ts +90 -0
- package/src/ui/{ActivityBars.tsx → chrome/ActivityBars.tsx} +1 -1
- package/src/ui/{ActivityIndicator.tsx → chrome/ActivityIndicator.tsx} +3 -3
- package/src/ui/{AnimatedStatusText.tsx → chrome/AnimatedStatusText.tsx} +3 -3
- package/src/ui/{AppShell.tsx → chrome/AppShell.tsx} +11 -11
- package/src/ui/{BottomComposer.tsx → chrome/BottomComposer.tsx} +15 -15
- package/src/ui/{DashCard.tsx → chrome/DashCard.tsx} +2 -2
- package/src/ui/{RunFooter.tsx → chrome/RunFooter.tsx} +3 -3
- package/src/ui/{RuntimeStatusBar.tsx → chrome/RuntimeStatusBar.tsx} +3 -3
- package/src/ui/{Spinner.tsx → chrome/Spinner.tsx} +1 -1
- package/src/ui/{TopHeader.tsx → chrome/TopHeader.tsx} +12 -12
- package/src/ui/{UpdateAvailableCard.tsx → chrome/UpdateAvailableCard.tsx} +3 -3
- package/src/ui/{commandNormalize.ts → input/commandNormalize.ts} +1 -1
- package/src/ui/{focus.ts → input/focus.ts} +1 -1
- package/src/ui/{inputBuffer.ts → input/inputBuffer.ts} +3 -3
- package/src/ui/{AttachmentImportPanel.tsx → panels/AttachmentImportPanel.tsx} +1 -1
- package/src/ui/{AuthPanel.tsx → panels/AuthPanel.tsx} +5 -5
- package/src/ui/{BackendPicker.tsx → panels/BackendPicker.tsx} +2 -2
- package/src/ui/{ModePicker.tsx → panels/ModePicker.tsx} +2 -2
- package/src/ui/{ModelPicker.tsx → panels/ModelPicker.tsx} +2 -2
- package/src/ui/{ModelPickerScreen.tsx → panels/ModelPickerScreen.tsx} +11 -9
- package/src/ui/{ModelReasoningPicker.tsx → panels/ModelReasoningPicker.tsx} +5 -5
- package/src/ui/{Panel.tsx → panels/Panel.tsx} +1 -1
- package/src/ui/{PermissionsPanel.tsx → panels/PermissionsPanel.tsx} +3 -3
- package/src/ui/{PlanActionPicker.tsx → panels/PlanActionPicker.tsx} +2 -2
- package/src/ui/{PlanReviewPanel.tsx → panels/PlanReviewPanel.tsx} +5 -5
- package/src/ui/{ProviderPicker.tsx → panels/ProviderPicker.tsx} +9 -7
- package/src/ui/{ReasoningPicker.tsx → panels/ReasoningPicker.tsx} +3 -3
- package/src/ui/{SelectionPanel.tsx → panels/SelectionPanel.tsx} +1 -1
- package/src/ui/{SettingsPanel.tsx → panels/SettingsPanel.tsx} +3 -3
- package/src/ui/{TextEntryPanel.tsx → panels/TextEntryPanel.tsx} +3 -3
- package/src/ui/{ThemePicker.tsx → panels/ThemePicker.tsx} +2 -2
- package/src/ui/{UpdatePromptPanel.tsx → panels/UpdatePromptPanel.tsx} +2 -2
- package/src/ui/{Markdown.tsx → render/Markdown.tsx} +2 -2
- package/src/ui/{diffRenderer.ts → render/diffRenderer.ts} +1 -1
- package/src/ui/{modeDisplay.ts → render/modeDisplay.ts} +2 -2
- package/src/ui/{outputPipeline.ts → render/outputPipeline.ts} +2 -2
- package/src/ui/{runtimeDisplay.ts → render/runtimeDisplay.ts} +9 -8
- package/src/ui/{ActionRequiredBlock.tsx → timeline/ActionRequiredBlock.tsx} +3 -3
- package/src/ui/{AgentBlock.tsx → timeline/AgentBlock.tsx} +10 -10
- package/src/ui/{StaticIntroItem.tsx → timeline/StaticIntroItem.tsx} +2 -2
- package/src/ui/{ThinkingBlock.tsx → timeline/ThinkingBlock.tsx} +4 -4
- package/src/ui/{Timeline.tsx → timeline/Timeline.tsx} +8 -8
- package/src/ui/{TranscriptShell.tsx → timeline/TranscriptShell.tsx} +6 -6
- package/src/ui/{TurnGroup.tsx → timeline/TurnGroup.tsx} +15 -15
- package/src/ui/{progressEntries.ts → timeline/progressEntries.ts} +3 -3
- package/src/ui/{runActivityView.ts → timeline/runActivityView.ts} +1 -1
- package/src/ui/{timelineMeasure.ts → timeline/timelineMeasure.ts} +14 -14
- /package/src/ui/{busyStatusAnimation.ts → chrome/busyStatusAnimation.ts} +0 -0
- /package/src/ui/{slashCommands.ts → input/slashCommands.ts} +0 -0
- /package/src/ui/{logoVariants.ts → render/logoVariants.ts} +0 -0
- /package/src/ui/{terminalAnswerFormat.ts → render/terminalAnswerFormat.ts} +0 -0
- /package/src/ui/{textLayout.ts → render/textLayout.ts} +0 -0
- /package/src/ui/{layoutListWindow.ts → timeline/layoutListWindow.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { runCommand } from "../process/CommandRunner.js";
|
|
2
2
|
import { sanitizeTerminalOutput } from "../terminal/terminalSanitize.js";
|
|
3
3
|
import type { ReasoningEffortCapability } from "../models/codexModelCapabilities.js";
|
|
4
|
+
import { loadCachedProviderModels } from "../models/providerModelCache.js";
|
|
4
5
|
import type { BackendRunHandlers } from "../providers/types.js";
|
|
5
6
|
import type {
|
|
6
7
|
ProviderBackendKind,
|
|
@@ -27,97 +28,144 @@ export const ANTIGRAVITY_DEFAULT_MODEL_ID = "gemini-3.5-flash";
|
|
|
27
28
|
export const ANTIGRAVITY_DEFAULT_REASONING = "high";
|
|
28
29
|
|
|
29
30
|
// ---------------------------------------------------------------------------
|
|
30
|
-
//
|
|
31
|
+
// Model definitions
|
|
31
32
|
// ---------------------------------------------------------------------------
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
interface AgySelectorMetadata {
|
|
35
|
+
provider: "antigravity";
|
|
36
|
+
selectors: Record<string, string>;
|
|
37
|
+
}
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
function normalizeAgyId(value: string): string {
|
|
40
|
+
return value
|
|
41
|
+
.trim()
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/[^a-z0-9.]+/g, "-")
|
|
44
|
+
.replace(/^-+|-+$/g, "");
|
|
45
|
+
}
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
supportedReasoningLevels: [AGY_LOW, AGY_MEDIUM, AGY_HIGH],
|
|
49
|
-
source: "fallback",
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
id: "gemini-3.1-pro",
|
|
53
|
-
modelId: "gemini-3.1-pro",
|
|
54
|
-
label: "Gemini 3.1 Pro",
|
|
55
|
-
description: "Antigravity-routed Gemini 3.1 Pro. Select effort with ←/→.",
|
|
56
|
-
defaultReasoningLevel: "high",
|
|
57
|
-
supportedReasoningLevels: [AGY_LOW, AGY_HIGH],
|
|
58
|
-
source: "fallback",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: "claude-sonnet-4-6-think",
|
|
62
|
-
modelId: "claude-sonnet-4-6-think",
|
|
63
|
-
label: "Claude Sonnet 4.6 (Thinking)",
|
|
64
|
-
description: "Antigravity-routed Claude Sonnet 4.6 with extended thinking.",
|
|
65
|
-
defaultReasoningLevel: null,
|
|
66
|
-
supportedReasoningLevels: null,
|
|
67
|
-
source: "fallback",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: "claude-opus-4-6-think",
|
|
71
|
-
modelId: "claude-opus-4-6-think",
|
|
72
|
-
label: "Claude Opus 4.6 (Thinking)",
|
|
73
|
-
description: "Antigravity-routed Claude Opus 4.6 with extended thinking.",
|
|
74
|
-
defaultReasoningLevel: null,
|
|
75
|
-
supportedReasoningLevels: null,
|
|
76
|
-
source: "fallback",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: "gpt-oss-120b",
|
|
80
|
-
modelId: "gpt-oss-120b",
|
|
81
|
-
label: "GPT-OSS 120B",
|
|
82
|
-
description: "Antigravity-routed GPT-OSS 120B.",
|
|
83
|
-
defaultReasoningLevel: null,
|
|
84
|
-
supportedReasoningLevels: null,
|
|
85
|
-
source: "fallback",
|
|
86
|
-
},
|
|
87
|
-
];
|
|
47
|
+
function formatAgyVariantLabel(value: string): string {
|
|
48
|
+
return value
|
|
49
|
+
.split(/[-_\s]+/)
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1).toLowerCase()}`)
|
|
52
|
+
.join(" ") || value;
|
|
53
|
+
}
|
|
88
54
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
55
|
+
function readAgySelectorMetadata(model: ProviderModel): AgySelectorMetadata | null {
|
|
56
|
+
if (!model.raw || typeof model.raw !== "object" || Array.isArray(model.raw)) return null;
|
|
57
|
+
const raw = model.raw as Partial<AgySelectorMetadata>;
|
|
58
|
+
if (raw.provider !== "antigravity" || !raw.selectors || typeof raw.selectors !== "object") return null;
|
|
59
|
+
return { provider: "antigravity", selectors: raw.selectors };
|
|
60
|
+
}
|
|
92
61
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
62
|
+
function preferredAgyDefault(modelId: string, efforts: readonly string[]): string {
|
|
63
|
+
if ((modelId === "gemini-3.5-flash" || modelId === "gemini-3.1-pro") && efforts.includes(ANTIGRAVITY_DEFAULT_REASONING)) {
|
|
64
|
+
return ANTIGRAVITY_DEFAULT_REASONING;
|
|
65
|
+
}
|
|
66
|
+
return efforts[0] ?? ANTIGRAVITY_DEFAULT_REASONING;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const AGY_REASONING_DISPLAY_ORDER = ["low", "medium", "high", "xhigh", "max"] as const;
|
|
70
|
+
|
|
71
|
+
function sortAgyReasoningLevels(levels: readonly ReasoningEffortCapability[]): ReasoningEffortCapability[] {
|
|
72
|
+
const rank = new Map<string, number>(AGY_REASONING_DISPLAY_ORDER.map((id, index) => [id, index]));
|
|
73
|
+
return levels
|
|
74
|
+
.map((level, index) => ({ level, index }))
|
|
75
|
+
.sort((left, right) => (rank.get(left.level.id) ?? AGY_REASONING_DISPLAY_ORDER.length + left.index)
|
|
76
|
+
- (rank.get(right.level.id) ?? AGY_REASONING_DISPLAY_ORDER.length + right.index))
|
|
77
|
+
.map(({ level }) => level);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function parseAgyModelsOutput(stdout: string): ProviderModel[] {
|
|
81
|
+
const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
82
|
+
const parsed = lines.map((selector) => {
|
|
83
|
+
const match = selector.match(/^(.*?)\s+\(([^()]+)\)$/);
|
|
84
|
+
return { selector, base: match?.[1]?.trim() ?? selector, variant: match?.[2]?.trim() ?? null };
|
|
85
|
+
});
|
|
86
|
+
const baseCounts = new Map<string, number>();
|
|
87
|
+
for (const item of parsed) baseCounts.set(item.base, (baseCounts.get(item.base) ?? 0) + 1);
|
|
88
|
+
|
|
89
|
+
const models: ProviderModel[] = [];
|
|
90
|
+
const grouped = new Map<string, ProviderModel>();
|
|
91
|
+
for (const item of parsed) {
|
|
92
|
+
const isVariantGroup = item.variant !== null && (baseCounts.get(item.base) ?? 0) > 1;
|
|
93
|
+
if (!isVariantGroup) {
|
|
94
|
+
const modelId = normalizeAgyId(item.selector);
|
|
95
|
+
models.push({
|
|
96
|
+
id: modelId,
|
|
97
|
+
modelId,
|
|
98
|
+
label: item.selector,
|
|
99
|
+
description: `Discovered from agy models: ${item.selector}`,
|
|
100
|
+
defaultReasoningLevel: null,
|
|
101
|
+
supportedReasoningLevels: null,
|
|
102
|
+
source: "discovered",
|
|
103
|
+
raw: { provider: "antigravity", selectors: { "": item.selector } } satisfies AgySelectorMetadata,
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
const modelId = normalizeAgyId(item.base);
|
|
109
|
+
const effortId = normalizeAgyId(item.variant ?? "");
|
|
110
|
+
const existing = grouped.get(item.base);
|
|
111
|
+
if (existing) {
|
|
112
|
+
const metadata = readAgySelectorMetadata(existing);
|
|
113
|
+
const levels = sortAgyReasoningLevels([...(existing.supportedReasoningLevels ?? []), {
|
|
114
|
+
id: effortId,
|
|
115
|
+
label: formatAgyVariantLabel(item.variant ?? effortId),
|
|
116
|
+
description: null,
|
|
117
|
+
}]);
|
|
118
|
+
const selectors = { ...(metadata?.selectors ?? {}), [effortId]: item.selector };
|
|
119
|
+
const updated = {
|
|
120
|
+
...existing,
|
|
121
|
+
defaultReasoningLevel: preferredAgyDefault(modelId, levels.map((level) => level.id)),
|
|
122
|
+
supportedReasoningLevels: levels,
|
|
123
|
+
raw: { provider: "antigravity", selectors } satisfies AgySelectorMetadata,
|
|
124
|
+
};
|
|
125
|
+
grouped.set(item.base, updated);
|
|
126
|
+
models[models.indexOf(existing)] = updated;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const level: ReasoningEffortCapability = {
|
|
131
|
+
id: effortId,
|
|
132
|
+
label: formatAgyVariantLabel(item.variant ?? effortId),
|
|
133
|
+
description: null,
|
|
134
|
+
};
|
|
135
|
+
const model: ProviderModel = {
|
|
136
|
+
id: modelId,
|
|
137
|
+
modelId,
|
|
138
|
+
label: item.base,
|
|
139
|
+
description: `Discovered from agy models. Select an advertised variant with ←/→.`,
|
|
140
|
+
defaultReasoningLevel: preferredAgyDefault(modelId, [effortId]),
|
|
141
|
+
supportedReasoningLevels: [level],
|
|
142
|
+
source: "discovered",
|
|
143
|
+
raw: { provider: "antigravity", selectors: { [effortId]: item.selector } } satisfies AgySelectorMetadata,
|
|
144
|
+
};
|
|
145
|
+
grouped.set(item.base, model);
|
|
146
|
+
models.push(model);
|
|
147
|
+
}
|
|
148
|
+
return models;
|
|
109
149
|
}
|
|
110
150
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
151
|
+
// Resolve persisted model/reasoning state to the exact selector advertised by `agy models`.
|
|
152
|
+
export function getAgyModelSelector(
|
|
153
|
+
modelId: string,
|
|
154
|
+
reasoning: string | null | undefined,
|
|
155
|
+
models: readonly ProviderModel[] = getActiveAgyModels(),
|
|
156
|
+
): string | null {
|
|
157
|
+
const model = models.find((item) => item.modelId === modelId || item.id === modelId);
|
|
158
|
+
if (!model) return null;
|
|
159
|
+
const metadata = readAgySelectorMetadata(model);
|
|
160
|
+
if (!metadata) return null;
|
|
161
|
+
if (!model.supportedReasoningLevels?.length) return metadata.selectors[""] ?? null;
|
|
162
|
+
if (reasoning) return metadata.selectors[reasoning] ?? null;
|
|
163
|
+
const effort = model.defaultReasoningLevel;
|
|
164
|
+
return effort ? metadata.selectors[effort] ?? null : null;
|
|
117
165
|
}
|
|
118
166
|
|
|
119
167
|
export function getAntigravityModelLabel(modelId: string): string {
|
|
120
|
-
return
|
|
168
|
+
return getActiveAgyModels().find((m) => m.id === modelId)?.label ?? modelId;
|
|
121
169
|
}
|
|
122
170
|
|
|
123
171
|
// ---------------------------------------------------------------------------
|
|
@@ -138,7 +186,9 @@ export function migrateAntigravityLegacyModelId(modelId: string): { modelId: str
|
|
|
138
186
|
"gemini-3.5-flash-low": { modelId: "gemini-3.5-flash", reasoning: "low" },
|
|
139
187
|
"gemini-3.1-pro-high": { modelId: "gemini-3.1-pro", reasoning: "high" },
|
|
140
188
|
"gemini-3.1-pro-low": { modelId: "gemini-3.1-pro", reasoning: "low" },
|
|
141
|
-
"
|
|
189
|
+
"claude-sonnet-4-6-think": { modelId: "claude-sonnet-4.6-thinking" },
|
|
190
|
+
"claude-opus-4-6-think": { modelId: "claude-opus-4.6-thinking" },
|
|
191
|
+
"gpt-oss-120b": { modelId: "gpt-oss-120b-medium" },
|
|
142
192
|
};
|
|
143
193
|
return legacy[modelId] ?? { modelId };
|
|
144
194
|
}
|
|
@@ -149,6 +199,52 @@ export function migrateAntigravityLegacyModelId(modelId: string): { modelId: str
|
|
|
149
199
|
|
|
150
200
|
let agyRouteValidated = false;
|
|
151
201
|
let resolvedAgyExecutable: string = "agy";
|
|
202
|
+
let discoveredAgyModels: readonly ProviderModel[] | null = null;
|
|
203
|
+
|
|
204
|
+
function getActiveAgyModels(): readonly ProviderModel[] {
|
|
205
|
+
if (discoveredAgyModels?.length) return discoveredAgyModels;
|
|
206
|
+
return loadCachedProviderModels("antigravity")?.models ?? [];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export async function discoverAgyModels(options: {
|
|
210
|
+
executable: string;
|
|
211
|
+
cwd: string;
|
|
212
|
+
runCommandImpl: typeof runCommand;
|
|
213
|
+
platform: NodeJS.Platform;
|
|
214
|
+
}): Promise<ProviderModelDiscoveryResult> {
|
|
215
|
+
const spawnSpec = buildSpawnSpec(options.executable, ["models"], options.platform);
|
|
216
|
+
const result = await options.runCommandImpl({
|
|
217
|
+
executable: spawnSpec.executable,
|
|
218
|
+
args: spawnSpec.args,
|
|
219
|
+
cwd: options.cwd,
|
|
220
|
+
timeoutMs: ANTIGRAVITY_VALIDATION_TIMEOUT_MS,
|
|
221
|
+
}).result;
|
|
222
|
+
const models = result.status === "completed" && result.exitCode === 0
|
|
223
|
+
? parseAgyModelsOutput(result.stdout)
|
|
224
|
+
: [];
|
|
225
|
+
if (models.length > 0) {
|
|
226
|
+
discoveredAgyModels = models;
|
|
227
|
+
return {
|
|
228
|
+
status: "ready",
|
|
229
|
+
providerId: "antigravity",
|
|
230
|
+
backendKind: "antigravity-cli-auth",
|
|
231
|
+
models,
|
|
232
|
+
message: `Loaded ${models.length} models from agy models.`,
|
|
233
|
+
diagnostics: { modelSource: "agy-models-command", modelsExitCode: result.exitCode, modelsStatus: result.status },
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const cached = loadCachedProviderModels("antigravity")?.models ?? [];
|
|
237
|
+
return {
|
|
238
|
+
status: cached.length > 0 ? "ready" : "not-configured",
|
|
239
|
+
providerId: "antigravity",
|
|
240
|
+
backendKind: cached.length > 0 ? "antigravity-cli-auth" : "unavailable",
|
|
241
|
+
models: cached,
|
|
242
|
+
message: cached.length > 0
|
|
243
|
+
? "Live agy model metadata is unavailable; using the last successful discovery."
|
|
244
|
+
: "Antigravity model metadata is unavailable. Run Refresh models after checking `agy models`.",
|
|
245
|
+
diagnostics: { modelSource: cached.length > 0 ? "cache" : "unavailable", modelsExitCode: result.exitCode, modelsStatus: result.status },
|
|
246
|
+
};
|
|
247
|
+
}
|
|
152
248
|
|
|
153
249
|
export function isAntigravityRouteConfigured(): boolean {
|
|
154
250
|
return agyRouteValidated;
|
|
@@ -157,6 +253,7 @@ export function isAntigravityRouteConfigured(): boolean {
|
|
|
157
253
|
export function resetAntigravityRouteValidationCacheForTests(): void {
|
|
158
254
|
agyRouteValidated = false;
|
|
159
255
|
resolvedAgyExecutable = "agy";
|
|
256
|
+
discoveredAgyModels = null;
|
|
160
257
|
resetAgyExecutableCacheForTests();
|
|
161
258
|
}
|
|
162
259
|
|
|
@@ -170,6 +267,24 @@ export async function validateAntigravityRoute(options: {
|
|
|
170
267
|
runCommandImpl?: typeof runCommand;
|
|
171
268
|
platform?: NodeJS.Platform;
|
|
172
269
|
}): Promise<ProviderRouteValidationResult> {
|
|
270
|
+
// Already validated this session: skip the executable probe and model
|
|
271
|
+
// re-discovery so re-activating antigravity is instant. "Refresh models"
|
|
272
|
+
// bypasses this via runtime.refreshModels, so a stale catalog stays
|
|
273
|
+
// user-recoverable.
|
|
274
|
+
if (agyRouteValidated && discoveredAgyModels?.length) {
|
|
275
|
+
return {
|
|
276
|
+
status: "ready",
|
|
277
|
+
providerId: "antigravity",
|
|
278
|
+
backendKind: "antigravity-cli-auth",
|
|
279
|
+
message: `Antigravity CLI found at: ${resolvedAgyExecutable}`,
|
|
280
|
+
diagnostics: {
|
|
281
|
+
resolvedCommand: resolvedAgyExecutable,
|
|
282
|
+
modelSource: "session-cache",
|
|
283
|
+
discoveredModelCount: discoveredAgyModels.length,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
173
288
|
let resolved: string;
|
|
174
289
|
try {
|
|
175
290
|
resolved = await resolveAgyExecutable({
|
|
@@ -213,13 +328,23 @@ export async function validateAntigravityRoute(options: {
|
|
|
213
328
|
|
|
214
329
|
resolvedAgyExecutable = resolved;
|
|
215
330
|
agyRouteValidated = true;
|
|
331
|
+
const modelDiscovery = await discoverAgyModels({
|
|
332
|
+
executable: resolved,
|
|
333
|
+
cwd: options.cwd ?? process.cwd(),
|
|
334
|
+
runCommandImpl,
|
|
335
|
+
platform: options.platform ?? process.platform,
|
|
336
|
+
});
|
|
216
337
|
|
|
217
338
|
return {
|
|
218
339
|
status: "ready",
|
|
219
340
|
providerId: "antigravity",
|
|
220
341
|
backendKind: "antigravity-cli-auth",
|
|
221
342
|
message: `Antigravity CLI found at: ${resolved}`,
|
|
222
|
-
diagnostics: {
|
|
343
|
+
diagnostics: {
|
|
344
|
+
resolvedCommand: resolved,
|
|
345
|
+
modelSource: modelDiscovery.diagnostics?.modelSource ?? "unavailable",
|
|
346
|
+
discoveredModelCount: modelDiscovery.models.length,
|
|
347
|
+
},
|
|
223
348
|
};
|
|
224
349
|
}
|
|
225
350
|
|
|
@@ -233,16 +358,23 @@ export function runAntigravityWithRunner(
|
|
|
233
358
|
runCommandImpl: typeof runCommand = runCommand,
|
|
234
359
|
executable: string = resolvedAgyExecutable,
|
|
235
360
|
platform: NodeJS.Platform = process.platform,
|
|
361
|
+
models: readonly ProviderModel[] = getActiveAgyModels(),
|
|
236
362
|
): () => void {
|
|
237
|
-
const
|
|
238
|
-
|
|
363
|
+
const selector = getAgyModelSelector(request.route.modelId, request.route.reasoning, models);
|
|
364
|
+
if (!selector) {
|
|
365
|
+
handlers.onError(
|
|
366
|
+
`Antigravity has no verified selector for ${request.route.modelId}${request.route.reasoning ? ` / ${request.route.reasoning}` : ""}. Refresh models and try again.`,
|
|
367
|
+
);
|
|
368
|
+
return () => undefined;
|
|
369
|
+
}
|
|
370
|
+
const spawnSpec = buildSpawnSpec(executable, ["--model", selector, "-p", request.prompt], platform);
|
|
239
371
|
|
|
240
372
|
const runner = runCommandImpl(
|
|
241
373
|
{
|
|
242
374
|
executable: spawnSpec.executable,
|
|
243
375
|
args: spawnSpec.args,
|
|
244
376
|
cwd: request.workspaceRoot,
|
|
245
|
-
env,
|
|
377
|
+
env: { ...process.env },
|
|
246
378
|
timeoutMs: ANTIGRAVITY_TIMEOUT_MS,
|
|
247
379
|
},
|
|
248
380
|
);
|
|
@@ -288,12 +420,36 @@ export const antigravityRuntime: ProviderRuntime = {
|
|
|
288
420
|
cwd: workspaceRoot,
|
|
289
421
|
configuredPath: antigravityCommandPath ?? null,
|
|
290
422
|
}),
|
|
291
|
-
discoverModels: (): ProviderModelDiscoveryResult =>
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
423
|
+
discoverModels: (): ProviderModelDiscoveryResult => {
|
|
424
|
+
const models = getActiveAgyModels();
|
|
425
|
+
return {
|
|
426
|
+
status: models.length > 0 ? "ready" : "not-configured",
|
|
427
|
+
providerId: "antigravity",
|
|
428
|
+
backendKind: models.length > 0 ? "antigravity-cli-auth" : "unavailable",
|
|
429
|
+
models,
|
|
430
|
+
...(models.length === 0 ? { message: "Antigravity model metadata is unavailable. Run Refresh models." } : {}),
|
|
431
|
+
};
|
|
432
|
+
},
|
|
433
|
+
refreshModels: async ({ cwd }): Promise<ProviderModelDiscoveryResult> => {
|
|
434
|
+
let executable = resolvedAgyExecutable;
|
|
435
|
+
try {
|
|
436
|
+
executable = await resolveAgyExecutable({ cwd });
|
|
437
|
+
resolvedAgyExecutable = executable;
|
|
438
|
+
} catch {
|
|
439
|
+
const cached = loadCachedProviderModels("antigravity")?.models ?? [];
|
|
440
|
+
return {
|
|
441
|
+
status: cached.length > 0 ? "ready" : "not-configured",
|
|
442
|
+
providerId: "antigravity",
|
|
443
|
+
backendKind: cached.length > 0 ? "antigravity-cli-auth" : "unavailable",
|
|
444
|
+
models: cached,
|
|
445
|
+
message: cached.length > 0
|
|
446
|
+
? "Antigravity CLI is unavailable; using the last successful model discovery."
|
|
447
|
+
: ANTIGRAVITY_ROUTE_SETUP_MESSAGE,
|
|
448
|
+
diagnostics: { modelSource: cached.length > 0 ? "cache" : "unavailable", resolvedCommand: null },
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
return discoverAgyModels({ executable, cwd, runCommandImpl: runCommand, platform: process.platform });
|
|
452
|
+
},
|
|
297
453
|
run: (request: ProviderChatRequest, handlers: BackendRunHandlers) => {
|
|
298
454
|
handlers.onProgress?.({
|
|
299
455
|
id: "antigravity-route",
|