@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.
Files changed (200) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +34 -17
  3. package/dist/acp-model-probe.d.ts +6 -4
  4. package/dist/acp-model-probe.js +3 -3
  5. package/dist/agent-protocol/acp/account-failure.d.ts +4 -2
  6. package/dist/agent-protocol/acp/account-failure.js +1 -1
  7. package/dist/agent-protocol/acp/json.d.ts +6 -6
  8. package/dist/agent-protocol/acp/json.js +3 -3
  9. package/dist/agent-protocol/acp/models.d.ts +10 -5
  10. package/dist/agent-protocol/acp/models.js +32 -31
  11. package/dist/agent-protocol/acp/session-params.d.ts +3 -1
  12. package/dist/agent-protocol/acp/session-params.js +2 -1
  13. package/dist/agent-protocol/acp/session.d.ts +28 -22
  14. package/dist/agent-protocol/acp/session.js +181 -147
  15. package/dist/agent-protocol/acp/text-suppression.d.ts +1 -1
  16. package/dist/agent-protocol/acp/text-suppression.js +1 -1
  17. package/dist/agent-protocol/acp/types.d.ts +3 -2
  18. package/dist/agent-protocol/acp/updates.d.ts +11 -11
  19. package/dist/agent-protocol/acp/updates.js +2 -2
  20. package/dist/agent-protocol/core/json-line-stream.d.ts +24 -8
  21. package/dist/agent-protocol/core/json-line-stream.js +8 -8
  22. package/dist/agent-protocol/pi-rpc/events.d.ts +5 -1
  23. package/dist/agent-protocol/pi-rpc/events.js +36 -36
  24. package/dist/agent-protocol/pi-rpc/internal.d.ts +4 -1
  25. package/dist/agent-protocol/pi-rpc/models.d.ts +3 -1
  26. package/dist/agent-protocol/pi-rpc/models.js +1 -1
  27. package/dist/agent-protocol/pi-rpc/session.d.ts +1 -1
  28. package/dist/agent-protocol/pi-rpc/session.js +33 -32
  29. package/dist/amr-model-cache.d.ts +12 -4
  30. package/dist/amr-model-cache.js +17 -21
  31. package/dist/amr-profile-resolver.d.ts +3 -1
  32. package/dist/anthropic-live-models.js +0 -0
  33. package/dist/artifact-taxonomy.d.ts +6 -2
  34. package/dist/auth.d.ts +52 -15
  35. package/dist/auth.js +36 -36
  36. package/dist/claude-code-models.js +2 -2
  37. package/dist/claude-stream.d.ts +22 -3
  38. package/dist/claude-stream.js +24 -8
  39. package/dist/copilot-stream.d.ts +7 -3
  40. package/dist/copilot-stream.js +3 -3
  41. package/dist/defs/aider.d.ts +8 -1
  42. package/dist/defs/aider.js +2 -2
  43. package/dist/defs/amp.d.ts +8 -1
  44. package/dist/defs/amp.js +2 -2
  45. package/dist/defs/amr.d.ts +22 -6
  46. package/dist/defs/amr.js +23 -23
  47. package/dist/defs/antigravity.d.ts +15 -4
  48. package/dist/defs/antigravity.js +9 -8
  49. package/dist/defs/auggie.d.ts +4 -1
  50. package/dist/defs/auggie.js +1 -1
  51. package/dist/defs/claude.d.ts +12 -2
  52. package/dist/defs/claude.js +5 -5
  53. package/dist/defs/cline.d.ts +4 -1
  54. package/dist/defs/cline.js +1 -1
  55. package/dist/defs/codebuddy.d.ts +8 -1
  56. package/dist/defs/codebuddy.js +2 -2
  57. package/dist/defs/codex.d.ts +18 -4
  58. package/dist/defs/codex.js +7 -7
  59. package/dist/defs/copilot.d.ts +8 -1
  60. package/dist/defs/copilot.js +2 -2
  61. package/dist/defs/crush.d.ts +8 -1
  62. package/dist/defs/crush.js +1 -1
  63. package/dist/defs/cursor-agent.d.ts +14 -3
  64. package/dist/defs/cursor-agent.js +5 -5
  65. package/dist/defs/deepseek.d.ts +8 -1
  66. package/dist/defs/deepseek.js +2 -2
  67. package/dist/defs/devin.d.ts +12 -2
  68. package/dist/defs/devin.js +3 -3
  69. package/dist/defs/droid.d.ts +8 -1
  70. package/dist/defs/droid.js +1 -1
  71. package/dist/defs/gemini.d.ts +8 -1
  72. package/dist/defs/gemini.js +1 -1
  73. package/dist/defs/goose.d.ts +4 -1
  74. package/dist/defs/goose.js +1 -1
  75. package/dist/defs/grok-build.d.ts +11 -2
  76. package/dist/defs/grok-build.js +3 -3
  77. package/dist/defs/hermes.d.ts +4 -1
  78. package/dist/defs/hermes.js +2 -2
  79. package/dist/defs/kilo.d.ts +4 -1
  80. package/dist/defs/kilo.js +2 -2
  81. package/dist/defs/kimi.d.ts +4 -1
  82. package/dist/defs/kimi.js +2 -2
  83. package/dist/defs/kiro.d.ts +4 -1
  84. package/dist/defs/kiro.js +2 -2
  85. package/dist/defs/mimo.d.ts +8 -1
  86. package/dist/defs/mimo.js +2 -2
  87. package/dist/defs/opencode.d.ts +9 -2
  88. package/dist/defs/opencode.js +2 -2
  89. package/dist/defs/pi.d.ts +12 -2
  90. package/dist/defs/pi.js +9 -9
  91. package/dist/defs/qoder.d.ts +8 -1
  92. package/dist/defs/qoder.js +2 -2
  93. package/dist/defs/qwen.d.ts +8 -1
  94. package/dist/defs/qwen.js +2 -2
  95. package/dist/defs/reasonix.d.ts +4 -1
  96. package/dist/defs/reasonix.js +3 -3
  97. package/dist/defs/shared.d.ts +4 -2
  98. package/dist/defs/shared.js +2 -2
  99. package/dist/defs/trae-cli.d.ts +12 -2
  100. package/dist/defs/trae-cli.js +3 -3
  101. package/dist/defs/vibe.d.ts +4 -1
  102. package/dist/defs/vibe.js +2 -2
  103. package/dist/detection.d.ts +19 -4
  104. package/dist/detection.js +33 -33
  105. package/dist/diagnostics.d.ts +14 -3
  106. package/dist/diagnostics.js +5 -5
  107. package/dist/env.d.ts +16 -4
  108. package/dist/env.js +7 -7
  109. package/dist/executables.d.ts +24 -8
  110. package/dist/executables.js +13 -13
  111. package/dist/index.d.ts +228 -4
  112. package/dist/index.js +230 -6
  113. package/dist/invocation.d.ts +6 -1
  114. package/dist/invocation.js +2 -2
  115. package/dist/json-event-stream.d.ts +7 -2
  116. package/dist/json-event-stream.js +3 -3
  117. package/dist/launch.d.ts +12 -2
  118. package/dist/launch.js +3 -3
  119. package/dist/log-file.d.ts +4 -1
  120. package/dist/log-file.js +2 -2
  121. package/dist/mcp.d.ts +6 -3
  122. package/dist/mcp.js +1 -1
  123. package/dist/metadata.d.ts +7 -3
  124. package/dist/metadata.js +1 -1
  125. package/dist/mmd-routes.d.ts +22 -6
  126. package/dist/mmd-routes.js +14 -14
  127. package/dist/model-catalog-cache.d.ts +50 -0
  128. package/dist/model-catalog-cache.js +61 -0
  129. package/dist/model-loading-state.d.ts +10 -0
  130. package/dist/model-loading-state.js +23 -0
  131. package/dist/model-registry.d.ts +28 -7
  132. package/dist/model-registry.js +11 -8
  133. package/dist/models.d.ts +31 -6
  134. package/dist/models.js +6 -6
  135. package/dist/opencode-log.d.ts +12 -4
  136. package/dist/opencode-log.js +8 -8
  137. package/dist/paths.d.ts +6 -2
  138. package/dist/paths.js +3 -3
  139. package/dist/pi-models.d.ts +3 -1
  140. package/dist/pi-models.js +2 -2
  141. package/dist/prompt-budget.d.ts +17 -4
  142. package/dist/prompt-budget.js +3 -3
  143. package/dist/prompt-file.d.ts +5 -1
  144. package/dist/prompt-file.js +1 -1
  145. package/dist/providers/aihubmix.d.ts +34 -9
  146. package/dist/providers/aihubmix.js +26 -26
  147. package/dist/providers/anthropic-messages.d.ts +77 -20
  148. package/dist/providers/anthropic-messages.js +53 -50
  149. package/dist/providers/azure-chat.d.ts +21 -7
  150. package/dist/providers/azure-chat.js +18 -16
  151. package/dist/providers/connection-guard.d.ts +45 -31
  152. package/dist/providers/connection-guard.js +40 -143
  153. package/dist/providers/connection-test.d.ts +1 -1
  154. package/dist/providers/connection-test.js +13 -30
  155. package/dist/providers/elevenlabs.d.ts +7 -2
  156. package/dist/providers/elevenlabs.js +4 -4
  157. package/dist/providers/google-messages.d.ts +44 -10
  158. package/dist/providers/google-messages.js +36 -34
  159. package/dist/providers/google-schema.d.ts +26 -0
  160. package/dist/providers/google-schema.js +253 -0
  161. package/dist/providers/google.d.ts +21 -6
  162. package/dist/providers/google.js +10 -10
  163. package/dist/providers/index.d.ts +3 -2
  164. package/dist/providers/index.js +3 -2
  165. package/dist/providers/model-catalog.d.ts +1 -1
  166. package/dist/providers/model-catalog.js +14 -27
  167. package/dist/providers/oauth-callback-server.d.ts +1 -1
  168. package/dist/providers/oauth-callback-server.js +3 -2
  169. package/dist/providers/oauth-credentials.d.ts +7 -1
  170. package/dist/providers/oauth-credentials.js +5 -5
  171. package/dist/providers/oauth-provider.d.ts +2 -2
  172. package/dist/providers/oauth-provider.js +20 -25
  173. package/dist/providers/oauth-tokens.d.ts +26 -6
  174. package/dist/providers/oauth-tokens.js +9 -9
  175. package/dist/providers/ollama-chat.d.ts +66 -31
  176. package/dist/providers/ollama-chat.js +64 -61
  177. package/dist/providers/openai-chat.d.ts +77 -22
  178. package/dist/providers/openai-chat.js +71 -67
  179. package/dist/providers/pkce.d.ts +33 -20
  180. package/dist/providers/pkce.js +75 -146
  181. package/dist/providers/sse-decode.d.ts +3 -1
  182. package/dist/providers/sse-decode.js +1 -1
  183. package/dist/providers/token-params.d.ts +16 -5
  184. package/dist/providers/token-params.js +6 -6
  185. package/dist/providers/tool-turn-types.d.ts +89 -0
  186. package/dist/providers/tool-turn-types.js +2 -0
  187. package/dist/providers/tool-turn.d.ts +10 -0
  188. package/dist/providers/tool-turn.js +252 -0
  189. package/dist/qoder-stream.d.ts +7 -3
  190. package/dist/qoder-stream.js +3 -3
  191. package/dist/registry.d.ts +6 -2
  192. package/dist/registry.js +4 -4
  193. package/dist/resolution.d.ts +5 -1
  194. package/dist/resolution.js +3 -3
  195. package/dist/role-marker-guard.d.ts +9 -5
  196. package/dist/role-marker-guard.js +5 -5
  197. package/dist/terminal-launch.d.ts +6 -1
  198. package/dist/terminal-launch.js +2 -2
  199. package/dist/types.d.ts +22 -6
  200. package/package.json +43 -4
