clawmoney 0.13.10 → 0.13.13
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/dist/relay/pricing.js
CHANGED
|
@@ -57,8 +57,12 @@ export const API_PRICES = {
|
|
|
57
57
|
"antigravity-gemini-3-pro": { input: 2, output: 12 },
|
|
58
58
|
"antigravity-gemini-3.1-pro": { input: 2, output: 12 },
|
|
59
59
|
"antigravity-gemini-3-flash": { input: 0.50, output: 3 },
|
|
60
|
-
"antigravity-
|
|
60
|
+
"antigravity-gemini-2.5-pro": { input: 1.25, output: 10 },
|
|
61
|
+
"antigravity-gemini-2.5-flash": { input: 0.30, output: 2.50 },
|
|
62
|
+
"antigravity-claude-opus-4-6": { input: 5, output: 25 },
|
|
61
63
|
"antigravity-claude-opus-4-6-thinking": { input: 5, output: 25 },
|
|
64
|
+
"antigravity-claude-sonnet-4-6": { input: 3, output: 15 },
|
|
65
|
+
"antigravity-claude-sonnet-4-5": { input: 3, output: 15 },
|
|
62
66
|
// ── Google (Gemini) ──
|
|
63
67
|
// Verified against LiteLLM pricing DB.
|
|
64
68
|
"gemini-3.1-pro-preview": { input: 2, output: 12 },
|
package/dist/relay/provider.js
CHANGED
|
@@ -97,8 +97,30 @@ function loadRelayConfig(cliOverride) {
|
|
|
97
97
|
agent_id: raw.agent_id,
|
|
98
98
|
agent_slug: raw.agent_slug,
|
|
99
99
|
relay,
|
|
100
|
+
proxy: typeof raw.proxy === "string" ? raw.proxy : undefined,
|
|
100
101
|
};
|
|
101
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Export the config's `proxy` setting into process.env so every downstream
|
|
105
|
+
* module (claude-api, codex-api, gemini-api, antigravity-api) that already
|
|
106
|
+
* reads HTTPS_PROXY at startup picks it up without any per-module changes.
|
|
107
|
+
* Silently no-ops if the env var is already set by the user's shell.
|
|
108
|
+
*/
|
|
109
|
+
function applyProxyFromConfig(config) {
|
|
110
|
+
if (!config.proxy)
|
|
111
|
+
return;
|
|
112
|
+
const alreadySet = process.env.HTTPS_PROXY ||
|
|
113
|
+
process.env.https_proxy ||
|
|
114
|
+
process.env.HTTP_PROXY ||
|
|
115
|
+
process.env.http_proxy;
|
|
116
|
+
if (alreadySet) {
|
|
117
|
+
logger.info(`[provider] shell HTTPS_PROXY=${alreadySet} overrides config.yaml proxy=${config.proxy}`);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
process.env.HTTPS_PROXY = config.proxy;
|
|
121
|
+
process.env.HTTP_PROXY = config.proxy;
|
|
122
|
+
logger.info(`[provider] using config.yaml proxy=${config.proxy}`);
|
|
123
|
+
}
|
|
102
124
|
// ── Request handler ──
|
|
103
125
|
function messagesToPrompt(messages) {
|
|
104
126
|
return messages.map((m) => String(m.content ?? "")).join("\n");
|
|
@@ -239,6 +261,10 @@ export function runRelayProvider(cliOverride) {
|
|
|
239
261
|
process.exit(1);
|
|
240
262
|
}
|
|
241
263
|
const config = loadRelayConfig(cliOverride);
|
|
264
|
+
// Make the config-level proxy visible to every upstream module that reads
|
|
265
|
+
// process.env.HTTPS_PROXY / http_proxy at init time. Must run BEFORE any
|
|
266
|
+
// preflight call so the first outbound request already goes through it.
|
|
267
|
+
applyProxyFromConfig(config);
|
|
242
268
|
// Prepare relay sandbox assets once at startup.
|
|
243
269
|
ensureEmptyMcpConfig();
|
|
244
270
|
ensureSandboxDir();
|
package/dist/relay/types.d.ts
CHANGED
|
@@ -87,4 +87,14 @@ export interface RelayProviderConfig {
|
|
|
87
87
|
agent_id?: string;
|
|
88
88
|
agent_slug?: string;
|
|
89
89
|
relay: RelayProviderSettings;
|
|
90
|
+
/**
|
|
91
|
+
* Upstream HTTPS proxy. When set, the daemon exports HTTPS_PROXY /
|
|
92
|
+
* HTTP_PROXY before running any fetch, so providers on GFW-side machines
|
|
93
|
+
* don't have to remember to `export https_proxy=` in every shell. Only
|
|
94
|
+
* plain HTTP(S) proxies are supported (SOCKS is ignored with a warning).
|
|
95
|
+
*
|
|
96
|
+
* Example:
|
|
97
|
+
* proxy: http://127.0.0.1:7897
|
|
98
|
+
*/
|
|
99
|
+
proxy?: string;
|
|
90
100
|
}
|
|
@@ -79,7 +79,11 @@ const ANTIGRAVITY_LOAD_ENDPOINTS = [
|
|
|
79
79
|
ANTIGRAVITY_ENDPOINT_PROD,
|
|
80
80
|
ANTIGRAVITY_ENDPOINT_DAILY,
|
|
81
81
|
];
|
|
82
|
-
|
|
82
|
+
// Antigravity upstream only supports streamGenerateContent — the non-stream
|
|
83
|
+
// variant returns a generic 500 "Unknown Error" for every model we tested.
|
|
84
|
+
// Documented in sub2api/backend/internal/service/antigravity_gateway_service.go:1409
|
|
85
|
+
// ("Antigravity 上游只支持流式请求"). We parse the ?alt=sse response inline.
|
|
86
|
+
const GENERATE_PATH = "/v1internal:streamGenerateContent?alt=sse";
|
|
83
87
|
/**
|
|
84
88
|
* Map our `antigravity-*` market-facing model IDs to the real model names
|
|
85
89
|
* Google's v1internal endpoint accepts. The `antigravity-` prefix only
|
|
@@ -90,8 +94,11 @@ const GENERATE_PATH = "/v1internal:generateContent";
|
|
|
90
94
|
* names.
|
|
91
95
|
*/
|
|
92
96
|
const ANTIGRAVITY_MODEL_MAP = {
|
|
93
|
-
|
|
94
|
-
"
|
|
97
|
+
// Gemini 3 Pro was retired in April 2026 — Google now returns a plain-text
|
|
98
|
+
// "no longer available, switch to Gemini 3.1 Pro" body if you ask for it.
|
|
99
|
+
// Route both the 3-pro and 3.1-pro market IDs to 3.1-pro-high.
|
|
100
|
+
"antigravity-gemini-3-pro": "gemini-3.1-pro-high",
|
|
101
|
+
"antigravity-gemini-3.1-pro": "gemini-3.1-pro-high",
|
|
95
102
|
"antigravity-gemini-3-flash": "gemini-3-flash",
|
|
96
103
|
"antigravity-gemini-2.5-pro": "gemini-2.5-pro",
|
|
97
104
|
"antigravity-gemini-2.5-flash": "gemini-2.5-flash",
|
|
@@ -589,8 +596,7 @@ async function doCallAntigravityApi(opts) {
|
|
|
589
596
|
throw err;
|
|
590
597
|
}
|
|
591
598
|
if (resp.ok) {
|
|
592
|
-
const
|
|
593
|
-
const parsed = parseAntigravityResponse(data, opts.model);
|
|
599
|
+
const parsed = await parseAntigravitySseResponse(resp, opts.model);
|
|
594
600
|
recordAntigravitySpend(parsed, opts.model);
|
|
595
601
|
return parsed;
|
|
596
602
|
}
|
|
@@ -640,23 +646,89 @@ function recordAntigravitySpend(parsed, model) {
|
|
|
640
646
|
const cost = calculateCost(model, input_tokens, output_tokens, cache_creation_tokens, cache_read_tokens);
|
|
641
647
|
rateGuard.recordSpend(cost.apiCost);
|
|
642
648
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
649
|
+
/**
|
|
650
|
+
* Parse Antigravity's streamGenerateContent?alt=sse response. Google sends
|
|
651
|
+
* Server-Sent Events where each line is `data: {json}`; the JSON shape
|
|
652
|
+
* matches a single `V1InternalGenerateResponse` chunk. Text parts accumulate
|
|
653
|
+
* across chunks, and usageMetadata is usually on the last chunk.
|
|
654
|
+
*
|
|
655
|
+
* Note: unlike vanilla Gemini API, Antigravity wraps each chunk's body in a
|
|
656
|
+
* top-level `response` field (mirroring the non-stream shape), so we unwrap.
|
|
657
|
+
*/
|
|
658
|
+
async function parseAntigravitySseResponse(resp, fallbackModel) {
|
|
659
|
+
const reader = resp.body?.getReader();
|
|
660
|
+
if (!reader) {
|
|
661
|
+
throw new Error("Antigravity streamGenerateContent returned no body");
|
|
662
|
+
}
|
|
663
|
+
const decoder = new TextDecoder("utf-8");
|
|
664
|
+
let buffer = "";
|
|
665
|
+
let text = "";
|
|
666
|
+
let inputTokens = 0;
|
|
667
|
+
let outputTokens = 0;
|
|
668
|
+
let cachedTokens = 0;
|
|
669
|
+
const processChunk = (jsonStr) => {
|
|
670
|
+
const trimmed = jsonStr.trim();
|
|
671
|
+
if (!trimmed || trimmed === "[DONE]")
|
|
672
|
+
return;
|
|
673
|
+
let chunk;
|
|
674
|
+
try {
|
|
675
|
+
chunk = JSON.parse(trimmed);
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
// Antigravity SSE sometimes emits chunks with fields at the top level
|
|
681
|
+
// (without the `response` wrapper). Handle both shapes.
|
|
682
|
+
const body = chunk.response ??
|
|
683
|
+
chunk;
|
|
684
|
+
const candidates = body?.candidates ?? [];
|
|
685
|
+
for (const cand of candidates) {
|
|
686
|
+
for (const part of cand.content?.parts ?? []) {
|
|
687
|
+
if (part.text)
|
|
688
|
+
text += part.text;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const usage = body?.usageMetadata;
|
|
692
|
+
if (usage) {
|
|
693
|
+
if (typeof usage.promptTokenCount === "number") {
|
|
694
|
+
inputTokens = usage.promptTokenCount;
|
|
695
|
+
}
|
|
696
|
+
if (typeof usage.candidatesTokenCount === "number") {
|
|
697
|
+
outputTokens = usage.candidatesTokenCount;
|
|
698
|
+
}
|
|
699
|
+
if (typeof usage.cachedContentTokenCount === "number") {
|
|
700
|
+
cachedTokens = usage.cachedContentTokenCount;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
while (true) {
|
|
705
|
+
const { value, done } = await reader.read();
|
|
706
|
+
if (done)
|
|
707
|
+
break;
|
|
708
|
+
buffer += decoder.decode(value, { stream: true });
|
|
709
|
+
let newlineIdx;
|
|
710
|
+
while ((newlineIdx = buffer.indexOf("\n")) >= 0) {
|
|
711
|
+
const line = buffer.slice(0, newlineIdx).replace(/\r$/, "");
|
|
712
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
713
|
+
if (!line)
|
|
714
|
+
continue;
|
|
715
|
+
if (line.startsWith("data:")) {
|
|
716
|
+
processChunk(line.slice(5));
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
// Flush tail (unlikely but safe)
|
|
721
|
+
if (buffer.startsWith("data:")) {
|
|
722
|
+
processChunk(buffer.slice(5));
|
|
723
|
+
}
|
|
652
724
|
return {
|
|
653
725
|
text,
|
|
654
726
|
sessionId: "",
|
|
655
727
|
usage: {
|
|
656
|
-
input_tokens: Math.max(0,
|
|
657
|
-
output_tokens:
|
|
728
|
+
input_tokens: Math.max(0, inputTokens - cachedTokens),
|
|
729
|
+
output_tokens: outputTokens,
|
|
658
730
|
cache_creation_tokens: 0,
|
|
659
|
-
cache_read_tokens:
|
|
731
|
+
cache_read_tokens: cachedTokens,
|
|
660
732
|
},
|
|
661
733
|
model: fallbackModel,
|
|
662
734
|
costUsd: 0,
|