@jini-ai/agent-runtime 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-protocol/acp/models.d.ts +11 -0
- package/dist/agent-protocol/acp/models.js +12 -3
- package/dist/capabilities.d.ts +1 -8
- package/dist/capabilities.js +8 -1
- package/dist/claude-code-models.d.ts +13 -1
- package/dist/claude-code-models.js +14 -16
- package/dist/claude-segment-usage.d.ts +26 -0
- package/dist/claude-segment-usage.js +63 -0
- package/dist/claude-stream.d.ts +6 -0
- package/dist/claude-stream.js +19 -4
- package/dist/defs/claude.d.ts +2 -0
- package/dist/defs/claude.js +10 -2
- package/dist/defs/codebuddy.js +1 -1
- package/dist/defs/cursor-agent.js +1 -1
- package/dist/defs/opencode.js +1 -1
- package/dist/detection.d.ts +28 -4
- package/dist/detection.js +81 -42
- package/dist/diagnostics.d.ts +6 -1
- package/dist/diagnostics.js +2 -2
- package/dist/executables.d.ts +15 -9
- package/dist/executables.js +72 -64
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/invocation.d.ts +24 -2
- package/dist/invocation.js +18 -6
- package/dist/launch.d.ts +2 -1
- package/dist/launch.js +2 -2
- package/dist/model-discovery-adapters.d.ts +5 -0
- package/dist/model-discovery-adapters.js +62 -49
- package/dist/model-discovery.js +2 -2
- package/dist/models.d.ts +9 -4
- package/dist/models.js +11 -11
- package/dist/probe-scheduler.d.ts +19 -0
- package/dist/probe-scheduler.js +30 -0
- package/dist/runtime-state.d.ts +41 -0
- package/dist/runtime-state.js +31 -0
- package/dist/types.d.ts +4 -0
- package/package.json +13 -8
- package/dist/defs/gemini.d.ts +0 -24
- package/dist/defs/gemini.js +0 -81
package/dist/index.d.ts
CHANGED
|
@@ -48,5 +48,6 @@ export * from './providers/index.js';
|
|
|
48
48
|
/** ACP + pi-rpc protocol adapters over the shared JSON-line-stream core. See aliases above. */
|
|
49
49
|
export { createJsonLineStream, type AcpMcpServerInput, type AcpPermissionDecision, type AcpPermissionHandler, type AcpPermissionOption, type AcpPermissionRequest, type AcpSessionController, type ModelOption, type AttachAcpSessionOptions, type AccountFailure, type AccountFailureClassifier, buildAcpSessionNewParams, normalizeModels, detectAcpModels, attachAcpSession, noopAccountFailureClassifier, mapPiRpcEvent, attachPiRpcSession, parsePiModels as parsePiRpcModels, type PiRpcSession, type PiRpcSessionOptions, } from './agent-protocol/index.js';
|
|
50
50
|
export * from './model-discovery.js';
|
|
51
|
-
export { defaultModelDiscoveryDeps, parseClaudeInitializeMetadata, parsePiRpcMetadata } from './model-discovery-adapters.js';
|
|
51
|
+
export { getRuntimeModelDiscoveryDeps, defaultModelDiscoveryDeps, parseClaudeInitializeMetadata, parsePiRpcMetadata } from './model-discovery-adapters.js';
|
|
52
|
+
export * from './runtime-state.js';
|
|
52
53
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -71,5 +71,6 @@ export * from './providers/index.js';
|
|
|
71
71
|
/** ACP + pi-rpc protocol adapters over the shared JSON-line-stream core. See aliases above. */
|
|
72
72
|
export { createJsonLineStream, buildAcpSessionNewParams, normalizeModels, detectAcpModels, attachAcpSession, noopAccountFailureClassifier, mapPiRpcEvent, attachPiRpcSession, parsePiModels as parsePiRpcModels, } from './agent-protocol/index.js';
|
|
73
73
|
export * from './model-discovery.js';
|
|
74
|
-
export { defaultModelDiscoveryDeps, parseClaudeInitializeMetadata, parsePiRpcMetadata } from './model-discovery-adapters.js';
|
|
74
|
+
export { getRuntimeModelDiscoveryDeps, defaultModelDiscoveryDeps, parseClaudeInitializeMetadata, parsePiRpcMetadata } from './model-discovery-adapters.js';
|
|
75
|
+
export * from './runtime-state.js';
|
|
75
76
|
//# sourceMappingURL=index.js.map
|
package/dist/invocation.d.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module invocation
|
|
3
|
+
*
|
|
4
|
+
* Short, read-only metadata probes (model-list / version / help /
|
|
5
|
+
* auth-status) for an agent CLI. Ported from OD's
|
|
6
|
+
* `apps/daemon/src/runtimes/invocation.ts` with one dependency swap:
|
|
7
|
+
* `createCommandInvocation` now comes from `@jini-ai/platform` instead of the
|
|
8
|
+
* OD workspace package it originally shipped from — the two are the same
|
|
9
|
+
* function (platform was already verbatim-lifted into `@jini-ai/platform`,
|
|
10
|
+
* see its `archived provenance ledger`).
|
|
11
|
+
*/
|
|
12
|
+
import { execFile } from 'node:child_process';
|
|
1
13
|
import type { RuntimeExecOptions } from './types.js';
|
|
14
|
+
declare const execFileP: typeof execFile.__promisify__;
|
|
15
|
+
type ProbeExecPort = (input: {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
options: RuntimeExecOptions & {
|
|
19
|
+
windowsVerbatimArguments?: boolean | undefined;
|
|
20
|
+
};
|
|
21
|
+
}, optional: Record<string, never>) => ReturnType<typeof execFileP>;
|
|
2
22
|
export declare function execAgentFile({ command, args }: {
|
|
3
23
|
command: string;
|
|
4
24
|
args: string[];
|
|
5
|
-
}, { options }?: {
|
|
25
|
+
}, { options, execute }?: {
|
|
6
26
|
options?: RuntimeExecOptions;
|
|
7
|
-
|
|
27
|
+
execute?: ProbeExecPort;
|
|
28
|
+
}): Promise<{
|
|
8
29
|
stdout: string | NonSharedBuffer;
|
|
9
30
|
stderr: string | NonSharedBuffer;
|
|
10
31
|
}>;
|
|
32
|
+
export {};
|
|
11
33
|
//# sourceMappingURL=invocation.d.ts.map
|
package/dist/invocation.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* see its `archived provenance ledger`).
|
|
11
11
|
*/
|
|
12
12
|
import { execFile } from 'node:child_process';
|
|
13
|
+
import { scheduleProbeProcess } from './probe-scheduler.js';
|
|
13
14
|
import os from 'node:os';
|
|
14
15
|
import { promisify } from 'node:util';
|
|
15
16
|
import { createCommandInvocation } from '@jini-ai/platform';
|
|
@@ -27,7 +28,7 @@ const execFileP = promisify(execFile);
|
|
|
27
28
|
// running dev server. A probe writing a stray lockfile under the OS temp
|
|
28
29
|
// dir is harmless. Actual agent runs spawn elsewhere with an explicit
|
|
29
30
|
// project cwd and are unaffected.
|
|
30
|
-
export function execAgentFile({ command, args }, { options = {} } = {}) {
|
|
31
|
+
export function execAgentFile({ command, args }, { options = {}, execute = (input) => execFileP(input.command, input.args, input.options) } = {}) {
|
|
31
32
|
const invocation = createCommandInvocation(options.env
|
|
32
33
|
? {
|
|
33
34
|
command,
|
|
@@ -38,10 +39,21 @@ export function execAgentFile({ command, args }, { options = {} } = {}) {
|
|
|
38
39
|
command,
|
|
39
40
|
args,
|
|
40
41
|
});
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
return scheduleProbeProcess({ work: async () => {
|
|
43
|
+
const pending = execute({ command: invocation.command, args: invocation.args, options: {
|
|
44
|
+
killSignal: 'SIGKILL', ...options, cwd: options.cwd ?? os.tmpdir(),
|
|
45
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
46
|
+
} }, {});
|
|
47
|
+
try {
|
|
48
|
+
return await pending;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
// AbortError can precede close. Hold the shared slot until the child actually exits.
|
|
52
|
+
const child = pending.child;
|
|
53
|
+
if (child?.pid && child.exitCode === null && child.signalCode === null) {
|
|
54
|
+
await new Promise(resolve => { child.once('close', () => resolve()); });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} }, { priority: args.includes('--version') ? 'version' : 'metadata', signal: options.signal });
|
|
46
58
|
}
|
|
47
59
|
//# sourceMappingURL=invocation.js.map
|
package/dist/launch.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ExecutableResolutionOptions } from './executables.js';
|
|
1
2
|
import { inspectAgentExecutableResolution } from './executables.js';
|
|
2
3
|
import type { RuntimeAgentDef } from './types.js';
|
|
3
4
|
export type AgentLaunchKind = 'selected' | 'codex-native';
|
|
@@ -9,7 +10,7 @@ export type AgentLaunchResolution = ReturnType<typeof inspectAgentExecutableReso
|
|
|
9
10
|
};
|
|
10
11
|
export declare function resolveAgentLaunch({ def }: {
|
|
11
12
|
def: RuntimeAgentDef;
|
|
12
|
-
},
|
|
13
|
+
}, options?: ExecutableResolutionOptions & {
|
|
13
14
|
configuredEnv?: Record<string, string>;
|
|
14
15
|
}): AgentLaunchResolution;
|
|
15
16
|
export declare function applyAgentLaunchEnv({ env, launch }: {
|
package/dist/launch.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
import { accessSync, closeSync, constants, openSync, readdirSync, readSync, realpathSync, statSync } from 'node:fs';
|
|
6
6
|
import path, { delimiter } from 'node:path';
|
|
7
7
|
import { inspectAgentExecutableResolution, userToolchainBinDirs } from './executables.js';
|
|
8
|
-
export function resolveAgentLaunch({ def },
|
|
9
|
-
const resolution = inspectAgentExecutableResolution({ def: def },
|
|
8
|
+
export function resolveAgentLaunch({ def }, options = {}) {
|
|
9
|
+
const resolution = inspectAgentExecutableResolution({ def: def }, options);
|
|
10
10
|
if (!resolution.selectedPath) {
|
|
11
11
|
return { ...resolution, launchPath: null, launchKind: 'selected', childPathPrepend: [], diagnostic: null };
|
|
12
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentRuntimeState } from './runtime-state.js';
|
|
1
2
|
import { type AgentDiscoveryConfiguration } from './model-discovery.js';
|
|
2
3
|
import type { ModelDiscoveryContext, ModelDiscoveryDeps, ModelProbeResult } from './model-discovery-types.js';
|
|
3
4
|
export declare function modelProbeTimeoutMs(agentId: string): number;
|
|
@@ -19,4 +20,8 @@ export declare function probeAgentCatalog(agentId: string, context: ModelDiscove
|
|
|
19
20
|
export declare const defaultModelDiscoveryDeps: ModelDiscoveryDeps;
|
|
20
21
|
/** Pi's native RPC supplies catalog AND current provider/id without making an inference call. */
|
|
21
22
|
export declare function parsePiRpcMetadata(stdout: string): ModelProbeResult;
|
|
23
|
+
/** Stable dependency identity preserves the existing per-host single-probe budget as well as its cache. */
|
|
24
|
+
export declare function getRuntimeModelDiscoveryDeps({ state }: {
|
|
25
|
+
state: AgentRuntimeState;
|
|
26
|
+
}, _optional?: Record<string, never>): ModelDiscoveryDeps;
|
|
22
27
|
//# sourceMappingURL=model-discovery-adapters.d.ts.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { defaultRuntimeState } from './runtime-state.js';
|
|
2
|
+
import { VENDOR_API_BASE_URLS } from '@jini-ai/integrations/media-providers/catalog';
|
|
1
3
|
import { execFile } from 'node:child_process';
|
|
2
4
|
import { readFile, stat } from 'node:fs/promises';
|
|
3
5
|
import { homedir } from 'node:os';
|
|
@@ -7,6 +9,7 @@ import { detectAcpModelMetadata } from './agent-protocol/acp/models.js';
|
|
|
7
9
|
import { CLAUDE_CODE_INITIALIZE_ARGS, CLAUDE_CODE_INITIALIZE_REQUEST } from './claude-code-models.js';
|
|
8
10
|
import { listProviderModels } from './providers/model-catalog.js';
|
|
9
11
|
import { execAgentFile } from './invocation.js';
|
|
12
|
+
import { scheduleProbeProcess } from './probe-scheduler.js';
|
|
10
13
|
import { probeCopilotSdk, probeDroidSdk } from './model-discovery-sdk.js';
|
|
11
14
|
import { parseSettingsJson, readModelConfiguration } from './model-discovery-config.js';
|
|
12
15
|
import { ModelProbeError, modelIdentityKind, withModelProbeTimeout } from './model-discovery.js';
|
|
@@ -252,49 +255,53 @@ function runProcess(input) {
|
|
|
252
255
|
cwd: input.context.cwd, env: input.context.env, signal: input.signal,
|
|
253
256
|
timeout: input.timeoutMs, killSignal: 'SIGKILL', maxBuffer: 8 * 1024 * 1024,
|
|
254
257
|
} }).then(({ stdout, stderr }) => ({ stdout: String(stdout), stderr: String(stderr) }));
|
|
255
|
-
return new Promise((resolve, reject) => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
catch { }
|
|
266
|
-
} };
|
|
267
|
-
// execFile forwards `detached` to spawn at runtime, but its typings omit it; a typed
|
|
268
|
-
// variable (not a literal) keeps the process-group option without a cast.
|
|
269
|
-
const options = { cwd: input.context.cwd, env: input.context.env,
|
|
270
|
-
timeout: input.timeoutMs, killSignal: 'SIGKILL', signal: input.signal, maxBuffer: 8 * 1024 * 1024,
|
|
271
|
-
detached: Boolean(tree),
|
|
272
|
-
windowsVerbatimArguments: invocation.windowsVerbatimArguments, };
|
|
273
|
-
const child = execFile(invocation.command, invocation.args, options, (error, stdout, stderr) => {
|
|
274
|
-
if (treeTimer)
|
|
275
|
-
clearTimeout(treeTimer);
|
|
276
|
-
input.signal.removeEventListener('abort', killTree);
|
|
277
|
-
if (error)
|
|
278
|
-
killTree();
|
|
279
|
-
error && !completed ? reject(error) : resolve({ stdout: String(stdout), stderr: String(stderr) });
|
|
280
|
-
});
|
|
281
|
-
if (tree) {
|
|
282
|
-
input.signal.addEventListener('abort', killTree, { once: true });
|
|
283
|
-
treeTimer = setTimeout(killTree, input.timeoutMs);
|
|
284
|
-
if (input.signal.aborted)
|
|
285
|
-
killTree();
|
|
286
|
-
}
|
|
287
|
-
if (input.complete)
|
|
288
|
-
child.stdout?.on('data', (chunk) => {
|
|
289
|
-
captured += String(chunk);
|
|
290
|
-
if (input.complete?.(captured)) {
|
|
291
|
-
completed = true;
|
|
292
|
-
child.kill('SIGKILL');
|
|
258
|
+
return scheduleProbeProcess({ work: () => new Promise((resolve, reject) => {
|
|
259
|
+
let completed = false;
|
|
260
|
+
let captured = '';
|
|
261
|
+
const invocation = createCommandInvocation({ command: input.context.executable, args: [...input.args], env: input.context.env });
|
|
262
|
+
const tree = input.terminateProcessTree && process.platform !== 'win32';
|
|
263
|
+
let treeTimer;
|
|
264
|
+
const killTree = () => { if (tree && child.pid) {
|
|
265
|
+
try {
|
|
266
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
293
267
|
}
|
|
268
|
+
catch { }
|
|
269
|
+
} };
|
|
270
|
+
// execFile forwards `detached` to spawn at runtime, but its typings omit it; a typed
|
|
271
|
+
// variable (not a literal) keeps the process-group option without a cast.
|
|
272
|
+
const options = { cwd: input.context.cwd, env: input.context.env,
|
|
273
|
+
timeout: input.timeoutMs, killSignal: 'SIGKILL', signal: input.signal, maxBuffer: 8 * 1024 * 1024,
|
|
274
|
+
detached: Boolean(tree),
|
|
275
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments, };
|
|
276
|
+
const child = execFile(invocation.command, invocation.args, options, (error, stdout, stderr) => {
|
|
277
|
+
if (treeTimer)
|
|
278
|
+
clearTimeout(treeTimer);
|
|
279
|
+
input.signal.removeEventListener('abort', killTree);
|
|
280
|
+
if (error)
|
|
281
|
+
killTree();
|
|
282
|
+
const settle = () => { error && !completed ? reject(error) : resolve({ stdout: String(stdout), stderr: String(stderr) }); };
|
|
283
|
+
if (child.pid && child.exitCode === null && child.signalCode === null)
|
|
284
|
+
child.once('close', settle);
|
|
285
|
+
else
|
|
286
|
+
settle();
|
|
294
287
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
288
|
+
if (tree) {
|
|
289
|
+
input.signal.addEventListener('abort', killTree, { once: true });
|
|
290
|
+
treeTimer = setTimeout(killTree, input.timeoutMs);
|
|
291
|
+
if (input.signal.aborted)
|
|
292
|
+
killTree();
|
|
293
|
+
}
|
|
294
|
+
if (input.complete)
|
|
295
|
+
child.stdout?.on('data', (chunk) => {
|
|
296
|
+
captured += String(chunk);
|
|
297
|
+
if (input.complete?.(captured)) {
|
|
298
|
+
completed = true;
|
|
299
|
+
child.kill('SIGKILL');
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
child.stdin?.on('error', () => { });
|
|
303
|
+
child.stdin?.end(input.stdin);
|
|
304
|
+
}) }, { signal: input.signal });
|
|
298
305
|
}
|
|
299
306
|
export const defaultModelDiscoveryDeps = {
|
|
300
307
|
process: { run: runProcess },
|
|
@@ -319,29 +326,29 @@ export const defaultModelDiscoveryDeps = {
|
|
|
319
326
|
// handles. BYOK env is usable only when it identifies this CLI's effective provider.
|
|
320
327
|
const env = context.env;
|
|
321
328
|
if (agentId === 'claude' && env.ANTHROPIC_API_KEY)
|
|
322
|
-
return { protocol: 'anthropic', baseUrl: env.ANTHROPIC_BASE_URL ||
|
|
329
|
+
return { protocol: 'anthropic', baseUrl: env.ANTHROPIC_BASE_URL || VENDOR_API_BASE_URLS.anthropic, apiKey: env.ANTHROPIC_API_KEY };
|
|
323
330
|
const selected = context.model || (agentId === 'aider' ? env.AIDER_MODEL : agentId === 'qwen' ? env.QWEN_MODEL || env.OPENAI_MODEL : undefined);
|
|
324
331
|
if (!selected)
|
|
325
332
|
return null;
|
|
326
333
|
if (/^(anthropic\/|claude-)/.test(selected) && env.ANTHROPIC_API_KEY)
|
|
327
|
-
return { protocol: 'anthropic', baseUrl: env.ANTHROPIC_BASE_URL ||
|
|
334
|
+
return { protocol: 'anthropic', baseUrl: env.ANTHROPIC_BASE_URL || VENDOR_API_BASE_URLS.anthropic, apiKey: env.ANTHROPIC_API_KEY };
|
|
328
335
|
if (/^(gemini\/|google\/|gemini-)/.test(selected) && env.GEMINI_API_KEY)
|
|
329
|
-
return { protocol: 'google', baseUrl:
|
|
336
|
+
return { protocol: 'google', baseUrl: VENDOR_API_BASE_URLS.google, apiKey: env.GEMINI_API_KEY };
|
|
330
337
|
if (/^openrouter\//.test(selected) && env.OPENROUTER_API_KEY)
|
|
331
|
-
return { protocol: 'openai', baseUrl: env.OPENROUTER_API_BASE ||
|
|
338
|
+
return { protocol: 'openai', baseUrl: env.OPENROUTER_API_BASE || VENDOR_API_BASE_URLS.openrouter, apiKey: env.OPENROUTER_API_KEY };
|
|
332
339
|
if ((/^(openai\/|gpt-|o\d)/.test(selected) || agentId === 'qwen' && (env.OPENAI_MODEL || env.OPENAI_BASE_URL)) && env.OPENAI_API_KEY)
|
|
333
|
-
return { protocol: 'openai', baseUrl: env.OPENAI_BASE_URL || env.OPENAI_API_BASE ||
|
|
340
|
+
return { protocol: 'openai', baseUrl: env.OPENAI_BASE_URL || env.OPENAI_API_BASE || VENDOR_API_BASE_URLS.openai, apiKey: env.OPENAI_API_KEY };
|
|
334
341
|
return null;
|
|
335
342
|
} },
|
|
336
343
|
acp: { async probe({ context, args, signal }) {
|
|
337
344
|
const invocation = createCommandInvocation({ command: context.executable, args: [...args], env: context.env });
|
|
338
|
-
const result = await detectAcpModelMetadata({ bin: invocation.command, args: invocation.args }, { cwd: context.cwd, env: context.env, timeoutMs: 15_000, signal });
|
|
345
|
+
const result = await scheduleProbeProcess({ work: () => detectAcpModelMetadata({ bin: invocation.command, args: invocation.args }, { cwd: context.cwd, env: context.env, timeoutMs: 15_000, signal }) }, { signal });
|
|
339
346
|
return { models: result.models, source: 'rpc', coverage: 'account', ...(result.currentModelId ? { defaultSelectionId: result.currentModelId } : {}) };
|
|
340
347
|
} },
|
|
341
348
|
rpc: { async probe({ agentId, context, signal }) {
|
|
342
349
|
// UNVERIFIED locally: use official prompt-free SDK interfaces, not invented CLI flags.
|
|
343
350
|
if (agentId === 'copilot')
|
|
344
|
-
return probeCopilotSdk(context, signal);
|
|
351
|
+
return scheduleProbeProcess({ work: () => probeCopilotSdk(context, signal) }, { signal });
|
|
345
352
|
if (agentId === 'droid')
|
|
346
353
|
return probeDroidSdk(context, defaultModelDiscoveryDeps, signal);
|
|
347
354
|
if (agentId !== 'pi')
|
|
@@ -358,7 +365,7 @@ export const defaultModelDiscoveryDeps = {
|
|
|
358
365
|
} });
|
|
359
366
|
return parsePiRpcMetadata(stdout);
|
|
360
367
|
} },
|
|
361
|
-
clock: { now: Date.now }, cache:
|
|
368
|
+
clock: { now: Date.now }, cache: defaultRuntimeState.modelCatalog,
|
|
362
369
|
};
|
|
363
370
|
/** Pi's native RPC supplies catalog AND current provider/id without making an inference call. */
|
|
364
371
|
export function parsePiRpcMetadata(stdout) {
|
|
@@ -388,4 +395,10 @@ export function parsePiRpcMetadata(stdout) {
|
|
|
388
395
|
throw new ModelProbeError('malformed-response');
|
|
389
396
|
return { models, source: 'rpc', coverage: 'account', ...(defaultSelectionId ? { defaultSelectionId } : {}) };
|
|
390
397
|
}
|
|
398
|
+
/** Stable dependency identity preserves the existing per-host single-probe budget as well as its cache. */
|
|
399
|
+
export function getRuntimeModelDiscoveryDeps({ state }, _optional = {}) {
|
|
400
|
+
if (state === defaultRuntimeState)
|
|
401
|
+
return defaultModelDiscoveryDeps;
|
|
402
|
+
return state.discoveryDeps ??= { ...defaultModelDiscoveryDeps, cache: state.modelCatalog };
|
|
403
|
+
}
|
|
391
404
|
//# sourceMappingURL=model-discovery-adapters.js.map
|
package/dist/model-discovery.js
CHANGED
|
@@ -30,11 +30,11 @@ export function modelLaunchFingerprint(context, configMaterial = '') {
|
|
|
30
30
|
class ProbeTimeout extends Error {
|
|
31
31
|
}
|
|
32
32
|
const probePools = new WeakMap();
|
|
33
|
-
/**
|
|
33
|
+
/** One cold catalog probe per host; queued callers keep cancellation responsive. */
|
|
34
34
|
async function boundedProbe(deps, work, signal) {
|
|
35
35
|
const pool = probePools.get(deps) || { active: 0, queue: [] };
|
|
36
36
|
probePools.set(deps, pool);
|
|
37
|
-
if (pool.active >=
|
|
37
|
+
if (pool.active >= 1) {
|
|
38
38
|
await new Promise((resolve, reject) => {
|
|
39
39
|
const ready = () => { signal?.removeEventListener('abort', abort); resolve(); };
|
|
40
40
|
const abort = () => { const index = pool.queue.indexOf(ready); if (index >= 0)
|
package/dist/models.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentRuntimeState } from './runtime-state.js';
|
|
1
2
|
/**
|
|
2
3
|
* @module models
|
|
3
4
|
* Model-option defaults, a per-agent last-surfaced live-model cache and model-id sanitization.
|
|
@@ -7,13 +8,15 @@ export declare const DEFAULT_MODEL_OPTION: RuntimeModelOption;
|
|
|
7
8
|
export declare function rememberLiveModels({ agentId, models }: {
|
|
8
9
|
agentId: string;
|
|
9
10
|
models: RuntimeModelOption[];
|
|
10
|
-
}, { scope }?: {
|
|
11
|
+
}, { scope, state }?: {
|
|
11
12
|
scope?: string | null;
|
|
13
|
+
state?: AgentRuntimeState;
|
|
12
14
|
}): void;
|
|
13
15
|
export declare function getRememberedLiveModels({ agentId }: {
|
|
14
16
|
agentId: string;
|
|
15
|
-
}, { scope }?: {
|
|
17
|
+
}, { scope, state }?: {
|
|
16
18
|
scope?: string | null;
|
|
19
|
+
state?: AgentRuntimeState;
|
|
17
20
|
}): RuntimeModelOption[];
|
|
18
21
|
export declare function preferFreshLiveModels({ freshModels, rememberedModels }: {
|
|
19
22
|
freshModels: RuntimeModelOption[];
|
|
@@ -22,15 +25,17 @@ export declare function preferFreshLiveModels({ freshModels, rememberedModels }:
|
|
|
22
25
|
export declare function isKnownModel({ def, modelId }: {
|
|
23
26
|
def: RuntimeAgentDef;
|
|
24
27
|
modelId: string | null | undefined;
|
|
25
|
-
}, { scope }?: {
|
|
28
|
+
}, { scope, state }?: {
|
|
26
29
|
scope?: string | null;
|
|
30
|
+
state?: AgentRuntimeState;
|
|
27
31
|
}): boolean;
|
|
28
32
|
export declare function resolveModelForAgent({ def, resolved }: {
|
|
29
33
|
def: RuntimeAgentDef;
|
|
30
34
|
resolved: string | null;
|
|
31
|
-
}, { env, liveModelScope }?: {
|
|
35
|
+
}, { env, liveModelScope, state }?: {
|
|
32
36
|
env?: Record<string, string | undefined>;
|
|
33
37
|
liveModelScope?: string | null;
|
|
38
|
+
state?: AgentRuntimeState;
|
|
34
39
|
}): string | null;
|
|
35
40
|
export declare function sanitizeCustomModel({ id }: {
|
|
36
41
|
id: string | null | undefined;
|
package/dist/models.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defaultRuntimeState } from './runtime-state.js';
|
|
1
2
|
export const DEFAULT_MODEL_OPTION = {
|
|
2
3
|
id: 'default',
|
|
3
4
|
label: 'Default (CLI config)',
|
|
@@ -7,33 +8,32 @@ export const DEFAULT_MODEL_OPTION = {
|
|
|
7
8
|
// recent live list (refreshed every detectAgents() call) and additionally
|
|
8
9
|
// trust any value present in the static fallback. A model that's neither
|
|
9
10
|
// gets rejected so a stale or hostile value can't smuggle arbitrary flags.
|
|
10
|
-
|
|
11
|
-
const liveModelOrder = new Map();
|
|
11
|
+
// Host state carries these maps; legacy callers use defaultRuntimeState.
|
|
12
12
|
function liveModelCacheKey(agentId, scope) {
|
|
13
13
|
const trimmedScope = typeof scope === 'string' ? scope.trim() : '';
|
|
14
14
|
return trimmedScope ? `${agentId}\0${trimmedScope}` : agentId;
|
|
15
15
|
}
|
|
16
|
-
export function rememberLiveModels({ agentId, models }, { scope } = {}) {
|
|
16
|
+
export function rememberLiveModels({ agentId, models }, { scope, state = defaultRuntimeState } = {}) {
|
|
17
17
|
if (!Array.isArray(models))
|
|
18
18
|
return;
|
|
19
19
|
const ids = models
|
|
20
20
|
.map((m) => m && m.id)
|
|
21
21
|
.filter((id) => typeof id === 'string');
|
|
22
22
|
const key = liveModelCacheKey(agentId, scope);
|
|
23
|
-
liveModelCache.set(key, new Set(ids));
|
|
24
|
-
liveModelOrder.set(key, ids);
|
|
23
|
+
state.liveModelCache.set(key, new Set(ids));
|
|
24
|
+
state.liveModelOrder.set(key, ids);
|
|
25
25
|
}
|
|
26
|
-
export function getRememberedLiveModels({ agentId }, { scope } = {}) {
|
|
27
|
-
const ids = liveModelOrder.get(liveModelCacheKey(agentId, scope)) ?? [];
|
|
26
|
+
export function getRememberedLiveModels({ agentId }, { scope, state = defaultRuntimeState } = {}) {
|
|
27
|
+
const ids = state.liveModelOrder.get(liveModelCacheKey(agentId, scope)) ?? [];
|
|
28
28
|
return ids.map((id) => ({ id, label: id }));
|
|
29
29
|
}
|
|
30
30
|
export function preferFreshLiveModels({ freshModels, rememberedModels }) {
|
|
31
31
|
return freshModels.length > 0 ? freshModels : rememberedModels;
|
|
32
32
|
}
|
|
33
|
-
export function isKnownModel({ def, modelId }, { scope } = {}) {
|
|
33
|
+
export function isKnownModel({ def, modelId }, { scope, state = defaultRuntimeState } = {}) {
|
|
34
34
|
if (!modelId)
|
|
35
35
|
return false;
|
|
36
|
-
const live = liveModelCache.get(liveModelCacheKey(def.id, scope));
|
|
36
|
+
const live = state.liveModelCache.get(liveModelCacheKey(def.id, scope));
|
|
37
37
|
if (live && live.has(modelId))
|
|
38
38
|
return true;
|
|
39
39
|
if (Array.isArray(def.fallbackModels)) {
|
|
@@ -49,7 +49,7 @@ export function isKnownModel({ def, modelId }, { scope } = {}) {
|
|
|
49
49
|
// surfaced to the UI, then fall back to the def's first concrete fallback
|
|
50
50
|
// id so the spawn layer always has a real model to forward. Defs that DO
|
|
51
51
|
// list 'default' (the common case) are left untouched.
|
|
52
|
-
export function resolveModelForAgent({ def, resolved }, { env = process.env, liveModelScope } = {}) {
|
|
52
|
+
export function resolveModelForAgent({ def, resolved }, { env = process.env, liveModelScope, state = defaultRuntimeState } = {}) {
|
|
53
53
|
if (resolved && resolved !== 'default')
|
|
54
54
|
return resolved;
|
|
55
55
|
// Host-process env override. Lets an operator pin a different fallback
|
|
@@ -66,7 +66,7 @@ export function resolveModelForAgent({ def, resolved }, { env = process.env, liv
|
|
|
66
66
|
const fallbacks = def.fallbackModels;
|
|
67
67
|
if (fallbacks.some((m) => m.id === 'default'))
|
|
68
68
|
return resolved;
|
|
69
|
-
const liveModels = liveModelOrder.get(liveModelCacheKey(def.id, liveModelScope)) ?? [];
|
|
69
|
+
const liveModels = state.liveModelOrder.get(liveModelCacheKey(def.id, liveModelScope)) ?? [];
|
|
70
70
|
const firstLive = liveModels[0];
|
|
71
71
|
if (firstLive)
|
|
72
72
|
return firstLive;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type Priority = 'version' | 'metadata';
|
|
2
|
+
/** All metadata process adapters share one process-wide slot. Version checks precede queued
|
|
3
|
+
* metadata, so expensive discovery cannot delay cheap availability checks. Actual chat runs
|
|
4
|
+
* never use this queue. A slot is held until the child adapter settles, including cancellation.
|
|
5
|
+
* @complexity O(q) queued selection, bounded by the runtime registry's probe count. */
|
|
6
|
+
export declare function createProbeScheduler(_input: Record<string, never>, _options?: Record<string, never>): <T>({ work }: {
|
|
7
|
+
work: () => Promise<T>;
|
|
8
|
+
}, { priority, signal }?: {
|
|
9
|
+
priority?: Priority;
|
|
10
|
+
signal?: AbortSignal | undefined;
|
|
11
|
+
}) => Promise<T>;
|
|
12
|
+
export declare const scheduleProbeProcess: <T>({ work }: {
|
|
13
|
+
work: () => Promise<T>;
|
|
14
|
+
}, { priority, signal }?: {
|
|
15
|
+
priority?: Priority;
|
|
16
|
+
signal?: AbortSignal | undefined;
|
|
17
|
+
}) => Promise<T>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=probe-scheduler.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** All metadata process adapters share one process-wide slot. Version checks precede queued
|
|
2
|
+
* metadata, so expensive discovery cannot delay cheap availability checks. Actual chat runs
|
|
3
|
+
* never use this queue. A slot is held until the child adapter settles, including cancellation.
|
|
4
|
+
* @complexity O(q) queued selection, bounded by the runtime registry's probe count. */
|
|
5
|
+
export function createProbeScheduler(_input, _options = {}) {
|
|
6
|
+
const queue = [];
|
|
7
|
+
let running = false;
|
|
8
|
+
function drain() {
|
|
9
|
+
if (running || !queue.length)
|
|
10
|
+
return;
|
|
11
|
+
const version = queue.findIndex(entry => entry.priority === 'version');
|
|
12
|
+
const entry = queue.splice(version < 0 ? 0 : version, 1)[0];
|
|
13
|
+
running = true;
|
|
14
|
+
entry.start();
|
|
15
|
+
}
|
|
16
|
+
return function schedule({ work }, { priority = 'metadata', signal } = {}) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
queue.push({ priority, start: () => {
|
|
19
|
+
Promise.resolve().then(() => {
|
|
20
|
+
if (signal?.aborted)
|
|
21
|
+
throw new Error('Probe cancelled');
|
|
22
|
+
return work();
|
|
23
|
+
}).then(resolve, reject).finally(() => { running = false; drain(); });
|
|
24
|
+
} });
|
|
25
|
+
drain();
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export const scheduleProbeProcess = createProbeScheduler({});
|
|
30
|
+
//# sourceMappingURL=probe-scheduler.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Mutable runtime data belongs to one host. Compatibility functions use defaultRuntimeState. */
|
|
2
|
+
import type { RuntimeAgentDef, RuntimeCapabilityMap, RuntimeModelOption, DetectedAgent } from './types.js';
|
|
3
|
+
import type { ModelCacheEntry, ModelDiscoveryDeps } from './model-discovery-types.js';
|
|
4
|
+
export interface AgentRuntimeState {
|
|
5
|
+
/** One in-flight or settled complete detection per launch scope until explicit Rescan. */
|
|
6
|
+
readonly detections: Map<string, Promise<DetectedAgent>>;
|
|
7
|
+
readonly capabilities: Map<string, RuntimeCapabilityMap>;
|
|
8
|
+
/** One in-flight or settled `--help` probe per def id + launch path, so a run never re-spawns it. */
|
|
9
|
+
readonly capabilityProbes: Map<string, Promise<void>>;
|
|
10
|
+
readonly liveModelCache: Map<string, Set<string>>;
|
|
11
|
+
readonly liveModelOrder: Map<string, string[]>;
|
|
12
|
+
readonly claudeModels: Map<string, {
|
|
13
|
+
expiresAt: number;
|
|
14
|
+
value: Promise<readonly RuntimeModelOption[] | null>;
|
|
15
|
+
}>;
|
|
16
|
+
discoveryDeps?: ModelDiscoveryDeps;
|
|
17
|
+
readonly modelCatalog: Map<string, ModelCacheEntry>;
|
|
18
|
+
readonly executable: {
|
|
19
|
+
/** Env var names consulted by detection-home/resource-root resolution. Overridable via `configureExecutableResolutionEnv`. */
|
|
20
|
+
envNames: {
|
|
21
|
+
agentHomeEnvVar: string;
|
|
22
|
+
resourceRootEnvVar: string;
|
|
23
|
+
};
|
|
24
|
+
toolchainKey: string | null;
|
|
25
|
+
toolchainDirs: string[] | null;
|
|
26
|
+
toolchainDirsAt: number;
|
|
27
|
+
};
|
|
28
|
+
/** Clear settled caches after host operations finish; retain its configured env names. */
|
|
29
|
+
clear(required: Record<string, never>, optional: Record<string, never>): void;
|
|
30
|
+
}
|
|
31
|
+
/** Independent state, including in-flight probes, for each embedding host.
|
|
32
|
+
* Returns empty owned maps; no I/O. @complexity O(1) initialization; retained data grows with probes. */
|
|
33
|
+
export declare function createAgentRuntimeState(_required: Record<string, never>, _optional?: Record<string, never>): AgentRuntimeState;
|
|
34
|
+
export declare const defaultRuntimeState: AgentRuntimeState;
|
|
35
|
+
/** Bind the agent argument builder to the same capability state detection and launch use.
|
|
36
|
+
* Returns a definition copy without mutating the registry. @complexity O(1). */
|
|
37
|
+
export declare function bindRuntimeAgentDef({ def, state }: {
|
|
38
|
+
def: RuntimeAgentDef;
|
|
39
|
+
state: AgentRuntimeState;
|
|
40
|
+
}, _optional?: Record<string, never>): RuntimeAgentDef;
|
|
41
|
+
//# sourceMappingURL=runtime-state.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Independent state, including in-flight probes, for each embedding host.
|
|
2
|
+
* Returns empty owned maps; no I/O. @complexity O(1) initialization; retained data grows with probes. */
|
|
3
|
+
export function createAgentRuntimeState(_required, _optional = {}) {
|
|
4
|
+
const state = {
|
|
5
|
+
detections: new Map(), capabilities: new Map(), capabilityProbes: new Map(), liveModelCache: new Map(), liveModelOrder: new Map(),
|
|
6
|
+
claudeModels: new Map(), modelCatalog: new Map(),
|
|
7
|
+
executable: { envNames: { agentHomeEnvVar: 'AGENT_RUNTIME_HOME', resourceRootEnvVar: 'AGENT_RUNTIME_RESOURCE_ROOT' }, toolchainKey: null, toolchainDirs: null, toolchainDirsAt: 0 },
|
|
8
|
+
clear() {
|
|
9
|
+
state.detections.clear();
|
|
10
|
+
state.capabilities.clear();
|
|
11
|
+
state.capabilityProbes.clear();
|
|
12
|
+
state.liveModelCache.clear();
|
|
13
|
+
state.liveModelOrder.clear();
|
|
14
|
+
state.claudeModels.clear();
|
|
15
|
+
state.modelCatalog.clear();
|
|
16
|
+
state.executable.toolchainKey = null;
|
|
17
|
+
state.executable.toolchainDirs = null;
|
|
18
|
+
state.executable.toolchainDirsAt = 0;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
return state;
|
|
22
|
+
}
|
|
23
|
+
export const defaultRuntimeState = createAgentRuntimeState({});
|
|
24
|
+
/** Bind the agent argument builder to the same capability state detection and launch use.
|
|
25
|
+
* Returns a definition copy without mutating the registry. @complexity O(1). */
|
|
26
|
+
export function bindRuntimeAgentDef({ def, state }, _optional = {}) {
|
|
27
|
+
return { ...def, buildArgs: (required, optional = {}) => def.buildArgs(required, {
|
|
28
|
+
...optional, options: { ...optional.options, capabilities: state.capabilities.get(def.id) ?? {} },
|
|
29
|
+
}) };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=runtime-state.js.map
|
package/dist/types.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ export type RuntimeReasoningInModelId = {
|
|
|
75
75
|
levels: readonly RuntimeReasoningOption[];
|
|
76
76
|
};
|
|
77
77
|
export type RuntimeBuildOptions = {
|
|
78
|
+
/** Host-scoped capability flags; absent retains the published compatibility cache. */
|
|
79
|
+
capabilities?: RuntimeCapabilityMap;
|
|
78
80
|
model?: string | null;
|
|
79
81
|
reasoning?: string | null;
|
|
80
82
|
permissionMode?: 'bypass' | 'restricted';
|
|
@@ -291,6 +293,8 @@ export type RuntimeAgentDef = Partial<AgentModelDiscoveryPort> & {
|
|
|
291
293
|
runtimeContext?: RuntimeContext;
|
|
292
294
|
}) => string[];
|
|
293
295
|
streamFormat: string;
|
|
296
|
+
/** Reported money spans a session or one run; absent preserves per-run adapter behavior. */
|
|
297
|
+
usageCostBasis?: 'session' | 'run';
|
|
294
298
|
fallbackBins?: string[];
|
|
295
299
|
versionProbeTimeoutMs?: number;
|
|
296
300
|
helpArgs?: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/agent-runtime",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Coding-agent runtime adapters: runtime registry, detection, launch, stream parsers, and the ACP/pi-rpc subprocess transport.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -77,20 +77,25 @@
|
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@vitest/coverage-v8": "^2.1.9",
|
|
79
79
|
"@jini-ai/core": "^0.4.0",
|
|
80
|
-
"@jini-ai/oauth": "^0.2.
|
|
81
|
-
"@jini-ai/
|
|
82
|
-
"@jini-ai/
|
|
80
|
+
"@jini-ai/oauth": "^0.2.2",
|
|
81
|
+
"@jini-ai/integrations": "^0.4.2",
|
|
82
|
+
"@jini-ai/platform": "^0.5.3",
|
|
83
|
+
"@jini-ai/protocol": "^0.4.4"
|
|
83
84
|
},
|
|
84
85
|
"dependencies": {
|
|
85
|
-
"@jini-ai/core": "^0.4.
|
|
86
|
+
"@jini-ai/core": "^0.4.3"
|
|
86
87
|
},
|
|
87
88
|
"peerDependencies": {
|
|
89
|
+
"@jini-ai/integrations": "^0.4.2",
|
|
88
90
|
"@github/copilot-sdk": "*",
|
|
89
|
-
"@jini-ai/oauth": "^0.2.
|
|
90
|
-
"@jini-ai/platform": "^0.5.
|
|
91
|
-
"@jini-ai/protocol": "^0.4.
|
|
91
|
+
"@jini-ai/oauth": "^0.2.2",
|
|
92
|
+
"@jini-ai/platform": "^0.5.3",
|
|
93
|
+
"@jini-ai/protocol": "^0.4.4"
|
|
92
94
|
},
|
|
93
95
|
"peerDependenciesMeta": {
|
|
96
|
+
"@jini-ai/integrations": {
|
|
97
|
+
"optional": true
|
|
98
|
+
},
|
|
94
99
|
"@github/copilot-sdk": {
|
|
95
100
|
"optional": true
|
|
96
101
|
},
|
package/dist/defs/gemini.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export declare const geminiAgentDef: {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
bin: string;
|
|
5
|
-
versionArgs: string[];
|
|
6
|
-
versionProbeTimeoutMs: number;
|
|
7
|
-
helpArgs: string[];
|
|
8
|
-
capabilityFlags: {
|
|
9
|
-
"--skip-trust": string;
|
|
10
|
-
};
|
|
11
|
-
fallbackModels: import("../types.js").RuntimeModelOption[];
|
|
12
|
-
buildArgs: ({ prompt: _prompt, imagePaths: _imagePaths }: {
|
|
13
|
-
prompt: string;
|
|
14
|
-
imagePaths: string[];
|
|
15
|
-
}, { extraAllowedDirs, options }?: {
|
|
16
|
-
extraAllowedDirs?: string[];
|
|
17
|
-
options?: import("../types.js").RuntimeBuildOptions;
|
|
18
|
-
runtimeContext?: import("../types.js").RuntimeContext;
|
|
19
|
-
} | undefined) => string[];
|
|
20
|
-
promptViaStdin: true;
|
|
21
|
-
streamFormat: string;
|
|
22
|
-
eventParser: string;
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=gemini.d.ts.map
|