@jini-ai/agent-runtime 0.3.10 → 0.4.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/CHANGELOG.md +103 -0
- package/README.md +34 -17
- package/dist/acp-model-probe.d.ts +6 -4
- package/dist/acp-model-probe.js +3 -3
- package/dist/agent-protocol/acp/account-failure.d.ts +4 -2
- package/dist/agent-protocol/acp/account-failure.js +1 -1
- package/dist/agent-protocol/acp/json.d.ts +6 -6
- package/dist/agent-protocol/acp/json.js +3 -3
- package/dist/agent-protocol/acp/models.d.ts +10 -5
- package/dist/agent-protocol/acp/models.js +32 -31
- package/dist/agent-protocol/acp/session-params.d.ts +3 -1
- package/dist/agent-protocol/acp/session-params.js +2 -1
- package/dist/agent-protocol/acp/session.d.ts +28 -22
- package/dist/agent-protocol/acp/session.js +181 -147
- package/dist/agent-protocol/acp/text-suppression.d.ts +1 -1
- package/dist/agent-protocol/acp/text-suppression.js +1 -1
- package/dist/agent-protocol/acp/types.d.ts +3 -2
- package/dist/agent-protocol/acp/updates.d.ts +11 -11
- package/dist/agent-protocol/acp/updates.js +2 -2
- package/dist/agent-protocol/core/json-line-stream.d.ts +24 -8
- package/dist/agent-protocol/core/json-line-stream.js +8 -8
- package/dist/agent-protocol/pi-rpc/events.d.ts +5 -1
- package/dist/agent-protocol/pi-rpc/events.js +36 -36
- package/dist/agent-protocol/pi-rpc/internal.d.ts +4 -1
- package/dist/agent-protocol/pi-rpc/models.d.ts +3 -1
- package/dist/agent-protocol/pi-rpc/models.js +1 -1
- package/dist/agent-protocol/pi-rpc/session.d.ts +1 -1
- package/dist/agent-protocol/pi-rpc/session.js +33 -32
- package/dist/amr-model-cache.d.ts +12 -4
- package/dist/amr-model-cache.js +17 -21
- package/dist/amr-profile-resolver.d.ts +3 -1
- package/dist/anthropic-live-models.js +0 -0
- package/dist/artifact-taxonomy.d.ts +6 -2
- package/dist/auth.d.ts +52 -15
- package/dist/auth.js +36 -36
- package/dist/claude-code-models.js +2 -2
- package/dist/claude-stream.d.ts +22 -3
- package/dist/claude-stream.js +24 -8
- package/dist/copilot-stream.d.ts +7 -3
- package/dist/copilot-stream.js +3 -3
- package/dist/defs/aider.d.ts +8 -1
- package/dist/defs/aider.js +2 -2
- package/dist/defs/amp.d.ts +8 -1
- package/dist/defs/amp.js +2 -2
- package/dist/defs/amr.d.ts +22 -6
- package/dist/defs/amr.js +23 -23
- package/dist/defs/antigravity.d.ts +15 -4
- package/dist/defs/antigravity.js +9 -8
- package/dist/defs/auggie.d.ts +4 -1
- package/dist/defs/auggie.js +1 -1
- package/dist/defs/claude.d.ts +12 -2
- package/dist/defs/claude.js +5 -5
- package/dist/defs/cline.d.ts +4 -1
- package/dist/defs/cline.js +1 -1
- package/dist/defs/codebuddy.d.ts +8 -1
- package/dist/defs/codebuddy.js +2 -2
- package/dist/defs/codex.d.ts +18 -4
- package/dist/defs/codex.js +7 -7
- package/dist/defs/copilot.d.ts +8 -1
- package/dist/defs/copilot.js +2 -2
- package/dist/defs/crush.d.ts +8 -1
- package/dist/defs/crush.js +1 -1
- package/dist/defs/cursor-agent.d.ts +14 -3
- package/dist/defs/cursor-agent.js +5 -5
- package/dist/defs/deepseek.d.ts +8 -1
- package/dist/defs/deepseek.js +2 -2
- package/dist/defs/devin.d.ts +12 -2
- package/dist/defs/devin.js +3 -3
- package/dist/defs/droid.d.ts +8 -1
- package/dist/defs/droid.js +1 -1
- package/dist/defs/gemini.d.ts +8 -1
- package/dist/defs/gemini.js +1 -1
- package/dist/defs/goose.d.ts +4 -1
- package/dist/defs/goose.js +1 -1
- package/dist/defs/grok-build.d.ts +11 -2
- package/dist/defs/grok-build.js +3 -3
- package/dist/defs/hermes.d.ts +4 -1
- package/dist/defs/hermes.js +2 -2
- package/dist/defs/kilo.d.ts +4 -1
- package/dist/defs/kilo.js +2 -2
- package/dist/defs/kimi.d.ts +4 -1
- package/dist/defs/kimi.js +2 -2
- package/dist/defs/kiro.d.ts +4 -1
- package/dist/defs/kiro.js +2 -2
- package/dist/defs/mimo.d.ts +8 -1
- package/dist/defs/mimo.js +2 -2
- package/dist/defs/opencode.d.ts +9 -2
- package/dist/defs/opencode.js +2 -2
- package/dist/defs/pi.d.ts +12 -2
- package/dist/defs/pi.js +9 -9
- package/dist/defs/qoder.d.ts +8 -1
- package/dist/defs/qoder.js +2 -2
- package/dist/defs/qwen.d.ts +8 -1
- package/dist/defs/qwen.js +2 -2
- package/dist/defs/reasonix.d.ts +4 -1
- package/dist/defs/reasonix.js +3 -3
- package/dist/defs/shared.d.ts +4 -2
- package/dist/defs/shared.js +2 -2
- package/dist/defs/trae-cli.d.ts +12 -2
- package/dist/defs/trae-cli.js +3 -3
- package/dist/defs/vibe.d.ts +4 -1
- package/dist/defs/vibe.js +2 -2
- package/dist/detection.d.ts +19 -4
- package/dist/detection.js +33 -33
- package/dist/diagnostics.d.ts +14 -3
- package/dist/diagnostics.js +5 -5
- package/dist/env.d.ts +16 -4
- package/dist/env.js +7 -7
- package/dist/executables.d.ts +24 -8
- package/dist/executables.js +13 -13
- package/dist/index.d.ts +228 -4
- package/dist/index.js +230 -6
- package/dist/invocation.d.ts +6 -1
- package/dist/invocation.js +2 -2
- package/dist/json-event-stream.d.ts +7 -2
- package/dist/json-event-stream.js +3 -3
- package/dist/launch.d.ts +12 -2
- package/dist/launch.js +3 -3
- package/dist/log-file.d.ts +4 -1
- package/dist/log-file.js +2 -2
- package/dist/mcp.d.ts +6 -3
- package/dist/mcp.js +1 -1
- package/dist/metadata.d.ts +7 -3
- package/dist/metadata.js +1 -1
- package/dist/mmd-routes.d.ts +22 -6
- package/dist/mmd-routes.js +14 -14
- package/dist/model-catalog-cache.d.ts +50 -0
- package/dist/model-catalog-cache.js +61 -0
- package/dist/model-loading-state.d.ts +10 -0
- package/dist/model-loading-state.js +23 -0
- package/dist/model-registry.d.ts +28 -7
- package/dist/model-registry.js +11 -8
- package/dist/models.d.ts +31 -6
- package/dist/models.js +6 -6
- package/dist/opencode-log.d.ts +12 -4
- package/dist/opencode-log.js +8 -8
- package/dist/paths.d.ts +6 -2
- package/dist/paths.js +3 -3
- package/dist/pi-models.d.ts +3 -1
- package/dist/pi-models.js +2 -2
- package/dist/prompt-budget.d.ts +17 -4
- package/dist/prompt-budget.js +3 -3
- package/dist/prompt-file.d.ts +5 -1
- package/dist/prompt-file.js +1 -1
- package/dist/providers/aihubmix.d.ts +34 -9
- package/dist/providers/aihubmix.js +26 -26
- package/dist/providers/anthropic-messages.d.ts +77 -20
- package/dist/providers/anthropic-messages.js +53 -50
- package/dist/providers/azure-chat.d.ts +21 -7
- package/dist/providers/azure-chat.js +18 -16
- package/dist/providers/connection-guard.d.ts +45 -31
- package/dist/providers/connection-guard.js +40 -143
- package/dist/providers/connection-test.d.ts +1 -1
- package/dist/providers/connection-test.js +13 -30
- package/dist/providers/elevenlabs.d.ts +7 -2
- package/dist/providers/elevenlabs.js +4 -4
- package/dist/providers/google-messages.d.ts +44 -10
- package/dist/providers/google-messages.js +36 -34
- package/dist/providers/google-schema.d.ts +26 -0
- package/dist/providers/google-schema.js +253 -0
- package/dist/providers/google.d.ts +21 -6
- package/dist/providers/google.js +10 -10
- package/dist/providers/index.d.ts +3 -2
- package/dist/providers/index.js +3 -2
- package/dist/providers/model-catalog.d.ts +1 -1
- package/dist/providers/model-catalog.js +14 -27
- package/dist/providers/oauth-callback-server.d.ts +1 -1
- package/dist/providers/oauth-callback-server.js +3 -2
- package/dist/providers/oauth-credentials.d.ts +7 -1
- package/dist/providers/oauth-credentials.js +5 -5
- package/dist/providers/oauth-provider.d.ts +2 -2
- package/dist/providers/oauth-provider.js +20 -25
- package/dist/providers/oauth-tokens.d.ts +26 -6
- package/dist/providers/oauth-tokens.js +9 -9
- package/dist/providers/ollama-chat.d.ts +66 -31
- package/dist/providers/ollama-chat.js +64 -61
- package/dist/providers/openai-chat.d.ts +77 -22
- package/dist/providers/openai-chat.js +71 -67
- package/dist/providers/pkce.d.ts +33 -20
- package/dist/providers/pkce.js +75 -146
- package/dist/providers/sse-decode.d.ts +3 -1
- package/dist/providers/sse-decode.js +1 -1
- package/dist/providers/token-params.d.ts +16 -5
- package/dist/providers/token-params.js +6 -6
- package/dist/providers/tool-turn-types.d.ts +89 -0
- package/dist/providers/tool-turn-types.js +2 -0
- package/dist/providers/tool-turn.d.ts +10 -0
- package/dist/providers/tool-turn.js +252 -0
- package/dist/qoder-stream.d.ts +7 -3
- package/dist/qoder-stream.js +3 -3
- package/dist/registry.d.ts +6 -2
- package/dist/registry.js +4 -4
- package/dist/resolution.d.ts +5 -1
- package/dist/resolution.js +3 -3
- package/dist/role-marker-guard.d.ts +9 -5
- package/dist/role-marker-guard.js +5 -5
- package/dist/terminal-launch.d.ts +6 -1
- package/dist/terminal-launch.js +2 -2
- package/dist/types.d.ts +22 -6
- package/package.json +43 -4
package/dist/auth.js
CHANGED
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
* `antigravityQuotaGuidance`, `reasonixAuthGuidance`, `claudeAuthGuidance`)
|
|
12
12
|
* and `genericAuthGuidance` took an implicit product name baked into nine
|
|
13
13
|
* literal strings (e.g. "expose CURSOR_API_KEY in the <product>'s process
|
|
14
|
-
* environment" — see `
|
|
14
|
+
* environment" — see `archived provenance ledger` for the exact original text). Each
|
|
15
15
|
* now takes an optional `hostName`
|
|
16
16
|
* parameter (default `'the host application'`) so the guidance text is
|
|
17
17
|
* product-neutral by default and a consumer can substitute its own name.
|
|
18
18
|
* `classifyAgentAuthFailure`/`probeAgentAuthStatus` thread `hostName`
|
|
19
|
-
* through to whichever guidance function they call. See `
|
|
19
|
+
* through to whichever guidance function they call. See `archived provenance ledger`.
|
|
20
20
|
*/
|
|
21
21
|
import { execAgentFile } from './invocation.js';
|
|
22
22
|
const DEFAULT_HOST_NAME = 'the host application';
|
|
@@ -66,28 +66,28 @@ function claudeAuthGuidanceText(hostName) {
|
|
|
66
66
|
function geminiAuthGuidanceText(hostName) {
|
|
67
67
|
return `Gemini CLI is installed but has no usable sign-in. Google no longer serves Gemini CLI's "Login with Google" for free, Google AI Pro or Ultra accounts. Use a Gemini API key instead: run \`gemini\` in a terminal, type /auth, choose "Use Gemini API key", and make GEMINI_API_KEY available to ${hostName}'s process environment (or configure Vertex AI). Google's replacement for individual accounts is Antigravity (\`agy\`), which you can pick here instead.`;
|
|
68
68
|
}
|
|
69
|
-
export function cursorAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
69
|
+
export function cursorAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
70
70
|
return cursorAuthGuidanceText(hostName);
|
|
71
71
|
}
|
|
72
|
-
export function deepseekAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
72
|
+
export function deepseekAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
73
73
|
return deepseekAuthGuidanceText(hostName);
|
|
74
74
|
}
|
|
75
|
-
export function antigravityAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
75
|
+
export function antigravityAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
76
76
|
return antigravityAuthGuidanceText(hostName);
|
|
77
77
|
}
|
|
78
78
|
export function antigravityQuotaGuidance() {
|
|
79
79
|
return antigravityQuotaGuidanceText();
|
|
80
80
|
}
|
|
81
|
-
export function reasonixAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
81
|
+
export function reasonixAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
82
82
|
return reasonixAuthGuidanceText(hostName);
|
|
83
83
|
}
|
|
84
|
-
export function claudeAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
84
|
+
export function claudeAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
85
85
|
return claudeAuthGuidanceText(hostName);
|
|
86
86
|
}
|
|
87
|
-
export function geminiAuthGuidance(hostName = DEFAULT_HOST_NAME) {
|
|
87
|
+
export function geminiAuthGuidance({}, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
88
88
|
return geminiAuthGuidanceText(hostName);
|
|
89
89
|
}
|
|
90
|
-
export function isCursorAuthFailureText(text) {
|
|
90
|
+
export function isCursorAuthFailureText({ text }) {
|
|
91
91
|
const value = String(text || '');
|
|
92
92
|
if (!value.trim())
|
|
93
93
|
return false;
|
|
@@ -107,7 +107,7 @@ export function isCursorAuthFailureText(text) {
|
|
|
107
107
|
// "error getting token source: You are not logged into Antigravity"
|
|
108
108
|
// Any of these is sufficient signal — match conservatively so the regex
|
|
109
109
|
// doesn't fire on prose containing the word "authentication" by accident.
|
|
110
|
-
export function isAntigravityAuthFailureText(text) {
|
|
110
|
+
export function isAntigravityAuthFailureText({ text }) {
|
|
111
111
|
const value = String(text || '');
|
|
112
112
|
if (!value.trim())
|
|
113
113
|
return false;
|
|
@@ -116,7 +116,7 @@ export function isAntigravityAuthFailureText(text) {
|
|
|
116
116
|
/not logged into antigravity/i.test(value) ||
|
|
117
117
|
/accounts\.google\.com\/o\/oauth2\/auth.*antigravity/i.test(value));
|
|
118
118
|
}
|
|
119
|
-
export function isDeepSeekAuthFailureText(text) {
|
|
119
|
+
export function isDeepSeekAuthFailureText({ text }) {
|
|
120
120
|
const value = String(text || '');
|
|
121
121
|
if (!value.trim())
|
|
122
122
|
return false;
|
|
@@ -126,7 +126,7 @@ export function isDeepSeekAuthFailureText(text) {
|
|
|
126
126
|
(/DEEPSEEK_API_KEY/i.test(value) &&
|
|
127
127
|
/auth|api[_ -]?key|missing|not set|required|unauthorized/i.test(value)));
|
|
128
128
|
}
|
|
129
|
-
export function isReasonixAuthFailureText(text) {
|
|
129
|
+
export function isReasonixAuthFailureText({ text }) {
|
|
130
130
|
const value = String(text || '');
|
|
131
131
|
if (!value.trim())
|
|
132
132
|
return false;
|
|
@@ -135,7 +135,7 @@ export function isReasonixAuthFailureText(text) {
|
|
|
135
135
|
(/DEEPSEEK_API_KEY/i.test(value) &&
|
|
136
136
|
/auth|missing|not set|required|unauthorized|invalid/i.test(value)));
|
|
137
137
|
}
|
|
138
|
-
export function isClaudeAuthFailureText(text) {
|
|
138
|
+
export function isClaudeAuthFailureText({ text }) {
|
|
139
139
|
const value = String(text || '');
|
|
140
140
|
if (!value.trim())
|
|
141
141
|
return false;
|
|
@@ -159,7 +159,7 @@ export function isClaudeAuthFailureText(text) {
|
|
|
159
159
|
/authentication required/i.test(value) ||
|
|
160
160
|
/please (?:sign|log)[ _-]?in/i.test(value));
|
|
161
161
|
}
|
|
162
|
-
export function isGeminiAuthFailureText(text) {
|
|
162
|
+
export function isGeminiAuthFailureText({ text }) {
|
|
163
163
|
const value = String(text || '');
|
|
164
164
|
if (!value.trim())
|
|
165
165
|
return false;
|
|
@@ -169,36 +169,36 @@ export function isGeminiAuthFailureText(text) {
|
|
|
169
169
|
/error authenticating/i.test(value) ||
|
|
170
170
|
/api key not valid/i.test(value));
|
|
171
171
|
}
|
|
172
|
-
export function classifyAgentAuthFailure(agentId, text, hostName = DEFAULT_HOST_NAME) {
|
|
172
|
+
export function classifyAgentAuthFailure({ agentId, text }, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
173
173
|
if (agentId === 'claude') {
|
|
174
|
-
if (!isClaudeAuthFailureText(text))
|
|
174
|
+
if (!isClaudeAuthFailureText({ text: text }))
|
|
175
175
|
return null;
|
|
176
|
-
return { status: 'missing', message: claudeAuthGuidance(hostName) };
|
|
176
|
+
return { status: 'missing', message: claudeAuthGuidance({}, { hostName: hostName }) };
|
|
177
177
|
}
|
|
178
178
|
if (agentId === 'cursor-agent') {
|
|
179
|
-
if (!isCursorAuthFailureText(text))
|
|
179
|
+
if (!isCursorAuthFailureText({ text: text }))
|
|
180
180
|
return null;
|
|
181
|
-
return { status: 'missing', message: cursorAuthGuidance(hostName) };
|
|
181
|
+
return { status: 'missing', message: cursorAuthGuidance({}, { hostName: hostName }) };
|
|
182
182
|
}
|
|
183
183
|
if (agentId === 'deepseek') {
|
|
184
|
-
if (!isDeepSeekAuthFailureText(text))
|
|
184
|
+
if (!isDeepSeekAuthFailureText({ text: text }))
|
|
185
185
|
return null;
|
|
186
|
-
return { status: 'missing', message: deepseekAuthGuidance(hostName) };
|
|
186
|
+
return { status: 'missing', message: deepseekAuthGuidance({}, { hostName: hostName }) };
|
|
187
187
|
}
|
|
188
188
|
if (agentId === 'antigravity') {
|
|
189
|
-
if (!isAntigravityAuthFailureText(text))
|
|
189
|
+
if (!isAntigravityAuthFailureText({ text: text }))
|
|
190
190
|
return null;
|
|
191
|
-
return { status: 'missing', message: antigravityAuthGuidance(hostName) };
|
|
191
|
+
return { status: 'missing', message: antigravityAuthGuidance({}, { hostName: hostName }) };
|
|
192
192
|
}
|
|
193
193
|
if (agentId === 'reasonix') {
|
|
194
|
-
if (!isReasonixAuthFailureText(text))
|
|
194
|
+
if (!isReasonixAuthFailureText({ text: text }))
|
|
195
195
|
return null;
|
|
196
|
-
return { status: 'missing', message: reasonixAuthGuidance(hostName) };
|
|
196
|
+
return { status: 'missing', message: reasonixAuthGuidance({}, { hostName: hostName }) };
|
|
197
197
|
}
|
|
198
198
|
if (agentId === 'gemini') {
|
|
199
|
-
if (!isGeminiAuthFailureText(text))
|
|
199
|
+
if (!isGeminiAuthFailureText({ text: text }))
|
|
200
200
|
return null;
|
|
201
|
-
return { status: 'missing', message: geminiAuthGuidance(hostName) };
|
|
201
|
+
return { status: 'missing', message: geminiAuthGuidance({}, { hostName: hostName }) };
|
|
202
202
|
}
|
|
203
203
|
return null;
|
|
204
204
|
}
|
|
@@ -228,7 +228,7 @@ const AGENT_UPSTREAM_FAILURE_RE = new RegExp(`(\\b(overloaded(?:_error)?|service
|
|
|
228
228
|
// process failure. Auth is checked before rate/upstream so a `401` is never
|
|
229
229
|
// misread as a `5xx`. Pure text match — no agent-specific assumptions — so it
|
|
230
230
|
// applies uniformly to any CLI agent.
|
|
231
|
-
export function classifyAgentServiceFailure(text) {
|
|
231
|
+
export function classifyAgentServiceFailure({ text }) {
|
|
232
232
|
const value = String(text || '');
|
|
233
233
|
if (!value.trim())
|
|
234
234
|
return null;
|
|
@@ -303,9 +303,9 @@ function hasProbeSatisfyingApiKey(def, env) {
|
|
|
303
303
|
// regexes.
|
|
304
304
|
function classifyProbedAuthFailure(def, text, hostName) {
|
|
305
305
|
if (TAILORED_AUTH_AGENTS.has(def.id)) {
|
|
306
|
-
return classifyAgentAuthFailure(def.id, text, hostName);
|
|
306
|
+
return classifyAgentAuthFailure({ agentId: def.id, text: text }, { hostName: hostName });
|
|
307
307
|
}
|
|
308
|
-
if (classifyAgentServiceFailure(text) === 'AGENT_AUTH_REQUIRED') {
|
|
308
|
+
if (classifyAgentServiceFailure({ text: text }) === 'AGENT_AUTH_REQUIRED') {
|
|
309
309
|
return { status: 'missing', message: genericAuthGuidance(def.name || def.id, hostName) };
|
|
310
310
|
}
|
|
311
311
|
return null;
|
|
@@ -314,18 +314,18 @@ function classifyProbedAuthFailure(def, text, hostName) {
|
|
|
314
314
|
// status/whoami command) and classify the result. Returns null when the
|
|
315
315
|
// adapter declares no `authProbe` — those agents are never actively probed;
|
|
316
316
|
// their auth status is inferred only from a real chat failure's error text.
|
|
317
|
-
export async function probeAgentAuthStatus(def, resolvedBin, env, hostName = DEFAULT_HOST_NAME) {
|
|
317
|
+
export async function probeAgentAuthStatus({ def, resolvedBin, env }, { hostName = DEFAULT_HOST_NAME } = {}) {
|
|
318
318
|
const probe = def.authProbe;
|
|
319
319
|
if (!probe)
|
|
320
320
|
return null;
|
|
321
321
|
if (hasProbeSatisfyingApiKey(def, env))
|
|
322
322
|
return { status: 'ok' };
|
|
323
323
|
try {
|
|
324
|
-
const { stdout, stderr } = await execAgentFile(resolvedBin, probe.args, {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
const { stdout, stderr } = await execAgentFile({ command: resolvedBin, args: probe.args }, { options: {
|
|
325
|
+
env: env,
|
|
326
|
+
timeout: probe.timeoutMs ?? 5000,
|
|
327
|
+
maxBuffer: 1024 * 1024,
|
|
328
|
+
} });
|
|
329
329
|
const stdoutText = typeof stdout === 'string' ? stdout : '';
|
|
330
330
|
const stderrText = typeof stderr === 'string' ? stderr : '';
|
|
331
331
|
const output = `${stdoutText}\n${stderrText}`;
|
|
@@ -126,7 +126,7 @@ function initializeEntryRows(entry) {
|
|
|
126
126
|
if (typeof raw !== 'string')
|
|
127
127
|
continue;
|
|
128
128
|
const id = normalizeClaudePickerModelId(raw);
|
|
129
|
-
if (id === 'default' || sanitizeCustomModel(id) !== id)
|
|
129
|
+
if (id === 'default' || sanitizeCustomModel({ id: id }) !== id)
|
|
130
130
|
continue;
|
|
131
131
|
const isAlias = !id.startsWith('claude-');
|
|
132
132
|
rows.push({ id, label: isAlias && displayName ? `${displayName} (alias)` : id });
|
|
@@ -221,7 +221,7 @@ async function discoverClaudeCodeModels(bin, env) {
|
|
|
221
221
|
if (!cached?.ok)
|
|
222
222
|
return null;
|
|
223
223
|
return cached.ids
|
|
224
|
-
.filter((id) => sanitizeCustomModel(id) === id)
|
|
224
|
+
.filter((id) => sanitizeCustomModel({ id: id }) === id)
|
|
225
225
|
.map((id) => ({ id, label: id }));
|
|
226
226
|
}
|
|
227
227
|
catch {
|
package/dist/claude-stream.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Ported verbatim from OD's `apps/daemon/src/runtimes/claude-stream.ts`
|
|
5
5
|
* (only the `role-marker-guard` import path changed — it now resolves
|
|
6
|
-
* within this package instead of two directories up). See `
|
|
6
|
+
* within this package instead of two directories up). See `archived provenance ledger`.
|
|
7
7
|
*
|
|
8
8
|
* Parses Claude Code's `--output-format stream-json --verbose` JSONL stream
|
|
9
9
|
* (with or without `--include-partial-messages`) into a small set of
|
|
@@ -57,6 +57,8 @@ export type ClaudeStreamEvent = {
|
|
|
57
57
|
model?: unknown;
|
|
58
58
|
sessionId?: unknown;
|
|
59
59
|
ttftMs?: number;
|
|
60
|
+
/** Init frames only: each MCP server's connection state as the CLI reported it (see {@link initMcpServers}). */
|
|
61
|
+
mcpServers?: McpServerStatus[];
|
|
60
62
|
} | {
|
|
61
63
|
type: 'text_delta' | 'thinking_delta';
|
|
62
64
|
delta: string;
|
|
@@ -139,6 +141,19 @@ export declare function isUnstreamedTextBlock(block: Record<string, unknown>, al
|
|
|
139
141
|
export declare function isUnstreamedThinkingBlock(block: Record<string, unknown>, alreadyStreamed: boolean): block is Record<string, unknown> & {
|
|
140
142
|
thinking: string;
|
|
141
143
|
};
|
|
144
|
+
/** One MCP server's state from an init frame's `mcp_servers`, e.g. `{ name: 'jini', status: 'failed' }`. */
|
|
145
|
+
export interface McpServerStatus {
|
|
146
|
+
readonly name: string;
|
|
147
|
+
readonly status: string;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The init frame's `mcp_servers`, reduced to `{name, status}`, or `undefined` when the frame has no
|
|
151
|
+
* such list. Kept on the event so a host can tell "its bridge did not connect" from "no bridge was
|
|
152
|
+
* configured": Claude Code times a dead MCP server out, reports it `failed` here, and carries on
|
|
153
|
+
* without its tools (the 2026-10-01 desktop incident). Entries without a string name and status are
|
|
154
|
+
* dropped rather than guessed at.
|
|
155
|
+
*/
|
|
156
|
+
export declare function initMcpServers(obj: Record<string, unknown>): McpServerStatus[] | undefined;
|
|
142
157
|
export declare function handleSystemMessage(obj: Record<string, unknown>, onEvent: EventSink): void;
|
|
143
158
|
export declare function stringifyToolResult(content: unknown): string;
|
|
144
159
|
export declare function handleUserMessage(obj: Record<string, unknown>, onEvent: EventSink): void;
|
|
@@ -147,8 +162,12 @@ export declare function emitAssistantErrorIfPresent(obj: Record<string, unknown>
|
|
|
147
162
|
interface ClaudeStreamHandlerOptions {
|
|
148
163
|
suppressHtmlArtifactsAfterFileWrite?: boolean;
|
|
149
164
|
}
|
|
150
|
-
export declare function createClaudeStreamHandler(onEvent
|
|
151
|
-
|
|
165
|
+
export declare function createClaudeStreamHandler({ onEvent }: {
|
|
166
|
+
onEvent: EventSink;
|
|
167
|
+
}, options?: ClaudeStreamHandlerOptions): {
|
|
168
|
+
feed: ({ chunk }: {
|
|
169
|
+
chunk: string;
|
|
170
|
+
}) => void;
|
|
152
171
|
flush: () => void;
|
|
153
172
|
};
|
|
154
173
|
export {};
|
package/dist/claude-stream.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Ported verbatim from OD's `apps/daemon/src/runtimes/claude-stream.ts`
|
|
5
5
|
* (only the `role-marker-guard` import path changed — it now resolves
|
|
6
|
-
* within this package instead of two directories up). See `
|
|
6
|
+
* within this package instead of two directories up). See `archived provenance ledger`.
|
|
7
7
|
*
|
|
8
8
|
* Parses Claude Code's `--output-format stream-json --verbose` JSONL stream
|
|
9
9
|
* (with or without `--include-partial-messages`) into a small set of
|
|
@@ -86,7 +86,7 @@ function nextGeneratedRuntimeTaskId(counter) {
|
|
|
86
86
|
// increases, it can never equal an id already present in the map at
|
|
87
87
|
// this point. Removed per the coverage skill's Phase 6.5 "dead
|
|
88
88
|
// branch" classification rather than fake a test for an unreachable
|
|
89
|
-
// loop; see
|
|
89
|
+
// loop; see archived provenance ledger.
|
|
90
90
|
const id = String(counter.next);
|
|
91
91
|
counter.next += 1;
|
|
92
92
|
return id;
|
|
@@ -161,7 +161,7 @@ export function emitCanonicalTaskSnapshot(toolUseId, name, input, registry, onEv
|
|
|
161
161
|
// reaching here (so the "changed" flag those returns guarded was
|
|
162
162
|
// always true here). Removed the dead double-guard per the coverage
|
|
163
163
|
// skill's Phase 6.5 "dead branch" classification rather than fake a
|
|
164
|
-
// test for an unreachable condition; see
|
|
164
|
+
// test for an unreachable condition; see archived provenance ledger.
|
|
165
165
|
registry.seenToolUseIds.add(toolUseId);
|
|
166
166
|
onEvent({
|
|
167
167
|
type: 'tool_use',
|
|
@@ -197,7 +197,7 @@ export function isFileWriteToolUse(name, input) {
|
|
|
197
197
|
// already made. Removed the runtime early-return per the coverage
|
|
198
198
|
// skill's Phase 6.5 "dead branch" classification rather than fake a
|
|
199
199
|
// test with a non-record `input` neither function can ever actually
|
|
200
|
-
// receive (see
|
|
200
|
+
// receive (see archived provenance ledger), replaced by a one-line type assertion
|
|
201
201
|
// (classification 4: TS-required, no real runtime path) so the
|
|
202
202
|
// parameter can stay `unknown` without disturbing the call sites.
|
|
203
203
|
export function fileWriteContent(input) {
|
|
@@ -260,13 +260,29 @@ export function isUnstreamedTextBlock(block, alreadyStreamed) {
|
|
|
260
260
|
export function isUnstreamedThinkingBlock(block, alreadyStreamed) {
|
|
261
261
|
return (!alreadyStreamed && block.type === 'thinking' && typeof block.thinking === 'string' && block.thinking.length > 0);
|
|
262
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* The init frame's `mcp_servers`, reduced to `{name, status}`, or `undefined` when the frame has no
|
|
265
|
+
* such list. Kept on the event so a host can tell "its bridge did not connect" from "no bridge was
|
|
266
|
+
* configured": Claude Code times a dead MCP server out, reports it `failed` here, and carries on
|
|
267
|
+
* without its tools (the 2026-10-01 desktop incident). Entries without a string name and status are
|
|
268
|
+
* dropped rather than guessed at.
|
|
269
|
+
*/
|
|
270
|
+
export function initMcpServers(obj) {
|
|
271
|
+
if (!Array.isArray(obj.mcp_servers))
|
|
272
|
+
return undefined;
|
|
273
|
+
return obj.mcp_servers.flatMap((server) => isRecord(server) && typeof server.name === 'string' && typeof server.status === 'string'
|
|
274
|
+
? [{ name: server.name, status: server.status }]
|
|
275
|
+
: []);
|
|
276
|
+
}
|
|
263
277
|
export function handleSystemMessage(obj, onEvent) {
|
|
264
278
|
if (obj.subtype === 'init') {
|
|
279
|
+
const mcpServers = initMcpServers(obj);
|
|
265
280
|
onEvent({
|
|
266
281
|
type: 'status',
|
|
267
282
|
label: 'initializing',
|
|
268
283
|
model: obj.model ?? null,
|
|
269
284
|
sessionId: obj.session_id ?? null,
|
|
285
|
+
...(mcpServers !== undefined ? { mcpServers } : {}),
|
|
270
286
|
});
|
|
271
287
|
return;
|
|
272
288
|
}
|
|
@@ -324,7 +340,7 @@ export function emitAssistantErrorIfPresent(obj, content, onEvent) {
|
|
|
324
340
|
code: obj.error,
|
|
325
341
|
});
|
|
326
342
|
}
|
|
327
|
-
export function createClaudeStreamHandler(onEvent, options = {}) {
|
|
343
|
+
export function createClaudeStreamHandler({ onEvent }, options = {}) {
|
|
328
344
|
let buffer = '';
|
|
329
345
|
// Per-content-block scratch, keyed by `${messageId}:${blockIndex}`.
|
|
330
346
|
const blocks = new Map();
|
|
@@ -431,7 +447,7 @@ export function createClaudeStreamHandler(onEvent, options = {}) {
|
|
|
431
447
|
function getOrCreateRoleGuard(msgId) {
|
|
432
448
|
let guard = roleGuards.get(msgId);
|
|
433
449
|
if (!guard) {
|
|
434
|
-
guard = createRoleMarkerGuard(msgId);
|
|
450
|
+
guard = createRoleMarkerGuard({ messageId: msgId });
|
|
435
451
|
roleGuards.set(msgId, guard);
|
|
436
452
|
}
|
|
437
453
|
return guard;
|
|
@@ -449,7 +465,7 @@ export function createClaudeStreamHandler(onEvent, options = {}) {
|
|
|
449
465
|
const guard = getOrCreateRoleGuard(msgId);
|
|
450
466
|
if (guard.contaminated)
|
|
451
467
|
return;
|
|
452
|
-
const safe = guard.feedText(text);
|
|
468
|
+
const safe = guard.feedText({ text: text });
|
|
453
469
|
if (safe.length > 0) {
|
|
454
470
|
onEvent({ type: eventType, delta: safe });
|
|
455
471
|
}
|
|
@@ -523,7 +539,7 @@ export function createClaudeStreamHandler(onEvent, options = {}) {
|
|
|
523
539
|
}
|
|
524
540
|
return startDuplicateArtifactCandidate(current, openIndex);
|
|
525
541
|
}
|
|
526
|
-
function feed(chunk) {
|
|
542
|
+
function feed({ chunk }) {
|
|
527
543
|
buffer += chunk;
|
|
528
544
|
let nl;
|
|
529
545
|
while ((nl = buffer.indexOf('\n')) !== -1) {
|
package/dist/copilot-stream.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Ported verbatim from OD's top-level `apps/daemon/src/copilot-stream.ts`
|
|
5
5
|
* (relocated under `runtimes/` in Jini's daemon per r1's recon; grouped
|
|
6
6
|
* with the other stream parsers here). Self-contained — no imports, no
|
|
7
|
-
* product coupling. See `
|
|
7
|
+
* product coupling. See `archived provenance ledger`.
|
|
8
8
|
*
|
|
9
9
|
* Parses GitHub Copilot CLI's `--output-format json` JSONL stream into the
|
|
10
10
|
* same UI-friendly events that claude-stream.js emits, so the chat panel
|
|
@@ -58,8 +58,12 @@ export type CopilotStreamEvent = {
|
|
|
58
58
|
durationMs: unknown;
|
|
59
59
|
};
|
|
60
60
|
type EventSink = (event: CopilotStreamEvent) => void;
|
|
61
|
-
export declare function createCopilotStreamHandler(onEvent
|
|
62
|
-
|
|
61
|
+
export declare function createCopilotStreamHandler({ onEvent }: {
|
|
62
|
+
onEvent: EventSink;
|
|
63
|
+
}): {
|
|
64
|
+
feed: ({ chunk }: {
|
|
65
|
+
chunk: string;
|
|
66
|
+
}) => void;
|
|
63
67
|
flush: () => void;
|
|
64
68
|
};
|
|
65
69
|
export {};
|
package/dist/copilot-stream.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Ported verbatim from OD's top-level `apps/daemon/src/copilot-stream.ts`
|
|
5
5
|
* (relocated under `runtimes/` in Jini's daemon per r1's recon; grouped
|
|
6
6
|
* with the other stream parsers here). Self-contained — no imports, no
|
|
7
|
-
* product coupling. See `
|
|
7
|
+
* product coupling. See `archived provenance ledger`.
|
|
8
8
|
*
|
|
9
9
|
* Parses GitHub Copilot CLI's `--output-format json` JSONL stream into the
|
|
10
10
|
* same UI-friendly events that claude-stream.js emits, so the chat panel
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
function isRecord(value) {
|
|
31
31
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
32
32
|
}
|
|
33
|
-
export function createCopilotStreamHandler(onEvent) {
|
|
33
|
+
export function createCopilotStreamHandler({ onEvent }) {
|
|
34
34
|
let buffer = '';
|
|
35
|
-
function feed(chunk) {
|
|
35
|
+
function feed({ chunk }) {
|
|
36
36
|
buffer += chunk;
|
|
37
37
|
let nl;
|
|
38
38
|
while ((nl = buffer.indexOf('\n')) !== -1) {
|
package/dist/defs/aider.d.ts
CHANGED
|
@@ -5,7 +5,14 @@ export declare const aiderAgentDef: {
|
|
|
5
5
|
versionArgs: string[];
|
|
6
6
|
fallbackModels: import("../types.js").RuntimeModelOption[];
|
|
7
7
|
fallbackModelsAssertedAt: string;
|
|
8
|
-
buildArgs: (prompt
|
|
8
|
+
buildArgs: ({ prompt, imagePaths: _imagePaths }: {
|
|
9
|
+
prompt: string;
|
|
10
|
+
imagePaths: string[];
|
|
11
|
+
}, { extraAllowedDirs: _extra, options }?: {
|
|
12
|
+
extraAllowedDirs?: string[];
|
|
13
|
+
options?: import("../types.js").RuntimeBuildOptions;
|
|
14
|
+
runtimeContext?: import("../types.js").RuntimeContext;
|
|
15
|
+
} | undefined) => string[];
|
|
9
16
|
maxPromptArgBytes: number;
|
|
10
17
|
streamFormat: string;
|
|
11
18
|
installUrl: string;
|
package/dist/defs/aider.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Ported from OD's `apps/daemon/src/runtimes/defs/aider.ts` (one de-branded comment; see `
|
|
1
|
+
/** Ported from OD's `apps/daemon/src/runtimes/defs/aider.ts` (one de-branded comment; see `archived provenance ledger`). */
|
|
2
2
|
import { DEFAULT_MODEL_OPTION } from './shared.js';
|
|
3
3
|
export const aiderAgentDef = {
|
|
4
4
|
id: 'aider',
|
|
@@ -49,7 +49,7 @@ export const aiderAgentDef = {
|
|
|
49
49
|
// --no-show-model-warnings — suppresses model-compat banners
|
|
50
50
|
// that would otherwise prefix every
|
|
51
51
|
// run with noise
|
|
52
|
-
buildArgs: (prompt, _imagePaths, _extra, options = {}) => {
|
|
52
|
+
buildArgs: ({ prompt, imagePaths: _imagePaths }, { extraAllowedDirs: _extra, options = {} } = {}) => {
|
|
53
53
|
const args = [
|
|
54
54
|
// See `RuntimeBuildOptions.permissionMode`'s doc: bypass is the default (unchanged
|
|
55
55
|
// behavior) unless a caller explicitly opts into a restricted run. Without
|
package/dist/defs/amp.d.ts
CHANGED
|
@@ -5,7 +5,14 @@ export declare const ampAgentDef: {
|
|
|
5
5
|
versionArgs: string[];
|
|
6
6
|
fallbackModels: import("../types.js").RuntimeModelOption[];
|
|
7
7
|
supportsCustomModel: false;
|
|
8
|
-
buildArgs: (
|
|
8
|
+
buildArgs: ({ prompt: _prompt, imagePaths: _imagePaths }: {
|
|
9
|
+
prompt: string;
|
|
10
|
+
imagePaths: string[];
|
|
11
|
+
}, { extraAllowedDirs: _extraAllowedDirs, options }?: {
|
|
12
|
+
extraAllowedDirs?: string[];
|
|
13
|
+
options?: import("../types.js").RuntimeBuildOptions;
|
|
14
|
+
runtimeContext?: import("../types.js").RuntimeContext;
|
|
15
|
+
} | undefined) => string[];
|
|
9
16
|
promptViaStdin: true;
|
|
10
17
|
streamFormat: string;
|
|
11
18
|
};
|
package/dist/defs/amp.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Ported verbatim from OD's `apps/daemon/src/runtimes/defs/amp.ts` (import path adjusted only). See `
|
|
1
|
+
/** Ported verbatim from OD's `apps/daemon/src/runtimes/defs/amp.ts` (import path adjusted only). See `archived provenance ledger`. */
|
|
2
2
|
import { DEFAULT_MODEL_OPTION } from './shared.js';
|
|
3
3
|
// Amp CLI (https://ampcode.com) is a full agentic coding CLI, argv-shaped
|
|
4
4
|
// much like Claude Code: it has a headless execute mode and emits a
|
|
@@ -43,7 +43,7 @@ export const ampAgentDef = {
|
|
|
43
43
|
{ id: 'rush', label: 'Rush (mode)' },
|
|
44
44
|
],
|
|
45
45
|
supportsCustomModel: false,
|
|
46
|
-
buildArgs: (_prompt, _imagePaths, _extraAllowedDirs = [], options = {}) => {
|
|
46
|
+
buildArgs: ({ prompt: _prompt, imagePaths: _imagePaths }, { extraAllowedDirs: _extraAllowedDirs = [], options = {} } = {}) => {
|
|
47
47
|
// See `RuntimeBuildOptions.permissionMode`'s doc: bypass is the default (unchanged
|
|
48
48
|
// behavior) unless a caller explicitly opts into a restricted run, in which case Amp
|
|
49
49
|
// blocks on tool calls that would need approval rather than auto-running them.
|
package/dist/defs/amr.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import type { RuntimeModelOption } from '../types.js';
|
|
2
2
|
export type VelaModelJsonSource = 'preset' | 'remote';
|
|
3
|
-
export declare function normalizeVelaModelId(rawId
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export declare function
|
|
7
|
-
|
|
3
|
+
export declare function normalizeVelaModelId({ rawId }: {
|
|
4
|
+
rawId: string;
|
|
5
|
+
}): string | null;
|
|
6
|
+
export declare function parseVelaModels({ stdout }: {
|
|
7
|
+
stdout: string;
|
|
8
|
+
}): RuntimeModelOption[];
|
|
9
|
+
export declare function parseVelaModelJson({ stdout, expectedSource }: {
|
|
10
|
+
stdout: string;
|
|
11
|
+
expectedSource: VelaModelJsonSource;
|
|
12
|
+
}): RuntimeModelOption[];
|
|
13
|
+
export declare function fetchVelaPresetModels({ resolvedBin, env }: {
|
|
14
|
+
resolvedBin: string;
|
|
15
|
+
env: NodeJS.ProcessEnv;
|
|
16
|
+
}): Promise<RuntimeModelOption[]>;
|
|
17
|
+
export declare function fetchVelaRemoteModelsWithRetry({ resolvedBin, env }: {
|
|
18
|
+
resolvedBin: string;
|
|
19
|
+
env: NodeJS.ProcessEnv;
|
|
20
|
+
}): Promise<RuntimeModelOption[]>;
|
|
8
21
|
/** Live account fields parsed from `vela billing summary --format json`. */
|
|
9
22
|
export interface VelaBillingSummary {
|
|
10
23
|
/** Real subscription tier (e.g. "max"); absent for free accounts. */
|
|
@@ -18,7 +31,10 @@ export interface VelaBillingSummary {
|
|
|
18
31
|
* contract rather than a separate HTTP call. Returns total available balance
|
|
19
32
|
* and the real membership tier.
|
|
20
33
|
*/
|
|
21
|
-
export declare function fetchVelaBillingSummary(resolvedBin
|
|
34
|
+
export declare function fetchVelaBillingSummary({ resolvedBin, env }: {
|
|
35
|
+
resolvedBin: string;
|
|
36
|
+
env: NodeJS.ProcessEnv;
|
|
37
|
+
}): Promise<VelaBillingSummary>;
|
|
22
38
|
export declare const amrAgentDef: {
|
|
23
39
|
id: string;
|
|
24
40
|
name: string;
|
package/dist/defs/amr.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Ported from OD's `apps/daemon/src/runtimes/defs/amr.ts` (two de-branded comments; see `
|
|
1
|
+
/** Ported from OD's `apps/daemon/src/runtimes/defs/amr.ts` (two de-branded comments; see `archived provenance ledger`). */
|
|
2
2
|
import { execAgentFile } from './shared.js';
|
|
3
3
|
const AMR_MODELS_TIMEOUT_MS = 10_000;
|
|
4
4
|
const AMR_MODELS_RETRY_DELAYS_MS = [250, 750];
|
|
@@ -11,7 +11,7 @@ const PREFERRED_AMR_CHAT_MODEL_ORDER = [
|
|
|
11
11
|
const PREFERRED_AMR_CHAT_MODEL_RANK = new Map(PREFERRED_AMR_CHAT_MODEL_ORDER.map((id, index) => [id, index]));
|
|
12
12
|
// AMR is the vela CLI's ACP stdio mode. `vela agent run --runtime opencode`
|
|
13
13
|
// starts a private OpenCode server and forwards stream-json over ACP JSON-RPC.
|
|
14
|
-
// Required env (
|
|
14
|
+
// Required env (supplied by the host process environment):
|
|
15
15
|
// VELA_RUNTIME_KEY — OpenRouter (or compatible) API key
|
|
16
16
|
// VELA_LINK_URL — OpenAI-compatible endpoint, e.g. https://openrouter.ai/api/v1
|
|
17
17
|
// VELA_OPENCODE_BIN — optional; absolute path to opencode when not on PATH
|
|
@@ -30,7 +30,7 @@ const PREFERRED_AMR_CHAT_MODEL_RANK = new Map(PREFERRED_AMR_CHAT_MODEL_ORDER.map
|
|
|
30
30
|
// the link-facing slug (`deepseek-v3.2` / `glm-5.1`), so this adapter
|
|
31
31
|
// normalizes those public ids at the spawn boundary until Vela exposes
|
|
32
32
|
// canonical ACP ids directly.
|
|
33
|
-
export function normalizeVelaModelId(rawId) {
|
|
33
|
+
export function normalizeVelaModelId({ rawId }) {
|
|
34
34
|
const trimmed = rawId.trim();
|
|
35
35
|
if (!trimmed)
|
|
36
36
|
return null;
|
|
@@ -108,7 +108,7 @@ function isVelaChatModelId(modelId) {
|
|
|
108
108
|
return false;
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
|
-
export function parseVelaModels(stdout) {
|
|
111
|
+
export function parseVelaModels({ stdout }) {
|
|
112
112
|
const seen = new Set();
|
|
113
113
|
const models = [];
|
|
114
114
|
for (const line of String(stdout || '').split('\n')) {
|
|
@@ -118,7 +118,7 @@ export function parseVelaModels(stdout) {
|
|
|
118
118
|
// `trimmed` is already non-empty and has no leading whitespace (checked
|
|
119
119
|
// above), so its first whitespace-split token is always non-empty too.
|
|
120
120
|
const rawId = trimmed.split(/\s+/)[0];
|
|
121
|
-
const id = normalizeVelaModelId(rawId);
|
|
121
|
+
const id = normalizeVelaModelId({ rawId: rawId });
|
|
122
122
|
if (!id || seen.has(id) || !isVelaChatModelId(id))
|
|
123
123
|
continue;
|
|
124
124
|
seen.add(id);
|
|
@@ -126,7 +126,7 @@ export function parseVelaModels(stdout) {
|
|
|
126
126
|
}
|
|
127
127
|
return orderAmrChatModels(models);
|
|
128
128
|
}
|
|
129
|
-
export function parseVelaModelJson(stdout, expectedSource) {
|
|
129
|
+
export function parseVelaModelJson({ stdout, expectedSource }) {
|
|
130
130
|
let parsed;
|
|
131
131
|
try {
|
|
132
132
|
parsed = JSON.parse(stdout);
|
|
@@ -193,15 +193,15 @@ function isRetriableVelaModelsError(error) {
|
|
|
193
193
|
'504',
|
|
194
194
|
].some((pattern) => message.includes(pattern));
|
|
195
195
|
}
|
|
196
|
-
export async function fetchVelaPresetModels(resolvedBin, env) {
|
|
197
|
-
const { stdout } = await execAgentFile(resolvedBin, ['model', 'preset', '--format', 'json'], {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return parseVelaModelJson(String(stdout), 'preset');
|
|
196
|
+
export async function fetchVelaPresetModels({ resolvedBin, env }) {
|
|
197
|
+
const { stdout } = await execAgentFile({ command: resolvedBin, args: ['model', 'preset', '--format', 'json'] }, { options: {
|
|
198
|
+
env,
|
|
199
|
+
timeout: AMR_MODELS_TIMEOUT_MS,
|
|
200
|
+
maxBuffer: 1024 * 1024,
|
|
201
|
+
} });
|
|
202
|
+
return parseVelaModelJson({ stdout: String(stdout), expectedSource: 'preset' });
|
|
203
203
|
}
|
|
204
|
-
export async function fetchVelaRemoteModelsWithRetry(resolvedBin, env) {
|
|
204
|
+
export async function fetchVelaRemoteModelsWithRetry({ resolvedBin, env }) {
|
|
205
205
|
// The internal exhaustion check below (`attempt === AMR_MODELS_RETRY_DELAYS_MS.length`)
|
|
206
206
|
// always throws on the last allowed attempt — strictly before the `for`
|
|
207
207
|
// condition itself would ever end the loop — so there's no way to fall
|
|
@@ -222,16 +222,16 @@ export async function fetchVelaRemoteModelsWithRetry(resolvedBin, env) {
|
|
|
222
222
|
// below) can never execute — v8/istanbul still instruments it because
|
|
223
223
|
// it can't prove an arbitrary `for(;;)` terminates, but the real control
|
|
224
224
|
// flow genuinely never reaches it. Documented here (and in
|
|
225
|
-
// `
|
|
225
|
+
// `archived provenance ledger`'s 2026-07-22 entry) instead of forced via a test,
|
|
226
226
|
// per this repo's no-`/* v8 ignore */` standard.
|
|
227
227
|
for (let attempt = 0;; attempt += 1) {
|
|
228
228
|
try {
|
|
229
|
-
const { stdout } = await execAgentFile(resolvedBin, ['model', 'list', '--format', 'json'], {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return parseVelaModelJson(String(stdout), 'remote');
|
|
229
|
+
const { stdout } = await execAgentFile({ command: resolvedBin, args: ['model', 'list', '--format', 'json'] }, { options: {
|
|
230
|
+
env,
|
|
231
|
+
timeout: AMR_MODELS_TIMEOUT_MS,
|
|
232
|
+
maxBuffer: 1024 * 1024,
|
|
233
|
+
} });
|
|
234
|
+
return parseVelaModelJson({ stdout: String(stdout), expectedSource: 'remote' });
|
|
235
235
|
}
|
|
236
236
|
catch (error) {
|
|
237
237
|
if (attempt === AMR_MODELS_RETRY_DELAYS_MS.length ||
|
|
@@ -248,8 +248,8 @@ export async function fetchVelaRemoteModelsWithRetry(resolvedBin, env) {
|
|
|
248
248
|
* contract rather than a separate HTTP call. Returns total available balance
|
|
249
249
|
* and the real membership tier.
|
|
250
250
|
*/
|
|
251
|
-
export async function fetchVelaBillingSummary(resolvedBin, env) {
|
|
252
|
-
const { stdout } = await execAgentFile(resolvedBin, ['billing', 'summary', '--format', 'json'], { env, timeout: AMR_MODELS_TIMEOUT_MS, maxBuffer: 1024 * 1024 });
|
|
251
|
+
export async function fetchVelaBillingSummary({ resolvedBin, env }) {
|
|
252
|
+
const { stdout } = await execAgentFile({ command: resolvedBin, args: ['billing', 'summary', '--format', 'json'] }, { options: { env, timeout: AMR_MODELS_TIMEOUT_MS, maxBuffer: 1024 * 1024 } });
|
|
253
253
|
const data = JSON.parse(String(stdout));
|
|
254
254
|
// Use `balanceUsd` — the same field the console wallet page renders as the
|
|
255
255
|
// headline "余额" — so the two surfaces always agree. Fall back to the total
|