@jini-ai/daemon 0.5.3 → 0.5.4

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 (72) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/agent-executor/contracts.d.ts +12 -10
  3. package/dist/agent-executor/contracts.js +0 -9
  4. package/dist/agent-executor/event-translation.d.ts +2 -2
  5. package/dist/agent-executor/event-translation.js +0 -2
  6. package/dist/agent-executor/events.d.ts +9 -4
  7. package/dist/agent-executor/events.js +21 -5
  8. package/dist/agent-executor/handoff.d.ts +1 -1
  9. package/dist/agent-executor/handoff.js +0 -1
  10. package/dist/agent-executor/launch.d.ts +1 -1
  11. package/dist/agent-executor/launch.js +22 -1
  12. package/dist/agent-executor/mcp-bridge.d.ts +2 -2
  13. package/dist/agent-executor/mcp-bridge.js +0 -2
  14. package/dist/agent-executor/model-receipts.d.ts +6 -0
  15. package/dist/agent-executor/model-receipts.js +26 -0
  16. package/dist/agent-executor.d.ts +7 -1665
  17. package/dist/agent-executor.js +7 -3007
  18. package/dist/core/read-only-tools.d.ts +130 -0
  19. package/dist/core/read-only-tools.js +115 -0
  20. package/dist/core/tool-audit.d.ts +131 -0
  21. package/dist/core/tool-audit.js +113 -0
  22. package/dist/http/active-context.d.ts +2 -2
  23. package/dist/http/agents.d.ts +8 -2
  24. package/dist/http/agents.js +6 -2
  25. package/dist/http/component-catalog.d.ts +2 -2
  26. package/dist/http/connectors.d.ts +17 -17
  27. package/dist/http/daemon-status.d.ts +2 -2
  28. package/dist/http/db-ops.d.ts +3 -3
  29. package/dist/http/delegated-tools.d.ts +1 -1
  30. package/dist/http/delegated-tools.js +1 -1
  31. package/dist/http/frontend-sessions.d.ts +1 -1
  32. package/dist/http/health.d.ts +6 -6
  33. package/dist/http/host-tools.d.ts +2 -2
  34. package/dist/http/media.d.ts +4 -4
  35. package/dist/http/memory.d.ts +15 -15
  36. package/dist/http/remote-run-events.d.ts +2 -2
  37. package/dist/http/research.d.ts +1 -1
  38. package/dist/http/routines.d.ts +7 -7
  39. package/dist/http/run-credentials.d.ts +2 -2
  40. package/dist/http/run-credentials.js +2 -2
  41. package/dist/http/runs.d.ts +4 -4
  42. package/dist/http/terminals.d.ts +6 -6
  43. package/dist/http/tool-catalog.d.ts +2 -2
  44. package/dist/http/xai.d.ts +6 -6
  45. package/dist/index.d.ts +75 -571
  46. package/dist/index.js +75 -571
  47. package/dist/read-only-tools.d.ts +1 -129
  48. package/dist/read-only-tools.js +2 -114
  49. package/dist/run-credentials.d.ts +47 -23
  50. package/dist/run-credentials.js +24 -8
  51. package/dist/scheduler.d.ts +5 -0
  52. package/dist/scheduler.js +13 -1
  53. package/dist/session-coordination.d.ts +58 -24
  54. package/dist/session-coordination.js +40 -12
  55. package/dist/store/event-log/sqlite.js +3 -3
  56. package/dist/surface-exchanges.d.ts +207 -61
  57. package/dist/surface-exchanges.js +167 -20
  58. package/dist/tool-audit.d.ts +1 -113
  59. package/dist/tool-audit.js +2 -94
  60. package/dist/tool-recovery/diagnostics.d.ts +132 -0
  61. package/dist/tool-recovery/diagnostics.js +110 -0
  62. package/dist/tool-recovery/federated-refusal.d.ts +92 -0
  63. package/dist/tool-recovery/federated-refusal.js +152 -0
  64. package/dist/tool-recovery/index.d.ts +6 -0
  65. package/dist/tool-recovery/index.js +6 -0
  66. package/dist/tool-recovery/recovery.d.ts +49 -0
  67. package/dist/tool-recovery/recovery.js +419 -0
  68. package/dist/tool-recovery/redaction.d.ts +166 -0
  69. package/dist/tool-recovery/redaction.js +192 -0
  70. package/dist/tool-recovery/stack.d.ts +69 -0
  71. package/dist/tool-recovery/stack.js +62 -0
  72. package/package.json +35 -12
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.5.4 — pending release
2
+
3
+ - Re-export the canonical core surface-exchange contracts and parameter constants. Store and ask/report behavior are unchanged; requires core 0.4.2.
4
+
1
5
  ## 0.5.3 — 2026-10-06
