@jini-ai/daemon 0.3.8 → 0.5.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 (173) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +50 -8
  3. package/dist/agent-executor/contracts.d.ts +736 -0
  4. package/dist/agent-executor/contracts.js +28 -0
  5. package/dist/agent-executor/event-translation.d.ts +87 -0
  6. package/dist/agent-executor/event-translation.js +230 -0
  7. package/dist/agent-executor/events.d.ts +190 -0
  8. package/dist/agent-executor/events.js +848 -0
  9. package/dist/agent-executor/handoff.d.ts +18 -0
  10. package/dist/agent-executor/handoff.js +16 -0
  11. package/dist/agent-executor/index.d.ts +98 -0
  12. package/dist/agent-executor/index.js +98 -0
  13. package/dist/agent-executor/launch.d.ts +375 -0
  14. package/dist/agent-executor/launch.js +1001 -0
  15. package/dist/agent-executor/mcp-bridge.d.ts +338 -0
  16. package/dist/agent-executor/mcp-bridge.js +835 -0
  17. package/dist/agent-executor/values.d.ts +5 -0
  18. package/dist/agent-executor/values.js +13 -0
  19. package/dist/agent-executor.d.ts +375 -176
  20. package/dist/agent-executor.js +388 -335
  21. package/dist/artifacts/index.d.ts +14 -0
  22. package/dist/artifacts/index.js +14 -0
  23. package/dist/artifacts/manifest.d.ts +90 -0
  24. package/dist/artifacts/manifest.js +229 -0
  25. package/dist/artifacts/publication-guard.d.ts +28 -0
  26. package/dist/artifacts/publication-guard.js +77 -0
  27. package/dist/artifacts/runtime-compat.d.ts +37 -0
  28. package/dist/artifacts/runtime-compat.js +33 -0
  29. package/dist/artifacts/store.d.ts +85 -0
  30. package/dist/artifacts/store.js +92 -0
  31. package/dist/artifacts/stub-guard.d.ts +73 -0
  32. package/dist/artifacts/stub-guard.js +198 -0
  33. package/dist/artifacts/text-suppression.d.ts +68 -0
  34. package/dist/artifacts/text-suppression.js +184 -0
  35. package/dist/close-status.d.ts +11 -8
  36. package/dist/close-status.js +31 -19
  37. package/dist/continuation/continuation-transport.d.ts +3 -1
  38. package/dist/continuation/continuation-transport.js +1 -1
  39. package/dist/continuation/journal.d.ts +12 -5
  40. package/dist/continuation/journal.js +4 -4
  41. package/dist/continuation/run-scoped-context-store.d.ts +13 -4
  42. package/dist/continuation/run-scoped-context-store.js +6 -6
  43. package/dist/continuation/run-start-handler.d.ts +1 -1
  44. package/dist/continuation/run-start-handler.js +3 -16
  45. package/dist/delegated-tool-bridge.d.ts +7 -3
  46. package/dist/delegated-tool-bridge.js +32 -31
  47. package/dist/event-log.d.ts +7 -5
  48. package/dist/event-log.js +12 -11
  49. package/dist/frontend-capability-tools.d.ts +1 -1
  50. package/dist/frontend-capability-tools.js +3 -2
  51. package/dist/frontend-session-registry.d.ts +32 -9
  52. package/dist/frontend-session-registry.js +12 -11
  53. package/dist/http/active-context.d.ts +105 -0
  54. package/dist/http/active-context.js +67 -0
  55. package/dist/http/agents.d.ts +68 -0
  56. package/dist/http/agents.js +12 -0
  57. package/dist/http/attachments.d.ts +618 -0
  58. package/dist/http/attachments.js +1034 -0
  59. package/dist/http/cancel-owned-runs.d.ts +49 -0
  60. package/dist/http/cancel-owned-runs.js +35 -0
  61. package/dist/http/component-catalog.d.ts +84 -0
  62. package/dist/http/component-catalog.js +64 -0
  63. package/dist/http/connectors.d.ts +209 -0
  64. package/dist/http/connectors.js +409 -0
  65. package/dist/http/daemon-status.d.ts +76 -0
  66. package/dist/http/daemon-status.js +55 -0
  67. package/dist/http/db-ops.d.ts +123 -0
  68. package/dist/http/db-ops.js +189 -0
  69. package/dist/http/delegated-tools.d.ts +113 -0
  70. package/dist/http/delegated-tools.js +230 -0
  71. package/dist/http/frontend-control.d.ts +136 -0
  72. package/dist/http/frontend-control.js +79 -0
  73. package/dist/http/frontend-sessions.d.ts +110 -0
  74. package/dist/http/frontend-sessions.js +180 -0
  75. package/dist/http/health.d.ts +95 -0
  76. package/dist/http/health.js +40 -0
  77. package/dist/http/host-tools.d.ts +214 -0
  78. package/dist/http/host-tools.js +329 -0
  79. package/dist/http/index.d.ts +52 -0
  80. package/dist/http/index.js +27 -0
  81. package/dist/http/media.d.ts +146 -0
  82. package/dist/http/media.js +346 -0
  83. package/dist/http/memory.d.ts +265 -0
  84. package/dist/http/memory.js +328 -0
  85. package/dist/http/model-proxy.d.ts +49 -0
  86. package/dist/http/model-proxy.js +642 -0
  87. package/dist/http/remote-run-events.d.ts +70 -0
  88. package/dist/http/remote-run-events.js +224 -0
  89. package/dist/http/research.d.ts +48 -0
  90. package/dist/http/research.js +315 -0
  91. package/dist/http/route-manifest.d.ts +35 -0
  92. package/dist/http/route-manifest.js +103 -0
  93. package/dist/http/routines.d.ts +120 -0
  94. package/dist/http/routines.js +298 -0
  95. package/dist/http/run-credentials.d.ts +73 -0
  96. package/dist/http/run-credentials.js +71 -0
  97. package/dist/http/runs.d.ts +91 -0
  98. package/dist/http/runs.js +221 -0
  99. package/dist/http/terminals.d.ts +138 -0
  100. package/dist/http/terminals.js +325 -0
  101. package/dist/http/tool-catalog.d.ts +78 -0
  102. package/dist/http/tool-catalog.js +66 -0
  103. package/dist/http/workspace-root.d.ts +77 -0
  104. package/dist/http/workspace-root.js +63 -0
  105. package/dist/http/xai.d.ts +90 -0
  106. package/dist/http/xai.js +655 -0
  107. package/dist/image-prompt-delivery.d.ts +13 -3
  108. package/dist/image-prompt-delivery.js +5 -5
  109. package/dist/index.d.ts +556 -4
  110. package/dist/index.js +556 -4
  111. package/dist/legacy-data-migration.d.ts +59 -8
  112. package/dist/legacy-data-migration.js +38 -33
  113. package/dist/read-only-tools.d.ts +130 -0
  114. package/dist/read-only-tools.js +115 -0
  115. package/dist/remote-tool-bridge.d.ts +11 -5
  116. package/dist/remote-tool-bridge.js +15 -15
  117. package/dist/routines/index.d.ts +1 -1
  118. package/dist/routines/index.js +1 -1
  119. package/dist/routines/routine-store.d.ts +34 -12
  120. package/dist/routines/routine-store.js +21 -20
  121. package/dist/routines/schedule.d.ts +48 -10
  122. package/dist/routines/schedule.js +21 -21
  123. package/dist/routines/scheduler.d.ts +32 -11
  124. package/dist/routines/scheduler.js +61 -57
  125. package/dist/routines/types.d.ts +10 -3
  126. package/dist/run/core/result.d.ts +6 -2
  127. package/dist/run/core/result.js +3 -3
  128. package/dist/run/core/retry.d.ts +17 -4
  129. package/dist/run/core/retry.js +7 -11
  130. package/dist/run/diagnostics/diagnostics.d.ts +14 -4
  131. package/dist/run/diagnostics/diagnostics.js +7 -7
  132. package/dist/run/index.d.ts +1 -1
  133. package/dist/run/index.js +1 -1
  134. package/dist/run-credentials.d.ts +138 -0
  135. package/dist/run-credentials.js +152 -0
  136. package/dist/run-lifecycle.d.ts +92 -33
  137. package/dist/run-lifecycle.js +81 -74
  138. package/dist/scheduler.d.ts +8 -0
  139. package/dist/scheduler.js +2 -0
  140. package/dist/session-coordination.d.ts +115 -0
  141. package/dist/session-coordination.js +111 -0
  142. package/dist/store/agent-sessions/errors.d.ts +8 -0
  143. package/dist/store/agent-sessions/errors.js +10 -0
  144. package/dist/store/agent-sessions/index.d.ts +12 -0
  145. package/dist/store/agent-sessions/index.js +19 -0
  146. package/dist/store/agent-sessions/pglite.d.ts +12 -0
  147. package/dist/store/agent-sessions/pglite.js +7 -0
  148. package/dist/store/agent-sessions/ports.d.ts +24 -0
  149. package/dist/store/agent-sessions/ports.js +2 -0
  150. package/dist/store/agent-sessions/postgres.d.ts +12 -0
  151. package/dist/store/agent-sessions/postgres.js +7 -0
  152. package/dist/store/agent-sessions/schema.d.ts +3 -0
  153. package/dist/store/agent-sessions/schema.js +23 -0
  154. package/dist/store/agent-sessions/sql.d.ts +35 -0
  155. package/dist/store/agent-sessions/sql.js +59 -0
  156. package/dist/store/agent-sessions/sqlite.d.ts +117 -0
  157. package/dist/store/agent-sessions/sqlite.js +128 -0
  158. package/dist/store/event-log/sqlite.d.ts +75 -0
  159. package/dist/store/event-log/sqlite.js +230 -0
  160. package/dist/surface-exchanges.d.ts +97 -0
  161. package/dist/surface-exchanges.js +153 -0
  162. package/dist/terminal-session.d.ts +43 -11
  163. package/dist/terminal-session.js +22 -20
  164. package/dist/tokens.js +4 -4
  165. package/dist/tool-audit.d.ts +114 -0
  166. package/dist/tool-audit.js +95 -0
  167. package/dist/tool-executor.d.ts +22 -7
  168. package/dist/tool-executor.js +16 -16
  169. package/dist/tool-result-media.d.ts +3 -1
  170. package/dist/tool-result-media.js +1 -1
  171. package/dist/tool-result-surfaces.d.ts +3 -1
  172. package/dist/tool-result-surfaces.js +1 -1
  173. package/package.json +127 -9
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Pure run-close classification and inactivity-timeout helpers, generalized
3
3
  * from OD's `apps/daemon/src/runtimes/chat-run-lifecycle.ts`
