@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
@@ -0,0 +1,138 @@
1
+ export interface RunScopedCaller {
2
+ readonly runId: string;
3
+ readonly principalId: string;
4
+ }
5
+ export interface CredentialCryptoPort {
6
+ mintToken(args: Record<string, never>): string;
7
+ digest(args: {
8
+ token: string;
9
+ }): string;
10
+ tokensMatch(args: {
11
+ presented: string;
12
+ expected: string;
13
+ }): boolean;
14
+ }
15
+ /** Explicit Node adapter; consumers can inject an alternate crypto implementation. */
16
+ export declare function createNodeCredentialCrypto(_args: Record<string, never>): CredentialCryptoPort;
17
+ export interface RunScopedCallerResolver {
18
+ resolveCaller(args: {
19
+ token: string;
20
+ }): RunScopedCaller | undefined;
21
+ }
22
+ export interface RunScopedCredentials extends RunScopedCallerResolver {
23
+ mint(args: {
24
+ runId: string;
25
+ }): string;
26
+ resolvePrincipal(args: {
27
+ token: string;
28
+ }): string | undefined;
29
+ revoke(args: {
30
+ runId: string;
31
+ }): void;
32
+ }
33
+ export declare function createRunScopedCredentials(deps: {
34
+ principalOfLiveRun(args: {
35
+ runId: string;
36
+ }): string | undefined;
37
+ crypto: Pick<CredentialCryptoPort, 'mintToken' | 'digest'>;
38
+ }): RunScopedCredentials;
39
+ export declare function ensureAgentDaemonToken({ env, envVarName, crypto }: {
40
+ env: Record<string, string | undefined>;
41
+ envVarName: string;
42
+ crypto: Pick<CredentialCryptoPort, 'mintToken'>;
43
+ }): string;
44
+ export interface RouteAccessPolicy {
45
+ /** Return a URL-decoded run ID; malformed encoding must throw URIError. */
46
+ targetRun(args: {
47
+ path: string;
48
+ }): string | undefined;
49
+ allowsRunScoped(args: {
50
+ method: string;
51
+ path: string;
52
+ }): boolean;
53
+ isDelegatedCall(args: {
54
+ method: string;
55
+ path: string;
56
+ }): boolean;
57
+ isEventStream(args: {
58
+ path: string;
59
+ }): boolean;
60
+ }
61
+ /** Host supplies route names; this module owns matching and run isolation. */
62
+ export declare function createRouteAccessPolicy({ runPathPrefix, delegatedToolCallsPath, eventStreamSuffix, allowedRoutes }: {
63
+ runPathPrefix: string;
64
+ delegatedToolCallsPath: string;
65
+ eventStreamSuffix: string;
66
+ allowedRoutes: readonly {
67
+ method: string;
68
+ path: RegExp;
69
+ }[];
70
+ }): RouteAccessPolicy;
71
+ export type AccessDecision = {
72
+ allowed: true;
73
+ principalHeader?: {
74
+ name: string;
75
+ value: string;
76
+ };
77
+ } | {
78
+ allowed: false;
79
+ status: 400 | 401 | 403 | 404 | 503;
80
+ body: unknown;
81
+ };
82
+ /** Transport-independent bearer gate. Apply principalHeader only after an allowed decision. */
83
+ export declare function authorizeDaemonRequest({ request, env, envVarName, principalHeaderName, authorizationHeaderName, crypto, routes }: {
84
+ request: {
85
+ method: string;
86
+ path: string;
87
+ headers: Readonly<Record<string, string | undefined>>;
88
+ body?: unknown;
89
+ };
90
+ env: Readonly<Record<string, string | undefined>>;
91
+ envVarName: string;
92
+ principalHeaderName: string;
93
+ authorizationHeaderName: string;
94
+ crypto: Pick<CredentialCryptoPort, 'tokensMatch'>;
95
+ routes: RouteAccessPolicy;
96
+ }, { exemptPaths, runScopedCallers, validateDelegatedRunId }?: {
97
+ exemptPaths?: readonly string[];
98
+ runScopedCallers?: RunScopedCallerResolver;
99
+ validateDelegatedRunId?: boolean;
100
+ }): AccessDecision;
101
+ export interface RunOwnerRegistry {
102
+ record(args: {
103
+ runId: string;
104
+ principalId: string;
105
+ }): void;
106
+ ownerOf(args: {
107
+ runId: string;
108
+ }): string | undefined;
109
+ forget(args: {
110
+ runId: string;
111
+ }): void;
112
+ }
113
+ export declare function createRunOwnerRegistry(_args: Record<string, never>): RunOwnerRegistry;
114
+ /** Mount after the bearer gate; principalId must be server verified. */
115
+ export declare function authorizeRunOwnership({ runId, principalId, principalHeaderName, registry, runExists, eventStream }: {
116
+ runId: string | undefined;
117
+ principalId: string | undefined;
118
+ principalHeaderName: string;
119
+ registry: RunOwnerRegistry;
120
+ runExists: (args: {
121
+ runId: string;
122
+ }) => Promise<boolean>;
123
+ eventStream: boolean;
124
+ }): Promise<AccessDecision>;
125
+ export declare function listOwnedRuns<Run extends {
126
+ id: string;
127
+ }>({ runs, registry, principalId, principalHeaderName }: {
128
+ runs: readonly Run[];
129
+ registry: RunOwnerRegistry;
130
+ principalId: string | undefined;
131
+ principalHeaderName: string;
132
+ }): {
133
+ allowed: true;
134
+ runs: Run[];
135
+ } | Exclude<AccessDecision, {
136
+ allowed: true;
137
+ }>;
138
+ //# sourceMappingURL=run-credentials.d.ts.map
@@ -0,0 +1,152 @@
1
+ import { timingSafeTokenMatch } from '@jini-ai/core';
2
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
3
+ /** Explicit Node adapter; consumers can inject an alternate crypto implementation. */
4
+ export function createNodeCredentialCrypto(_args) {
5
+ return {
6
+ mintToken: () => randomBytes(32).toString('hex'),
7
+ digest: ({ token }) => createHash('sha256').update(token, 'utf8').digest('hex'),
8
+ tokensMatch({ presented, expected }) {
9
+ return timingSafeTokenMatch({ presented, expected, timingSafeEqual: ({ left, right }) => timingSafeEqual(left, right) });
10
+ },
11
+ };
12
+ }
13
+ export function createRunScopedCredentials(deps) {
14
+ const runByDigest = new Map();
15
+ const tokens = new Map();
16
+ const resolveCaller = ({ token }) => {
17
+ const runId = runByDigest.get(deps.crypto.digest({ token }));
18
+ if (runId === undefined)
19
+ return undefined;
20
+ const principalId = deps.principalOfLiveRun({ runId });
21
+ return principalId === undefined ? undefined : { runId, principalId };
22
+ };
23
+ return {
24
+ mint({ runId }) {
25
+ if (deps.principalOfLiveRun({ runId }) === undefined)
26
+ throw new Error(`cannot mint a credential for run "${runId}": it is not live`);
27
+ const existing = tokens.get(runId);
28
+ if (existing !== undefined)
29
+ return existing;
30
+ const token = deps.crypto.mintToken({});
31
+ const digest = deps.crypto.digest({ token });
32
+ if (!token || runByDigest.has(digest))
33
+ throw new Error('run credential must be nonempty and unique');
34
+ tokens.set(runId, token);
35
+ runByDigest.set(digest, runId);
36
+ return token;
37
+ },
38
+ resolveCaller,
39
+ resolvePrincipal: args => resolveCaller(args)?.principalId,
40
+ revoke({ runId }) {
41
+ const token = tokens.get(runId);
42
+ if (token === undefined)
43
+ return;
44
+ tokens.delete(runId);
45
+ runByDigest.delete(deps.crypto.digest({ token }));
46
+ },
47
+ };
48
+ }
49
+ export function ensureAgentDaemonToken({ env, envVarName, crypto }) {
50
+ const existing = env[envVarName];
51
+ if (typeof existing === 'string' && existing.length > 0)
52
+ return existing;
53
+ const token = crypto.mintToken({});
54
+ if (!token)
55
+ throw new Error('daemon credential must be nonempty');
56
+ env[envVarName] = token;
57
+ return token;
58
+ }
59
+ /** Host supplies route names; this module owns matching and run isolation. */
60
+ export function createRouteAccessPolicy({ runPathPrefix, delegatedToolCallsPath, eventStreamSuffix, allowedRoutes }) {
61
+ return {
62
+ targetRun({ path }) {
63
+ // Binding is case insensitive as in the original gate, while the allowlist remains exact.
64
+ const prefix = runPathPrefix.endsWith('/') ? runPathPrefix : `${runPathPrefix}/`;
65
+ if (!path.toLowerCase().startsWith(prefix.toLowerCase()))
66
+ return undefined;
67
+ const segment = path.slice(prefix.length).split('/')[0];
68
+ return segment ? decodeURIComponent(segment) : undefined;
69
+ },
70
+ allowsRunScoped({ method, path }) {
71
+ // Strip stateful flags so repeated calls cannot alternate permission decisions.
72
+ return allowedRoutes.some(route => route.method === method && new RegExp(route.path.source, route.path.flags.replace(/[gy]/g, '')).test(path));
73
+ },
74
+ isDelegatedCall: ({ method, path }) => method === 'POST' && path === delegatedToolCallsPath,
75
+ isEventStream: ({ path }) => path.toLowerCase().replace(/\/$/, '').endsWith(eventStreamSuffix.toLowerCase()),
76
+ };
77
+ }
78
+ const bearerPattern = /^Bearer[ \t]+(\S+)[ \t]*$/i;
79
+ function notFound(runId, stream) {
80
+ return { allowed: false, status: 404, body: { error: { code: 'NOT_FOUND', message: stream ? 'run was not found' : `run "${runId}" was not found` } } };
81
+ }
82
+ /** Transport-independent bearer gate. Apply principalHeader only after an allowed decision. */
83
+ export function authorizeDaemonRequest({ request, env, envVarName, principalHeaderName, authorizationHeaderName, crypto, routes }, { exemptPaths = [], runScopedCallers, validateDelegatedRunId = false } = {}) {
84
+ const authorization = request.headers[authorizationHeaderName];
85
+ if (exemptPaths.includes(request.path) && authorization === undefined)
86
+ return { allowed: true };
87
+ const expected = env[envVarName];
88
+ if (typeof expected !== 'string' || expected.length === 0)
89
+ return {
90
+ allowed: false, status: 503, body: { error: `the agent daemon is not configured: ${envVarName} is unset`, code: 'AGENT_DAEMON_UNCONFIGURED' },
91
+ };
92
+ const token = bearerPattern.exec(authorization ?? '')?.[1];
93
+ if (token !== undefined && crypto.tokensMatch({ presented: token, expected }))
94
+ return { allowed: true };
95
+ const caller = token === undefined ? undefined : runScopedCallers?.resolveCaller({ token });
96
+ if (caller === undefined)
97
+ return { allowed: false, status: 401, body: { error: `Authorization: Bearer <${envVarName}> is required`, code: 'UNAUTHENTICATED' } };
98
+ let target;
99
+ try {
100
+ target = routes.targetRun({ path: request.path });
101
+ }
102
+ catch (error) {
103
+ if (!(error instanceof URIError))
104
+ throw error;
105
+ return { allowed: false, status: 400, body: { error: { code: 'BAD_REQUEST', message: 'runId is not valid URL encoding' } } };
106
+ }
107
+ if (target !== undefined && target !== caller.runId)
108
+ return notFound(target, routes.isEventStream({ path: request.path }));
109
+ if (!routes.allowsRunScoped(request))
110
+ return { allowed: false, status: 403, body: { error: `a run-scoped credential cannot call ${request.method} ${request.path}`, code: 'FORBIDDEN' } };
111
+ if (validateDelegatedRunId && routes.isDelegatedCall(request)) {
112
+ const bodyRunId = request.body !== null && typeof request.body === 'object' ? request.body['runId'] : undefined;
113
+ if (bodyRunId !== caller.runId)
114
+ return { allowed: false, status: 403, body: { error: 'a run-scoped credential requires body.runId to match its own run', code: 'FORBIDDEN' } };
115
+ }
116
+ return { allowed: true, principalHeader: { name: principalHeaderName, value: caller.principalId } };
117
+ }
118
+ export function createRunOwnerRegistry(_args) {
119
+ const owners = new Map();
120
+ return {
121
+ record: ({ runId, principalId }) => { owners.set(runId, principalId); },
122
+ ownerOf: ({ runId }) => owners.get(runId),
123
+ forget: ({ runId }) => { owners.delete(runId); },
124
+ };
125
+ }
126
+ function principalRequired(principalHeaderName) {
127
+ return { allowed: false, status: 401, body: { error: { code: 'UNAUTHENTICATED', message: `${principalHeaderName} is required on run-scoped requests` } } };
128
+ }
129
+ /** Mount after the bearer gate; principalId must be server verified. */
130
+ export async function authorizeRunOwnership({ runId, principalId, principalHeaderName, registry, runExists, eventStream }) {
131
+ if (!principalId)
132
+ return principalRequired(principalHeaderName);
133
+ if (!runId)
134
+ return { allowed: true };
135
+ const owner = registry.ownerOf({ runId });
136
+ if (owner === principalId)
137
+ return { allowed: true };
138
+ if (owner !== undefined)
139
+ return notFound(runId, eventStream);
140
+ let exists = true;
141
+ try {
142
+ exists = await runExists({ runId });
143
+ }
144
+ catch { /* Unknown ownership fails closed on lookup failure. */ }
145
+ return exists ? notFound(runId, eventStream) : { allowed: true };
146
+ }
147
+ export function listOwnedRuns({ runs, registry, principalId, principalHeaderName }) {
148
+ if (!principalId)
149
+ return principalRequired(principalHeaderName);
150
+ return { allowed: true, runs: runs.filter(run => registry.ownerOf({ runId: run.id }) === principalId) };
151
+ }
152
+ //# sourceMappingURL=run-credentials.js.map
@@ -10,7 +10,7 @@ export interface StartRunInput {
10
10
  * returns the original run (`started: false`) instead of creating a
11
11
  * second one — new behavior this port builds fresh, since OD's own
12
12
  * `clientRequestId` is threaded through but never actually deduplicated
13
- * against (confirmed absent upstream; see `source-map.md`).
13
+ * against (confirmed absent upstream; see `archived provenance ledger`).
14
14
  */
15
15
  readonly idempotencyKey?: string;
16
16
  /** Override the generated run id — test/fixture hook only. */
@@ -70,23 +70,35 @@ export type StreamSubscribeResult = {
70
70
  }>;
71
71
  export interface RunLifecycle {
72
72
  /** Rebuilds the in-memory run index from durable EventLog records. Hosts must await this once during boot before accepting run requests. */
73
- rehydrate(): Promise<void>;
74
- start(input: StartRunInput): Promise<StartRunResult>;
75
- get(runId: string): Promise<RunStatus | undefined>;
76
- list(contextRef?: string): Promise<readonly RunStatus[]>;
73
+ rehydrate(_args: Record<string, never>): Promise<void>;
74
+ start(requiredArgs: Pick<StartRunInput, "contextRef">, optionalArgs?: Pick<StartRunInput, "agentId" | "idempotencyKey" | "runId" | "inactivityTimeoutMs">): Promise<StartRunResult>;
75
+ get(args: {
76
+ readonly runId: string;
77
+ }): Promise<RunStatus | undefined>;
78
+ list(args: Record<string, never>, optionalArgs?: {
79
+ readonly contextRef?: string;
80
+ }): Promise<readonly RunStatus[]>;
77
81
  /** Records cancellation intent. Idempotent — cancelling an already-terminal run is a no-op, not an error. */
78
82
  cancel(request: RunCancelRequest): Promise<RunStatus>;
79
83
  /** Registers a listener fired synchronously when `cancel()` is called for `runId`. Returns an unsubscribe function. */
80
- onCancelRequested(runId: string, listener: (request: RunCancelRequest) => void): Unsubscribe;
84
+ onCancelRequested(args: {
85
+ readonly runId: string;
86
+ readonly listener: (request: RunCancelRequest) => void;
87
+ }): Unsubscribe;
81
88
  /** Appends a driver-observed event and fans it out to live subscribers. Throws if `runId` is unknown or already terminal. */
82
- emit(runId: string, input: DriverEmittableInput): Promise<RunProtocolEvent>;
89
+ emit(args: {
90
+ readonly runId: string;
91
+ readonly input: DriverEmittableInput;
92
+ }): Promise<RunProtocolEvent>;
83
93
  /** Idempotent terminal transition; a second call while already terminal is a no-op that returns the existing status unchanged. */
84
- finish(input: FinishRunInput): Promise<RunStatus>;
85
- resume(runId: string): Promise<ResumeRunResult>;
94
+ finish(requiredArgs: Pick<FinishRunInput, "runId" | "status" | "code" | "signal" | "resumable">, optionalArgs?: Pick<FinishRunInput, "sessionRef">): Promise<RunStatus>;
95
+ resume(args: {
96
+ readonly runId: string;
97
+ }): Promise<ResumeRunResult>;
86
98
  /**
87
99
  * Suspends the slow-run watchdog for `runId` while a daemon-managed operation of legitimately
88
100
  * unbounded duration is in flight (e.g. an auto-resolved tool call the daemon itself awaits) — pair
89
- * with {@link RunLifecycle.resumeSlowRunNotice} once that operation concludes. `emit()` is the
101
+ * with {@link RunLifecycle.resumeSlowRunNotice} once that operation concludes. `emit()` of an agent event (excluding the notice itself) is the
90
102
  * *only* other reset signal the watchdog has, and it fires nothing while such an operation is
91
103
  * running (there is no output to stream), so without this call a tool that legitimately runs past
92
104
  * the threshold (an install, a build, a repo-wide scan) is indistinguishable from the exact
@@ -95,16 +107,22 @@ export interface RunLifecycle {
95
107
  * rather than leaving the watchdog to guess from silence alone. No-op if `runId` is unknown,
96
108
  * already terminal, or the slow-run notice is disabled kernel-wide (`slowRunThresholdMs: null`).
97
109
  */
98
- suspendSlowRunNotice(runId: string): void;
110
+ suspendSlowRunNotice(args: {
111
+ readonly runId: string;
112
+ }): void;
99
113
  /**
100
114
  * Re-arms the slow-run watchdog for `runId` with a fresh timeout window, undoing
101
115
  * {@link RunLifecycle.suspendSlowRunNotice} once the known operation concludes — so a genuinely
102
116
  * stalled stretch starting *after* that point is still caught. No-op under the same conditions as
103
117
  * `suspendSlowRunNotice`.
104
118
  */
105
- resumeSlowRunNotice(runId: string): void;
119
+ resumeSlowRunNotice(args: {
120
+ readonly runId: string;
121
+ }): void;
106
122
  /** Resolves once `runId` reaches a terminal state; resolves immediately if it already has. */
107
- waitForTerminal(runId: string): Promise<RunStatus>;
123
+ waitForTerminal(args: {
124
+ readonly runId: string;
125
+ }): Promise<RunStatus>;
108
126
  /**
109
127
  * Replays buffered history after `options.afterCursor` (or from the
110
128
  * beginning if omitted/null) and then subscribes `onEvent` for live
@@ -114,23 +132,37 @@ export interface RunLifecycle {
114
132
  * of the final `'end'` event, so a client can never silently miss the
115
133
  * terminal signal (`runs.ts` `stream()`, researched source).
116
134
  */
117
- stream(runId: string, onEvent: (event: RunProtocolEvent) => void, options?: StreamOptions): Promise<StreamSubscribeResult>;
135
+ stream(args: {
136
+ readonly runId: string;
137
+ readonly onEvent: (event: RunProtocolEvent) => void;
138
+ }, optionalArgs?: StreamOptions): Promise<StreamSubscribeResult>;
118
139
  }
119
140
  /**
120
141
  * `start()`'s idempotency-replay lookup: the run id an existing `idempotencyKey` already maps to,
121
142
  * or `undefined` when there is no key or no existing mapping (a fresh start proceeds normally).
122
143
  * Pure.
123
144
  */
124
- export declare function resolveIdempotentReplayRunId(idempotencyIndex: ReadonlyMap<string, string>, idempotencyKey: string | undefined): string | undefined;
145
+ export declare function resolveIdempotentReplayRunId({ idempotencyIndex, idempotencyKey }: {
146
+ readonly idempotencyIndex: ReadonlyMap<string, string>;
147
+ readonly idempotencyKey: string | undefined;
148
+ }): string | undefined;
125
149
  /** Registers `runId` under `idempotencyKey` in `idempotencyIndex` — a no-op when no key was supplied. */
126
- export declare function registerIdempotencyKeyIfPresent(idempotencyIndex: Map<string, string>, idempotencyKey: string | undefined, runId: string): void;
150
+ export declare function registerIdempotencyKeyIfPresent({ idempotencyIndex, idempotencyKey, runId }: {
151
+ readonly idempotencyIndex: Map<string, string>;
152
+ readonly idempotencyKey: string | undefined;
153
+ readonly runId: string;
154
+ }): void;
127
155
  /**
128
156
  * Removes `idempotencyKey`'s mapping from `idempotencyIndex`, but only when it still points at
129
157
  * `runId` — used to roll back a failed durable `'start'` append without clobbering a different
130
158
  * run that may have since claimed the same key (defensive; `start()`'s own locking makes that
131
159
  * race unreachable today, but the check costs nothing and documents the invariant).
132
160
  */
133
- export declare function clearIdempotencyIndexEntryIfMatching(idempotencyIndex: Map<string, string>, idempotencyKey: string | undefined, runId: string): void;
161
+ export declare function clearIdempotencyIndexEntryIfMatching({ idempotencyIndex, idempotencyKey, runId }: {
162
+ readonly idempotencyIndex: Map<string, string>;
163
+ readonly idempotencyKey: string | undefined;
164
+ readonly runId: string;
165
+ }): void;
134
166
  /**
135
167
  * Default terminal-run retention window: how long a completed/failed/cancelled run's in-memory
136
168
  * record stays readable via `get`/`list`/`stream`/`resume` before eviction. `runs.set()` never had
@@ -152,7 +184,7 @@ export declare const DEFAULT_TERMINAL_RETENTION_MS: number;
152
184
  export declare const DEFAULT_MAX_TERMINAL_RUNS = 1000;
153
185
  /**
154
186
  * Default wall-clock threshold for the slow-run notice (distinct from the crash/inactivity watchdog
155
- * above): how long a run may go with no `emit()` before a `'slow_running'` agent event tells the UI
187
+ * above): how long a run may go with no agent-event `emit()` (excluding the notice itself) before a `'slow_running'` agent event tells the UI
156
188
  * "this is taking longer than usual," without ever finishing the run. See {@link armSlowRunWatchdogIfConfigured}'s
157
189
  * doc for the full "why a second, non-terminating watchdog" rationale. 45s was picked as long enough
158
190
  * that an ordinary quiet stretch (the agent thinking between tool calls, a slow but healthy model
@@ -169,17 +201,28 @@ export declare const DEFAULT_SLOW_RUN_THRESHOLD_MS = 45000;
169
201
  * where a run may have gone terminal long before this process started) schedules an immediate
170
202
  * eviction rather than a negative-delay timer. Pure.
171
203
  */
172
- export declare function computeRetentionDelayMs(terminalAt: number, retentionMs: number, now: number): number;
204
+ export declare function computeRetentionDelayMs({ terminalAt, retentionMs, now }: {
205
+ readonly terminalAt: number;
206
+ readonly retentionMs: number;
207
+ readonly now: number;
208
+ }): number;
173
209
  /** The durable `'start'` entry's payload — pure field mapping, split out of `start()` so its two optional-field spreads don't count toward that method's own complexity. */
174
- export declare function buildStartPayload(runId: string, startInput: Pick<StartRunInput, 'contextRef' | 'agentId' | 'idempotencyKey'>): RunStartPayload;
210
+ export declare function buildStartPayload({ runId, startInput }: {
211
+ readonly runId: string;
212
+ readonly startInput: Pick<StartRunInput, 'contextRef' | 'agentId' | 'idempotencyKey'>;
213
+ }): RunStartPayload;
175
214
  /**
176
215
  * Arms `record.watchdog` when `timeoutMs` is configured — a no-op otherwise. `record` is typed as a
177
216
  * plain `{watchdog}` shape (not `Pick<RunRecord, 'watchdog'>`) purely so this function can be
178
217
  * exported without naming the private `RunRecord` type in a public signature.
179
218
  */
180
- export declare function armWatchdogIfConfigured(record: {
181
- watchdog: InactivityWatchdog | undefined;
182
- }, timeoutMs: number | undefined, onTimeout: () => void): void;
219
+ export declare function armWatchdogIfConfigured({ record, timeoutMs, onTimeout }: {
220
+ readonly record: {
221
+ watchdog: InactivityWatchdog | undefined;
222
+ };
223
+ readonly timeoutMs: number | undefined;
224
+ readonly onTimeout: () => void;
225
+ }): void;
183
226
  /**
184
227
  * Arms `record.slowRunWatchdog` when `timeoutMs` is configured — a no-op otherwise (the kernel-wide
185
228
  * opt-out: `CreateRunLifecycleInput.slowRunThresholdMs: null`). Deliberately a sibling of
@@ -190,31 +233,47 @@ export declare function armWatchdogIfConfigured(record: {
190
233
  * three-line dedup. `record` is typed as a plain `{slowRunWatchdog}` shape for the same exportability
191
234
  * reason {@link armWatchdogIfConfigured} already documents.
192
235
  */
193
- export declare function armSlowRunWatchdogIfConfigured(record: {
194
- slowRunWatchdog: InactivityWatchdog | undefined;
195
- }, timeoutMs: number | undefined, onTimeout: () => void): void;
236
+ export declare function armSlowRunWatchdogIfConfigured({ record, timeoutMs, onTimeout }: {
237
+ readonly record: {
238
+ slowRunWatchdog: InactivityWatchdog | undefined;
239
+ };
240
+ readonly timeoutMs: number | undefined;
241
+ readonly onTimeout: () => void;
242
+ }): void;
196
243
  /**
197
244
  * `stream()`'s replay-delivery step: sends every already-durable entry to `onEvent`, returning the
198
245
  * delivered eventIds so a caller can avoid re-delivering the same event from a different source
199
246
  * (buffered live events observed during the replay, a terminal catch-up event). Pure aside from
200
247
  * calling the injected `onEvent`.
201
248
  */
202
- export declare function deliverReplayedEvents(runId: string, entries: readonly EventLogEntry[], onEvent: (event: RunProtocolEvent) => void): Set<string>;
249
+ export declare function deliverReplayedEvents({ runId, entries, onEvent }: {
250
+ readonly runId: string;
251
+ readonly entries: readonly EventLogEntry[];
252
+ readonly onEvent: (event: RunProtocolEvent) => void;
253
+ }): Set<string>;
203
254
  /**
204
255
  * Delivers every event in `events` not already present in `deliveredEventIds`, marking each as
205
256
  * delivered as it goes. Reused in `stream()` for both the buffered-live-event catch-up and the
206
257
  * single terminal-event catch-up, so the "don't double-deliver" bookkeeping lives in one place.
207
258
  */
208
- export declare function deliverUndeliveredEvents(events: readonly RunProtocolEvent[], deliveredEventIds: Set<string>, onEvent: (event: RunProtocolEvent) => void): void;
259
+ export declare function deliverUndeliveredEvents({ events, deliveredEventIds, onEvent }: {
260
+ readonly events: readonly RunProtocolEvent[];
261
+ readonly deliveredEventIds: Set<string>;
262
+ readonly onEvent: (event: RunProtocolEvent) => void;
263
+ }): void;
209
264
  /**
210
265
  * Closes out a `stream()` subscription once replay and catch-up delivery are done: a terminal run's
211
266
  * subscriber is removed immediately (no further event will ever come), a still-live run's stays
212
267
  * registered behind the returned `unsubscribe`. `record` is typed as a plain `{subscribers}` shape
213
268
  * for the same exportability reason as {@link armWatchdogIfConfigured}.
214
269
  */
215
- export declare function finishStreamSubscription(record: {
216
- subscribers: Set<(event: RunProtocolEvent) => void>;
217
- }, subscriber: (event: RunProtocolEvent) => void, terminal: boolean): StreamSubscribeResult;
270
+ export declare function finishStreamSubscription({ record, subscriber, terminal }: {
271
+ readonly record: {
272
+ subscribers: Set<(event: RunProtocolEvent) => void>;
273
+ };
274
+ readonly subscriber: (event: RunProtocolEvent) => void;
275
+ readonly terminal: boolean;
276
+ }): StreamSubscribeResult;
218
277
  export interface CreateRunLifecycleInput {
219
278
  readonly eventLog: EventLog;
220
279
  /** Host-owned sink for asynchronous lifecycle failures that cannot be returned to a caller. Defaults to `console.error`. */
@@ -224,7 +283,7 @@ export interface CreateRunLifecycleInput {
224
283
  /** Hard cap on concurrently-retained terminal run records. See {@link DEFAULT_MAX_TERMINAL_RUNS}. Defaults to that constant. */
225
284
  readonly maxTerminalRuns?: number;
226
285
  /**
227
- * How long a run may go with no `emit()` before a `'slow_running'` agent event tells the UI the
286
+ * How long a run may go with no agent-event `emit()` (excluding the notice itself) before a `'slow_running'` agent event tells the UI the
228
287
  * turn is taking longer than usual — never a terminating action; see
229
288
  * {@link armSlowRunWatchdogIfConfigured}'s doc. Applies kernel-wide to every `start()`ed run, unlike
230
289
  * `StartRunInput.inactivityTimeoutMs` (which requires a per-call opt-in and none of this codebase's
@@ -249,5 +308,5 @@ export interface RunLifecycleInternalErrorContext {
249
308
  * @complexity Per-call complexities documented on each method; the registry itself is a `Map` keyed by `runId` (O(1) lookup). Memory is bounded: non-terminal runs are O(n) in concurrently-live runs, and terminal runs are capped at `maxTerminalRuns` (each additionally bounded in retention time by `terminalRetentionMs`) rather than growing for the life of the process.
250
309
  * @overallScore 100/100
251
310
  */
252
- export declare function createRunLifecycle(input: CreateRunLifecycleInput): RunLifecycle;
311
+ export declare function createRunLifecycle(requiredArgs: Pick<CreateRunLifecycleInput, "eventLog">, optionalArgs?: Pick<CreateRunLifecycleInput, "onInternalError" | "terminalRetentionMs" | "maxTerminalRuns" | "slowRunThresholdMs">): RunLifecycle;
253
312
  //# sourceMappingURL=run-lifecycle.d.ts.map