2
6
 
3
7
  - Message attachments reach every runtime: new `prepareMessageAttachments` / `messageContentWithImages` (+ `MessageAttachmentImage`, `MessageAttachmentSource`, `MessageAttachmentReader`) turn claimed refs into image pixels for providers and a file notice for non-images.
@@ -1,13 +1,13 @@
1
1
  import type { MessageAttachmentImage } from '../attachment-content.js';
2
- import { type spawn as nodeSpawn, type ChildProcess } from 'node:child_process';
3
- import { type Principal } from '@jini-ai/core';
4
- import { type RunAgentPayload, type RunErrorPayload } from '@jini-ai/protocol';
5
- import { type applyAgentLaunchEnv, type ensureAgentCapabilities, type getAgentDef, type resolveAgentLaunch, type attachAcpSession, type attachPiRpcSession, type prepareAgentLogFile, type preparePromptFileForAgent, type AcpMcpServerInput, type AcpPermissionHandler, type PromptAugmenter } from '@jini-ai/agent-runtime';
6
- import { type createCommandInvocation, type listProcessSnapshots, type ProcessSnapshot, type StopProcessesResult } from '@jini-ai/platform';
7
- import { type RunByteJournal } from '../continuation/journal.js';
8
- import { type RunRetrySideEffectState } from '../run/core/index.js';
9
- import { type ToolExecutor } from '../tool-executor.js';
10
- import { type RunLifecycle } from '../run-lifecycle.js';
2
+ import type { spawn as nodeSpawn, ChildProcess } from 'node:child_process';
3
+ import type { Principal } from '@jini-ai/core';
4
+ import type { RunAgentPayload, RunErrorPayload } from '@jini-ai/protocol';
5
+ import type { applyAgentLaunchEnv, ensureAgentCapabilities, resolveModelForLaunch, getAgentDef, resolveAgentLaunch, attachAcpSession, attachPiRpcSession, prepareAgentLogFile, preparePromptFileForAgent, AcpMcpServerInput, AcpPermissionHandler, PromptAugmenter } from '@jini-ai/agent-runtime';
6
+ import type { createCommandInvocation, listProcessSnapshots, ProcessSnapshot, StopProcessesResult } from '@jini-ai/platform';
7
+ import type { RunByteJournal } from '../continuation/journal.js';
8
+ import type { RunRetrySideEffectState } from '../run/core/index.js';
9
+ import type { ToolExecutor } from '../tool-executor.js';
10
+ import type { RunLifecycle } from '../run-lifecycle.js';
11
11
  /**
12
12
  * A parsed, loosely-typed event as produced by one of `@jini-ai/agent-runtime`'s
13
13
  * four stream-parser factories — each parser's `onEvent` callback receives
@@ -90,7 +90,7 @@ export type AgentRuntimeEventTranslation = {
90
90
  readonly kind: 'ignored';
91
91
  };
92
92
  /** Machine-readable failure reasons `run()` can reject with — every one is preceded by a `lifecycle.finish({status:'failed'})` call (see index.ts module doc's Invariant section). */
93
- export type AgentExecutorErrorCode = 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
93
+ export type AgentExecutorErrorCode = 'AGENT_MODEL_UNRESOLVED' | 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
94
94
  /** Thrown by `AgentExecutor.run()` on every failure path — never a bare `Error`, so callers can branch on `.code` instead of parsing `.message`. */