4
- * (`arch/server-startserver-endgame` branch — see `source-map.md`). The
4
+ * (`arch/server-startserver-endgame` branch — see `archived provenance ledger`). The
5
5
  * origin file mixes a generic close-status decision tree with several
6
6
  * OD/ACP-vendor-specific escape hatches (forced-shutdown-but-actually-clean
7
7
  * heuristics for a specific agent-CLI protocol, artifact-quiet-period
8
- * nuance). Only the generic skeleton is kept here — see `source-map.md` for
8
+ * nuance). Only the generic skeleton is kept here — see `archived provenance ledger` for
9
9
  * the itemized list of what was dropped and why.
10
10
  */
11
11
  /**
@@ -20,7 +20,8 @@
20
20
  * @complexity O(1).
21
21
  * @overallScore 100/100
22
22
  */
23
- export function classifyRunCloseStatus(input) {
23
+ export function classifyRunCloseStatus(requiredArgs, optionalArgs = {}) {
24
+ const input = { ...requiredArgs, ...optionalArgs };
24
25
  if (input.cancelRequested) {
25
26
  return 'cancelled';
26
27
  }
@@ -43,7 +44,8 @@ export function classifyRunCloseStatus(input) {
43
44
  * @complexity O(1).
44
45
  * @overallScore 100/100
45
46
  */
46
- export function resolveTimeoutMs(input) {
47
+ export function resolveTimeoutMs(requiredArgs, optionalArgs = {}) {
48
+ const input = { ...requiredArgs, ...optionalArgs };
47
49
  const env = input.env ?? (typeof process !== 'undefined' ? process.env : {});
48
50
  const rawFromEnv = input.envVar ? env[input.envVar] : undefined;
49
51
  const fromEnv = rawFromEnv !== undefined ? Number(rawFromEnv) : undefined;
@@ -58,7 +60,7 @@ export function resolveTimeoutMs(input) {
58
60
  * `onTimeout` callback is where that would plug in).
59
61
  *
60
62
  * @param input.timeoutMs - Milliseconds of inactivity before `onTimeout` fires.
61
- * @param input.onTimeout - Fired at most once per watchdog instance.
63
+ * @param input.onTimeout - Fired once per armed timeout window; later activity can start a new window until cancellation.
62
64
  * @returns A handle to reset (`noteActivity`) or permanently disarm (`cancel`) the timer.
63
65
  * @remarks Side effect: starts a `setTimeout` immediately and calls
64
66
  * `.unref()` on it (when available) so a bare watchdog never keeps a Node
@@ -66,25 +68,35 @@ export function resolveTimeoutMs(input) {
66
68
  * @complexity O(1) per call.
67
69
  * @overallScore 100/100
68
70
  */
69
- export function createInactivityWatchdog(input) {
70
- let timer;
71
+ export function createInactivityWatchdog(input, { scheduler } = {}) {
72
+ const timers = scheduler ?? {
73
+ schedule({ delayMs, callback }) {
74
+ const timer = setTimeout(callback, delayMs);
75
+ if (typeof timer.unref === 'function')
76
+ timer.unref();
77
+ return () => clearTimeout(timer);
78
+ },
79
+ };
80
+ let cancelTimer;
81
+ // Terminal cancellation must survive activity arriving from an already-queued callback.
82
+ let cancelled = false;
71
83
  const arm = () => {
72
- if (timer) {
73
- clearTimeout(timer);
74
- }
75
- timer = setTimeout(input.onTimeout, input.timeoutMs);
76
- if (typeof timer.unref === 'function') {
77
- timer.unref();
78
- }
84
+ if (cancelled)
85
+ return;
86
+ cancelTimer?.();
87
+ cancelTimer = timers.schedule({
88
+ delayMs: input.timeoutMs,
89
+ callback: () => { if (!cancelled)
90
+ input.onTimeout(); },
91
+ });
79
92
  };
80
93
  arm();
81
94
  return {
82
95
  noteActivity: arm,
83
- cancel: () => {
84
- if (timer) {
85
- clearTimeout(timer);
86
- timer = undefined;
87
- }
96
+ cancel: (_args) => {
97
+ cancelled = true;
98
+ cancelTimer?.();
99
+ cancelTimer = undefined;
88
100
  },
89
101
  };
90
102
  }
@@ -37,5 +37,7 @@ export type ContinuationTransport = 'mcp-callback' | 'stdin-injection' | 'none';
37
37
  * @complexity O(1).
38
38
  * @overallScore 100/100
39
39
  */
40
- export declare function resolveContinuationTransport(def: RuntimeAgentDef): ContinuationTransport;
40
+ export declare function resolveContinuationTransport({ def }: {
41
+ readonly def: RuntimeAgentDef;
42
+ }): ContinuationTransport;
41
43
  //# sourceMappingURL=continuation-transport.d.ts.map
@@ -8,7 +8,7 @@
8
8
  * @complexity O(1).
9
9
  * @overallScore 100/100
10
10
  */
11
- export function resolveContinuationTransport(def) {
11
+ export function resolveContinuationTransport({ def }) {
12
12
  if (def.externalMcpInjection !== undefined)
13
13
  return 'mcp-callback';
14
14
  if (def.promptInputFormat === 'stream-json' && def.promptViaStdin === true)
@@ -14,17 +14,22 @@
14
14
  * would either leak raw, potentially untrusted agent bytes into the public
15
15
  * run-event stream or force widening `RunProtocolEvent` itself. A caller
16
16
  * supplies its own `EventLog` instance here — reusing the exact same port
17
- * type and, for a durable deployment, the exact same `@jini-ai/sqlite` adapter
17
+ * type and, for a durable deployment, the exact same `@jini-ai/daemon/store/event-log/sqlite` adapter
18
18
  * — so the journal gets the identical durability/replay guarantees without
19
19
  * touching the run-protocol vocabulary at all.
20
20
  */
21
21
  import type { JournalEntry } from '@jini-ai/protocol';
22
22
  import type { EventLog } from '../event-log.js';
23
23
  export interface RunByteJournal {
24
- /** Durably appends one journal entry for `runId`. Never rejects into caller code — see {@link createRunByteJournal}. */
25
- record(runId: string, entry: JournalEntry): Promise<void>;
24
+ /** Durably appends one journal entry for `runId`. Propagates append failures so the driver can report journal durability loss; see {@link createRunByteJournal}. */
25
+ record(args: {
26
+ readonly runId: string;
27
+ readonly entry: JournalEntry;
28
+ }): Promise<void>;
26
29
  /** Replays every journal entry recorded for `runId`, oldest first. */
27
- read(runId: string): Promise<readonly JournalEntry[]>;
30
+ read(args: {
31
+ readonly runId: string;
32
+ }): Promise<readonly JournalEntry[]>;
28
33
  }
29
34
  /**
30
35
  * Creates a `RunByteJournal` over the given `EventLog` instance.
@@ -33,5 +38,7 @@ export interface RunByteJournal {
33
38
  * @complexity Both methods are exactly as expensive as the underlying `EventLog`'s `append`/`replay`.
34
39
  * @overallScore 100/100
35
40
  */
36
- export declare function createRunByteJournal(eventLog: EventLog): RunByteJournal;
41
+ export declare function createRunByteJournal({ eventLog }: {
42
+ readonly eventLog: EventLog;
43
+ }): RunByteJournal;
37
44
  //# sourceMappingURL=journal.d.ts.map
@@ -7,13 +7,13 @@ const JOURNAL_EVENT_NAME = 'journal';
7
7
  * @complexity Both methods are exactly as expensive as the underlying `EventLog`'s `append`/`replay`.
8
8
  * @overallScore 100/100
9
9
  */
10
- export function createRunByteJournal(eventLog) {
10
+ export function createRunByteJournal({ eventLog }) {
11
11
  return {
12
- async record(runId, entry) {
12
+ async record({ runId, entry }) {
13
13
  await eventLog.append({ runId, event: JOURNAL_EVENT_NAME, data: entry });
14
14
  },
15
- async read(runId) {
16
- const replay = await eventLog.replay(runId, null);
15
+ async read({ runId }) {
16
+ const replay = await eventLog.replay({ runId: runId, afterCursor: null });
17
17
  if (replay.kind !== 'ok')
18
18
  return [];
19
19
  return replay.entries.map((entry) => entry.data);
@@ -38,7 +38,9 @@ import type { RunLifecycle } from '../run-lifecycle.js';
38
38
  */
39
39
  export declare class RunContextNotBoundError extends Error {
40
40
  readonly runId: string;
41
- constructor(runId: string);
41
+ constructor({ runId }: {
42
+ readonly runId: string;
43
+ });
42
44
  }
43
45
  export interface RunScopedContextStore<T> {
44
46
  /**
@@ -46,15 +48,22 @@ export interface RunScopedContextStore<T> {
46
48
  * state. Binding the same `runId` twice replaces the value without adding a second eviction
47
49
  * subscription.
48
50
  */
49
- bind(runId: string, value: T): void;
51
+ bind(args: {
52
+ readonly runId: string;
53
+ readonly value: T;
54
+ }): void;
50
55
  /**
51
56
  * The value bound for `runId`.
52
57
  * @throws {@link RunContextNotBoundError} when the run is unknown, already finished, or was never
53
58
  * bound. Never returns a default — see this module's doc on why fabricating one would be the bug.
54
59
  */
55
- resolve(runId: string): T;
60
+ resolve(args: {
61
+ readonly runId: string;
62
+ }): T;
56
63
  /** Whether `runId` currently has a binding. For callers that need a check without a throw. */
57
- has(runId: string): boolean;
64
+ has(args: {
65
+ readonly runId: string;
66
+ }): boolean;
58
67
  /** Live binding count. Exists so a host (or a test) can assert the map actually drains. */
59
68
  readonly size: number;
60
69
  }
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export class RunContextNotBoundError extends Error {
8
8
  runId;
9
- constructor(runId) {
9
+ constructor({ runId }) {
10
10
  super(`no context is bound for run "${runId}"`);
11
11
  this.runId = runId;
12
12
  this.name = 'RunContextNotBoundError';
@@ -25,7 +25,7 @@ export class RunContextNotBoundError extends Error {
25
25
  export function createRunScopedContextStore(options) {
26
26
  const values = new Map();
27
27
  return {
28
- bind(runId, value) {
28
+ bind({ runId, value }) {
29
29
  // Re-binding replaces the value but must not subscribe twice: each subscription is a retained
30
30
  // promise callback, and one eviction is all a run can need.
31
31
  const alreadyTracked = values.has(runId);
@@ -38,14 +38,14 @@ export function createRunScopedContextStore(options) {
38
38
  // `then(evict, evict)`, not `.finally(evict)`: a rejecting `waitForTerminal` would leave
39
39
  // `.finally`'s returned promise rejected, and nothing awaits it — an unhandled rejection that
40
40
  // could take the process down. Either outcome means the run is over, so both evict.
41
- void options.lifecycle.waitForTerminal(runId).then(evict, evict);
41
+ void options.lifecycle.waitForTerminal({ runId: runId }).then(evict, evict);
42
42
  },
43
- resolve(runId) {
43
+ resolve({ runId }) {
44
44
  if (!values.has(runId))
45
- throw new RunContextNotBoundError(runId);
45
+ throw new RunContextNotBoundError({ runId: runId });
46
46
  return values.get(runId);
47
47
  },
48
- has(runId) {
48
+ has({ runId }) {
49
49
  return values.has(runId);
50
50
  },
51
51
  get size() {
@@ -44,7 +44,7 @@ export interface ResolvedRunInput {
44
44
  * has an auto-approve flag (`bypassPermissions` / `--yolo` / `--dangerously-skip-permissions`) uses
45
45
  * it by default when this is absent. So a host that had been passing `'restricted'` to
46
46
  * `AgentExecutor.run()` by hand and then adopted `createDefaultRunStartHandler` would silently have
47
- * started auto-approving every action — a security regression wearing the clothes of a refactor.
47
+ * started auto-approving every action — the historical security regression this field prevented.
48
48
  * This field is what makes that host's existing posture expressible through the default handler.
49
49
  */
50
50
  readonly permissionMode?: 'bypass' | 'restricted';
@@ -21,22 +21,9 @@ export function createDefaultRunStartHandler(options) {
21
21
  ...(context.request.agentId !== undefined ? { agentId: context.request.agentId } : {}),
22
22
  });
23
23
  // Each optional field is spread only when present, never passed as an explicit `undefined`:
24
- // `AgentExecutor.run()` distinguishes absent from undefined for `permissionMode` in particular,
25
- // where absent means "use the def's own auto-approve default".
26
- await options.agentExecutor.run({
27
- runId: context.run.id,
28
- agentId: resolved.agentId,
29
- prompt: resolved.prompt,
30
- cwd: resolved.cwd,
31
- ...(resolved.env !== undefined ? { env: resolved.env } : {}),
32
- ...(resolved.permissionMode !== undefined ? { permissionMode: resolved.permissionMode } : {}),
33
- ...(resolved.model !== undefined ? { model: resolved.model } : {}),
34
- ...(resolved.reasoning !== undefined ? { reasoning: resolved.reasoning } : {}),
35
- ...(resolved.credentialEnv !== undefined ? { credentialEnv: resolved.credentialEnv } : {}),
36
- ...(resolved.imagePaths !== undefined ? { imagePaths: resolved.imagePaths } : {}),
37
- ...(resolved.extraAllowedDirs !== undefined ? { extraAllowedDirs: resolved.extraAllowedDirs } : {}),
38
- ...(resolved.uploadRoot !== undefined ? { uploadRoot: resolved.uploadRoot } : {}),
39
- });
24
+ // Keep absent optional fields absent on the runtime port; permission mode now defaults restricted,
25
+ // where absent now selects the daemon's fail-closed restricted default.
26
+ await options.agentExecutor.run({ runId: context.run.id, agentId: resolved.agentId, prompt: resolved.prompt, cwd: resolved.cwd }, { ...(resolved.env !== undefined ? { env: resolved.env } : {}), ...(resolved.permissionMode !== undefined ? { permissionMode: resolved.permissionMode } : {}), ...(resolved.model !== undefined ? { model: resolved.model } : {}), ...(resolved.reasoning !== undefined ? { reasoning: resolved.reasoning } : {}), ...(resolved.credentialEnv !== undefined ? { credentialEnv: resolved.credentialEnv } : {}), ...(resolved.imagePaths !== undefined ? { imagePaths: resolved.imagePaths } : {}), ...(resolved.extraAllowedDirs !== undefined ? { extraAllowedDirs: resolved.extraAllowedDirs } : {}), ...(resolved.uploadRoot !== undefined ? { uploadRoot: resolved.uploadRoot } : {}) });
40
27
  };
41
28
  }
42
29
  //# sourceMappingURL=run-start-handler.js.map
@@ -37,20 +37,24 @@ export interface DelegatedToolBridge {
37
37
  * routing errors from `ToolExecutor` and are rethrown after their error
38
38
  * result is recorded.
39
39
  */
40
- execute(invocation: DelegatedToolInvocation): Promise<ToolExecutionResult>;
40
+ execute(requiredArgs: Pick<DelegatedToolInvocation, "runId" | "toolUseId" | "toolId" | "principal" | "input">, optionalArgs?: Pick<DelegatedToolInvocation, "signal">): Promise<ToolExecutionResult>;
41
41
  }
42
42
  export interface CreateDelegatedToolBridgeOptions {
43
43
  readonly lifecycle: RunLifecycle;
44
44
  readonly toolExecutor: ToolExecutor;
45
45
  }
46
46
  /** Converts arbitrary registered-tool output into the string-bearing run protocol. */
47
- export declare function serializeDelegatedToolOutput(output: unknown): string;
47
+ export declare function serializeDelegatedToolOutput({ output }: {
48
+ readonly output: unknown;
49
+ }): string;
48
50
  /**
49
51
  * Maps a `ToolExecutionResult`'s status to the string a delegated-tool caller (this bridge, or
50
52
  * gap 3's stdin-tool-result injector in `agent-executor.ts`) reports back as the tool's visible
51
53
  * output/failure reason. Exported so both real callers share one mapping rather than drifting.
52
54
  */
53
- export declare function resultContent(result: ToolExecutionResult): string;
55
+ export declare function resultContent({ result }: {
56
+ readonly result: ToolExecutionResult;
57
+ }): string;
54
58
  /**
55
59
  * Creates the transport-neutral bridge used by future ACP-delegate, MCP, or
56
60
  * other host protocols. This module does not invent a server transport: a
@@ -30,7 +30,7 @@ function errorMessage(error) {
30
30
  return error instanceof Error ? error.message : String(error);
31
31
  }
32
32
  /** Converts arbitrary registered-tool output into the string-bearing run protocol. */
33
- export function serializeDelegatedToolOutput(output) {
33
+ export function serializeDelegatedToolOutput({ output }) {
34
34
  if (typeof output === 'string')
35
35
  return output;
36
36
  if (output === undefined)
@@ -48,10 +48,10 @@ export function serializeDelegatedToolOutput(output) {
48
48
  * gap 3's stdin-tool-result injector in `agent-executor.ts`) reports back as the tool's visible
49
49
  * output/failure reason. Exported so both real callers share one mapping rather than drifting.
50
50
  */
51
- export function resultContent(result) {
51
+ export function resultContent({ result }) {
52
52
  switch (result.status) {
53
53
  case 'completed':
54
- return serializeDelegatedToolOutput(result.output);
54
+ return serializeDelegatedToolOutput({ output: result.output });
55
55
  case 'denied':
56
56
  return 'Tool execution denied by policy.';
57
57
  case 'confirmation-denied':
@@ -72,14 +72,15 @@ export function resultContent(result) {
72
72
  */
73
73
  export function createDelegatedToolBridge(options) {
74
74
  const { lifecycle, toolExecutor } = options;
75
- async function execute(invocation) {
75
+ async function execute(requiredArgs, optionalArgs = {}) {
76
+ const invocation = { ...requiredArgs, ...optionalArgs };
76
77
  const { runId, toolUseId, toolId, principal, input } = invocation;
77
- await lifecycle.emit(runId, {
78
- event: 'agent',
79
- data: { type: 'tool_use', id: toolUseId, name: toolId, input },
80
- });
78
+ await lifecycle.emit({ runId: runId, input: {
79
+ event: 'agent',
80
+ data: { type: 'tool_use', id: toolUseId, name: toolId, input },
81
+ } });
81
82
  const controller = new AbortController();
82
- const unsubscribeCancel = lifecycle.onCancelRequested(runId, () => controller.abort());
83
+ const unsubscribeCancel = lifecycle.onCancelRequested({ runId: runId, listener: () => controller.abort() });
83
84
  const abortFromTransport = () => controller.abort();
84
85
  if (invocation.signal) {
85
86
  if (invocation.signal.aborted)
@@ -138,11 +139,11 @@ export function createDelegatedToolBridge(options) {
138
139
  type: emission.channel,
139
140
  ...correlationFor(emission.channel, toolUseId),
140
141
  };
141
- await lifecycle.emit(runId, { event: 'agent', data });
142
+ await lifecycle.emit({ runId: runId, input: { event: 'agent', data } });
142
143
  };
143
144
  try {
144
145
  try {
145
- const executed = await toolExecutor.execute(principal, run, toolId, input, controller.signal, emitSurface);
146
+ const executed = await toolExecutor.execute({ principal: principal, run: run, toolId: toolId, input: input }, { signal: controller.signal, emitSurface: emitSurface });
146
147
  settled = true;
147
148
  // Recognized media blocks (images) are collected here purely to populate the sibling
148
149
  // `media` field the `tool_result` event carries below, for a UI that wants to render one
@@ -157,7 +158,7 @@ export function createDelegatedToolBridge(options) {
157
158
  // that the sibling `media` field was the only channel a caller needed — true for a UI
158
159
  // reading the run's event stream, false for `@jini-ai/mcp`'s `execute_delegated_tool`, which
159
160
  // hands the bridge's RETURN VALUE to the model with no access to that event stream at all.)
160
- const { media } = extractResultMedia(executed.output);
161
+ const { media } = extractResultMedia({ output: executed.output });
161
162
  // THE MODEL/HUMAN FORK. A tool call's return value is definitionally what the model
162
163
  // receives, so a UI resource left inside it is model-visible context no matter what any
163
164
  // downstream layer does — `@jini-ai/mcp`'s `okResult()` JSON.stringifies the whole result
@@ -167,34 +168,34 @@ export function createDelegatedToolBridge(options) {
167
168
  // Whitelist, not blacklist: only block types known to be model-safe survive into `output`;
168
169
  // everything else is withheld and emitted for the human. See `tool-result-surfaces.ts` for
169
170
  // why that direction is load-bearing.
170
- const { modelOutput, surfaces } = splitToolResultSurfaces(executed.output);
171
+ const { modelOutput, surfaces } = splitToolResultSurfaces({ output: executed.output });
171
172
  const result = surfaces.length === 0 ? executed : { ...executed, output: modelOutput };
172
173
  // Emitted BEFORE `tool_result` so the surface is on screen by the time the transcript shows
173
174
  // the call completing — otherwise the human is asked to confirm something not yet visible.
174
175
  for (const surface of surfaces) {
175
- await lifecycle.emit(runId, {
176
- event: 'agent',
177
- data: { type: MCP_UI_EVENT_TYPE, toolUseId, resource: surface },
178
- });
176
+ await lifecycle.emit({ runId: runId, input: {
177
+ event: 'agent',
178
+ data: { type: MCP_UI_EVENT_TYPE, toolUseId, resource: surface },
179
+ } });
179
180
  }
180
- await lifecycle.emit(runId, {
181
- event: 'agent',
182
- data: {
183
- type: 'tool_result',
184
- toolUseId,
185
- content: resultContent(result),
186
- ...(result.status === 'completed' ? {} : { isError: true }),
187
- ...(media.length > 0 ? { media } : {}),
188
- },
189
- });
181
+ await lifecycle.emit({ runId: runId, input: {
182
+ event: 'agent',
183
+ data: {
184
+ type: 'tool_result',
185
+ toolUseId,
186
+ content: resultContent({ result }),
187
+ ...(result.status === 'completed' ? {} : { isError: true }),
188
+ ...(media.length > 0 ? { media } : {}),
189
+ },
190
+ } });
190
191
  return result;
191
192
  }
192
193
  catch (error) {
193
194
  settled = true;
194
- await lifecycle.emit(runId, {
195
- event: 'agent',
196
- data: { type: 'tool_result', toolUseId, content: errorMessage(error), isError: true },
197
- });
195
+ await lifecycle.emit({ runId: runId, input: {
196
+ event: 'agent',
197
+ data: { type: 'tool_result', toolUseId, content: errorMessage(error), isError: true },
198
+ } });
198
199
  throw error;
199
200
  }
200
201
  }
@@ -14,27 +14,29 @@
14
14
  * JSONL tail file that nothing ever reads back for replay. Because the durable half lives outside
15
15
  * any port, a non-OD consumer that only wires the in-memory ring silently loses in-flight output
16
16
  * on a long-run reload. `EventLog` is the fix: a single, storage-agnostic port that any adapter
17
- * (this module's in-memory reference implementation, or `@jini-ai/sqlite`'s durable adapter)
17
+ * (this module's in-memory reference implementation, or `@jini-ai/daemon/store/event-log/sqlite`'s durable adapter)
18
18
  * can satisfy.
19
19
  */
20
- export type { EventLog, EventLogAppendInput, EventLogEntry, EventLogReplayResult, } from '@jini-ai/protocol';
20
+ export type { EventLog, EventLogAppendInput, EventLogAppendOptions, EventLogEntry, EventLogReplayResult, } from '@jini-ai/protocol';
21
21
  import type { EventLog } from '@jini-ai/protocol';
22
22
  export interface InMemoryEventLogOptions {
23
23
  /**
24
24
  * Maximum entries retained per run before the oldest are evicted. Eviction is opt-in: if
25
25
  * omitted, retention is unbounded and nothing is ever silently dropped. Pass an explicit
26
- * value only when bounded memory (or, for `@jini-ai/sqlite`, bounded disk) is a deliberate
26
+ * value only when bounded memory (or, for `@jini-ai/daemon/store/event-log/sqlite`, bounded disk) is a deliberate
27
27
  * choice — the caller then owns the tradeoff, rather than inheriting a hidden 2000-entry
28
28
  * cap OD's own in-memory ring happened to use.
29
29
  */
30
30
  readonly maxEntriesPerRun?: number;
31
+ /** Host clock; defaults to Date.now to preserve recorded timestamps. */
32
+ readonly now?: () => number;
31
33
  }
32
34
  /**
33
35
  * Reference `EventLog` implementation: a per-run FIFO array, optionally capped at
34
36
  * `maxEntriesPerRun` (opt-in — see {@link InMemoryEventLogOptions}), functionally a ring
35
37
  * buffer once a cap is set (oldest entries evicted once the cap is exceeded) without needing
36
38
  * an actual circular-index structure at this scale. This is the in-memory half only — no
37
- * durable copy — matching this task's scope (a real persistent adapter is `@jini-ai/sqlite`'s
39
+ * durable copy — matching this task's scope (a real persistent adapter is `@jini-ai/daemon/store/event-log/sqlite`'s
38
40
  * job).
39
41
  *
40
42
  * @param options.maxEntriesPerRun - Retention cap per run, see {@link InMemoryEventLogOptions}.
@@ -43,5 +45,5 @@ export interface InMemoryEventLogOptions {
43
45
  * splice, k = entries over cap, which is normally 1). `replay` is O(n) in
44
46
  * the number of retained entries for the run.
45
47
  */
46
- export declare function createInMemoryEventLog(options?: InMemoryEventLogOptions): EventLog;
48
+ export declare function createInMemoryEventLog(_requiredArgs: Record<string, never>, options?: InMemoryEventLogOptions): EventLog;
47
49
  //# sourceMappingURL=event-log.d.ts.map
package/dist/event-log.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * `maxEntriesPerRun` (opt-in — see {@link InMemoryEventLogOptions}), functionally a ring
4
4
  * buffer once a cap is set (oldest entries evicted once the cap is exceeded) without needing
5
5
  * an actual circular-index structure at this scale. This is the in-memory half only — no
6
- * durable copy — matching this task's scope (a real persistent adapter is `@jini-ai/sqlite`'s
6
+ * durable copy — matching this task's scope (a real persistent adapter is `@jini-ai/daemon/store/event-log/sqlite`'s
7
7
  * job).
8
8
  *
9
9
  * @param options.maxEntriesPerRun - Retention cap per run, see {@link InMemoryEventLogOptions}.
@@ -12,8 +12,9 @@
12
12
  * splice, k = entries over cap, which is normally 1). `replay` is O(n) in
13
13
  * the number of retained entries for the run.
14
14
  */
15
- export function createInMemoryEventLog(options = {}) {
15
+ export function createInMemoryEventLog(_requiredArgs, options = {}) {
16
16
  const maxEntriesPerRun = options.maxEntriesPerRun;
17
+ const now = options.now ?? Date.now;
17
18
  const runs = new Map();
18
19
  function getOrCreateRunLog(runId) {
19
20
  let runLog = runs.get(runId);
@@ -24,10 +25,10 @@ export function createInMemoryEventLog(options = {}) {
24
25
  return runLog;
25
26
  }
26
27
  return {
27
- async append(input) {
28
+ async append(input, options = {}) {
28
29
  const runLog = getOrCreateRunLog(input.runId);
29
- if (input.dedupeKey !== undefined) {
30
- const existing = runLog.dedupeIndex.get(input.dedupeKey);
30
+ if (options.dedupeKey !== undefined) {
31
+ const existing = runLog.dedupeIndex.get(options.dedupeKey);
31
32
  if (existing) {
32
33
  return existing;
33
34
  }
@@ -36,19 +37,19 @@ export function createInMemoryEventLog(options = {}) {
36
37
  id: String(runLog.nextId),
37
38
  event: input.event,
38
39
  data: input.data,
39
- recordedAt: Date.now(),
40
+ recordedAt: now(),
40
41
  };
41
42
  runLog.nextId += 1;
42
43
  runLog.entries.push(entry);
43
- if (input.dedupeKey !== undefined) {
44
- runLog.dedupeIndex.set(input.dedupeKey, entry);
44
+ if (options.dedupeKey !== undefined) {
45
+ runLog.dedupeIndex.set(options.dedupeKey, entry);
45
46
  }
46
47
  if (maxEntriesPerRun !== undefined && runLog.entries.length > maxEntriesPerRun) {
47
48
  runLog.entries.splice(0, runLog.entries.length - maxEntriesPerRun);
48
49
  }
49
50
  return entry;
50
51
  },
51
- async replay(runId, afterCursor) {
52
+ async replay({ runId, afterCursor }) {
52
53
  const runLog = runs.get(runId);
53
54
  if (!runLog) {
54
55
  return { kind: 'unknown-run' };
@@ -80,10 +81,10 @@ export function createInMemoryEventLog(options = {}) {
80
81
  entries: runLog.entries.filter((entry) => Number(entry.id) > afterCursorNum),
81
82
  };
82
83
  },
83
- async listRunIds() {
84
+ async listRunIds(_requiredArgs) {
84
85
  return Array.from(runs.keys()).sort();
85
86
  },
86
- async drop(runId) {
87
+ async drop({ runId }) {
87
88
  runs.delete(runId);
88
89
  },
89
90
  };
@@ -98,5 +98,5 @@ export interface CreateFrontendCapabilityRegistrationsOptions {
98
98
  *
99
99
  * @complexity O(n) in `capabilities`; each handler is O(1) plus the round trip to the surface.
100
100
  */
101
- export declare function createFrontendCapabilityRegistrations(options: CreateFrontendCapabilityRegistrationsOptions): readonly ToolRegistration[];
101
+ export declare function createFrontendCapabilityRegistrations(requiredArgs: Pick<CreateFrontendCapabilityRegistrationsOptions, "registry" | "capabilities">, optionalArgs?: Pick<CreateFrontendCapabilityRegistrationsOptions, "policy" | "timeoutMs" | "maxOutputBytes">): readonly ToolRegistration[];
102
102
  //# sourceMappingURL=frontend-capability-tools.d.ts.map
@@ -43,7 +43,8 @@ function toCapabilityInput(capabilityId, input) {
43
43
  *
44
44
  * @complexity O(n) in `capabilities`; each handler is O(1) plus the round trip to the surface.
45
45
  */
46
- export function createFrontendCapabilityRegistrations(options) {
46
+ export function createFrontendCapabilityRegistrations(requiredArgs, optionalArgs = {}) {
47
+ const options = { ...requiredArgs, ...optionalArgs };
47
48
  const { registry, capabilities, policy = denyAllFrontendCapabilityPolicy, timeoutMs = DEFAULT_FRONTEND_CAPABILITY_TIMEOUT_MS, maxOutputBytes, } = options;
48
49
  return capabilities.map((capability) => ({
49
50
  descriptor: {
@@ -62,7 +63,7 @@ export function createFrontendCapabilityRegistrations(options) {
62
63
  policy,
63
64
  // `ctx.signal` is `ToolExecutor`'s own timeout/cancel signal, so the descriptor's `timeoutMs`
64
65
  // and a cancelled run both reach the pending invocation without this module owning a timer.
65
- handler: async (ctx) => registry.invoke(ctx.run.id, capability.id, toCapabilityInput(capability.id, ctx.input), ctx.signal),
66
+ handler: async (ctx) => registry.invoke({ runId: ctx.run.id, capabilityId: capability.id, input: toCapabilityInput(capability.id, ctx.input) }, { signal: ctx.signal }),
66
67
  }));
67
68
  }
68
69
  //# sourceMappingURL=frontend-capability-tools.js.map