@@ -39,7 +39,7 @@ function stringifyContent(value) {
39
39
  // `JSON.parse`, the same "keep the defensive branch, document it, don't
40
40
  // force a test around impossible data" call `@jini-ai/cli`'s
41
41
  // `defaultReadFile`'s `finish()` guard made on 2026-07-22 — see
42
- // `source-map.md`'s 2026-07-22 entry for the full re-derivation.
42
+ // `archived provenance ledger`'s 2026-07-22 entry for the full re-derivation.
43
43
  return String(value);
44
44
  }
45
45
  }
@@ -860,7 +860,7 @@ function handleCodexEvent(obj, onEvent, state) {
860
860
  }
861
861
  return false;
862
862
  }
863
- export function createJsonEventStreamHandler(kind, onEvent) {
863
+ export function createJsonEventStreamHandler({ kind, onEvent }) {
864
864
  let buffer = '';
865
865
  const state = {
866
866
  cursorTextSoFar: '',
@@ -896,7 +896,7 @@ export function createJsonEventStreamHandler(kind, onEvent) {
896
896
  return;
897
897
  onEvent({ type: 'raw', line });
898
898
  }
899
- function feed(chunk) {
899
+ function feed({ chunk }) {
900
900
  buffer += chunk;
901
901
  let nl;
902
902
  while ((nl = buffer.indexOf('\n')) !== -1) {
package/dist/launch.d.ts CHANGED
@@ -7,6 +7,16 @@ export type AgentLaunchResolution = ReturnType<typeof inspectAgentExecutableReso
7
7
  childPathPrepend: string[];
8
8
  diagnostic: string | null;
9
9
  };
10
- export declare function resolveAgentLaunch(def: RuntimeAgentDef, configuredEnv?: Record<string, string>): AgentLaunchResolution;
11
- export declare function applyAgentLaunchEnv(env: NodeJS.ProcessEnv, launch: Pick<AgentLaunchResolution, 'childPathPrepend'>, nodeBinDir?: string, appendPathDirs?: string[]): NodeJS.ProcessEnv;
10
+ export declare function resolveAgentLaunch({ def }: {
11
+ def: RuntimeAgentDef;
12
+ }, { configuredEnv }?: {
13
+ configuredEnv?: Record<string, string>;
14
+ }): AgentLaunchResolution;
15
+ export declare function applyAgentLaunchEnv({ env, launch }: {
16
+ env: NodeJS.ProcessEnv;
17
+ launch: Pick<AgentLaunchResolution, 'childPathPrepend'>;
18
+ }, { nodeBinDir, appendPathDirs }?: {
19
+ nodeBinDir?: string;
20
+ appendPathDirs?: string[];
21
+ }): NodeJS.ProcessEnv;
12
22
  //# sourceMappingURL=launch.d.ts.map
package/dist/launch.js CHANGED
@@ -9,8 +9,8 @@
9
9
  import { accessSync, closeSync, constants, openSync, readdirSync, readSync, realpathSync, statSync } from 'node:fs';
10
10
  import path, { delimiter } from 'node:path';
11
11
  import { inspectAgentExecutableResolution, userToolchainBinDirs } from './executables.js';
12
- export function resolveAgentLaunch(def, configuredEnv = {}) {
13
- const resolution = inspectAgentExecutableResolution(def, configuredEnv);
12
+ export function resolveAgentLaunch({ def }, { configuredEnv = {} } = {}) {
13
+ const resolution = inspectAgentExecutableResolution({ def: def }, { configuredEnv: configuredEnv });
14
14
  if (!resolution.selectedPath) {
15
15
  return { ...resolution, launchPath: null, launchKind: 'selected', childPathPrepend: [], diagnostic: null };
16
16
  }
@@ -29,7 +29,7 @@ export function resolveAgentLaunch(def, configuredEnv = {}) {
29
29
  diagnostic: native.diagnostic,
30
30
  };
31
31
  }
32
- export function applyAgentLaunchEnv(env, launch, nodeBinDir = path.dirname(process.execPath), appendPathDirs = userToolchainBinDirs()) {
32
+ export function applyAgentLaunchEnv({ env, launch }, { nodeBinDir = path.dirname(process.execPath), appendPathDirs = userToolchainBinDirs() } = {}) {
33
33
  // Build the ordered list of directories to guarantee are at the front of
34
34
  // PATH: the running Node binary directory first (so npm .cmd shims on
35
35
  // Windows that invoke bare "node" find the correct binary even when the
@@ -19,5 +19,8 @@ export type PreparedAgentLogFile = {
19
19
  * @complexity One `mkdtemp` syscall; `null` return path does no I/O at all.
20
20
  * @overallScore 100/100
21
21
  */
22
- export declare function prepareAgentLogFile(def: RuntimeAgentDef | null | undefined, label: string): Promise<PreparedAgentLogFile | null>;
22
+ export declare function prepareAgentLogFile({ def, label }: {
23
+ def: RuntimeAgentDef | null | undefined;
24
+ label: string;
25
+ }): Promise<PreparedAgentLogFile | null>;
23
26
  //# sourceMappingURL=log-file.d.ts.map
package/dist/log-file.js CHANGED
@@ -21,7 +21,7 @@
21
21
  * No OD provenance: OD's daemon derived antigravity's `--log-file` path
22
22
  * inline in `server.ts` rather than through a reusable helper. Extracted as
23
23
  * one here so the staging is testable on its own and so a second adapter with
24
- * a log-file flag needs no new code — see `source-map.md`.
24
+ * a log-file flag needs no new code — see `archived provenance ledger`.
25
25
  */
26
26
  import { promises as fs } from 'node:fs';
27
27
  import os from 'node:os';
@@ -40,7 +40,7 @@ import path from 'node:path';
40
40
  * @complexity One `mkdtemp` syscall; `null` return path does no I/O at all.
41
41
  * @overallScore 100/100
42
42
  */
43
- export async function prepareAgentLogFile(def, label) {
43
+ export async function prepareAgentLogFile({ def, label }) {
44
44
  if (!def?.needsAgentLogFile)
45
45
  return null;
46
46
  const safeLabel = label.replace(/[^a-zA-Z0-9_.-]/g, '-').slice(0, 80) || 'agent';
package/dist/mcp.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * function was hardwired to inject exactly one product feature — a
10
10
  * specifically-named, specifically-branded MCP server spawned via that
11
11
  * product's own CLI binary, with a fixed args tail baked in (see
12
- * `source-map.md` for the exact literal). That's a specific product's MCP
12
+ * `archived provenance ledger` for the exact literal). That's a specific product's MCP
13
13
  * tool, not a generic runtime concern, so it is not ported. What genuinely
14
14
  * is generic — and is kept
15
15
  * here — is the *gating + env-shape* mechanism: only attach a server when
@@ -17,7 +17,7 @@
17
17
  * field as an array (`[{name, value}]`) or a map (`{KEY: value}`) per
18
18
  * `def.acpMcpEnvFormat`, since different ACP implementations expect
19
19
  * different shapes there. The host application supplies the actual server
20
- * name/command/args. See `source-map.md`.
20
+ * name/command/args. See `archived provenance ledger`.
21
21
  */
22
22
  import type { RuntimeAgentDef } from './types.js';
23
23
  export type AcpMcpServerSpec = {
@@ -40,5 +40,8 @@ export type AcpMcpServerEntry = {
40
40
  value: string;
41
41
  }>;
42
42
  };
43
- export declare function buildAcpMcpServersForAgent(def: Pick<RuntimeAgentDef, 'mcpDiscovery' | 'acpMcpEnvFormat'>, spec: AcpMcpServerSpec): AcpMcpServerEntry[];
43
+ export declare function buildAcpMcpServersForAgent({ def, spec }: {
44
+ def: Pick<RuntimeAgentDef, 'mcpDiscovery' | 'acpMcpEnvFormat'>;
45
+ spec: AcpMcpServerSpec;
46
+ }): AcpMcpServerEntry[];
44
47
  //# sourceMappingURL=mcp.d.ts.map
package/dist/mcp.js CHANGED
@@ -1,4 +1,4 @@
1
- export function buildAcpMcpServersForAgent(def, spec) {
1
+ export function buildAcpMcpServersForAgent({ def, spec }) {
2
2
  const { name, command, args = [], extraEnv = {}, enabled = true } = spec;
3
3
  if (!enabled || def?.mcpDiscovery !== 'mature-acp')
4
4
  return [];
@@ -10,9 +10,9 @@
10
10
  * drops the three OD-self-referential entries the origin had for `amr`,
11
11
  * `pi`, and `hermes` (an install URL and two docs URLs that pointed at
12
12
  * OD's own site/fork rather than at the third-party CLI vendor — see
13
- * `source-map.md` for the exact original URLs), so they don't belong in a
13
+ * `archived provenance ledger` for the exact original URLs), so they don't belong in a
14
14
  * product-neutral default. Every other agent's real third-party vendor
15
- * link is unchanged. See `source-map.md`.
15
+ * link is unchanged. See `archived provenance ledger`.
16
16
  */
17
17
  export type AgentInstallMeta = {
18
18
  installUrl?: string;
@@ -20,5 +20,9 @@ export type AgentInstallMeta = {
20
20
  };
21
21
  /** HTTPS links for a Settings-shaped UI when an agent is unavailable. Keys match `RuntimeAgentDef.id`. */
22
22
  export declare const DEFAULT_AGENT_INSTALL_LINKS: Record<string, AgentInstallMeta>;
23
- export declare function installMetaForAgent(agentId: string, table?: Record<string, AgentInstallMeta>): AgentInstallMeta;
23
+ export declare function installMetaForAgent({ agentId }: {
24
+ agentId: string;
25
+ }, { table }?: {
26
+ table?: Record<string, AgentInstallMeta>;
27
+ }): AgentInstallMeta;
24
28
  //# sourceMappingURL=metadata.d.ts.map
package/dist/metadata.js CHANGED
@@ -110,7 +110,7 @@ function sanitizeHttpsUrl(value) {
110
110
  return undefined;
111
111
  }
112
112
  }
113
- export function installMetaForAgent(agentId, table = DEFAULT_AGENT_INSTALL_LINKS) {
113
+ export function installMetaForAgent({ agentId }, { table = DEFAULT_AGENT_INSTALL_LINKS } = {}) {
114
114
  const meta = table[agentId];
115
115
  if (!meta)
116
116
  return {};
@@ -3,10 +3,26 @@ export type MmdRouteLaunchEnv = {
3
3
  ANTHROPIC_BASE_URL: string;
4
4
  ANTHROPIC_AUTH_TOKEN?: string;
5
5
  };
6
- export declare function resolveMmdRoutesFile(env: RuntimeEnv): string | null;
7
- export declare function parseMmdRouteModelIds(raw: unknown): string[];
8
- export declare function resolveMmdRouteLaunchEnv(raw: unknown, modelId: string | null | undefined): MmdRouteLaunchEnv | null;
9
- export declare function mergeMmdRouteModels(routeIds: readonly string[], fallbackModels: readonly RuntimeModelOption[]): RuntimeModelOption[];
10
- export declare function loadMmdRouteModels(env: RuntimeEnv, fallbackModels: readonly RuntimeModelOption[]): Promise<RuntimeModelOption[] | null>;
11
- export declare function loadMmdRouteLaunchEnv(env: RuntimeEnv, modelId: string | null | undefined): Promise<MmdRouteLaunchEnv | null>;
6
+ export declare function resolveMmdRoutesFile({ env }: {
7
+ env: RuntimeEnv;
8
+ }): string | null;
9
+ export declare function parseMmdRouteModelIds({ raw }: {
10
+ raw: unknown;
11
+ }): string[];
12
+ export declare function resolveMmdRouteLaunchEnv({ raw, modelId }: {
13
+ raw: unknown;
14
+ modelId: string | null | undefined;
15
+ }): MmdRouteLaunchEnv | null;
16
+ export declare function mergeMmdRouteModels({ routeIds, fallbackModels }: {
17
+ routeIds: readonly string[];
18
+ fallbackModels: readonly RuntimeModelOption[];
19
+ }): RuntimeModelOption[];
20
+ export declare function loadMmdRouteModels({ env, fallbackModels }: {
21
+ env: RuntimeEnv;
22
+ fallbackModels: readonly RuntimeModelOption[];
23
+ }): Promise<RuntimeModelOption[] | null>;
24
+ export declare function loadMmdRouteLaunchEnv({ env, modelId }: {
25
+ env: RuntimeEnv;
26
+ modelId: string | null | undefined;
27
+ }): Promise<MmdRouteLaunchEnv | null>;
12
28
  //# sourceMappingURL=mmd-routes.d.ts.map
@@ -32,7 +32,7 @@ function expandRoutesFileOverride(raw, env) {
32
32
  }
33
33
  return raw;
34
34
  }
35
- export function resolveMmdRoutesFile(env) {
35
+ export function resolveMmdRoutesFile({ env }) {
36
36
  const override = stringEnv(env, MMD_MODEL_ROUTES_FILE_ENV);
37
37
  if (override)
38
38
  return expandRoutesFileOverride(override, env);
@@ -44,13 +44,13 @@ export function resolveMmdRoutesFile(env) {
44
44
  function isRecord(value) {
45
45
  return typeof value === 'object' && value !== null && !Array.isArray(value);
46
46
  }
47
- export function parseMmdRouteModelIds(raw) {
47
+ export function parseMmdRouteModelIds({ raw }) {
48
48
  if (!isRecord(raw) || !isRecord(raw.routes))
49
49
  return [];
50
50
  const seen = new Set();
51
51
  const ids = [];
52
52
  for (const rawId of Object.keys(raw.routes)) {
53
- const id = sanitizeCustomModel(rawId);
53
+ const id = sanitizeCustomModel({ id: rawId });
54
54
  if (!id || seen.has(id))
55
55
  continue;
56
56
  seen.add(id);
@@ -58,8 +58,8 @@ export function parseMmdRouteModelIds(raw) {
58
58
  }
59
59
  return ids;
60
60
  }
61
- export function resolveMmdRouteLaunchEnv(raw, modelId) {
62
- const id = sanitizeCustomModel(modelId);
61
+ export function resolveMmdRouteLaunchEnv({ raw, modelId }) {
62
+ const id = sanitizeCustomModel({ id: modelId });
63
63
  if (!id || !isRecord(raw) || !isRecord(raw.routes))
64
64
  return null;
65
65
  const route = raw.routes[id];
@@ -79,7 +79,7 @@ export function resolveMmdRouteLaunchEnv(raw, modelId) {
79
79
  };
80
80
  }
81
81
  function addModel(out, seen, option) {
82
- const id = sanitizeCustomModel(option.id);
82
+ const id = sanitizeCustomModel({ id: option.id });
83
83
  if (!id || seen.has(id))
84
84
  return;
85
85
  seen.add(id);
@@ -88,7 +88,7 @@ function addModel(out, seen, option) {
88
88
  : id;
89
89
  out.push({ id, label });
90
90
  }
91
- export function mergeMmdRouteModels(routeIds, fallbackModels) {
91
+ export function mergeMmdRouteModels({ routeIds, fallbackModels }) {
92
92
  const out = [];
93
93
  const seen = new Set();
94
94
  addModel(out, seen, DEFAULT_MODEL_OPTION);
@@ -100,8 +100,8 @@ export function mergeMmdRouteModels(routeIds, fallbackModels) {
100
100
  }
101
101
  return out;
102
102
  }
103
- export async function loadMmdRouteModels(env, fallbackModels) {
104
- const routesFile = resolveMmdRoutesFile(env);
103
+ export async function loadMmdRouteModels({ env, fallbackModels }) {
104
+ const routesFile = resolveMmdRoutesFile({ env: env });
105
105
  if (!routesFile)
106
106
  return null;
107
107
  let text;
@@ -118,13 +118,13 @@ export async function loadMmdRouteModels(env, fallbackModels) {
118
118
  catch {
119
119
  return null;
120
120
  }
121
- const routeIds = parseMmdRouteModelIds(parsed);
121
+ const routeIds = parseMmdRouteModelIds({ raw: parsed });
122
122
  if (routeIds.length === 0)
123
123
  return null;
124
- return mergeMmdRouteModels(routeIds, fallbackModels);
124
+ return mergeMmdRouteModels({ routeIds: routeIds, fallbackModels: fallbackModels });
125
125
  }
126
- export async function loadMmdRouteLaunchEnv(env, modelId) {
127
- const routesFile = resolveMmdRoutesFile(env);
126
+ export async function loadMmdRouteLaunchEnv({ env, modelId }) {
127
+ const routesFile = resolveMmdRoutesFile({ env: env });
128
128
  if (!routesFile)
129
129
  return null;
130
130
  let text;
@@ -141,6 +141,6 @@ export async function loadMmdRouteLaunchEnv(env, modelId) {
141
141
  catch {
142
142
  return null;
143
143
  }
144
- return resolveMmdRouteLaunchEnv(parsed, modelId);
144
+ return resolveMmdRouteLaunchEnv({ raw: parsed, modelId: modelId });
145
145
  }
146
146
  //# sourceMappingURL=mmd-routes.js.map
@@ -0,0 +1,50 @@
1
+ import type { Clock } from '@jini-ai/core/primitives';
2
+ /** Components are encoded as a JSON tuple; delimiter characters cannot alias another tenant's key. Hosts include all credential/provider scopes affecting discovery. */
3
+ export type ModelCatalogCacheKey = readonly string[];
4
+ export type ModelDiscovery<Model> = (input: {
5
+ cacheKey: ModelCatalogCacheKey;
6
+ }) => Promise<readonly Model[] | null>;
7
+ export type ModelMerger<Model> = (input: {
8
+ fallback: readonly Model[];
9
+ live: readonly Model[];
10
+ }) => readonly Model[];
11
+ export interface ModelCatalogCacheDependencies<Model> {
12
+ readonly discover: ModelDiscovery<Model>;
13
+ readonly clock: Clock;
14
+ readonly merge: ModelMerger<Model>;
15
+ }
16
+ export interface ModelCatalogCacheOptions {
17
+ readonly ttlMs?: number;
18
+ /** Called once per failed discovery, after fallback state is recorded. */
19
+ readonly onDiscoveryError?: (input: {
20
+ error: unknown;
21
+ cacheKey: ModelCatalogCacheKey;
22
+ }) => void;
23
+ }
24
+ /** Per-call discovery can close over a credential the host has already resolved. */
25
+ export interface ModelCatalogReadOptions<Model> {
26
+ readonly discover?: ModelDiscovery<Model>;
27
+ }
28
+ /** Blocking live-discovery enrichment backed by the same single-flight loader as the legacy model cache. Successes and failures share the TTL; the host resolves credentials before calling get. */
29
+ export declare class ModelCatalogCache<Model> {
30
+ private readonly required;
31
+ private readonly optional;
32
+ private readonly states;
33
+ private readonly ttlMs;
34
+ constructor(required: ModelCatalogCacheDependencies<Model>, optional?: ModelCatalogCacheOptions);
35
+ /** Returns the current fallback merged with cached live data, awaiting at most one discovery per key.
36
+ * Local key work is proportional to the key's encoded length; discovery and merge cost belongs to the host ports. State retains one entry per distinct key until this instance is discarded.
37
+ */
38
+ get({ cacheKey, fallback }: {
39
+ cacheKey: ModelCatalogCacheKey;
40
+ fallback: readonly Model[];
41
+ }, options?: ModelCatalogReadOptions<Model>): Promise<readonly Model[]>;
42
+ }
43
+ /** Keeps every fallback entry and its metadata in order, then appends each unseen live ID once. Neither input list is mutated. Time and space are O(fallback.length + live.length). */
44
+ export declare function unionModels<Model extends {
45
+ readonly id: string;
46
+ }>({ fallback, live }: {
47
+ fallback: readonly Model[];
48
+ live: readonly Model[];
49
+ }): Model[];
50
+ //# sourceMappingURL=model-catalog-cache.d.ts.map
@@ -0,0 +1,61 @@
1
+ import { coalesceModelLoad } from './model-loading-state.js';
2
+ /** Blocking live-discovery enrichment backed by the same single-flight loader as the legacy model cache. Successes and failures share the TTL; the host resolves credentials before calling get. */
3
+ export class ModelCatalogCache {
4
+ required;
5
+ optional;
6
+ states = new Map();
7
+ ttlMs;
8
+ constructor(required, optional = {}) {
9
+ this.required = required;
10
+ this.optional = optional;
11
+ this.ttlMs = optional.ttlMs ?? 5 * 60_000;
12
+ if (!Number.isFinite(this.ttlMs) || this.ttlMs < 0)
13
+ throw new RangeError('ttlMs must be finite and non-negative');
14
+ }
15
+ /** Returns the current fallback merged with cached live data, awaiting at most one discovery per key.
16
+ * Local key work is proportional to the key's encoded length; discovery and merge cost belongs to the host ports. State retains one entry per distinct key until this instance is discarded.
17
+ */
18
+ async get({ cacheKey, fallback }, options = {}) {
19
+ const key = JSON.stringify(cacheKey);
20
+ let state = this.states.get(key);
21
+ if (!state) {
22
+ state = { inFlight: null, expiresAt: -Infinity, live: null };
23
+ this.states.set(key, state);
24
+ }
25
+ if (state.inFlight) {
26
+ await state.inFlight;
27
+ }
28
+ else if (state.expiresAt <= this.required.clock.nowMs()) {
29
+ state.expiresAt = this.required.clock.nowMs() + this.ttlMs;
30
+ const current = state;
31
+ const discover = options.discover ?? this.required.discover;
32
+ // Snapshot the key before crossing the asynchronous discovery boundary.
33
+ const scopedKey = [...cacheKey];
34
+ await coalesceModelLoad({
35
+ state: current, load: async () => {
36
+ try {
37
+ current.live = await discover({ cacheKey: scopedKey });
38
+ }
39
+ catch (error) {
40
+ current.live = null;
41
+ this.optional.onDiscoveryError?.({ error, cacheKey: scopedKey });
42
+ }
43
+ }
44
+ });
45
+ }
46
+ return this.required.merge({ fallback, live: state.live ?? [] });
47
+ }
48
+ }
49
+ /** Keeps every fallback entry and its metadata in order, then appends each unseen live ID once. Neither input list is mutated. Time and space are O(fallback.length + live.length). */
50
+ export function unionModels({ fallback, live }) {
51
+ const seen = new Set(fallback.map(model => model.id));
52
+ const merged = [...fallback];
53
+ for (const model of live) {
54
+ if (seen.has(model.id))
55
+ continue;
56
+ seen.add(model.id);
57
+ merged.push(model);
58
+ }
59
+ return merged;
60
+ }
61
+ //# sourceMappingURL=model-catalog-cache.js.map
@@ -0,0 +1,10 @@
1
+ /** Mutable state owned by one cache instance and one key. */
2
+ export interface ModelLoadingState {
3
+ inFlight: Promise<void> | null;
4
+ }
5
+ /** Shares one load until it settles. Install the promise before invoking the collaborator so a synchronous completion cannot leave a stuck in-flight entry. The load callback owns error policy; an uncaught load error rejects the shared promise. Local work and space are O(1). */
6
+ export declare function coalesceModelLoad({ state, load }: {
7
+ state: ModelLoadingState;
8
+ load: () => Promise<void>;
9
+ }): Promise<void>;
10
+ //# sourceMappingURL=model-loading-state.d.ts.map
@@ -0,0 +1,23 @@
1
+ /** Shares one load until it settles. Install the promise before invoking the collaborator so a synchronous completion cannot leave a stuck in-flight entry. The load callback owns error policy; an uncaught load error rejects the shared promise. Local work and space are O(1). */
2
+ export function coalesceModelLoad({ state, load }) {
3
+ if (state.inFlight)
4
+ return state.inFlight;
5
+ let finish;
6
+ let fail;
7
+ const pending = new Promise((resolve, reject) => { finish = resolve; fail = reject; });
8
+ state.inFlight = pending;
9
+ void (async () => {
10
+ try {
11
+ await load();
12
+ finish();
13
+ }
14
+ catch (error) {
15
+ fail(error);
16
+ }
17
+ finally {
18
+ state.inFlight = null;
19
+ }
20
+ })();
21
+ return pending;
22
+ }
23
+ //# sourceMappingURL=model-loading-state.js.map
@@ -14,7 +14,7 @@
14
14
  * `packages/contracts/src/api/app-config.ts` (`AgentModelPrefs`),
15
15
  * `apps/web/src/components/providerModelsCache.ts`, and
16
16
  * `apps/web/src/components/agentModelSelection.ts` — see
17
- * `packages/agent-runtime/source-map.md` for the full per-symbol mapping.
17
+ * `packages/agent-runtime/archived provenance ledger` for the full per-symbol mapping.
18
18
  * No OD product-identity strings or OD-specific gating (e.g. the original's
19
19
  * hardcoded `agent.id === 'amr'` carve-out) survived the port.
20
20
  *
@@ -47,32 +47,53 @@ export interface AgentModelChoice {
47
47
  * doesn't require credentials is always `available`; otherwise the status
48
48
  * depends on whether a credential has actually been stored.
49
49
  */
50
- export declare function resolveCredentialStatus(provider: Pick<ModelProvider, 'credentialsRequired'>, hasStoredCredential: boolean): CredentialStatus;
50
+ export declare function resolveCredentialStatus({ provider, hasStoredCredential }: {
51
+ provider: Pick<ModelProvider, 'credentialsRequired'>;
52
+ hasStoredCredential: boolean;
53
+ }): CredentialStatus;
51
54
  /**
52
55
  * Merges a live-fetched model list with a static suggestion list, keeping
53
56
  * fetched entries first and deduping by id (first write wins). Blank ids are
54
57
  * dropped; blank labels fall back to the id.
55
58
  */
56
- export declare function mergeModelOptions(fetchedModels: readonly ModelCatalogOption[], suggestedModels: readonly ModelCatalogOption[]): ModelCatalogOption[];
59
+ export declare function mergeModelOptions({ fetchedModels, suggestedModels }: {
60
+ fetchedModels: readonly ModelCatalogOption[];
61
+ suggestedModels: readonly ModelCatalogOption[];
62
+ }): ModelCatalogOption[];
57
63
  /** Deterministic, non-reversible fingerprint — never persist or transmit the raw credential. */
58
- export declare function fingerprintCredential(value: string): string;
64
+ export declare function fingerprintCredential({ value }: {
65
+ value: string;
66
+ }): string;
59
67
  /**
60
68
  * A stable key for caching a fetched model catalogue, scoped to the
61
69
  * provider, endpoint, and credential in use — so switching any one of them
62
70
  * misses the cache instead of silently reusing another provider's list.
63
71
  * `variant` covers protocols that key on more than credential + endpoint
64
72
  * (e.g. an API version).
73
+ * @throws {TypeError} When a supplied variant is not a string.
65
74
  */
66
- export declare function modelCatalogCacheKey(providerId: string, baseUrl: string, credential: string, variant?: string): string;
75
+ export declare function modelCatalogCacheKey({ providerId, baseUrl, credential }: {
76
+ providerId: string;
77
+ baseUrl: string;
78
+ credential: string;
79
+ }, { variant }?: {
80
+ variant?: unknown;
81
+ }): string;
67
82
  /**
68
83
  * If `choice` names a model no longer in the agent's current catalogue,
69
84
  * falls back to the agent's first available model. Returns `null` when no
70
85
  * normalization is needed (nothing to change) or possible (no configured
71
86
  * model, or the agent has no models to fall back to).
72
87
  */
73
- export declare function normalizeAgentModelChoice(agent: Pick<AgentDefinition, 'models'> | null | undefined, choice: AgentModelChoice | undefined): AgentModelChoice | null;
88
+ export declare function normalizeAgentModelChoice({ agent, choice }: {
89
+ agent: Pick<AgentDefinition, 'models'> | null | undefined;
90
+ choice: AgentModelChoice | undefined;
91
+ }): AgentModelChoice | null;
74
92
  /** `normalizeAgentModelChoice`'s result if normalization applied, else the original choice. */
75
- export declare function effectiveAgentModelChoice(agent: Pick<AgentDefinition, 'models'> | null | undefined, choice: AgentModelChoice | undefined): AgentModelChoice | undefined;
93
+ export declare function effectiveAgentModelChoice({ agent, choice }: {
94
+ agent: Pick<AgentDefinition, 'models'> | null | undefined;
95
+ choice: AgentModelChoice | undefined;
96
+ }): AgentModelChoice | undefined;
76
97
  /**
77
98
  * Model/provider/agent catalogue vocabulary. Moved to `@jini-ai/protocol` on 2026-07-29 (see that
78
99
  * package's `agent-catalog.ts`) so a browser package can consume it without depending on this
@@ -3,7 +3,7 @@
3
3
  * doesn't require credentials is always `available`; otherwise the status
4
4
  * depends on whether a credential has actually been stored.
5
5
  */
6
- export function resolveCredentialStatus(provider, hasStoredCredential) {
6
+ export function resolveCredentialStatus({ provider, hasStoredCredential }) {
7
7
  if (provider.credentialsRequired === false)
8
8
  return 'available';
9
9
  return hasStoredCredential ? 'configured' : 'unconfigured';
@@ -13,7 +13,7 @@ export function resolveCredentialStatus(provider, hasStoredCredential) {
13
13
  * fetched entries first and deduping by id (first write wins). Blank ids are
14
14
  * dropped; blank labels fall back to the id.
15
15
  */
16
- export function mergeModelOptions(fetchedModels, suggestedModels) {
16
+ export function mergeModelOptions({ fetchedModels, suggestedModels }) {
17
17
  const seen = new Set();
18
18
  const merged = [];
19
19
  const add = (model) => {
@@ -30,7 +30,7 @@ export function mergeModelOptions(fetchedModels, suggestedModels) {
30
30
  return merged;
31
31
  }
32
32
  /** Deterministic, non-reversible fingerprint — never persist or transmit the raw credential. */
33
- export function fingerprintCredential(value) {
33
+ export function fingerprintCredential({ value }) {
34
34
  let hash = 0x811c9dc5;
35
35
  for (let i = 0; i < value.length; i += 1) {
36
36
  hash ^= value.charCodeAt(i);
@@ -44,12 +44,15 @@ export function fingerprintCredential(value) {
44
44
  * misses the cache instead of silently reusing another provider's list.
45
45
  * `variant` covers protocols that key on more than credential + endpoint
46
46
  * (e.g. an API version).
47
+ * @throws {TypeError} When a supplied variant is not a string.
47
48
  */
48
- export function modelCatalogCacheKey(providerId, baseUrl, credential, variant = '') {
49
+ export function modelCatalogCacheKey({ providerId, baseUrl, credential }, { variant = '' } = {}) {
50
+ if (typeof variant !== 'string')
51
+ throw new TypeError('Model catalog variant must be a string');
49
52
  return [
50
53
  providerId,
51
54
  baseUrl.trim().replace(/\/+$/, ''),
52
- fingerprintCredential(credential.trim()),
55
+ fingerprintCredential({ value: credential.trim() }),
53
56
  variant.trim(),
54
57
  ].join('\n');
55
58
  }
@@ -59,7 +62,7 @@ export function modelCatalogCacheKey(providerId, baseUrl, credential, variant =
59
62
  * normalization is needed (nothing to change) or possible (no configured
60
63
  * model, or the agent has no models to fall back to).
61
64
  */
62
- export function normalizeAgentModelChoice(agent, choice) {
65
+ export function normalizeAgentModelChoice({ agent, choice }) {
63
66
  const configuredModel = typeof choice?.model === 'string' && choice.model ? choice.model : null;
64
67
  if (!configuredModel)
65
68
  return null;
@@ -71,7 +74,7 @@ export function normalizeAgentModelChoice(agent, choice) {
71
74
  return { ...choice, model: modelIds[0] };
72
75
  }
73
76
  /** `normalizeAgentModelChoice`'s result if normalization applied, else the original choice. */
74
- export function effectiveAgentModelChoice(agent, choice) {
75
- return normalizeAgentModelChoice(agent, choice) ?? choice;
77
+ export function effectiveAgentModelChoice({ agent, choice }) {
78
+ return normalizeAgentModelChoice({ agent: agent, choice: choice }) ?? choice;
76
79
  }
77
80
  //# sourceMappingURL=model-registry.js.map
package/dist/models.d.ts CHANGED
@@ -7,10 +7,35 @@
7
7
  */
8
8
  import type { RuntimeAgentDef, RuntimeModelOption } from './types.js';
9
9
  export declare const DEFAULT_MODEL_OPTION: RuntimeModelOption;
10
- export declare function rememberLiveModels(agentId: string, models: RuntimeModelOption[], scope?: string | null): void;
11
- export declare function getRememberedLiveModels(agentId: string, scope?: string | null): RuntimeModelOption[];
12
- export declare function preferFreshLiveModels(freshModels: RuntimeModelOption[], rememberedModels: RuntimeModelOption[]): RuntimeModelOption[];
13
- export declare function isKnownModel(def: RuntimeAgentDef, modelId: string | null | undefined, scope?: string | null): boolean;
14
- export declare function resolveModelForAgent(def: RuntimeAgentDef, resolved: string | null, env?: Record<string, string | undefined>, liveModelScope?: string | null): string | null;
15
- export declare function sanitizeCustomModel(id: string | null | undefined): string | null;
10
+ export declare function rememberLiveModels({ agentId, models }: {
11
+ agentId: string;
12
+ models: RuntimeModelOption[];
13
+ }, { scope }?: {
14
+ scope?: string | null;
15
+ }): void;
16
+ export declare function getRememberedLiveModels({ agentId }: {
17
+ agentId: string;
18
+ }, { scope }?: {
19
+ scope?: string | null;
20
+ }): RuntimeModelOption[];
21
+ export declare function preferFreshLiveModels({ freshModels, rememberedModels }: {
22
+ freshModels: RuntimeModelOption[];
23
+ rememberedModels: RuntimeModelOption[];
24
+ }): RuntimeModelOption[];
25
+ export declare function isKnownModel({ def, modelId }: {
26
+ def: RuntimeAgentDef;
27
+ modelId: string | null | undefined;
28
+ }, { scope }?: {
29
+ scope?: string | null;
30
+ }): boolean;
31
+ export declare function resolveModelForAgent({ def, resolved }: {
32
+ def: RuntimeAgentDef;
33
+ resolved: string | null;
34
+ }, { env, liveModelScope }?: {
35
+ env?: Record<string, string | undefined>;
36
+ liveModelScope?: string | null;
37
+ }): string | null;
38
+ export declare function sanitizeCustomModel({ id }: {
39
+ id: string | null | undefined;
40
+ }): string | null;
16
41
  //# sourceMappingURL=models.d.ts.map