nolo-cli 0.108.0-alpha.1 → 0.108.0-alpha.2
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/{_executeModel-GTYLDSJW.js → _executeModel-BY3P5LBB.js} +12 -12
- package/{agentDeleteCommand-OWYHN6D6.js → agentDeleteCommand-66KXCSRR.js} +7 -6
- package/{agentEmailCommands-C6J2KUL2.js → agentEmailCommands-63UTONDK.js} +18 -17
- package/{agentListCommands-B2V4YAC4.js → agentListCommands-NXCOTTZL.js} +9 -8
- package/{agentMachineCommands-UDEXV472.js → agentMachineCommands-Z6RGPZSG.js} +7 -6
- package/{agentProviderCommands-GNPTL5XR.js → agentProviderCommands-X3UNW77C.js} +1 -1
- package/{agentRecordCommands-XBVDEYVC.js → agentRecordCommands-JP54ZWND.js} +17 -16
- package/{agentRunCommand-V6RTNFRH.js → agentRunCommand-RMQWWSHF.js} +17 -16
- package/{agentRuntimeLocal-KCMC2TBD.js → agentRuntimeLocal-E67CTV45.js} +5 -4
- package/{agentSlice-TNH7BSUC.js → agentSlice-DG5TIQHE.js} +1 -1
- package/{appDeleteCommands-JEPA3EWE.js → appDeleteCommands-Z36CLGUK.js} +8 -7
- package/{appDeployCommands-UTB76XFM.js → appDeployCommands-ECMUWG6S.js} +8 -7
- package/{appDeployStatusCommands-LGHF2SBD.js → appDeployStatusCommands-CL24TDMA.js} +8 -7
- package/{appGetCommands-PX2BFHOB.js → appGetCommands-ITHGOYGJ.js} +8 -7
- package/{appListCommands-BSMPTWKC.js → appListCommands-EEOSI6RC.js} +8 -7
- package/{authCommand-YW42YZA4.js → authCommand-HGP2XTKC.js} +99 -7
- package/{chatQueueReduxAdapter-XMFWRG3P.js → chatQueueReduxAdapter-DKLWTT3G.js} +2 -2
- package/{chunk-PQFHGD77.js → chunk-2OASQKU2.js} +1 -1
- package/{chunk-62CATUYY.js → chunk-4NNTATRH.js} +12 -769
- package/{chunk-EEGDMATE.js → chunk-AODJ7WSF.js} +3 -3
- package/{chunk-CSC3CU4K.js → chunk-CW67PN7L.js} +3 -3
- package/{chunk-7U6P3PHS.js → chunk-DOTZ5GTO.js} +1 -1
- package/chunk-FV3JEYR3.js +870 -0
- package/{chunk-RRM7AJ3M.js → chunk-G4VIHCGJ.js} +3 -3
- package/chunk-GMZLP5DV.js +82 -0
- package/{chunk-UZGQNTVW.js → chunk-GNCCNNZD.js} +3 -1
- package/{chunk-GO3Z72MT.js → chunk-H4AHY5BU.js} +3 -80
- package/{chunk-NA35QHCF.js → chunk-HSSRGGXJ.js} +1 -1
- package/{chunk-GEPUP7OO.js → chunk-IQPFGYO3.js} +1 -1
- package/{chunk-XT35TTFG.js → chunk-KZJP33ZK.js} +1 -1
- package/{chunk-GPCZ7UXG.js → chunk-LJ5VW2UJ.js} +1 -1
- package/{chunk-AG2AZ6GX.js → chunk-LPIYPEME.js} +9 -9
- package/{chunk-AEOE4Z6Q.js → chunk-LWKP7AWH.js} +1 -1
- package/{chunk-QQWJUHSL.js → chunk-P3GYTNDF.js} +1 -1
- package/{chunk-ETI2NYVF.js → chunk-PHXD6JTX.js} +1 -1
- package/{chunk-TYYSADX4.js → chunk-PWBDVI4R.js} +5 -5
- package/{chunk-KQ4ONNQD.js → chunk-QU7KDSZX.js} +1 -1
- package/{chunk-RRPWH4LX.js → chunk-RVE4DCV3.js} +2 -2
- package/{chunk-R7RHOSZU.js → chunk-RZGLXO2B.js} +26 -22
- package/{chunk-DUK4OQNO.js → chunk-SYXOBWOC.js} +4 -4
- package/{chunk-L7OXGGBN.js → chunk-T3GEOSRJ.js} +2 -2
- package/{chunk-QWL5QZGU.js → chunk-TR22GEUU.js} +2 -2
- package/{chunk-BVGTK7MR.js → chunk-UDIIVXKA.js} +41 -28
- package/{chunk-PVZT43MU.js → chunk-YTLRHRH3.js} +3 -3
- package/{chunk-TWQWYIMJ.js → chunk-YWIEQS6H.js} +8 -8
- package/{chunk-53HEEOTT.js → chunk-Z5625XML.js} +1 -1
- package/{contentThunks-3Z6NAUW6.js → contentThunks-JHK6X2KU.js} +3 -3
- package/{createAgentAutomationAction-OBH7GPW5.js → createAgentAutomationAction-7HX7KBES.js} +3 -3
- package/{createDialogAction-7XW3RX2A.js → createDialogAction-VUUUZL54.js} +4 -4
- package/{createPageAction-JJ7UUTWC.js → createPageAction-QWNMGO3O.js} +3 -3
- package/{dialogCommands-H7FPUYUQ.js → dialogCommands-EN7TYD3I.js} +8 -7
- package/{dialogSlice-6Z2BPC3T.js → dialogSlice-P2K47T3P.js} +2 -2
- package/{docCreateCommands-WRG2JLGM.js → docCreateCommands-43JKQEIH.js} +7 -6
- package/{docDeleteCommands-SHWJIBJS.js → docDeleteCommands-RL6D46XE.js} +8 -7
- package/{docReadCommands-WJN3WT6O.js → docReadCommands-TOEUEQDG.js} +7 -6
- package/{docStore-7WUS6XXX.js → docStore-3AHKTJRI.js} +1 -1
- package/{docUpdateCommands-IE32IL6O.js → docUpdateCommands-FWU5G2XB.js} +7 -6
- package/{handleSendMessageAction-GUBOMCGM.js → handleSendMessageAction-ID5IKXUE.js} +2 -2
- package/index.js +51 -51
- package/{machineCommands-KSN4COGR.js → machineCommands-TTKK4F7C.js} +16 -15
- package/{machineWsRunDispatch-AAG6PDBY.js → machineWsRunDispatch-RX64L3ET.js} +16 -15
- package/package.json +1 -1
- package/{providerPresetApply-FG6NZ57W.js → providerPresetApply-XI3WUPTI.js} +2 -2
- package/{providerRegistry-757OWH3O.js → providerRegistry-KEPWWGXD.js} +2 -2
- package/{readlineWorkspace-HO62DKCG.js → readlineWorkspace-KIMUDPPV.js} +20 -19
- package/{runAgentClientLoop-JLRJIF3F.js → runAgentClientLoop-AN4WIRPQ.js} +10 -10
- package/{spaceCommands-5GLCWZPO.js → spaceCommands-NA4JMIGT.js} +7 -6
- package/{streamAgentChatTurn-DZ3PP7ZH.js → streamAgentChatTurn-3TYTHZPJ.js} +11 -11
- package/{tools-XA4ZWLH4.js → tools-34SEJSLQ.js} +8 -8
- package/{tuiSummaryLlmCaller-OHHFTHMG.js → tuiSummaryLlmCaller-UFGFOIIW.js} +2 -1
- package/{updateDialogTitleAction-VWZT4J6J.js → updateDialogTitleAction-RDHNT265.js} +3 -3
- package/chunk-Q5FJJ6XI.js +0 -103
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
import {
|
|
2
|
+
streamSseDataValues
|
|
3
|
+
} from "./chunk-GMZLP5DV.js";
|
|
4
|
+
import {
|
|
5
|
+
getAntigravityUserAgent,
|
|
6
|
+
readAntigravityProjectId,
|
|
7
|
+
resolveAntigravityCloudCodeBaseUrl
|
|
8
|
+
} from "./chunk-GNCCNNZD.js";
|
|
9
|
+
import {
|
|
10
|
+
asOptionalTrimmedString
|
|
11
|
+
} from "./chunk-G3SUCT4W.js";
|
|
12
|
+
|
|
13
|
+
// packages/core/chat/upstreamErrorBody.ts
|
|
14
|
+
function parseUpstreamErrorBody(errorText, statusText) {
|
|
15
|
+
if (errorText) {
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(errorText);
|
|
18
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19
|
+
const error = parsed.error;
|
|
20
|
+
if (error && typeof error === "object" && !Array.isArray(error)) {
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { error: { message: errorText || statusText } };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
31
|
+
import { randomUUID } from "node:crypto";
|
|
32
|
+
|
|
33
|
+
// packages/agent-runtime/antigravityWireModel.ts
|
|
34
|
+
var WIRE_PROFILES = {
|
|
35
|
+
// Antigravity discovery exposes 3.7 Flash as one tiered wire model.
|
|
36
|
+
// The UI labels its effort variants (Low/Medium/High), but the literal
|
|
37
|
+
// -medium/-high ids return 404 from streamGenerateContent.
|
|
38
|
+
"gemini-3.7-flash-tiered": { modelEnum: "MODEL_PLACEHOLDER_M301", maxOutputTokens: 65536 },
|
|
39
|
+
// Gemini 3.8 Flash 沿用 3.7 的 tiered 兼容策略:仓库内暂无 Antigravity discovery
|
|
40
|
+
// 证据确认 3.8 的 wire modelEnum,禁止虚构,先只声明同档输出上限;enum 待
|
|
41
|
+
// discovery 证据到位后补齐。
|
|
42
|
+
"gemini-3.8-flash-tiered": { maxOutputTokens: 65536 },
|
|
43
|
+
"gemini-3.6-flash-low": { maxOutputTokens: 65536 },
|
|
44
|
+
"gemini-3.6-flash-medium": { maxOutputTokens: 65536 },
|
|
45
|
+
"gemini-3.6-flash-high": { maxOutputTokens: 65536 },
|
|
46
|
+
// 旧模型 wire 映射保留:存量自定义 agent 仍可能引用(注册表已下线不影响此处)。
|
|
47
|
+
"gemini-3.5-flash-extra-low": { modelEnum: "MODEL_PLACEHOLDER_M187", maxOutputTokens: 65536 },
|
|
48
|
+
"gemini-3.5-flash-low": { modelEnum: "MODEL_PLACEHOLDER_M20", maxOutputTokens: 65536 },
|
|
49
|
+
"gemini-3-flash-agent": { modelEnum: "MODEL_PLACEHOLDER_M132", maxOutputTokens: 65536 },
|
|
50
|
+
"gemini-3.1-pro-low": { modelEnum: "MODEL_PLACEHOLDER_M36", maxOutputTokens: 65535 },
|
|
51
|
+
"gemini-pro-agent": { modelEnum: "MODEL_PLACEHOLDER_M16", maxOutputTokens: 65535 },
|
|
52
|
+
"claude-sonnet-5": { maxOutputTokens: 64e3 },
|
|
53
|
+
"claude-sonnet-4-6": { maxOutputTokens: 64e3 },
|
|
54
|
+
"claude-opus-4-6-thinking": { maxOutputTokens: 64e3 },
|
|
55
|
+
"gemini-2.5-flash": { maxOutputTokens: 65536 },
|
|
56
|
+
"gemini-2.5-pro": { maxOutputTokens: 65536 }
|
|
57
|
+
};
|
|
58
|
+
function resolveAntigravityWireModel(logicalModelId) {
|
|
59
|
+
const id = logicalModelId.trim();
|
|
60
|
+
const lower = id.toLowerCase();
|
|
61
|
+
if (lower === "gemini-3.5-flash") {
|
|
62
|
+
const wireModelId = "gemini-3.5-flash-low";
|
|
63
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
64
|
+
}
|
|
65
|
+
if (lower === "gemini-3.7-flash" || ["gemini-3.7-flash-low", "gemini-3.7-flash-medium", "gemini-3.7-flash-high"].includes(lower)) {
|
|
66
|
+
const wireModelId = "gemini-3.7-flash-tiered";
|
|
67
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
68
|
+
}
|
|
69
|
+
if (lower === "gemini-3.8-flash" || ["gemini-3.8-flash-low", "gemini-3.8-flash-medium", "gemini-3.8-flash-high"].includes(lower)) {
|
|
70
|
+
const wireModelId = "gemini-3.8-flash-tiered";
|
|
71
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
72
|
+
}
|
|
73
|
+
if (lower === "gemini-3.6-flash") {
|
|
74
|
+
const wireModelId = "gemini-3.6-flash-low";
|
|
75
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
76
|
+
}
|
|
77
|
+
if (lower === "gemini-3.1-pro" || lower === "gemini-3.1-pro-preview") {
|
|
78
|
+
const wireModelId = "gemini-3.1-pro-low";
|
|
79
|
+
return { wireModelId, profile: WIRE_PROFILES[wireModelId] };
|
|
80
|
+
}
|
|
81
|
+
if (WIRE_PROFILES[id]) {
|
|
82
|
+
return { wireModelId: id, profile: WIRE_PROFILES[id] };
|
|
83
|
+
}
|
|
84
|
+
return { wireModelId: id };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// packages/agent-runtime/sseDataLine.ts
|
|
88
|
+
function parseSseDataLineJson(line) {
|
|
89
|
+
const trimmed = line.trim();
|
|
90
|
+
if (!trimmed.startsWith("data:")) return null;
|
|
91
|
+
const payload = trimmed.slice(5).trim();
|
|
92
|
+
if (!payload || payload === "[DONE]") return null;
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(payload);
|
|
95
|
+
} catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function parseSseDataLineObject(line) {
|
|
100
|
+
const parsed = parseSseDataLineJson(line);
|
|
101
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// packages/agent-runtime/geminiNativeShared.ts
|
|
105
|
+
var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
|
|
106
|
+
function resolveGeminiModelQuirks(modelId) {
|
|
107
|
+
const lower = modelId.toLowerCase();
|
|
108
|
+
const isGemini3 = lower.includes("gemini-3");
|
|
109
|
+
const isStrictSignatureModel = lower.includes("gemini-3.5") || lower.includes("flash-preview");
|
|
110
|
+
const isClaude = lower.includes("claude");
|
|
111
|
+
return {
|
|
112
|
+
requiresThoughtSignature: isGemini3,
|
|
113
|
+
allowsThoughtSignatureSentinel: isGemini3 && !isStrictSignatureModel,
|
|
114
|
+
isClaudeCrossModel: isClaude
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function isGemini3Model(modelId) {
|
|
118
|
+
return resolveGeminiModelQuirks(modelId).requiresThoughtSignature;
|
|
119
|
+
}
|
|
120
|
+
function messageText(content) {
|
|
121
|
+
if (typeof content === "string") return content;
|
|
122
|
+
if (!Array.isArray(content)) return "";
|
|
123
|
+
return content.filter(
|
|
124
|
+
(part) => part?.type === "text"
|
|
125
|
+
).map((part) => part.text).join("\n").trim();
|
|
126
|
+
}
|
|
127
|
+
function parseDataUrlToInlineData(url) {
|
|
128
|
+
const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
|
|
129
|
+
url
|
|
130
|
+
);
|
|
131
|
+
if (!match) return null;
|
|
132
|
+
return { mimeType: match[1], data: match[2] };
|
|
133
|
+
}
|
|
134
|
+
function extractInlineDataParts(content) {
|
|
135
|
+
if (!Array.isArray(content)) return [];
|
|
136
|
+
const parts = [];
|
|
137
|
+
for (const part of content) {
|
|
138
|
+
if (!part || typeof part !== "object") continue;
|
|
139
|
+
if (part.type !== "image_url") continue;
|
|
140
|
+
const url = part.image_url?.url;
|
|
141
|
+
if (typeof url !== "string" || !url.trim()) continue;
|
|
142
|
+
const inline = parseDataUrlToInlineData(url);
|
|
143
|
+
if (inline) parts.push({ inlineData: inline });
|
|
144
|
+
}
|
|
145
|
+
return parts;
|
|
146
|
+
}
|
|
147
|
+
function convertOpenAiMessagesToGemini(messages, options) {
|
|
148
|
+
const contents = [];
|
|
149
|
+
const systemTexts = [];
|
|
150
|
+
let toolCallIndex = 0;
|
|
151
|
+
let pendingFunctionCalls = [];
|
|
152
|
+
const pushOrMergeContent = (role, parts) => {
|
|
153
|
+
if (parts.length === 0) return;
|
|
154
|
+
const last = contents[contents.length - 1];
|
|
155
|
+
if (last && last.role === role) {
|
|
156
|
+
last.parts.push(...parts);
|
|
157
|
+
} else {
|
|
158
|
+
contents.push({ role, parts });
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const flushPendingFunctionCalls = () => {
|
|
162
|
+
if (pendingFunctionCalls.length === 0) return;
|
|
163
|
+
const dummyResponses = pendingFunctionCalls.map(
|
|
164
|
+
({ name, id }) => ({
|
|
165
|
+
functionResponse: {
|
|
166
|
+
name,
|
|
167
|
+
response: { output: "{}" },
|
|
168
|
+
...id ? { id } : {}
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
);
|
|
172
|
+
pendingFunctionCalls = [];
|
|
173
|
+
pushOrMergeContent("user", dummyResponses);
|
|
174
|
+
};
|
|
175
|
+
for (const raw of messages) {
|
|
176
|
+
if (!raw || typeof raw !== "object" || !("role" in raw)) continue;
|
|
177
|
+
const role = String(raw.role);
|
|
178
|
+
const content = "content" in raw ? raw.content : null;
|
|
179
|
+
if (role === "system") {
|
|
180
|
+
const text = messageText(
|
|
181
|
+
content
|
|
182
|
+
);
|
|
183
|
+
if (text) systemTexts.push(text);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (role === "user") {
|
|
187
|
+
flushPendingFunctionCalls();
|
|
188
|
+
const text = messageText(
|
|
189
|
+
content
|
|
190
|
+
);
|
|
191
|
+
const imageParts = extractInlineDataParts(
|
|
192
|
+
content
|
|
193
|
+
);
|
|
194
|
+
if (!text && imageParts.length === 0) continue;
|
|
195
|
+
const parts = [];
|
|
196
|
+
if (text) parts.push({ text });
|
|
197
|
+
for (const img of imageParts) parts.push(img);
|
|
198
|
+
pushOrMergeContent("user", parts);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (role === "assistant") {
|
|
202
|
+
flushPendingFunctionCalls();
|
|
203
|
+
const text = messageText(
|
|
204
|
+
content
|
|
205
|
+
);
|
|
206
|
+
const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
|
|
207
|
+
const parts = [];
|
|
208
|
+
if (text) {
|
|
209
|
+
parts.push({ text });
|
|
210
|
+
}
|
|
211
|
+
for (const call of toolCalls) {
|
|
212
|
+
const name = call?.function?.name?.trim();
|
|
213
|
+
if (!name) continue;
|
|
214
|
+
const id = call.id?.trim() || `${name}_${toolCallIndex++}`;
|
|
215
|
+
pendingFunctionCalls.push({ name, id });
|
|
216
|
+
const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
|
|
217
|
+
const isFirstFunctionCallPart = !parts.some(
|
|
218
|
+
(p) => "functionCall" in p
|
|
219
|
+
);
|
|
220
|
+
const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
|
|
221
|
+
const part = {
|
|
222
|
+
functionCall: {
|
|
223
|
+
name,
|
|
224
|
+
args: parseToolArgs(call.function?.arguments),
|
|
225
|
+
...id ? { id } : {}
|
|
226
|
+
},
|
|
227
|
+
...signature ? { thoughtSignature: signature } : {}
|
|
228
|
+
};
|
|
229
|
+
parts.push(part);
|
|
230
|
+
}
|
|
231
|
+
pushOrMergeContent("model", parts);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (role === "tool") {
|
|
235
|
+
const toolCallId = "tool_call_id" in raw && typeof raw.tool_call_id === "string" ? raw.tool_call_id : "";
|
|
236
|
+
const rawName = "name" in raw && typeof raw.name === "string" ? raw.name.trim() : "";
|
|
237
|
+
const pendingIndex = pendingFunctionCalls.findIndex(
|
|
238
|
+
(p) => toolCallId ? p.id === toolCallId : rawName ? p.name === rawName : true
|
|
239
|
+
);
|
|
240
|
+
if (pendingIndex === -1) continue;
|
|
241
|
+
const [{ name, id }] = pendingFunctionCalls.splice(pendingIndex, 1);
|
|
242
|
+
const output = messageText(content) || "{}";
|
|
243
|
+
pushOrMergeContent("user", [
|
|
244
|
+
{
|
|
245
|
+
functionResponse: {
|
|
246
|
+
name,
|
|
247
|
+
response: { output },
|
|
248
|
+
// 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
|
|
249
|
+
// Gemini contents 转成 Claude messages 时需要 functionResponse →
|
|
250
|
+
// tool_result 的 tool_use_id;缺 id 时网关报
|
|
251
|
+
// "tool_result.tool_use_id: Field required"(HTTP 400)。
|
|
252
|
+
...id ? { id } : {}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
flushPendingFunctionCalls();
|
|
259
|
+
if (contents.length > 0 && contents[0]?.role === "model") {
|
|
260
|
+
contents.unshift({
|
|
261
|
+
role: "user",
|
|
262
|
+
parts: [{ text: "Continue the conversation." }]
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return { contents, systemTexts };
|
|
266
|
+
}
|
|
267
|
+
function parseToolArgs(raw) {
|
|
268
|
+
if (typeof raw === "string") {
|
|
269
|
+
try {
|
|
270
|
+
const parsed = JSON.parse(raw);
|
|
271
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
272
|
+
return parsed;
|
|
273
|
+
}
|
|
274
|
+
} catch {
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
278
|
+
return raw;
|
|
279
|
+
}
|
|
280
|
+
return {};
|
|
281
|
+
}
|
|
282
|
+
function sanitizeGeminiSchemaNode(node, active) {
|
|
283
|
+
const out = {};
|
|
284
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
285
|
+
return { type: "string" };
|
|
286
|
+
}
|
|
287
|
+
if (active?.has(node)) {
|
|
288
|
+
return { type: "object", description: "(circular schema reference)" };
|
|
289
|
+
}
|
|
290
|
+
const seen = active ?? /* @__PURE__ */ new WeakSet();
|
|
291
|
+
seen.add(node);
|
|
292
|
+
try {
|
|
293
|
+
return sanitizeGeminiSchemaNodeInner(node, out, seen);
|
|
294
|
+
} finally {
|
|
295
|
+
seen.delete(node);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function sanitizeGeminiSchemaNodeInner(src, out, seen) {
|
|
299
|
+
if (Array.isArray(src.type)) {
|
|
300
|
+
const firstNonNull = src.type.find((t) => t !== "null");
|
|
301
|
+
if (typeof firstNonNull === "string") out.type = firstNonNull;
|
|
302
|
+
out.nullable = true;
|
|
303
|
+
} else if (typeof src.type === "string") {
|
|
304
|
+
out.type = src.type;
|
|
305
|
+
}
|
|
306
|
+
if (typeof src.description === "string") out.description = src.description;
|
|
307
|
+
if (typeof src.minimum === "number") out.minimum = src.minimum;
|
|
308
|
+
if (typeof src.maximum === "number") out.maximum = src.maximum;
|
|
309
|
+
if (Array.isArray(src.enum) && src.enum.length > 0) out.enum = src.enum;
|
|
310
|
+
if (src.nullable === true) out.nullable = true;
|
|
311
|
+
if ("const" in src && src.const !== void 0 && !out.enum) {
|
|
312
|
+
out.enum = [src.const];
|
|
313
|
+
}
|
|
314
|
+
const variantBranches = [
|
|
315
|
+
...Array.isArray(src.oneOf) ? src.oneOf : [],
|
|
316
|
+
...Array.isArray(src.anyOf) ? src.anyOf : []
|
|
317
|
+
];
|
|
318
|
+
if (variantBranches.length > 0) {
|
|
319
|
+
const mergedProperties = {};
|
|
320
|
+
let requiredIntersection;
|
|
321
|
+
for (const branch of variantBranches) {
|
|
322
|
+
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
323
|
+
const branchProperties = sanitized.properties ?? {};
|
|
324
|
+
for (const [key, value] of Object.entries(branchProperties)) {
|
|
325
|
+
const previous = mergedProperties[key];
|
|
326
|
+
const prevEnum = previous?.enum;
|
|
327
|
+
const nextEnum = value?.enum;
|
|
328
|
+
if (prevEnum && nextEnum) {
|
|
329
|
+
mergedProperties[key] = {
|
|
330
|
+
...value,
|
|
331
|
+
enum: [.../* @__PURE__ */ new Set([...prevEnum, ...nextEnum])]
|
|
332
|
+
};
|
|
333
|
+
} else {
|
|
334
|
+
mergedProperties[key] = value;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const branchRequired = Array.isArray(sanitized.required) ? sanitized.required : [];
|
|
338
|
+
requiredIntersection = requiredIntersection === void 0 ? [...branchRequired] : requiredIntersection.filter((r) => branchRequired.includes(r));
|
|
339
|
+
}
|
|
340
|
+
out.properties = {
|
|
341
|
+
...out.properties ?? {},
|
|
342
|
+
...mergedProperties
|
|
343
|
+
};
|
|
344
|
+
if (requiredIntersection !== void 0 && requiredIntersection.length > 0) {
|
|
345
|
+
out.required = requiredIntersection;
|
|
346
|
+
}
|
|
347
|
+
if (typeof out.type !== "string") out.type = "object";
|
|
348
|
+
}
|
|
349
|
+
if (Array.isArray(src.allOf)) {
|
|
350
|
+
for (const branch of src.allOf) {
|
|
351
|
+
const sanitized = sanitizeGeminiSchemaNode(branch, seen);
|
|
352
|
+
out.properties = {
|
|
353
|
+
...out.properties ?? {},
|
|
354
|
+
...sanitized.properties ?? {}
|
|
355
|
+
};
|
|
356
|
+
if (Array.isArray(sanitized.required)) {
|
|
357
|
+
out.required = [
|
|
358
|
+
.../* @__PURE__ */ new Set([
|
|
359
|
+
...out.required ?? [],
|
|
360
|
+
...sanitized.required ?? []
|
|
361
|
+
])
|
|
362
|
+
];
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (typeof out.type !== "string") out.type = "object";
|
|
366
|
+
}
|
|
367
|
+
if (src.properties && typeof src.properties === "object") {
|
|
368
|
+
const properties = {};
|
|
369
|
+
for (const [key, value] of Object.entries(
|
|
370
|
+
src.properties
|
|
371
|
+
)) {
|
|
372
|
+
properties[key] = sanitizeGeminiSchemaNode(value, seen);
|
|
373
|
+
}
|
|
374
|
+
out.properties = properties;
|
|
375
|
+
if (typeof out.type !== "string") out.type = "object";
|
|
376
|
+
}
|
|
377
|
+
if (Array.isArray(src.required)) {
|
|
378
|
+
const properties = out.properties ?? {};
|
|
379
|
+
const required = [...new Set(src.required)].filter(
|
|
380
|
+
(r) => typeof r === "string" && r in properties
|
|
381
|
+
);
|
|
382
|
+
if (required.length > 0) out.required = required;
|
|
383
|
+
}
|
|
384
|
+
if (src.items !== void 0) {
|
|
385
|
+
out.items = sanitizeGeminiSchemaNode(src.items, seen);
|
|
386
|
+
if (typeof out.type !== "string") out.type = "array";
|
|
387
|
+
}
|
|
388
|
+
if (typeof out.type !== "string") out.type = "object";
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
function convertOpenAiToolsToGemini(tools) {
|
|
392
|
+
if (!Array.isArray(tools) || tools.length === 0) return void 0;
|
|
393
|
+
const declarations = [];
|
|
394
|
+
for (const tool of tools) {
|
|
395
|
+
if (!tool || typeof tool !== "object" || !("function" in tool)) continue;
|
|
396
|
+
const fn = tool.function;
|
|
397
|
+
const name = typeof fn.name === "string" ? fn.name : "";
|
|
398
|
+
if (!name) continue;
|
|
399
|
+
declarations.push({
|
|
400
|
+
name,
|
|
401
|
+
description: typeof fn.description === "string" ? fn.description : "",
|
|
402
|
+
parameters: sanitizeGeminiSchemaNode(
|
|
403
|
+
fn.parameters ?? { type: "object", properties: {} }
|
|
404
|
+
)
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
if (declarations.length === 0) return void 0;
|
|
408
|
+
return [{ functionDeclarations: declarations }];
|
|
409
|
+
}
|
|
410
|
+
function createGeminiAccumulatorState() {
|
|
411
|
+
return {
|
|
412
|
+
text: "",
|
|
413
|
+
toolCalls: [],
|
|
414
|
+
reasoning: "",
|
|
415
|
+
events: []
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function applyGeminiChunk(chunk, state, options) {
|
|
419
|
+
if (!chunk || typeof chunk !== "object") return;
|
|
420
|
+
const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
|
|
421
|
+
if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
|
|
422
|
+
const meta = response.usageMetadata;
|
|
423
|
+
const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
|
|
424
|
+
const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
|
|
425
|
+
const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
|
|
426
|
+
const cached = typeof meta.cachedContentTokenCount === "number" && Number.isFinite(meta.cachedContentTokenCount) ? (
|
|
427
|
+
// cached ⊆ prompt;对畸形上游防御性钳位,避免 cache_read > input 破坏归一化与计费
|
|
428
|
+
Math.min(Math.max(0, Math.floor(meta.cachedContentTokenCount)), prompt)
|
|
429
|
+
) : 0;
|
|
430
|
+
state.usage = {
|
|
431
|
+
prompt_tokens: prompt,
|
|
432
|
+
completion_tokens: candidates2,
|
|
433
|
+
total_tokens: total,
|
|
434
|
+
...cached > 0 ? { cache_read_input_tokens: cached } : {}
|
|
435
|
+
};
|
|
436
|
+
state.events.push({ kind: "usage", usage: state.usage });
|
|
437
|
+
}
|
|
438
|
+
const candidates = Array.isArray(response.candidates) ? response.candidates : [];
|
|
439
|
+
for (const candidate of candidates) {
|
|
440
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
441
|
+
const candidateFinishReason = candidate.finishReason;
|
|
442
|
+
if (typeof candidateFinishReason === "string" && candidateFinishReason.trim()) {
|
|
443
|
+
state.finishReason = candidateFinishReason.trim();
|
|
444
|
+
state.events.push({ kind: "finish", reason: state.finishReason });
|
|
445
|
+
}
|
|
446
|
+
const parts = Array.isArray(
|
|
447
|
+
candidate.content?.parts
|
|
448
|
+
) ? candidate.content.parts : [];
|
|
449
|
+
for (const part of parts) {
|
|
450
|
+
if (!part || typeof part !== "object") continue;
|
|
451
|
+
const partSignature = part.thoughtSignature;
|
|
452
|
+
const isThought = Boolean(part.thought);
|
|
453
|
+
if ("text" in part && typeof part.text === "string") {
|
|
454
|
+
const piece = part.text;
|
|
455
|
+
if (!isThought) {
|
|
456
|
+
state.text += piece;
|
|
457
|
+
if (piece) {
|
|
458
|
+
state.events.push({ kind: "text", text: piece });
|
|
459
|
+
if (options?.onTextDelta) options.onTextDelta(piece);
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
state.reasoning += piece;
|
|
463
|
+
if (piece) {
|
|
464
|
+
state.events.push({ kind: "reasoning", text: piece });
|
|
465
|
+
if (options?.onReasoningDelta) options.onReasoningDelta(piece);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
if (isThought && typeof partSignature === "string" && partSignature) {
|
|
470
|
+
state.pendingThoughtSignature = partSignature;
|
|
471
|
+
}
|
|
472
|
+
if ("functionCall" in part && part.functionCall) {
|
|
473
|
+
const call = part.functionCall;
|
|
474
|
+
const name = typeof call.name === "string" ? call.name : "tool";
|
|
475
|
+
const id = typeof call.id === "string" ? call.id : `${name}_${state.toolCalls.length}`;
|
|
476
|
+
const argsObj = call.args && typeof call.args === "object" ? call.args : {};
|
|
477
|
+
const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : state.pendingThoughtSignature;
|
|
478
|
+
state.pendingThoughtSignature = void 0;
|
|
479
|
+
const toolCall = {
|
|
480
|
+
id,
|
|
481
|
+
type: "function",
|
|
482
|
+
function: { name, arguments: JSON.stringify(argsObj) },
|
|
483
|
+
...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
|
|
484
|
+
};
|
|
485
|
+
state.toolCalls.push(toolCall);
|
|
486
|
+
state.events.push({ kind: "tool_call", toolCall });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function accumulateGeminiChunks(chunks, options) {
|
|
492
|
+
const state = createGeminiAccumulatorState();
|
|
493
|
+
for (const chunk of chunks) {
|
|
494
|
+
applyGeminiChunk(chunk, state, options);
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
text: state.text,
|
|
498
|
+
toolCalls: state.toolCalls,
|
|
499
|
+
usage: state.usage,
|
|
500
|
+
finishReason: state.finishReason,
|
|
501
|
+
reasoningContent: state.reasoning,
|
|
502
|
+
events: state.events
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
async function accumulateGeminiStream(stream, options) {
|
|
506
|
+
const state = createGeminiAccumulatorState();
|
|
507
|
+
for await (const chunk of stream) {
|
|
508
|
+
applyGeminiChunk(chunk, state, options);
|
|
509
|
+
}
|
|
510
|
+
return {
|
|
511
|
+
text: state.text,
|
|
512
|
+
toolCalls: state.toolCalls,
|
|
513
|
+
usage: state.usage,
|
|
514
|
+
finishReason: state.finishReason,
|
|
515
|
+
reasoningContent: state.reasoning,
|
|
516
|
+
events: state.events
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
|
|
520
|
+
return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
|
|
521
|
+
}
|
|
522
|
+
function buildGeminiGenerateContentRequest(args) {
|
|
523
|
+
const { contents, systemTexts } = convertOpenAiMessagesToGemini(
|
|
524
|
+
args.messages,
|
|
525
|
+
{ attachSkipThoughtSignature: args.attachSkipThoughtSignature }
|
|
526
|
+
);
|
|
527
|
+
const request = { contents };
|
|
528
|
+
if (systemTexts.length > 0) {
|
|
529
|
+
request.systemInstruction = {
|
|
530
|
+
role: "user",
|
|
531
|
+
parts: systemTexts.map((text) => ({ text }))
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const toolsResult = convertOpenAiToolsToGemini(args.tools);
|
|
535
|
+
if (toolsResult) {
|
|
536
|
+
request.tools = toolsResult;
|
|
537
|
+
request.toolConfig = { functionCallingConfig: { mode: "AUTO" } };
|
|
538
|
+
}
|
|
539
|
+
const generationConfig = {};
|
|
540
|
+
if (typeof args.maxTokens === "number" && args.maxTokens > 0) {
|
|
541
|
+
generationConfig.maxOutputTokens = args.maxTokens;
|
|
542
|
+
}
|
|
543
|
+
if (typeof args.temperature === "number") {
|
|
544
|
+
generationConfig.temperature = args.temperature;
|
|
545
|
+
}
|
|
546
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
547
|
+
request.generationConfig = generationConfig;
|
|
548
|
+
}
|
|
549
|
+
return request;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// packages/agent-runtime/antigravityCloudCodeProvider.ts
|
|
553
|
+
var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
554
|
+
function buildCloudCodeAssistPayload(args) {
|
|
555
|
+
const projectId = readAntigravityProjectId(args.metadata);
|
|
556
|
+
if (!projectId) {
|
|
557
|
+
throw new Error(
|
|
558
|
+
"Antigravity OAuth credential is missing metadata.projectId. Re-run `nolo auth antigravity`."
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
|
|
562
|
+
const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
|
|
563
|
+
const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
|
|
564
|
+
const quirks = resolveGeminiModelQuirks(model);
|
|
565
|
+
const isClaude = quirks.isClaudeCrossModel;
|
|
566
|
+
const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
|
|
567
|
+
attachSkipThoughtSignature: quirks.allowsThoughtSignatureSentinel
|
|
568
|
+
});
|
|
569
|
+
if (contents.length === 0) {
|
|
570
|
+
throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
|
|
571
|
+
}
|
|
572
|
+
const prompt = args.agentConfig.prompt?.trim();
|
|
573
|
+
if (prompt) systemTexts.unshift(prompt);
|
|
574
|
+
const request = { contents };
|
|
575
|
+
if (systemTexts.length > 0) {
|
|
576
|
+
request.systemInstruction = {
|
|
577
|
+
role: "user",
|
|
578
|
+
parts: systemTexts.map((text) => ({ text }))
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
const tools = convertOpenAiToolsToGemini(
|
|
582
|
+
Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
|
|
583
|
+
);
|
|
584
|
+
if (tools) {
|
|
585
|
+
request.tools = tools;
|
|
586
|
+
request.toolConfig = { functionCallingConfig: { mode: "AUTO" } };
|
|
587
|
+
}
|
|
588
|
+
const generationConfig = {};
|
|
589
|
+
if (profile?.maxOutputTokens) {
|
|
590
|
+
generationConfig.maxOutputTokens = profile.maxOutputTokens;
|
|
591
|
+
} else if (typeof args.agentConfig.max_tokens === "number" && args.agentConfig.max_tokens > 0) {
|
|
592
|
+
generationConfig.maxOutputTokens = args.agentConfig.max_tokens;
|
|
593
|
+
}
|
|
594
|
+
if (typeof args.agentConfig.temperature === "number") {
|
|
595
|
+
generationConfig.temperature = args.agentConfig.temperature;
|
|
596
|
+
}
|
|
597
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
598
|
+
request.generationConfig = generationConfig;
|
|
599
|
+
}
|
|
600
|
+
const agentId = randomUUID();
|
|
601
|
+
const trajectoryId = randomUUID();
|
|
602
|
+
const step = 2;
|
|
603
|
+
const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
|
|
604
|
+
const labels = {
|
|
605
|
+
trajectory_id: trajectoryId,
|
|
606
|
+
last_step_index: String(step - 1),
|
|
607
|
+
used_claude: String(isClaude),
|
|
608
|
+
used_claude_conservative: String(isClaude)
|
|
609
|
+
};
|
|
610
|
+
if (profile?.modelEnum) {
|
|
611
|
+
labels.model_enum = profile.modelEnum;
|
|
612
|
+
}
|
|
613
|
+
request.labels = labels;
|
|
614
|
+
request.sessionId = `-${Math.floor(Math.random() * 9e15)}`;
|
|
615
|
+
return {
|
|
616
|
+
url: `${resolveAntigravityCloudCodeBaseUrl(args.agentConfig.customProviderUrl)}${STREAM_PATH}`,
|
|
617
|
+
envelope: {
|
|
618
|
+
project: projectId,
|
|
619
|
+
model,
|
|
620
|
+
request,
|
|
621
|
+
requestId,
|
|
622
|
+
requestType: "agent",
|
|
623
|
+
userAgent: "antigravity"
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
function resolveAntigravityFinishReason(upstream) {
|
|
628
|
+
const normalized = (upstream ?? "").trim().toUpperCase();
|
|
629
|
+
if (normalized === "MAX_TOKENS") return "length";
|
|
630
|
+
if (normalized === "SAFETY" || normalized === "RECITATION" || normalized === "PROHIBITED_CONTENT" || normalized === "BLOCKLIST") {
|
|
631
|
+
return "content_filter";
|
|
632
|
+
}
|
|
633
|
+
return "stop";
|
|
634
|
+
}
|
|
635
|
+
function normalizeAntigravityCompletion(decoded) {
|
|
636
|
+
const { text, toolCalls, usage, finishReason, reasoningContent, events } = decoded;
|
|
637
|
+
const normalizedFinishReason = (finishReason ?? "").trim().toUpperCase();
|
|
638
|
+
if (!text && !reasoningContent && toolCalls.length === 0 && !finishReason && !usage) {
|
|
639
|
+
const body = {
|
|
640
|
+
error: {
|
|
641
|
+
message: "antigravity upstream returned an empty stream (no content, finishReason or usage); channel degradation, not model emptiness"
|
|
642
|
+
},
|
|
643
|
+
provider_events: events
|
|
644
|
+
};
|
|
645
|
+
return {
|
|
646
|
+
status: 502,
|
|
647
|
+
text: "",
|
|
648
|
+
toolCalls: [],
|
|
649
|
+
providerEvents: events,
|
|
650
|
+
body
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
if (normalizedFinishReason === "MALFORMED_FUNCTION_CALL") {
|
|
654
|
+
const message2 = "antigravity upstream returned MALFORMED_FUNCTION_CALL (model generated an invalid function call or tool arguments were rejected by upstream)";
|
|
655
|
+
const providerFailure = {
|
|
656
|
+
kind: "provider_failure",
|
|
657
|
+
provider: "antigravity",
|
|
658
|
+
code: "MALFORMED_FUNCTION_CALL",
|
|
659
|
+
message: message2,
|
|
660
|
+
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
661
|
+
retryable: false,
|
|
662
|
+
status: 502
|
|
663
|
+
};
|
|
664
|
+
return {
|
|
665
|
+
status: 502,
|
|
666
|
+
text: "",
|
|
667
|
+
toolCalls: [],
|
|
668
|
+
finishReason,
|
|
669
|
+
providerEvents: events,
|
|
670
|
+
providerFailure,
|
|
671
|
+
runtimeProviderFailure: {
|
|
672
|
+
message: providerFailure.message,
|
|
673
|
+
retryable: providerFailure.retryable
|
|
674
|
+
},
|
|
675
|
+
body: {
|
|
676
|
+
error: {
|
|
677
|
+
message: message2,
|
|
678
|
+
code: "MALFORMED_FUNCTION_CALL",
|
|
679
|
+
category: "malformed_function_call",
|
|
680
|
+
providerReason: "MALFORMED_FUNCTION_CALL",
|
|
681
|
+
retryable: false
|
|
682
|
+
},
|
|
683
|
+
provider_failure: providerFailure,
|
|
684
|
+
provider_events: events
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
const message = {
|
|
689
|
+
role: "assistant",
|
|
690
|
+
content: text || null
|
|
691
|
+
};
|
|
692
|
+
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
693
|
+
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
694
|
+
return {
|
|
695
|
+
status: 200,
|
|
696
|
+
text,
|
|
697
|
+
...reasoningContent ? { reasoningContent } : {},
|
|
698
|
+
toolCalls,
|
|
699
|
+
...usage ? { usage } : {},
|
|
700
|
+
...finishReason ? { finishReason } : {},
|
|
701
|
+
providerEvents: events,
|
|
702
|
+
body: {
|
|
703
|
+
choices: [{
|
|
704
|
+
index: 0,
|
|
705
|
+
message,
|
|
706
|
+
finish_reason: toolCalls.length > 0 ? "tool_calls" : resolveAntigravityFinishReason(finishReason)
|
|
707
|
+
}],
|
|
708
|
+
...usage ? { usage } : {},
|
|
709
|
+
provider_events: events
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
async function fetchAntigravityCloudCodeCompletion(args) {
|
|
714
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
715
|
+
const { url, envelope } = buildCloudCodeAssistPayload(args);
|
|
716
|
+
const response = await fetchImpl(url, {
|
|
717
|
+
method: "POST",
|
|
718
|
+
headers: {
|
|
719
|
+
Authorization: `Bearer ${args.accessToken}`,
|
|
720
|
+
"Content-Type": "application/json",
|
|
721
|
+
"User-Agent": getAntigravityUserAgent()
|
|
722
|
+
},
|
|
723
|
+
body: JSON.stringify(envelope),
|
|
724
|
+
signal: args.signal
|
|
725
|
+
});
|
|
726
|
+
if (!response.ok) {
|
|
727
|
+
const errorText = await response.text();
|
|
728
|
+
return {
|
|
729
|
+
status: response.status,
|
|
730
|
+
text: "",
|
|
731
|
+
toolCalls: [],
|
|
732
|
+
providerEvents: [],
|
|
733
|
+
// 保留上游结构:Antigravity 的限流 body 同样携带结构化的重置信息,
|
|
734
|
+
// 压成字符串会让冷却退化成 5 分钟默认值。
|
|
735
|
+
body: parseUpstreamErrorBody(errorText, response.statusText)
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
const chunkStream = streamSseDataValues(response, parseSseDataLineJson);
|
|
739
|
+
const { text, toolCalls, usage, finishReason, reasoningContent, events } = await accumulateGeminiStream(chunkStream, {
|
|
740
|
+
onTextDelta: args.onTextDelta,
|
|
741
|
+
onReasoningDelta: args.onReasoningDelta
|
|
742
|
+
});
|
|
743
|
+
const normalized = normalizeAntigravityCompletion({
|
|
744
|
+
text,
|
|
745
|
+
toolCalls,
|
|
746
|
+
usage,
|
|
747
|
+
finishReason,
|
|
748
|
+
reasoningContent,
|
|
749
|
+
events
|
|
750
|
+
});
|
|
751
|
+
if (normalized.status !== 200 || !text && toolCalls.length === 0) {
|
|
752
|
+
console.warn(
|
|
753
|
+
`[antigravity] empty completion: finishReason=${JSON.stringify(finishReason)} reasoningLen=${reasoningContent?.length ?? 0} usage=${JSON.stringify(usage) ?? "none"} model=${String(envelope.model)} base=${new URL(url).host}`
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
return normalized;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// packages/agent-runtime/devinOAuth.ts
|
|
760
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
761
|
+
import { homedir } from "node:os";
|
|
762
|
+
import { join } from "node:path";
|
|
763
|
+
var DEVIN_CONNECT_URL = "https://server.codeium.com/exa.api_server_pb.ApiServerService/GetChatMessage";
|
|
764
|
+
function buildDevinAuthUrl(orgId) {
|
|
765
|
+
const cleanOrg = orgId?.trim();
|
|
766
|
+
if (cleanOrg) {
|
|
767
|
+
return `https://app.devin.ai/org/${encodeURIComponent(cleanOrg)}/settings/keys`;
|
|
768
|
+
}
|
|
769
|
+
return "https://app.devin.ai/settings/keys";
|
|
770
|
+
}
|
|
771
|
+
function extractDevinToken(input) {
|
|
772
|
+
const raw = input?.trim();
|
|
773
|
+
if (!raw) return null;
|
|
774
|
+
if (/^https?:\/\//i.test(raw)) {
|
|
775
|
+
try {
|
|
776
|
+
const url = new URL(raw);
|
|
777
|
+
const queryToken = url.searchParams.get("token") || url.searchParams.get("access_token") || url.searchParams.get("auth_token");
|
|
778
|
+
if (queryToken?.trim()) return queryToken.trim();
|
|
779
|
+
if (url.hash) {
|
|
780
|
+
const hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
|
|
781
|
+
const hashToken = hashParams.get("token") || hashParams.get("access_token") || hashParams.get("auth_token");
|
|
782
|
+
if (hashToken?.trim()) return hashToken.trim();
|
|
783
|
+
}
|
|
784
|
+
} catch {
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return raw || null;
|
|
788
|
+
}
|
|
789
|
+
function parseDevinCredentialsToml(content) {
|
|
790
|
+
for (const line of content.split(/\r?\n/)) {
|
|
791
|
+
const cogMatch = line.match(/(cog_[A-Za-z0-9_-]+)/);
|
|
792
|
+
if (cogMatch?.[1]) {
|
|
793
|
+
return cogMatch[1].trim();
|
|
794
|
+
}
|
|
795
|
+
const match = line.match(
|
|
796
|
+
/^\s*(?:windsurf_api_key|devin_api_key|api_key|api_token|token)\s*=\s*"([^"]+)"\s*$/i
|
|
797
|
+
);
|
|
798
|
+
if (match?.[1]) {
|
|
799
|
+
return match[1].trim();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
function detectLocalDevinCredentials(options) {
|
|
805
|
+
const baseHome = options?.homeDir || homedir();
|
|
806
|
+
const xdgData = process.env.XDG_DATA_HOME;
|
|
807
|
+
const candidateCliPaths = [
|
|
808
|
+
xdgData ? join(xdgData, "devin", "credentials.toml") : null,
|
|
809
|
+
join(baseHome, ".local", "share", "devin", "credentials.toml"),
|
|
810
|
+
process.env.APPDATA ? join(process.env.APPDATA, "devin", "credentials.toml") : null
|
|
811
|
+
].filter((p) => Boolean(p));
|
|
812
|
+
for (const credPath of candidateCliPaths) {
|
|
813
|
+
if (existsSync(credPath)) {
|
|
814
|
+
try {
|
|
815
|
+
const content = readFileSync(credPath, "utf-8");
|
|
816
|
+
const token = parseDevinCredentialsToml(content);
|
|
817
|
+
if (token) {
|
|
818
|
+
return {
|
|
819
|
+
found: true,
|
|
820
|
+
token,
|
|
821
|
+
source: "devin-cli",
|
|
822
|
+
sourcePath: credPath
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
} catch {
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
const codeiumPath = join(baseHome, ".codeium", "config.json");
|
|
830
|
+
if (existsSync(codeiumPath)) {
|
|
831
|
+
try {
|
|
832
|
+
const parsed = JSON.parse(readFileSync(codeiumPath, "utf-8"));
|
|
833
|
+
const token = parsed.apiKey || parsed.api_key;
|
|
834
|
+
if (token?.trim()) {
|
|
835
|
+
return {
|
|
836
|
+
found: true,
|
|
837
|
+
token: token.trim(),
|
|
838
|
+
source: "codeium-config",
|
|
839
|
+
sourcePath: codeiumPath
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
} catch {
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return { found: false };
|
|
846
|
+
}
|
|
847
|
+
function buildDevinOAuthCredential(token, now = Date.now()) {
|
|
848
|
+
return {
|
|
849
|
+
provider: "devin",
|
|
850
|
+
accessToken: token.trim(),
|
|
851
|
+
obtainedAt: now
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
export {
|
|
856
|
+
parseSseDataLineJson,
|
|
857
|
+
parseSseDataLineObject,
|
|
858
|
+
parseUpstreamErrorBody,
|
|
859
|
+
isGemini3Model,
|
|
860
|
+
accumulateGeminiChunks,
|
|
861
|
+
shouldUseGeminiNativeToolRoute,
|
|
862
|
+
buildGeminiGenerateContentRequest,
|
|
863
|
+
resolveAntigravityFinishReason,
|
|
864
|
+
fetchAntigravityCloudCodeCompletion,
|
|
865
|
+
DEVIN_CONNECT_URL,
|
|
866
|
+
buildDevinAuthUrl,
|
|
867
|
+
extractDevinToken,
|
|
868
|
+
detectLocalDevinCredentials,
|
|
869
|
+
buildDevinOAuthCredential
|
|
870
|
+
};
|