95
95
  export declare class AgentExecutorError extends Error {
96
96
  readonly code: AgentExecutorErrorCode;
@@ -543,6 +543,8 @@ export interface FailureClassificationContext {
543
543
  export type ClassifyFailure = (context: FailureClassificationContext) => boolean | Promise<boolean>;
544
544
  export interface CreateAgentExecutorOptions {
545
545
  readonly lifecycle: RunLifecycle;
546
+ /** Resolves/pins the concrete starting model against the actual launch scope. */
547
+ readonly resolveModelForLaunch?: typeof resolveModelForLaunch;
546
548
  /** @default the real `@jini-ai/agent-runtime` registry lookup */
547
549
  readonly getAgentDef?: typeof getAgentDef;
548
550
  /** @default the real `@jini-ai/agent-runtime` launch resolver */
@@ -1,12 +1,3 @@
1
- import {} from 'node:child_process';
2
- import {} from '@jini-ai/core';
3
- import {} from '@jini-ai/protocol';
4
- import {} from '@jini-ai/agent-runtime';
5
- import {} from '@jini-ai/platform';
6
- import {} from '../continuation/journal.js';
7
- import {} from '../run/core/index.js';
8
- import {} from '../tool-executor.js';
9
- import {} from '../run-lifecycle.js';
10
1
  export const SUPPORTED_STREAM_FORMATS = [
11
2
  'claude-stream-json',
12
3
  'json-event-stream',
@@ -1,5 +1,5 @@
1
- import { type RunAgentPayload, type RunErrorPayload } from '@jini-ai/protocol';
2
- import { type AgentRuntimeEventTranslation } from './contracts.js';
1
+ import type { RunAgentPayload, RunErrorPayload } from '@jini-ai/protocol';
2
+ import type { AgentRuntimeEventTranslation } from './contracts.js';
3
3
  /**
4
4
  * Narrows a parsed `usage` event's `usage` sub-object (`{input_tokens?, output_tokens?}`) — the one
5
5
  * piece of {@link translateUsagePayload} with real nested branching (an optional container holding
@@ -1,5 +1,3 @@
1
- import {} from '@jini-ai/protocol';
2
- import {} from './contracts.js';
3
1
  import { isRecord, asString, asOptionalString, } from './values.js';
4
2
  function asOptionalNumber(value) {
5
3
  return typeof value === 'number' ? value : undefined;
@@ -1,8 +1,9 @@
1
- import { type ChildProcess } from 'node:child_process';
1
+ import type { ModelCatalogSnapshot } from '@jini-ai/agent-runtime';
2
+ import type { ChildProcess } from 'node:child_process';
2
3
  import { attachAcpSession, attachPiRpcSession, type AcpPermissionHandler, type RuntimeAgentDef } from '@jini-ai/agent-runtime';
3
- import { type RunByteJournal } from '../continuation/journal.js';
4
- import { type RunLifecycle } from '../run-lifecycle.js';
5
- import { type ChildDrivenStreamFormat, type TerminateChildTreeDeps, type AgentCleanupFailureContext, type StdinCloseHandle, type ContinuationOptions, type McpBridgeDelivery, type ClassifyFailure, type FailBeforeSpawn } from './contracts.js';
4
+ import type { RunByteJournal } from '../continuation/journal.js';
5
+ import type { RunLifecycle } from '../run-lifecycle.js';
6
+ import type { ChildDrivenStreamFormat, TerminateChildTreeDeps, AgentCleanupFailureContext, StdinCloseHandle, ContinuationOptions, McpBridgeDelivery, ClassifyFailure, FailBeforeSpawn } from './contracts.js';
6
7
  /** Default sink when a host does not supply `onCleanupFailure`: still observable, never silent. Redacted per SEC-007 (a spawn/permission error can embed paths/host detail). */
7
8
  export declare function defaultCleanupFailureSink(context: AgentCleanupFailureContext): void;
8
9
  /**
@@ -22,6 +23,8 @@ export declare function defaultCleanupFailureSink(context: AgentCleanupFailureCo
22
23
  */
23
24
  export declare const DEFAULT_BUFFERED_STDOUT_MAX_BYTES: number;
24
25
  interface WireChildLifecycleContext extends TerminateChildTreeDeps {
26
+ readonly startingModel?: string;
27
+ readonly modelCatalog?: ModelCatalogSnapshot;
25
28
  readonly runId: string;
26
29
  readonly def: RuntimeAgentDef;
27
30
  readonly streamFormat: ChildDrivenStreamFormat;
@@ -141,6 +144,7 @@ interface RunAcpDispatchInput {
141
144
  readonly prompt: string;
142
145
  readonly cwd: string;
143
146
  readonly model: string | undefined;
147
+ readonly modelCatalog?: ModelCatalogSnapshot;
144
148
  readonly imagePaths: readonly string[];
145
149
  readonly envFormat: 'array' | 'map' | undefined;
146
150
  readonly mcpBridge: McpBridgeDelivery | null;
@@ -168,6 +172,7 @@ interface RunPiRpcDispatchInput {
168
172
  readonly prompt: string;
169
173
  readonly cwd: string;
170
174
  readonly model: string | undefined;
175
+ readonly modelCatalog?: ModelCatalogSnapshot;
171
176
  readonly imagePaths: readonly string[];
172
177
  readonly uploadRoot: string | undefined;
173
178
  }
@@ -1,16 +1,12 @@
1
+ import { createModelReceiptTracker } from './model-receipts.js';
1
2
  import { messageContentWithImages } from '../attachment-content.js';
2
- import {} from 'node:child_process';
3
3
  import { redactSecrets, } from '@jini-ai/core';
4
- import {} from '@jini-ai/protocol';
5
4
  import { createClaudeStreamHandler, createCopilotStreamHandler, createJsonEventStreamHandler, createQoderStreamHandler, attachAcpSession, attachPiRpcSession, } from '@jini-ai/agent-runtime';
6
5
  import { collectProcessTreePids, listProcessSnapshots, stopProcesses, } from '@jini-ai/platform';
7
6
  import { classifyRunCloseStatus, } from '../close-status.js';
8
7
  import { resolveContinuationTransport, } from '../continuation/continuation-transport.js';
9
- import {} from '../continuation/journal.js';
10
8
  import { resultContent, } from '../delegated-tool-bridge.js';
11
9
  import { extractResultMedia, } from '../tool-result-media.js';
12
- import {} from '../run-lifecycle.js';
13
- import {} from './contracts.js';
14
10
  import { translateAgentRuntimeEvent, translateAcpError, applyAgentTranslationSideEffects, } from './event-translation.js';
15
11
  import { errorMessage, } from './values.js';
16
12
  import { MCP_BRIDGE_UNAVAILABLE, unavailableJiniBridgeStatus, bridgeUnavailableMessage, } from './mcp-bridge.js';
@@ -260,6 +256,7 @@ function bufferedStdoutTruncationNotice(droppedBytes, maxBytes) {
260
256
  */
261
257
  export function wireChildLifecycle(ctx) {
262
258
  const { runId, def, streamFormat, child, lifecycle, journal, continuation, classifyFailure } = ctx;
259
+ const modelReceipt = createModelReceiptTracker(ctx.startingModel, ctx.modelCatalog?.models);
263
260
  let stdinClosed = false;
264
261
  let cancelRequested = false;
265
262
  let emitQueue = Promise.resolve();
@@ -306,6 +303,8 @@ export function wireChildLifecycle(ctx) {
306
303
  }
307
304
  });
308
305
  }
306
+ if (ctx.startingModel)
307
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.startingModel } } }));
309
308
  function closeStdinOnce() {
310
309
  if (stdinClosed)
311
310
  return;
@@ -399,6 +398,9 @@ export function wireChildLifecycle(ctx) {
399
398
  return;
400
399
  const translation = translateAgentRuntimeEvent({ rawEvent: rawEvent });
401
400
  if (translation.kind === 'agent') {
401
+ const receipt = modelReceipt(translation.payload);
402
+ if (receipt)
403
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
402
404
  if (translation.sessionId !== undefined)
403
405
  capturedSessionId = translation.sessionId;
404
406
  if (!bridgeChecked && translation.payload.type === 'status' && translation.payload.label === 'initializing') {
@@ -570,6 +572,7 @@ export function wireChildLifecycle(ctx) {
570
572
  * success.
571
573
  */
572
574
  function wireAcpLifecycle(ctx) {
575
+ const modelReceipt = createModelReceiptTracker(ctx.model, ctx.modelCatalog?.models);
573
576
  const { runId, agentId, child, lifecycle, journal, classifyFailure } = ctx;
574
577
  let cancelRequested = false;
575
578
  let emitQueue = Promise.resolve();
@@ -589,6 +592,8 @@ function wireAcpLifecycle(ctx) {
589
592
  }
590
593
  });
591
594
  }
595
+ if (ctx.model)
596
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.model } } }));
592
597
  child.stdout?.on('data', (chunk) => {
593
598
  const text = chunk.toString('utf8');
594
599
  if (journal)
@@ -632,6 +637,9 @@ function wireAcpLifecycle(ctx) {
632
637
  if (event === 'agent') {
633
638
  const translation = translateAgentRuntimeEvent({ rawEvent: payload });
634
639
  if (translation.kind === 'agent') {
640
+ const receipt = modelReceipt(translation.payload);
641
+ if (receipt)
642
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
635
643
  applyAgentTranslationSideEffects({ payload: translation.payload, sessionId: translation.sessionId, sink: {
636
644
  onSessionId: ({ sessionId }) => { capturedSessionId = sessionId; },
637
645
  onToolCall: () => { toolCallSeen = true; },
@@ -674,6 +682,7 @@ function wireAcpLifecycle(ctx) {
674
682
  * multi-turn tool continuation, resumable session ids, etc.).
675
683
  */
676
684
  function wirePiRpcLifecycle(ctx) {
685
+ const modelReceipt = createModelReceiptTracker(ctx.model, ctx.modelCatalog?.models);
677
686
  const { runId, agentId, child, lifecycle, journal, classifyFailure } = ctx;
678
687
  let cancelRequested = false;
679
688
  let emitQueue = Promise.resolve();
@@ -693,6 +702,8 @@ function wirePiRpcLifecycle(ctx) {
693
702
  }
694
703
  });
695
704
  }
705
+ if (ctx.model)
706
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.model } } }));
696
707
  child.stdout?.on('data', (chunk) => {
697
708
  const text = chunk.toString('utf8');
698
709
  if (journal)
@@ -735,6 +746,9 @@ function wirePiRpcLifecycle(ctx) {
735
746
  session = ctx.attachPiRpcSession({ child: ctx.child, prompt: ctx.prompt, send({ payload }) {
736
747
  const translation = translateAgentRuntimeEvent({ rawEvent: payload });
737
748
  if (translation.kind === 'agent') {
749
+ const receipt = modelReceipt(translation.payload);
750
+ if (receipt)
751
+ enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
738
752
  if (translation.sessionId !== undefined)
739
753
  capturedSessionId = translation.sessionId;
740
754
  if (translation.payload.type === 'tool_use') {
@@ -795,6 +809,7 @@ export async function runAcpDispatch({ input, deps }) {
795
809
  prompt: input.prompt,
796
810
  cwd: input.cwd,
797
811
  model: input.model,
812
+ ...(input.modelCatalog ? { modelCatalog: input.modelCatalog } : {}),
798
813
  imagePaths: input.imagePaths,
799
814
  envFormat: input.envFormat,
800
815
  // Mechanism 2 of 5 — see `WireAcpLifecycleContext.mcpServers`. `undefined` for any def that
@@ -831,6 +846,7 @@ export async function runPiRpcDispatch({ input, deps }) {
831
846
  prompt: input.prompt,
832
847
  cwd: input.cwd,
833
848
  model: input.model,
849
+ ...(input.modelCatalog ? { modelCatalog: input.modelCatalog } : {}),
834
850
  imagePaths: input.imagePaths,
835
851
  uploadRoot: input.uploadRoot,
836
852
  attachPiRpcSession: deps.attachPiRpcSession,
@@ -1,4 +1,4 @@
1
- import { type RuntimeAgentDef, type RuntimeLockHold } from '@jini-ai/agent-runtime';
1
+ import type { RuntimeAgentDef, RuntimeLockHold } from '@jini-ai/agent-runtime';
2
2
  /**
3
3
  * Phase 7: acquires a `runtimeLock` def's process-global mutex before `buildArgs` runs — see
4
4
  * `RuntimeLock`'s own doc for the concrete race. A no-op (`undefined`) for the 23 of 24 defs with no
@@ -1,4 +1,3 @@
1
- import {} from '@jini-ai/agent-runtime';
2
1
  /**
3
2
  * Phase 7: acquires a `runtimeLock` def's process-global mutex before `buildArgs` runs — see
4
3
  * `RuntimeLock`'s own doc for the concrete race. A no-op (`undefined`) for the 23 of 24 defs with no
@@ -370,6 +370,6 @@ export declare function confirmChildSpawned({ input, deps }: {
370
370
  * @complexity `run()`'s own setup is O(1); steady-state cost is the chosen stream parser's.
371
371
  * @overallScore 100/100
372
372
  */
373
- export declare function createAgentExecutor(requiredArgs: Pick<CreateAgentExecutorOptions, "lifecycle">, optionalArgs?: Pick<CreateAgentExecutorOptions, "getAgentDef" | "resolveAgentLaunch" | "ensureAgentCapabilities" | "applyAgentLaunchEnv" | "createCommandInvocation" | "spawn" | "attachAcpSession" | "acpPermissionHandler" | "attachPiRpcSession" | "preparePromptFileForAgent" | "prepareAgentLogFile" | "listProcessSnapshots" | "collectProcessTreePids" | "stopProcesses" | "onCleanupFailure" | "journal" | "continuation" | "classifyFailure" | "mcpJsonInjection" | "claudeConfigDirIsolation" | "claudeConfigDirIsolationEnabled" | "bufferedStdoutMaxBytes" | "promptAugmenter">): AgentExecutor;
373
+ export declare function createAgentExecutor(requiredArgs: Pick<CreateAgentExecutorOptions, "lifecycle">, optionalArgs?: Pick<CreateAgentExecutorOptions, "getAgentDef" | "resolveAgentLaunch" | "resolveModelForLaunch" | "ensureAgentCapabilities" | "applyAgentLaunchEnv" | "createCommandInvocation" | "spawn" | "attachAcpSession" | "acpPermissionHandler" | "attachPiRpcSession" | "preparePromptFileForAgent" | "prepareAgentLogFile" | "listProcessSnapshots" | "collectProcessTreePids" | "stopProcesses" | "onCleanupFailure" | "journal" | "continuation" | "classifyFailure" | "mcpJsonInjection" | "claudeConfigDirIsolation" | "claudeConfigDirIsolationEnabled" | "bufferedStdoutMaxBytes" | "promptAugmenter">): AgentExecutor;
374
374
  export {};
375
375
  //# sourceMappingURL=launch.d.ts.map
@@ -2,7 +2,7 @@ import { spawn as nodeSpawn, } from 'node:child_process';
2
2
  import { promises as fsPromises, } from 'node:fs';
3
3
  import { tmpdir, } from 'node:os';
4
4
  import { join, } from 'node:path';
5
- import { agentCapabilities, applyAgentLaunchEnv, ensureAgentCapabilities, getAgentDef, resolveAgentLaunch, attachAcpSession, attachPiRpcSession, checkPromptArgvBudget, checkWindowsCmdShimCommandLineBudget, checkWindowsDirectExeCommandLineBudget, prepareAgentLogFile, preparePromptFileForAgent, } from '@jini-ai/agent-runtime';
5
+ import { agentCapabilities, applyAgentLaunchEnv, ensureAgentCapabilities, resolveModelForLaunch, getAgentDef, resolveAgentLaunch, attachAcpSession, attachPiRpcSession, checkPromptArgvBudget, checkWindowsCmdShimCommandLineBudget, checkWindowsDirectExeCommandLineBudget, prepareAgentLogFile, preparePromptFileForAgent, } from '@jini-ai/agent-runtime';
6
6
  import { collectProcessTreePids, createCommandInvocation, listProcessSnapshots, stopProcesses, } from '@jini-ai/platform';
7
7
  import { applyImagePromptDelivery, } from '../image-prompt-delivery.js';
8
8
  import { SUPPORTED_STREAM_FORMATS, AgentExecutorError, } from './contracts.js';
@@ -706,6 +706,23 @@ export function createAgentExecutor(requiredArgs, optionalArgs = {}) {
706
706
  const resolvedEnv = { ...(def.env ?? {}), ...resolveRunEnv({ input: input, hostEnv: process.env }) };
707
707
  const launch = await resolveLaunch({ input: { runId: input.runId, def, resolvedEnv }, deps: { resolveAgentLaunch: resolveAgentLaunchFn, failBeforeSpawn } });
708
708
  const spawnEnv = applyAgentLaunchEnvFn({ env: { ...resolvedEnv }, launch });
709
+ // Resolve from the launch environment before staging or sending any prompt. Pin the same
710
+ // concrete ID that the picker displays; an opaque native route cannot silently start a run.
711
+ let modelCatalog;
712
+ try {
713
+ const selection = await (options.resolveModelForLaunch ?? resolveModelForLaunch)({ def, context: {
714
+ executable: launch.launchPath, cwd: input.cwd, env: spawnEnv,
715
+ ...(input.model && input.model !== 'default' ? { model: input.model } : {}),
716
+ ...(input.resumeSessionId ? { resumeSessionId: input.resumeSessionId } : {}),
717
+ ...(input.settingSources ? { settingSources: input.settingSources } : {}),
718
+ ...(input.settings ? { settings: input.settings } : {}),
719
+ } });
720
+ input.model = selection.model;
721
+ modelCatalog = selection.catalog;
722
+ }
723
+ catch {
724
+ return failBeforeSpawn({ runId: input.runId, code: 'AGENT_MODEL_UNRESOLVED', message: 'AgentExecutor: pick a concrete model; the starting model could not be resolved for this launch.' });
725
+ }
709
726
  // Fill the def's `--help` capability gate before `buildArgs` reads it. Without this, only a
710
727
  // host that happened to call `detectAgents` in THIS process ever had the gate filled, so e.g.
711
728
  // `claude` never got `--include-partial-messages` (no streamed text). Probes once per binary;
@@ -898,6 +915,8 @@ export function createAgentExecutor(requiredArgs, optionalArgs = {}) {
898
915
  const formatForStdin = { streamFormat };
899
916
  const stdinHandle = isStdinDrivenFormat(formatForStdin)
900
917
  ? wireChildLifecycle({
918
+ startingModel: input.model,
919
+ modelCatalog,
901
920
  runId: input.runId,
902
921
  def,
903
922
  streamFormat: formatForStdin.streamFormat,
@@ -937,6 +956,7 @@ export function createAgentExecutor(requiredArgs, optionalArgs = {}) {
937
956
  prompt: `${overlayDelivery.promptPrefix}${input.prompt}`,
938
957
  cwd: input.cwd,
939
958
  model: input.model,
959
+ modelCatalog,
940
960
  imagePaths: input.imagePaths ?? [],
941
961
  envFormat: def.acpMcpEnvFormat,
942
962
  mcpBridge,
@@ -967,6 +987,7 @@ export function createAgentExecutor(requiredArgs, optionalArgs = {}) {
967
987
  prompt: `${overlayDelivery.promptPrefix}${input.prompt}`,
968
988
  cwd: input.cwd,
969
989
  model: input.model,
990
+ modelCatalog,
970
991
  imagePaths: input.imagePaths ?? [],
971
992
  uploadRoot: input.uploadRoot,
972
993
  }, deps: {
@@ -1,5 +1,5 @@
1
- import { type AcpMcpServerInput, type RuntimeAgentDef } from '@jini-ai/agent-runtime';
2
- import { type McpJsonInjectionOptions, type McpJsonServerEntry, type McpBridgeDelivery, type PreparedCodexHome, type PreparedClaudeConfigDir, type ClaudeConfigDirIsolationOptions, type FailBeforeSpawn } from './contracts.js';
1
+ import type { AcpMcpServerInput, RuntimeAgentDef } from '@jini-ai/agent-runtime';
2
+ import type { McpJsonInjectionOptions, McpJsonServerEntry, McpBridgeDelivery, PreparedCodexHome, PreparedClaudeConfigDir, ClaudeConfigDirIsolationOptions, FailBeforeSpawn } from './contracts.js';
3
3
  /** The run-error code a run gets when its CLI reports the injected `jini` bridge as anything but connected. */
4
4
  export declare const MCP_BRIDGE_UNAVAILABLE = "MCP_BRIDGE_UNAVAILABLE";
5
5
  /**
@@ -1,9 +1,7 @@
1
1
  import { promises as fsPromises, } from 'node:fs';
2
2
  import { homedir, tmpdir, } from 'node:os';
3
3
  import { join, } from 'node:path';
4
- import {} from '@jini-ai/agent-runtime';
5
4
  import { isRecord, errorMessage, } from './values.js';
6
- import {} from './contracts.js';
7
5
  const JINI_MCP_SERVER_KEY = 'jini';
8
6
  /** The run-error code a run gets when its CLI reports the injected `jini` bridge as anything but connected. */
9
7
  export const MCP_BRIDGE_UNAVAILABLE = 'MCP_BRIDGE_UNAVAILABLE';
@@ -0,0 +1,6 @@
1
+ import type { RunAgentPayload } from '@jini-ai/protocol';
2
+ import { type DiscoveredModel } from '@jini-ai/agent-runtime';
3
+ /** Status metadata comes from CLI/RPC frames, never generated text. Dedupe repeats and record
4
+ * each observed transition separately so durable run events can describe model switches. */
5
+ export declare function createModelReceiptTracker(startingModel?: string, models?: readonly DiscoveredModel[]): (payload: RunAgentPayload) => RunAgentPayload | null;
6
+ //# sourceMappingURL=model-receipts.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { modelIdentityKind } from '@jini-ai/agent-runtime';
2
+ /** Status metadata comes from CLI/RPC frames, never generated text. Dedupe repeats and record
3
+ * each observed transition separately so durable run events can describe model switches. */
4
+ export function createModelReceiptTracker(startingModel, models = []) {
5
+ // The catalog is launch-scoped evidence. Normalize both the pinned and reported names
6
+ // so a CLI's alias/display spelling does not fabricate a durable model transition.
7
+ const normalize = (id) => {
8
+ const row = models.find(model => model.id === id) || models.find(model => model.label === id);
9
+ return row?.resolvedId || row?.id || id;
10
+ };
11
+ let current = startingModel && normalize(startingModel);
12
+ return (payload) => {
13
+ if (payload.type !== 'status' || !payload.model || typeof payload.model !== 'string')
14
+ return null;
15
+ const observed = normalize(payload.model);
16
+ if (modelIdentityKind(observed) !== 'concrete')
17
+ return null;
18
+ if (observed === current)
19
+ return null;
20
+ const prior = current;
21
+ current = observed;
22
+ return { type: 'status', label: prior ? 'model_switch' : 'observed_model', model: current,
23
+ ...(prior ? { previousModel: prior, detail: `Previous model: ${prior}` } : {}) };
24
+ };
25
+ }
26
+ //# sourceMappingURL=model-receipts.js.map