@jini-ai/daemon 0.3.8 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +124 -0
- package/README.md +50 -8
- package/dist/agent-executor/contracts.d.ts +736 -0
- package/dist/agent-executor/contracts.js +28 -0
- package/dist/agent-executor/event-translation.d.ts +87 -0
- package/dist/agent-executor/event-translation.js +230 -0
- package/dist/agent-executor/events.d.ts +190 -0
- package/dist/agent-executor/events.js +848 -0
- package/dist/agent-executor/handoff.d.ts +18 -0
- package/dist/agent-executor/handoff.js +16 -0
- package/dist/agent-executor/index.d.ts +98 -0
- package/dist/agent-executor/index.js +98 -0
- package/dist/agent-executor/launch.d.ts +375 -0
- package/dist/agent-executor/launch.js +1001 -0
- package/dist/agent-executor/mcp-bridge.d.ts +338 -0
- package/dist/agent-executor/mcp-bridge.js +835 -0
- package/dist/agent-executor/values.d.ts +5 -0
- package/dist/agent-executor/values.js +13 -0
- package/dist/agent-executor.d.ts +375 -176
- package/dist/agent-executor.js +388 -335
- package/dist/close-status.d.ts +11 -8
- package/dist/close-status.js +31 -19
- package/dist/continuation/continuation-transport.d.ts +3 -1
- package/dist/continuation/continuation-transport.js +1 -1
- package/dist/continuation/journal.d.ts +12 -5
- package/dist/continuation/journal.js +4 -4
- package/dist/continuation/run-scoped-context-store.d.ts +13 -4
- package/dist/continuation/run-scoped-context-store.js +6 -6
- package/dist/continuation/run-start-handler.d.ts +1 -1
- package/dist/continuation/run-start-handler.js +3 -16
- package/dist/delegated-tool-bridge.d.ts +7 -3
- package/dist/delegated-tool-bridge.js +32 -31
- package/dist/event-log.d.ts +7 -5
- package/dist/event-log.js +12 -11
- package/dist/frontend-capability-tools.d.ts +1 -1
- package/dist/frontend-capability-tools.js +3 -2
- package/dist/frontend-session-registry.d.ts +32 -9
- package/dist/frontend-session-registry.js +12 -11
- package/dist/http/active-context.d.ts +105 -0
- package/dist/http/active-context.js +67 -0
- package/dist/http/agents.d.ts +68 -0
- package/dist/http/agents.js +12 -0
- package/dist/http/attachments.d.ts +618 -0
- package/dist/http/attachments.js +1034 -0
- package/dist/http/cancel-owned-runs.d.ts +49 -0
- package/dist/http/cancel-owned-runs.js +35 -0
- package/dist/http/component-catalog.d.ts +84 -0
- package/dist/http/component-catalog.js +64 -0
- package/dist/http/connectors.d.ts +209 -0
- package/dist/http/connectors.js +409 -0
- package/dist/http/daemon-status.d.ts +76 -0
- package/dist/http/daemon-status.js +55 -0
- package/dist/http/db-ops.d.ts +123 -0
- package/dist/http/db-ops.js +189 -0
- package/dist/http/delegated-tools.d.ts +113 -0
- package/dist/http/delegated-tools.js +230 -0
- package/dist/http/frontend-control.d.ts +136 -0
- package/dist/http/frontend-control.js +79 -0
- package/dist/http/frontend-sessions.d.ts +110 -0
- package/dist/http/frontend-sessions.js +180 -0
- package/dist/http/health.d.ts +95 -0
- package/dist/http/health.js +40 -0
- package/dist/http/host-tools.d.ts +214 -0
- package/dist/http/host-tools.js +329 -0
- package/dist/http/index.d.ts +52 -0
- package/dist/http/index.js +27 -0
- package/dist/http/media.d.ts +146 -0
- package/dist/http/media.js +346 -0
- package/dist/http/memory.d.ts +265 -0
- package/dist/http/memory.js +328 -0
- package/dist/http/model-proxy.d.ts +49 -0
- package/dist/http/model-proxy.js +642 -0
- package/dist/http/remote-run-events.d.ts +70 -0
- package/dist/http/remote-run-events.js +224 -0
- package/dist/http/research.d.ts +48 -0
- package/dist/http/research.js +315 -0
- package/dist/http/route-manifest.d.ts +35 -0
- package/dist/http/route-manifest.js +103 -0
- package/dist/http/routines.d.ts +120 -0
- package/dist/http/routines.js +298 -0
- package/dist/http/run-credentials.d.ts +73 -0
- package/dist/http/run-credentials.js +71 -0
- package/dist/http/runs.d.ts +91 -0
- package/dist/http/runs.js +221 -0
- package/dist/http/terminals.d.ts +138 -0
- package/dist/http/terminals.js +325 -0
- package/dist/http/tool-catalog.d.ts +78 -0
- package/dist/http/tool-catalog.js +66 -0
- package/dist/http/workspace-root.d.ts +77 -0
- package/dist/http/workspace-root.js +63 -0
- package/dist/http/xai.d.ts +90 -0
- package/dist/http/xai.js +655 -0
- package/dist/image-prompt-delivery.d.ts +13 -3
- package/dist/image-prompt-delivery.js +5 -5
- package/dist/index.d.ts +556 -4
- package/dist/index.js +556 -4
- package/dist/legacy-data-migration.d.ts +59 -8
- package/dist/legacy-data-migration.js +38 -33
- package/dist/read-only-tools.d.ts +130 -0
- package/dist/read-only-tools.js +115 -0
- package/dist/remote-tool-bridge.d.ts +11 -5
- package/dist/remote-tool-bridge.js +15 -15
- package/dist/routines/index.d.ts +1 -1
- package/dist/routines/index.js +1 -1
- package/dist/routines/routine-store.d.ts +34 -12
- package/dist/routines/routine-store.js +21 -20
- package/dist/routines/schedule.d.ts +48 -10
- package/dist/routines/schedule.js +21 -21
- package/dist/routines/scheduler.d.ts +32 -11
- package/dist/routines/scheduler.js +61 -57
- package/dist/routines/types.d.ts +10 -3
- package/dist/run/core/result.d.ts +6 -2
- package/dist/run/core/result.js +3 -3
- package/dist/run/core/retry.d.ts +17 -4
- package/dist/run/core/retry.js +7 -11
- package/dist/run/diagnostics/diagnostics.d.ts +14 -4
- package/dist/run/diagnostics/diagnostics.js +7 -7
- package/dist/run/index.d.ts +1 -1
- package/dist/run/index.js +1 -1
- package/dist/run-credentials.d.ts +138 -0
- package/dist/run-credentials.js +152 -0
- package/dist/run-lifecycle.d.ts +92 -33
- package/dist/run-lifecycle.js +81 -74
- package/dist/scheduler.d.ts +8 -0
- package/dist/scheduler.js +2 -0
- package/dist/session-coordination.d.ts +115 -0
- package/dist/session-coordination.js +111 -0
- package/dist/store/agent-sessions/errors.d.ts +8 -0
- package/dist/store/agent-sessions/errors.js +10 -0
- package/dist/store/agent-sessions/index.d.ts +12 -0
- package/dist/store/agent-sessions/index.js +19 -0
- package/dist/store/agent-sessions/pglite.d.ts +12 -0
- package/dist/store/agent-sessions/pglite.js +7 -0
- package/dist/store/agent-sessions/ports.d.ts +24 -0
- package/dist/store/agent-sessions/ports.js +2 -0
- package/dist/store/agent-sessions/postgres.d.ts +12 -0
- package/dist/store/agent-sessions/postgres.js +7 -0
- package/dist/store/agent-sessions/schema.d.ts +3 -0
- package/dist/store/agent-sessions/schema.js +23 -0
- package/dist/store/agent-sessions/sql.d.ts +35 -0
- package/dist/store/agent-sessions/sql.js +59 -0
- package/dist/store/agent-sessions/sqlite.d.ts +117 -0
- package/dist/store/agent-sessions/sqlite.js +128 -0
- package/dist/store/event-log/sqlite.d.ts +75 -0
- package/dist/store/event-log/sqlite.js +230 -0
- package/dist/surface-exchanges.d.ts +97 -0
- package/dist/surface-exchanges.js +153 -0
- package/dist/terminal-session.d.ts +43 -11
- package/dist/terminal-session.js +22 -20
- package/dist/tokens.js +4 -4
- package/dist/tool-audit.d.ts +114 -0
- package/dist/tool-audit.js +95 -0
- package/dist/tool-executor.d.ts +22 -7
- package/dist/tool-executor.js +16 -16
- package/dist/tool-result-media.d.ts +3 -1
- package/dist/tool-result-media.js +1 -1
- package/dist/tool-result-surfaces.d.ts +3 -1
- package/dist/tool-result-surfaces.js +1 -1
- package/package.json +127 -9
package/dist/close-status.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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 `
|
|
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 `
|
|
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
|
+
import type { SchedulerPort } from './scheduler.js';
|
|
11
12
|
export type TerminalRunOutcome = 'succeeded' | 'failed' | 'cancelled';
|
|
12
13
|
export interface CloseStatusInput {
|
|
13
14
|
/** Whether `RunLifecycle.cancel` had already been called for this run. */
|
|
@@ -27,7 +28,7 @@ export interface CloseStatusInput {
|
|
|
27
28
|
* @complexity O(1).
|
|
28
29
|
* @overallScore 100/100
|
|
29
30
|
*/
|
|
30
|
-
export declare function classifyRunCloseStatus(
|
|
31
|
+
export declare function classifyRunCloseStatus(requiredArgs: Pick<CloseStatusInput, "cancelRequested" | "code">, optionalArgs?: Pick<CloseStatusInput, "signal">): TerminalRunOutcome;
|
|
31
32
|
export interface ResolveTimeoutMsInput {
|
|
32
33
|
/** Env var name checked first (highest precedence), e.g. `'JINI_RUN_INACTIVITY_TIMEOUT_MS'`. */
|
|
33
34
|
readonly envVar?: string;
|
|
@@ -54,12 +55,12 @@ export interface ResolveTimeoutMsInput {
|
|
|
54
55
|
* @complexity O(1).
|
|
55
56
|
* @overallScore 100/100
|
|
56
57
|
*/
|
|
57
|
-
export declare function resolveTimeoutMs(
|
|
58
|
+
export declare function resolveTimeoutMs(requiredArgs: Pick<ResolveTimeoutMsInput, "defaultMs" | "maxMs">, optionalArgs?: Pick<ResolveTimeoutMsInput, "envVar" | "agentDefaultMs" | "env">): number;
|
|
58
59
|
export interface InactivityWatchdog {
|
|
59
60
|
/** Resets the timeout window — call on every observed unit of run activity (an emitted event, a stdout chunk). */
|
|
60
|
-
noteActivity(): void;
|
|
61
|
+
noteActivity(_args: Record<string, never>): void;
|
|
61
62
|
/** Disarms the watchdog permanently (e.g. once the run reaches a terminal state). Safe to call more than once. */
|
|
62
|
-
cancel(): void;
|
|
63
|
+
cancel(_args: Record<string, never>): void;
|
|
63
64
|
}
|
|
64
65
|
export interface CreateInactivityWatchdogInput {
|
|
65
66
|
readonly timeoutMs: number;
|
|
@@ -74,7 +75,7 @@ export interface CreateInactivityWatchdogInput {
|
|
|
74
75
|
* `onTimeout` callback is where that would plug in).
|
|
75
76
|
*
|
|
76
77
|
* @param input.timeoutMs - Milliseconds of inactivity before `onTimeout` fires.
|
|
77
|
-
* @param input.onTimeout - Fired
|
|
78
|
+
* @param input.onTimeout - Fired once per armed timeout window; later activity can start a new window until cancellation.
|
|
78
79
|
* @returns A handle to reset (`noteActivity`) or permanently disarm (`cancel`) the timer.
|
|
79
80
|
* @remarks Side effect: starts a `setTimeout` immediately and calls
|
|
80
81
|
* `.unref()` on it (when available) so a bare watchdog never keeps a Node
|
|
@@ -82,5 +83,7 @@ export interface CreateInactivityWatchdogInput {
|
|
|
82
83
|
* @complexity O(1) per call.
|
|
83
84
|
* @overallScore 100/100
|
|
84
85
|
*/
|
|
85
|
-
export declare function createInactivityWatchdog(input: CreateInactivityWatchdogInput
|
|
86
|
+
export declare function createInactivityWatchdog(input: CreateInactivityWatchdogInput, { scheduler }?: {
|
|
87
|
+
scheduler?: SchedulerPort;
|
|
88
|
+
}): InactivityWatchdog;
|
|
86
89
|
//# sourceMappingURL=close-status.d.ts.map
|
package/dist/close-status.js
CHANGED
|
@@ -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 `
|
|
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 `
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
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`.
|
|
25
|
-
record(
|
|
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(
|
|
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
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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 —
|
|
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
|
-
//
|
|
25
|
-
// where absent
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
79
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
196
|
-
|
|
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
|
}
|
package/dist/event-log.d.ts
CHANGED
|
@@ -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 (
|
|
30
|
-
const existing = runLog.dedupeIndex.get(
|
|
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:
|
|
40
|
+
recordedAt: now(),
|
|
40
41
|
};
|
|
41
42
|
runLog.nextId += 1;
|
|
42
43
|
runLog.entries.push(entry);
|
|
43
|
-
if (
|
|
44
|
-
runLog.dedupeIndex.set(
|
|
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(
|
|
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(
|
|
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
|