@automatalabs/acp-agents 0.12.0 → 0.14.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.
- package/dist/acp-client.d.ts +24 -2
- package/dist/acp-client.d.ts.map +1 -1
- package/dist/acp-client.js +174 -14
- package/dist/capabilities.d.ts +11 -0
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +28 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/interactive.d.ts +14 -2
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +19 -0
- package/dist/permissions.d.ts +4 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +3 -2
- package/dist/protocol-coverage.d.ts +3 -1
- package/dist/protocol-coverage.d.ts.map +1 -1
- package/dist/protocol-coverage.js +6 -6
- package/dist/runner.d.ts +45 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +141 -53
- package/package.json +2 -2
package/dist/acp-client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ContentBlock, type AgentNotificationMethod, type AgentNotificationParamsByMethod, type AgentRequestMethod, type AgentRequestParamsByMethod, type AgentRequestResponsesByMethod, type PromptRequest, type PromptResponse, type RequestPermissionResponse, type SendRequestOptions, type SessionConfigOption, type SessionNotification, type SetSessionConfigOptionRequest, type SetSessionConfigOptionResponse } from "@agentclientprotocol/sdk";
|
|
1
|
+
import { type ContentBlock, type AgentNotificationMethod, type AgentNotificationParamsByMethod, type AgentRequestMethod, type AgentRequestParamsByMethod, type AgentRequestResponsesByMethod, type DeleteSessionRequest, type ListSessionsRequest, type ListSessionsResponse, type PromptRequest, type PromptResponse, type RequestPermissionResponse, type SendRequestOptions, type SessionConfigOption, type SessionModeState, type SessionNotification, type SetSessionConfigOptionRequest, type SetSessionConfigOptionResponse, type SetSessionModeRequest, type SetSessionModeResponse } from "@agentclientprotocol/sdk";
|
|
2
2
|
import type { TSchema } from "typebox";
|
|
3
3
|
import { type AgentHistoryEntry, type McpServerConfig } from "@automatalabs/shared-types";
|
|
4
4
|
import type { Backend, BackendId, StructuredSource } from "./backend.js";
|
|
@@ -26,10 +26,11 @@ declare class SessionState {
|
|
|
26
26
|
readonly usage: UsageAccumulator;
|
|
27
27
|
readonly pendingPermissions: Set<(outcome: RequestPermissionResponse) => void>;
|
|
28
28
|
rawResultSuccess: RawResultSuccess | undefined;
|
|
29
|
+
modes: SessionModeState | null | undefined;
|
|
29
30
|
private turnStartIndex;
|
|
30
31
|
/** `label`/`runId` are carried here ONLY so the MultiplexClient can stamp them onto emitted
|
|
31
32
|
* events as context — they never affect routing or the wire request. */
|
|
32
|
-
constructor(cwd: string, policy: ToolPolicy, permissionResolver?: PermissionResolver | undefined, label?: string | undefined, runId?: string | undefined, retainSessionLog?: boolean);
|
|
33
|
+
constructor(cwd: string, policy: ToolPolicy, permissionResolver?: PermissionResolver | undefined, label?: string | undefined, runId?: string | undefined, modes?: SessionModeState | null, retainSessionLog?: boolean);
|
|
33
34
|
/** Mark the start of a new turn so currentTurnText()/structured_output read only this turn.
|
|
34
35
|
* Long-lived interactive sessions can opt out of retaining old text/history because hosts
|
|
35
36
|
* stream live events and keep their own transcript; clearing here prevents dead logs from
|
|
@@ -126,6 +127,9 @@ export declare class PooledConnection {
|
|
|
126
127
|
/** Drop the backend-declared bare `_meta` keys the connected agent did not advertise support
|
|
127
128
|
* for (see gateCustomMeta). Applied to BOTH session/new and session/prompt `_meta`. */
|
|
128
129
|
gateCustomMeta(meta: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
|
|
130
|
+
private assertSupportedMcpServers;
|
|
131
|
+
private sessionRequestMeta;
|
|
132
|
+
private assertLifecycleSupported;
|
|
129
133
|
/** Mark this connection dead exactly once, then ask the pool to evict it. Idempotent. */
|
|
130
134
|
private die;
|
|
131
135
|
private stderrSuffix;
|
|
@@ -139,10 +143,22 @@ export declare class PooledConnection {
|
|
|
139
143
|
* synchronously (before the first await) so the pool's load accounting is race-free.
|
|
140
144
|
*/
|
|
141
145
|
openSession(opts: AcpSessionOptions): Promise<SessionHandle>;
|
|
146
|
+
/** Reopen an existing session and replay its transcript through the router before resolving. */
|
|
147
|
+
loadSession(sessionId: string, opts: AcpSessionOptions): Promise<SessionHandle>;
|
|
148
|
+
/** Reopen an existing session without transcript replay. */
|
|
149
|
+
resumeSession(sessionId: string, opts: AcpSessionOptions): Promise<SessionHandle>;
|
|
150
|
+
private rawAgentRequest;
|
|
151
|
+
private reattachSession;
|
|
152
|
+
/** session/list on a dedicated connection, gated on the initialize advertisement. */
|
|
153
|
+
listSessions(request: ListSessionsRequest, label?: string): Promise<ListSessionsResponse>;
|
|
154
|
+
/** session/delete on a dedicated connection, gated on the initialize advertisement. */
|
|
155
|
+
deleteSession(request: DeleteSessionRequest, label?: string): Promise<void>;
|
|
142
156
|
/** session/prompt on this connection, raced against process death. */
|
|
143
157
|
prompt(request: PromptRequest): Promise<PromptResponse>;
|
|
144
158
|
/** session/set_config_option on this connection, raced against process death. */
|
|
145
159
|
setSessionConfigOption(request: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse>;
|
|
160
|
+
/** session/set_mode on this connection, raced against process death. */
|
|
161
|
+
setSessionMode(request: SetSessionModeRequest): Promise<SetSessionModeResponse>;
|
|
146
162
|
/** RAW protocol escape hatch: this makes the full ACP spec reachable (for example
|
|
147
163
|
* session/set_mode, session/fork, authenticate). Prefer the named wrappers when they exist
|
|
148
164
|
* because they preserve engine semantics such as accumulation/drain and usage recording;
|
|
@@ -184,6 +200,10 @@ export declare class SessionHandle implements StructuredSource {
|
|
|
184
200
|
get usage(): UsageAccumulator;
|
|
185
201
|
/** Diagnostic message/tool history accumulated across this session's run. */
|
|
186
202
|
get history(): AgentHistoryEntry[];
|
|
203
|
+
/** Assistant text accumulated across the retained session log. */
|
|
204
|
+
get text(): string;
|
|
205
|
+
/** Agent-advertised session mode catalog plus the currently active mode, if supported. */
|
|
206
|
+
get modes(): SessionModeState | null | undefined;
|
|
187
207
|
/**
|
|
188
208
|
* Select the model for this session from the agent-advertised config options (§5.4).
|
|
189
209
|
* Returns `matched:false` (the caller fires onModelFallback) when the catalog has no value
|
|
@@ -220,6 +240,8 @@ export declare class SessionHandle implements StructuredSource {
|
|
|
220
240
|
* A boolean value drives a `type: "boolean"` option (the request must carry the type
|
|
221
241
|
* discriminator on the wire); a string value drives a select option. */
|
|
222
242
|
private applyConfigOption;
|
|
243
|
+
/** Switch the session's operating mode through ACP's strict confinement channel. */
|
|
244
|
+
setMode(modeId: string): Promise<void>;
|
|
223
245
|
/** Send a prompt turn and drain it; returns the final PromptResponse. */
|
|
224
246
|
prompt(content: string | ContentBlock[], promptMeta?: Record<string, unknown>): Promise<PromptResponse>;
|
|
225
247
|
/** StructuredSource — the latest turn's assistant text. */
|
package/dist/acp-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acp-client.d.ts","sourceRoot":"","sources":["../src/acp-client.ts"],"names":[],"mappings":"AAwBA,OAAO,EAUL,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,+BAA+B,EACpC,KAAK,kBAAkB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,
|
|
1
|
+
{"version":3,"file":"acp-client.d.ts","sourceRoot":"","sources":["../src/acp-client.ts"],"names":[],"mappings":"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"}
|
package/dist/acp-client.js
CHANGED
|
@@ -24,7 +24,7 @@ import { spawn } from "node:child_process";
|
|
|
24
24
|
import { Readable, Writable } from "node:stream";
|
|
25
25
|
import { AGENT_METHODS, client, CLIENT_METHODS, ndJsonStream, PROTOCOL_VERSION, RequestError, } from "@agentclientprotocol/sdk";
|
|
26
26
|
import { META_KEYS, WorkflowError, WorkflowErrorCode, } from "@automatalabs/shared-types";
|
|
27
|
-
import { adaptPromptContent, gateCustomMeta, isSupportedProtocolVersion, negotiateCapabilities, unsupportedMcpServer, } from "./capabilities.js";
|
|
27
|
+
import { adaptPromptContent, describeLifecycleAdvertisement, gateCustomMeta, isSupportedProtocolVersion, negotiateCapabilities, unsupportedMcpServer, } from "./capabilities.js";
|
|
28
28
|
import { emitSessionUpdate } from "./events.js";
|
|
29
29
|
import { decidePermission } from "./permissions.js";
|
|
30
30
|
import { UsageAccumulator } from "./usage.js";
|
|
@@ -42,6 +42,15 @@ const CLOSE_SESSION_TIMEOUT_MS = 5_000;
|
|
|
42
42
|
/** Bound the graceful SIGTERM shutdown before escalating to SIGKILL. */
|
|
43
43
|
const DISPOSE_SIGKILL_GRACE_MS = 2_000;
|
|
44
44
|
const TOMBSTONE_SESSION_CAP = 64;
|
|
45
|
+
const GUARDED_STATEFUL_REQUESTS = new Map([
|
|
46
|
+
[AGENT_METHODS.session_new, "use openSession()"],
|
|
47
|
+
[AGENT_METHODS.session_load, "use loadSession()"],
|
|
48
|
+
[AGENT_METHODS.session_resume, "use resumeSession()"],
|
|
49
|
+
[
|
|
50
|
+
AGENT_METHODS.session_fork,
|
|
51
|
+
"no driven wrapper yet; raw forked sessions cannot be routed (permissions auto-cancel)",
|
|
52
|
+
],
|
|
53
|
+
]);
|
|
45
54
|
/** Per-session accumulator: assistant text, tool history, usage, the Claude raw structured_output,
|
|
46
55
|
* and the permission policy/resolver used to answer permission requests for THIS session. */
|
|
47
56
|
class SessionState {
|
|
@@ -56,16 +65,18 @@ class SessionState {
|
|
|
56
65
|
usage = new UsageAccumulator();
|
|
57
66
|
pendingPermissions = new Set();
|
|
58
67
|
rawResultSuccess;
|
|
68
|
+
modes;
|
|
59
69
|
turnStartIndex = 0;
|
|
60
70
|
/** `label`/`runId` are carried here ONLY so the MultiplexClient can stamp them onto emitted
|
|
61
71
|
* events as context — they never affect routing or the wire request. */
|
|
62
|
-
constructor(cwd, policy, permissionResolver, label, runId, retainSessionLog = true) {
|
|
72
|
+
constructor(cwd, policy, permissionResolver, label, runId, modes, retainSessionLog = true) {
|
|
63
73
|
this.cwd = cwd;
|
|
64
74
|
this.policy = policy;
|
|
65
75
|
this.permissionResolver = permissionResolver;
|
|
66
76
|
this.label = label;
|
|
67
77
|
this.runId = runId;
|
|
68
78
|
this.retainSessionLog = retainSessionLog;
|
|
79
|
+
this.modes = modes;
|
|
69
80
|
}
|
|
70
81
|
/** Mark the start of a new turn so currentTurnText()/structured_output read only this turn.
|
|
71
82
|
* Long-lived interactive sessions can opt out of retaining old text/history because hosts
|
|
@@ -116,6 +127,13 @@ class SessionState {
|
|
|
116
127
|
this.usage.recordContextTokens(update.used, update.size);
|
|
117
128
|
break;
|
|
118
129
|
}
|
|
130
|
+
case "current_mode_update": {
|
|
131
|
+
this.modes = {
|
|
132
|
+
...(this.modes ?? { availableModes: [] }),
|
|
133
|
+
currentModeId: update.currentModeId,
|
|
134
|
+
};
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
119
137
|
default:
|
|
120
138
|
break;
|
|
121
139
|
}
|
|
@@ -309,6 +327,35 @@ function cancelledPermissionResponse() {
|
|
|
309
327
|
function methodNotAdvertised(method) {
|
|
310
328
|
return new RequestError(-32601, `${method} was not advertised by this client`, { method });
|
|
311
329
|
}
|
|
330
|
+
function assertSafeRawRequest(method) {
|
|
331
|
+
const guidance = GUARDED_STATEFUL_REQUESTS.get(method);
|
|
332
|
+
if (!guidance)
|
|
333
|
+
return;
|
|
334
|
+
throw new Error(`Raw ACP request "${method}" is guarded: ${guidance}. Sessions created, reopened, or forked ` +
|
|
335
|
+
"outside the router are unregistered: session/update notifications do not fold into an " +
|
|
336
|
+
"accumulator, permission requests auto-cancel, and fs/terminal dispatch fails for unknown sessions.");
|
|
337
|
+
}
|
|
338
|
+
function modeIds(modes) {
|
|
339
|
+
return modes?.availableModes.map((mode) => mode.id) ?? [];
|
|
340
|
+
}
|
|
341
|
+
function modeSelectionError(backendId, requested, advertisedIds, label, cause) {
|
|
342
|
+
const advertised = advertisedIds.length > 0 ? advertisedIds.join(", ") : "none";
|
|
343
|
+
const suffix = cause ? `: ${thrownMessage(cause)}` : "";
|
|
344
|
+
return new WorkflowError(`ACP agent (${backendId}) cannot apply session mode "${requested}" (advertised modes: ${advertised})${suffix}`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: label, details: cause });
|
|
345
|
+
}
|
|
346
|
+
function lifecycleCapabilityError(backendId, method, capabilities, label) {
|
|
347
|
+
const advertised = capabilities
|
|
348
|
+
? describeLifecycleAdvertisement(capabilities.agent)
|
|
349
|
+
: "initialize did not complete";
|
|
350
|
+
return new WorkflowError(`ACP agent (${backendId}) does not advertise ${method}; advertised lifecycle capabilities: ${advertised}`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: label });
|
|
351
|
+
}
|
|
352
|
+
function thrownMessage(error) {
|
|
353
|
+
if (error instanceof Error)
|
|
354
|
+
return error.message;
|
|
355
|
+
if (typeof error === "string")
|
|
356
|
+
return error;
|
|
357
|
+
return String(error);
|
|
358
|
+
}
|
|
312
359
|
const DEFAULT_INIT_TIMEOUT_MS = 60_000;
|
|
313
360
|
/** Deadline for the one-time ACP `initialize` handshake per pooled process. Overridable via
|
|
314
361
|
* AGENTPRISM_ACP_INIT_TIMEOUT_MS (e.g. for slow cold-start backends). Clamped to >= 1s. */
|
|
@@ -466,6 +513,35 @@ export class PooledConnection {
|
|
|
466
513
|
gateCustomMeta(meta) {
|
|
467
514
|
return gateCustomMeta(meta, this.negotiated?.customMetaSupport, this.negotiated?.gatedKeys);
|
|
468
515
|
}
|
|
516
|
+
assertSupportedMcpServers(opts) {
|
|
517
|
+
const unsupported = this.negotiated
|
|
518
|
+
? unsupportedMcpServer(opts.mcpServers, this.negotiated.agent)
|
|
519
|
+
: undefined;
|
|
520
|
+
if (!unsupported)
|
|
521
|
+
return;
|
|
522
|
+
throw new WorkflowError(`MCP server "${unsupported.name}" uses the "${unsupported.transport}" transport, which the ` +
|
|
523
|
+
`${this.backendId} agent does not support`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: opts.label });
|
|
524
|
+
}
|
|
525
|
+
sessionRequestMeta(opts) {
|
|
526
|
+
return this.gateCustomMeta(stampRunId(layerMeta(this.backend.sessionMetaDefaults?.(), opts.meta, this.backend.sessionMeta(opts.schema, {
|
|
527
|
+
baseInstructions: opts.baseInstructions,
|
|
528
|
+
developerInstructions: opts.developerInstructions,
|
|
529
|
+
})), opts.runId));
|
|
530
|
+
}
|
|
531
|
+
assertLifecycleSupported(method, label) {
|
|
532
|
+
const supported = method === AGENT_METHODS.session_load
|
|
533
|
+
? this.negotiated?.supportsLoadSession
|
|
534
|
+
: method === AGENT_METHODS.session_list
|
|
535
|
+
? this.negotiated?.supportsListSessions
|
|
536
|
+
: method === AGENT_METHODS.session_delete
|
|
537
|
+
? this.negotiated?.supportsDeleteSession
|
|
538
|
+
: method === AGENT_METHODS.session_resume
|
|
539
|
+
? this.negotiated?.supportsResumeSession
|
|
540
|
+
: false;
|
|
541
|
+
if (supported)
|
|
542
|
+
return;
|
|
543
|
+
throw lifecycleCapabilityError(this.backendId, method, this.negotiated, label);
|
|
544
|
+
}
|
|
469
545
|
/** Mark this connection dead exactly once, then ask the pool to evict it. Idempotent. */
|
|
470
546
|
die(error) {
|
|
471
547
|
if (!this._alive)
|
|
@@ -553,24 +629,14 @@ export class PooledConnection {
|
|
|
553
629
|
// does not advertise (http/sse gated on mcpCapabilities; stdio is always serviceable).
|
|
554
630
|
// Fail-fast and non-recoverable — re-running the same incompatible transport can never
|
|
555
631
|
// succeed. Lenient for agents that advertise no mcpCapabilities (the legacy passthrough).
|
|
556
|
-
|
|
557
|
-
? unsupportedMcpServer(opts.mcpServers, this.negotiated.agent)
|
|
558
|
-
: undefined;
|
|
559
|
-
if (unsupported) {
|
|
560
|
-
throw new WorkflowError(`MCP server "${unsupported.name}" uses the "${unsupported.transport}" transport, which the ` +
|
|
561
|
-
`${this.backendId} agent does not support`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: opts.label });
|
|
562
|
-
}
|
|
563
|
-
const state = new SessionState(opts.cwd, opts.policy, opts.permissionResolver, opts.label, opts.runId, opts.retainSessionLog ?? true);
|
|
632
|
+
this.assertSupportedMcpServers(opts);
|
|
564
633
|
// session/new `_meta`, layered lowest-to-highest precedence: the backend's static
|
|
565
634
|
// defaults (a custom registry entry's `sessionMeta`), then the generic user passthrough
|
|
566
635
|
// (opts.meta), then the backend's protocol-critical `_meta` (Claude schema channel;
|
|
567
636
|
// Codex base/developer instructions), then the engine runId correlation stamp. The result
|
|
568
637
|
// is gated against the agent's advertised custom capabilities (a declared key the agent
|
|
569
638
|
// said it does not honor is dropped). When no layer survives, no `_meta` is sent.
|
|
570
|
-
const meta = this.
|
|
571
|
-
baseInstructions: opts.baseInstructions,
|
|
572
|
-
developerInstructions: opts.developerInstructions,
|
|
573
|
-
})), opts.runId));
|
|
639
|
+
const meta = this.sessionRequestMeta(opts);
|
|
574
640
|
const request = {
|
|
575
641
|
cwd: opts.cwd,
|
|
576
642
|
// Client-provided MCP servers (additive run input), else the default empty list.
|
|
@@ -578,6 +644,7 @@ export class PooledConnection {
|
|
|
578
644
|
...(meta ? { _meta: meta } : {}),
|
|
579
645
|
};
|
|
580
646
|
const response = await this.race(this.connection.agent.request(AGENT_METHODS.session_new, request));
|
|
647
|
+
const state = new SessionState(opts.cwd, opts.policy, opts.permissionResolver, opts.label, opts.runId, response.modes, opts.retainSessionLog ?? true);
|
|
581
648
|
this.client.register(response.sessionId, state);
|
|
582
649
|
return new SessionHandle(this, response.sessionId, state, response.configOptions ?? [], opts);
|
|
583
650
|
}
|
|
@@ -586,6 +653,71 @@ export class PooledConnection {
|
|
|
586
653
|
throw error;
|
|
587
654
|
}
|
|
588
655
|
}
|
|
656
|
+
/** Reopen an existing session and replay its transcript through the router before resolving. */
|
|
657
|
+
loadSession(sessionId, opts) {
|
|
658
|
+
return this.reattachSession(AGENT_METHODS.session_load, sessionId, opts);
|
|
659
|
+
}
|
|
660
|
+
/** Reopen an existing session without transcript replay. */
|
|
661
|
+
resumeSession(sessionId, opts) {
|
|
662
|
+
return this.reattachSession(AGENT_METHODS.session_resume, sessionId, opts);
|
|
663
|
+
}
|
|
664
|
+
rawAgentRequest(method, params) {
|
|
665
|
+
// SDK 1.2.0 still maps session/load through emptyObjectResponse in ClientContext.request(),
|
|
666
|
+
// but both supported adapters return configOptions/modes there and the driven wrapper must
|
|
667
|
+
// adopt them. This bypasses only the SDK response mapper, not JSON-RPC validation/racing.
|
|
668
|
+
const agent = this.connection.agent;
|
|
669
|
+
return this.race(agent.sendRequest(method, params));
|
|
670
|
+
}
|
|
671
|
+
async reattachSession(method, sessionId, opts) {
|
|
672
|
+
this._activeSessions += 1;
|
|
673
|
+
let registered = false;
|
|
674
|
+
const state = new SessionState(opts.cwd, opts.policy, opts.permissionResolver, opts.label, opts.runId, undefined, opts.retainSessionLog ?? true);
|
|
675
|
+
try {
|
|
676
|
+
await this.ready;
|
|
677
|
+
this.assertLifecycleSupported(method, opts.label);
|
|
678
|
+
this.assertSupportedMcpServers(opts);
|
|
679
|
+
const meta = this.sessionRequestMeta(opts);
|
|
680
|
+
const request = {
|
|
681
|
+
sessionId,
|
|
682
|
+
cwd: opts.cwd,
|
|
683
|
+
mcpServers: opts.mcpServers ?? [],
|
|
684
|
+
...(meta ? { _meta: meta } : {}),
|
|
685
|
+
};
|
|
686
|
+
// Replayed updates and permission requests can arrive before the response, so the
|
|
687
|
+
// caller-provided id must be routable before the wire call leaves this process.
|
|
688
|
+
this.client.register(sessionId, state);
|
|
689
|
+
registered = true;
|
|
690
|
+
let response;
|
|
691
|
+
if (method === AGENT_METHODS.session_load) {
|
|
692
|
+
const loadRequest = request;
|
|
693
|
+
response = await this.rawAgentRequest(AGENT_METHODS.session_load, loadRequest);
|
|
694
|
+
}
|
|
695
|
+
else {
|
|
696
|
+
const resumeRequest = request;
|
|
697
|
+
response = await this.rawAgentRequest(AGENT_METHODS.session_resume, resumeRequest);
|
|
698
|
+
}
|
|
699
|
+
state.modes = response.modes;
|
|
700
|
+
return new SessionHandle(this, sessionId, state, response.configOptions ?? [], opts);
|
|
701
|
+
}
|
|
702
|
+
catch (error) {
|
|
703
|
+
if (registered)
|
|
704
|
+
this.client.unregister(sessionId);
|
|
705
|
+
this._activeSessions -= 1;
|
|
706
|
+
throw error;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/** session/list on a dedicated connection, gated on the initialize advertisement. */
|
|
710
|
+
async listSessions(request, label) {
|
|
711
|
+
await this.ready;
|
|
712
|
+
this.assertLifecycleSupported(AGENT_METHODS.session_list, label);
|
|
713
|
+
return this.race(this.connection.agent.request(AGENT_METHODS.session_list, request));
|
|
714
|
+
}
|
|
715
|
+
/** session/delete on a dedicated connection, gated on the initialize advertisement. */
|
|
716
|
+
async deleteSession(request, label) {
|
|
717
|
+
await this.ready;
|
|
718
|
+
this.assertLifecycleSupported(AGENT_METHODS.session_delete, label);
|
|
719
|
+
await this.race(this.connection.agent.request(AGENT_METHODS.session_delete, request));
|
|
720
|
+
}
|
|
589
721
|
/** session/prompt on this connection, raced against process death. */
|
|
590
722
|
prompt(request) {
|
|
591
723
|
return this.race(this.connection.agent.request(AGENT_METHODS.session_prompt, request));
|
|
@@ -594,7 +726,12 @@ export class PooledConnection {
|
|
|
594
726
|
setSessionConfigOption(request) {
|
|
595
727
|
return this.race(this.connection.agent.request(AGENT_METHODS.session_set_config_option, request));
|
|
596
728
|
}
|
|
729
|
+
/** session/set_mode on this connection, raced against process death. */
|
|
730
|
+
setSessionMode(request) {
|
|
731
|
+
return this.race(this.connection.agent.request(AGENT_METHODS.session_set_mode, request));
|
|
732
|
+
}
|
|
597
733
|
request(method, params, options) {
|
|
734
|
+
assertSafeRawRequest(method);
|
|
598
735
|
return this.race(this.connection.agent.request(method, params, options));
|
|
599
736
|
}
|
|
600
737
|
notify(method, params) {
|
|
@@ -715,6 +852,14 @@ export class SessionHandle {
|
|
|
715
852
|
get history() {
|
|
716
853
|
return this.state.history;
|
|
717
854
|
}
|
|
855
|
+
/** Assistant text accumulated across the retained session log. */
|
|
856
|
+
get text() {
|
|
857
|
+
return this.state.textChunks.join("");
|
|
858
|
+
}
|
|
859
|
+
/** Agent-advertised session mode catalog plus the currently active mode, if supported. */
|
|
860
|
+
get modes() {
|
|
861
|
+
return this.state.modes;
|
|
862
|
+
}
|
|
718
863
|
/**
|
|
719
864
|
* Select the model for this session from the agent-advertised config options (§5.4).
|
|
720
865
|
* Returns `matched:false` (the caller fires onModelFallback) when the catalog has no value
|
|
@@ -816,6 +961,21 @@ export class SessionHandle {
|
|
|
816
961
|
const response = await this.pooled.setSessionConfigOption(request);
|
|
817
962
|
this.configOptions = response.configOptions;
|
|
818
963
|
}
|
|
964
|
+
/** Switch the session's operating mode through ACP's strict confinement channel. */
|
|
965
|
+
async setMode(modeId) {
|
|
966
|
+
const modes = this.state.modes;
|
|
967
|
+
const ids = modeIds(modes);
|
|
968
|
+
if (!modes || !ids.includes(modeId)) {
|
|
969
|
+
throw modeSelectionError(this.pooled.backendId, modeId, ids, this.opts.label);
|
|
970
|
+
}
|
|
971
|
+
try {
|
|
972
|
+
await this.pooled.setSessionMode({ sessionId: this.sessionId, modeId });
|
|
973
|
+
}
|
|
974
|
+
catch (error) {
|
|
975
|
+
throw modeSelectionError(this.pooled.backendId, modeId, ids, this.opts.label, error);
|
|
976
|
+
}
|
|
977
|
+
this.state.modes = { ...modes, currentModeId: modeId };
|
|
978
|
+
}
|
|
819
979
|
/** Send a prompt turn and drain it; returns the final PromptResponse. */
|
|
820
980
|
async prompt(content, promptMeta) {
|
|
821
981
|
this.opts.signal?.throwIfAborted();
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -18,6 +18,15 @@ export interface NegotiatedCapabilities {
|
|
|
18
18
|
agentInfo: Implementation | undefined;
|
|
19
19
|
/** Whether session/close is advertised (gates the best-effort release-time close). */
|
|
20
20
|
supportsClose: boolean;
|
|
21
|
+
/** Whether session/load is advertised. The current SDK keeps this as the legacy top-level
|
|
22
|
+
* `loadSession` flag; tolerate a future sessionCapabilities.load shape for forward compat. */
|
|
23
|
+
supportsLoadSession: boolean;
|
|
24
|
+
/** Whether session/list is advertised. */
|
|
25
|
+
supportsListSessions: boolean;
|
|
26
|
+
/** Whether session/delete is advertised. */
|
|
27
|
+
supportsDeleteSession: boolean;
|
|
28
|
+
/** Whether session/resume is advertised. */
|
|
29
|
+
supportsResumeSession: boolean;
|
|
21
30
|
/** The parsed backend-declared custom-capability block (the namespaced `_meta` object), or
|
|
22
31
|
* undefined when the backend declared none or the agent did not advertise it — passthrough. */
|
|
23
32
|
customMetaSupport: Record<string, unknown> | undefined;
|
|
@@ -27,6 +36,8 @@ export interface NegotiatedCapabilities {
|
|
|
27
36
|
}
|
|
28
37
|
/** Parse an initialize response into the connection's derived capability state. */
|
|
29
38
|
export declare function negotiateCapabilities(response: InitializeResponse, customCapabilities?: Backend["customCapabilities"]): NegotiatedCapabilities;
|
|
39
|
+
/** Human-readable lifecycle advertisement summary for strict wrapper gate errors. */
|
|
40
|
+
export declare function describeLifecycleAdvertisement(agent: AgentCapabilities): string;
|
|
30
41
|
/** True only when the agent selected EXACTLY PROTOCOL_VERSION. This client implements that one wire
|
|
31
42
|
* version and adapts its behavior to no other, so any other selected version — older or newer —
|
|
32
43
|
* means close the connection per the ACP spec's SHOULD-close rule. Per the spec the agent echoes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQ5C;;;iGAGiG;AACjG,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAInD,CAAC;AAEF,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACrC;0FACsF;IACtF,eAAe,EAAE,MAAM,CAAC;IACxB;4DACwD;IACxD,KAAK,EAAE,iBAAiB,CAAC;IACzB,+DAA+D;IAC/D,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,sFAAsF;IACtF,aAAa,EAAE,OAAO,CAAC;IACvB;oGACgG;IAChG,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACvD;+EAC2E;IAC3E,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC1C;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GACjD,sBAAsB,
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAkBA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQ5C;;;iGAGiG;AACjG,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAInD,CAAC;AAEF,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACrC;0FACsF;IACtF,eAAe,EAAE,MAAM,CAAC;IACxB;4DACwD;IACxD,KAAK,EAAE,iBAAiB,CAAC;IACzB,+DAA+D;IAC/D,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IACtC,sFAAsF;IACtF,aAAa,EAAE,OAAO,CAAC;IACvB;mGAC+F;IAC/F,mBAAmB,EAAE,OAAO,CAAC;IAC7B,0CAA0C;IAC1C,oBAAoB,EAAE,OAAO,CAAC;IAC9B,4CAA4C;IAC5C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,4CAA4C;IAC5C,qBAAqB,EAAE,OAAO,CAAC;IAC/B;oGACgG;IAChG,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACvD;+EAC2E;IAC3E,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC1C;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GACjD,sBAAsB,CAkBxB;AAMD,qFAAqF;AACrF,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAiB/E;AAaD;;;;+DAI+D;AAC/D,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED;;;gEAGgE;AAChE,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,SAAS,GAAE,SAAS,MAAM,EAA2B,GACpD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAWrC;AAED;;;;;2EAK2E;AAC3E,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EAAE,EACtB,KAAK,EAAE,iBAAiB,EACxB,SAAS,EAAE,MAAM,GAChB,YAAY,EAAE,CAchB;AAkCD;;;;0EAI0E;AAC1E,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EAAE,GAAG,SAAS,EACtC,KAAK,EAAE,iBAAiB,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAA;CAAE,GAAG,SAAS,CAYzD"}
|
package/dist/capabilities.js
CHANGED
|
@@ -35,17 +35,44 @@ export const GATED_CUSTOM_META_KEYS = [
|
|
|
35
35
|
/** Parse an initialize response into the connection's derived capability state. */
|
|
36
36
|
export function negotiateCapabilities(response, customCapabilities) {
|
|
37
37
|
const agent = response.agentCapabilities ?? {};
|
|
38
|
+
const sessionCapabilities = agent.sessionCapabilities;
|
|
38
39
|
return {
|
|
39
40
|
protocolVersion: response.protocolVersion,
|
|
40
41
|
agent,
|
|
41
42
|
agentInfo: response.agentInfo ?? undefined,
|
|
42
|
-
supportsClose:
|
|
43
|
+
supportsClose: advertised(sessionCapabilities?.close),
|
|
44
|
+
supportsLoadSession: agent.loadSession === true || advertised(sessionCapabilities?.load),
|
|
45
|
+
supportsListSessions: advertised(sessionCapabilities?.list),
|
|
46
|
+
supportsDeleteSession: advertised(sessionCapabilities?.delete),
|
|
47
|
+
supportsResumeSession: advertised(sessionCapabilities?.resume),
|
|
43
48
|
customMetaSupport: customCapabilities
|
|
44
49
|
? readCustomNamespace(agent._meta, customCapabilities.namespace)
|
|
45
50
|
: undefined,
|
|
46
51
|
gatedKeys: customCapabilities ? [...customCapabilities.gatedKeys] : undefined,
|
|
47
52
|
};
|
|
48
53
|
}
|
|
54
|
+
function advertised(capability) {
|
|
55
|
+
return capability !== undefined && capability !== null && capability !== false;
|
|
56
|
+
}
|
|
57
|
+
/** Human-readable lifecycle advertisement summary for strict wrapper gate errors. */
|
|
58
|
+
export function describeLifecycleAdvertisement(agent) {
|
|
59
|
+
const sessionCapabilities = agent.sessionCapabilities;
|
|
60
|
+
const session = [
|
|
61
|
+
["close", sessionCapabilities?.close],
|
|
62
|
+
["list", sessionCapabilities?.list],
|
|
63
|
+
["delete", sessionCapabilities?.delete],
|
|
64
|
+
["resume", sessionCapabilities?.resume],
|
|
65
|
+
["fork", sessionCapabilities?.fork],
|
|
66
|
+
["additionalDirectories", sessionCapabilities?.additionalDirectories],
|
|
67
|
+
["load", sessionCapabilities?.load],
|
|
68
|
+
]
|
|
69
|
+
.filter(([, value]) => advertised(value))
|
|
70
|
+
.map(([name]) => name);
|
|
71
|
+
return [
|
|
72
|
+
`loadSession=${agent.loadSession === true ? "true" : "false"}`,
|
|
73
|
+
`sessionCapabilities=${session.length > 0 ? session.join(", ") : "none"}`,
|
|
74
|
+
].join("; ");
|
|
75
|
+
}
|
|
49
76
|
function readCustomNamespace(meta, namespace) {
|
|
50
77
|
if (!meta || typeof meta !== "object")
|
|
51
78
|
return undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { AcpAgentRunner, createAcpRunner, selectBackend } from "./runner.js";
|
|
2
|
-
export type { AcpRunnerOptions } from "./runner.js";
|
|
2
|
+
export type { AcpRunnerOptions, DeleteSessionOptions, ListSessionsOptions, ReattachSessionOptions, } from "./runner.js";
|
|
3
3
|
export { InteractiveSession } from "./interactive.js";
|
|
4
4
|
export type { InteractiveSessionOptions, InteractiveTurn } from "./interactive.js";
|
|
5
5
|
export { AGENT_METHODS, CLIENT_METHODS } from "@agentclientprotocol/sdk";
|
|
6
|
-
export type { AgentNotificationMethod, AgentNotificationParamsByMethod, AgentRequestMethod, AgentRequestParamsByMethod, AgentRequestResponsesByMethod, SendRequestOptions, } from "@agentclientprotocol/sdk";
|
|
6
|
+
export type { AgentNotificationMethod, AgentNotificationParamsByMethod, AgentRequestMethod, AgentRequestParamsByMethod, AgentRequestResponsesByMethod, DeleteSessionRequest, DeleteSessionResponse, ListSessionsRequest, ListSessionsResponse, LoadSessionRequest, LoadSessionResponse, ResumeSessionRequest, ResumeSessionResponse, SessionMode, SessionModeState, SessionInfo, SendRequestOptions, } from "@agentclientprotocol/sdk";
|
|
7
7
|
export { BACKENDS_ENV, registryWithRunBackends, resolveBackendRegistry } from "./registry.js";
|
|
8
8
|
export type { BackendRegistry, CustomBackendConfig, RegisteredBackend } from "./registry.js";
|
|
9
9
|
export { PooledConnection, SessionHandle } from "./acp-client.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7E,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/interactive.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AgentNotificationMethod, AgentNotificationParamsByMethod, AgentRequestMethod, AgentRequestParamsByMethod, AgentRequestResponsesByMethod, ContentBlock, SendRequestOptions, StopReason } from "@agentclientprotocol/sdk";
|
|
2
|
-
import type { McpServerConfig, PromptImage } from "@automatalabs/shared-types";
|
|
1
|
+
import type { AgentNotificationMethod, AgentNotificationParamsByMethod, AgentRequestMethod, AgentRequestParamsByMethod, AgentRequestResponsesByMethod, ContentBlock, SendRequestOptions, SessionModeState, StopReason } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { AgentHistoryEntry, McpServerConfig, PromptImage } from "@automatalabs/shared-types";
|
|
3
3
|
import type { RunOptions } from "@automatalabs/shared-types";
|
|
4
4
|
import type { Backend, BackendId } from "./backend.js";
|
|
5
5
|
import type { NegotiatedCapabilities } from "./capabilities.js";
|
|
@@ -14,6 +14,8 @@ import type { PermissionResolver } from "./permissions.js";
|
|
|
14
14
|
export interface InteractiveSessionOptions {
|
|
15
15
|
/** Model spec (`provider/modelId`, bare model id, or registered custom backend route). */
|
|
16
16
|
model?: string;
|
|
17
|
+
/** Agent-advertised session mode id. Strict: openSession fails rather than running unconfined. */
|
|
18
|
+
mode?: string;
|
|
17
19
|
/** Coarse tier consulted only when `model` is unset. */
|
|
18
20
|
tier?: string;
|
|
19
21
|
/** Absolute working directory for ACP session/new. Required for held-open sessions. */
|
|
@@ -40,6 +42,8 @@ export interface InteractiveSessionOptions {
|
|
|
40
42
|
developerInstructions?: string;
|
|
41
43
|
/** Client-provided MCP servers to attach at session/new. */
|
|
42
44
|
mcpServers?: McpServerConfig[];
|
|
45
|
+
/** Keep accumulated text/history after each prompt turn; default false for held-open sessions. */
|
|
46
|
+
retainSessionLog?: boolean;
|
|
43
47
|
/** Host-owned cancellation. Aborting releases this interactive session. */
|
|
44
48
|
signal?: AbortSignal;
|
|
45
49
|
}
|
|
@@ -89,6 +93,12 @@ export declare class InteractiveSession {
|
|
|
89
93
|
constructor(deps: InteractiveSessionDeps);
|
|
90
94
|
/** Negotiated initialize capabilities for this session's dedicated connection. */
|
|
91
95
|
get capabilities(): NegotiatedCapabilities | undefined;
|
|
96
|
+
/** Agent-advertised session mode catalog plus the currently active mode, if supported. */
|
|
97
|
+
get modes(): SessionModeState | null | undefined;
|
|
98
|
+
/** Assistant text accumulated in this session's retained log. */
|
|
99
|
+
get text(): string;
|
|
100
|
+
/** Message/tool history accumulated in this session's retained log. */
|
|
101
|
+
get history(): readonly AgentHistoryEntry[];
|
|
92
102
|
/** Send one prompt turn. A concurrent prompt on the same InteractiveSession is rejected with a
|
|
93
103
|
* clear host-side error; queueing is deliberately left to the host so turn boundaries remain
|
|
94
104
|
* explicit. Per-turn images are appended only to this prompt, and SessionHandle.prompt()
|
|
@@ -103,6 +113,8 @@ export declare class InteractiveSession {
|
|
|
103
113
|
* recording; calling session/prompt here bypasses those paths. */
|
|
104
114
|
request<Method extends AgentRequestMethod>(method: Method, params: AgentRequestParamsByMethod[Method], options?: SendRequestOptions): Promise<AgentRequestResponsesByMethod[Method]>;
|
|
105
115
|
request<Response = unknown, Params = unknown>(method: string, params?: Params, options?: SendRequestOptions): Promise<Response>;
|
|
116
|
+
/** Switch this session's ACP operating mode. Fails strictly when the agent did not advertise it. */
|
|
117
|
+
setMode(modeId: string): Promise<void>;
|
|
106
118
|
/** RAW protocol notification escape hatch for held-open sessions. Params carry `sessionId`
|
|
107
119
|
* explicitly; use `session.sessionId` so the wire call targets this session. */
|
|
108
120
|
notify<Method extends AgentNotificationMethod>(method: Method, params: AgentNotificationParamsByMethod[Method]): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,uBAAuB,EACvB,+BAA+B,EAC/B,kBAAkB,EAClB,0BAA0B,EAC1B,6BAA6B,EAC7B,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACX,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
|
package/dist/interactive.js
CHANGED
|
@@ -49,6 +49,18 @@ export class InteractiveSession {
|
|
|
49
49
|
get capabilities() {
|
|
50
50
|
return this.connection.capabilities;
|
|
51
51
|
}
|
|
52
|
+
/** Agent-advertised session mode catalog plus the currently active mode, if supported. */
|
|
53
|
+
get modes() {
|
|
54
|
+
return this.session.modes;
|
|
55
|
+
}
|
|
56
|
+
/** Assistant text accumulated in this session's retained log. */
|
|
57
|
+
get text() {
|
|
58
|
+
return this.session.text;
|
|
59
|
+
}
|
|
60
|
+
/** Message/tool history accumulated in this session's retained log. */
|
|
61
|
+
get history() {
|
|
62
|
+
return this.session.history;
|
|
63
|
+
}
|
|
52
64
|
/** Send one prompt turn. A concurrent prompt on the same InteractiveSession is rejected with a
|
|
53
65
|
* clear host-side error; queueing is deliberately left to the host so turn boundaries remain
|
|
54
66
|
* explicit. Per-turn images are appended only to this prompt, and SessionHandle.prompt()
|
|
@@ -80,6 +92,13 @@ export class InteractiveSession {
|
|
|
80
92
|
throw new Error("InteractiveSession has been released");
|
|
81
93
|
return this.connection.request(method, params, options);
|
|
82
94
|
}
|
|
95
|
+
/** Switch this session's ACP operating mode. Fails strictly when the agent did not advertise it. */
|
|
96
|
+
async setMode(modeId) {
|
|
97
|
+
if (this.releasePromise)
|
|
98
|
+
throw new Error("InteractiveSession has been released");
|
|
99
|
+
this.signal?.throwIfAborted();
|
|
100
|
+
await this.session.setMode(modeId);
|
|
101
|
+
}
|
|
83
102
|
async notify(method, params) {
|
|
84
103
|
if (this.releasePromise)
|
|
85
104
|
throw new Error("InteractiveSession has been released");
|
package/dist/permissions.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface ToolPolicy {
|
|
|
13
13
|
allow?: string[];
|
|
14
14
|
/** Deny-list (agentType `disallowedTools`), applied after the allow-list. */
|
|
15
15
|
deny?: string[];
|
|
16
|
+
/** No-match fallback for the headless auto-responder. Default "allow" preserves historical
|
|
17
|
+
* behavior. Explicit ACP session modes set this to "deny" unless a permission resolver is
|
|
18
|
+
* present, otherwise read-only/plan confinement can be bypassed by auto-approved escalations. */
|
|
19
|
+
defaultOutcome?: "allow" | "deny";
|
|
16
20
|
}
|
|
17
21
|
/** Decide the auto-response for one permission request given the tool policy. */
|
|
18
22
|
export declare function decidePermission(request: RequestPermissionRequest, policy: ToolPolicy): RequestPermissionResponse;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../src/permissions.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAGV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;;;wDAMwD;AACxD,MAAM,MAAM,kBAAkB,GAAG,CAC/B,MAAM,EAAE,wBAAwB,EAChC,GAAG,EAAE,eAAe,KACjB,OAAO,CAAC,yBAAyB,CAAC,GAAG,yBAAyB,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;sGAEkG;IAClG,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACnC;AAKD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,wBAAwB,EACjC,MAAM,EAAE,UAAU,GACjB,yBAAyB,CAsC3B"}
|
package/dist/permissions.js
CHANGED
|
@@ -9,6 +9,7 @@ export function decidePermission(request, policy) {
|
|
|
9
9
|
const allPool = [...toolNames, ...decoration];
|
|
10
10
|
const denyList = policy.deny ?? [];
|
|
11
11
|
const allowList = policy.allow ?? [];
|
|
12
|
+
const defaultOutcome = policy.defaultOutcome ?? "allow";
|
|
12
13
|
const hasDeny = denyList.length > 0;
|
|
13
14
|
const hasAllowList = allowList.length > 0;
|
|
14
15
|
const denyExact = hasDeny && exactMatchesAny(exactPool, denyList);
|
|
@@ -20,12 +21,12 @@ export function decidePermission(request, policy) {
|
|
|
20
21
|
// (Suppresses loose substring matches: a deny `read` no longer catches an exactly
|
|
21
22
|
// allow-listed `thread-reader`.)
|
|
22
23
|
denied = denyExact;
|
|
23
|
-
allowedByList =
|
|
24
|
+
allowedByList = hasAllowList ? allowExact : defaultOutcome === "allow";
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
27
|
// (b) No exact match in either list -> best-effort bidirectional substring fallback.
|
|
27
28
|
denied = hasDeny && substringMatchesAny(allPool, denyList);
|
|
28
|
-
allowedByList =
|
|
29
|
+
allowedByList = hasAllowList ? substringMatchesAny(allPool, allowList) : defaultOutcome === "allow";
|
|
29
30
|
}
|
|
30
31
|
const wantAllow = !denied && allowedByList;
|
|
31
32
|
const option = pickOption(request.options, wantAllow);
|
|
@@ -3,7 +3,9 @@ type ValueOf<T> = T[keyof T];
|
|
|
3
3
|
type ClientMethod = ValueOf<typeof CLIENT_METHODS>;
|
|
4
4
|
type AgentMethod = ValueOf<typeof AGENT_METHODS>;
|
|
5
5
|
export type ClientMethodCoverage = "served" | "pending";
|
|
6
|
-
|
|
6
|
+
/** `guarded` means the raw passthrough would create/reopen session state outside the router, so
|
|
7
|
+
* the client rejects it until a driven wrapper can route updates, permissions, and terminals. */
|
|
8
|
+
export type AgentMethodCoverage = "driven" | "passthrough" | "guarded";
|
|
7
9
|
/** Enforceable definition of "full ACP spec support": every SDK method constant is classified
|
|
8
10
|
* here, and the tripwire test fails when an SDK bump silently widens or shrinks the protocol. */
|
|
9
11
|
export declare const CLIENT_METHOD_COVERAGE: Record<ClientMethod, ClientMethodCoverage>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol-coverage.d.ts","sourceRoot":"","sources":["../src/protocol-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEzE,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B,KAAK,YAAY,GAAG,OAAO,CAAC,OAAO,cAAc,CAAC,CAAC;AACnD,KAAK,WAAW,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACxD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol-coverage.d.ts","sourceRoot":"","sources":["../src/protocol-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEzE,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7B,KAAK,YAAY,GAAG,OAAO,CAAC,OAAO,cAAc,CAAC,CAAC;AACnD,KAAK,WAAW,GAAG,OAAO,CAAC,OAAO,aAAa,CAAC,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,SAAS,CAAC;AACxD;kGACkG;AAClG,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,GAAG,SAAS,CAAC;AAEvE;kGACkG;AAClG,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,YAAY,EAAE,oBAAoB,CAe7E,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,WAAW,EAAE,mBAAmB,CA6B1E,CAAC"}
|
|
@@ -24,16 +24,16 @@ export const AGENT_METHOD_COVERAGE = {
|
|
|
24
24
|
[AGENT_METHODS.providers_set]: "passthrough",
|
|
25
25
|
[AGENT_METHODS.providers_disable]: "passthrough",
|
|
26
26
|
[AGENT_METHODS.session_new]: "driven",
|
|
27
|
-
[AGENT_METHODS.session_load]: "
|
|
28
|
-
[AGENT_METHODS.session_set_mode]: "
|
|
27
|
+
[AGENT_METHODS.session_load]: "driven",
|
|
28
|
+
[AGENT_METHODS.session_set_mode]: "driven",
|
|
29
29
|
[AGENT_METHODS.session_set_config_option]: "driven",
|
|
30
30
|
[AGENT_METHODS.session_prompt]: "driven",
|
|
31
31
|
[AGENT_METHODS.session_cancel]: "driven",
|
|
32
32
|
[AGENT_METHODS.mcp_message]: "passthrough",
|
|
33
|
-
[AGENT_METHODS.session_list]: "
|
|
34
|
-
[AGENT_METHODS.session_delete]: "
|
|
35
|
-
[AGENT_METHODS.session_fork]: "
|
|
36
|
-
[AGENT_METHODS.session_resume]: "
|
|
33
|
+
[AGENT_METHODS.session_list]: "driven",
|
|
34
|
+
[AGENT_METHODS.session_delete]: "driven",
|
|
35
|
+
[AGENT_METHODS.session_fork]: "guarded",
|
|
36
|
+
[AGENT_METHODS.session_resume]: "driven",
|
|
37
37
|
[AGENT_METHODS.session_close]: "driven",
|
|
38
38
|
[AGENT_METHODS.logout]: "passthrough",
|
|
39
39
|
[AGENT_METHODS.nes_start]: "passthrough",
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AgentResult, type AgentRunner, type RunOptions } from "@automatalabs/shared-types";
|
|
2
|
+
import type { ListSessionsResponse } from "@agentclientprotocol/sdk";
|
|
2
3
|
import type { TSchema } from "typebox";
|
|
3
4
|
import { type AcpPoolOptions } from "./pool.js";
|
|
4
5
|
import { type AcpEventListener, type AcpEventName } from "./events.js";
|
|
@@ -6,6 +7,39 @@ import type { Backend } from "./backend.js";
|
|
|
6
7
|
import { InteractiveSession, type InteractiveSessionOptions } from "./interactive.js";
|
|
7
8
|
import { type BackendRegistry, type CustomBackendConfig } from "./registry.js";
|
|
8
9
|
import type { PermissionResolver } from "./permissions.js";
|
|
10
|
+
interface LifecycleRoutingOptions {
|
|
11
|
+
/** Model spec used only to select the backend process. */
|
|
12
|
+
model?: string;
|
|
13
|
+
/** Coarse tier consulted only when `model` is unset. */
|
|
14
|
+
tier?: string;
|
|
15
|
+
/** Event/telemetry label used in strict capability errors. */
|
|
16
|
+
label?: string;
|
|
17
|
+
/** Host-owned cancellation while the lifecycle request is in flight. */
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
}
|
|
20
|
+
/** Options for AcpAgentRunner.listSessions(). */
|
|
21
|
+
export interface ListSessionsOptions extends LifecycleRoutingOptions {
|
|
22
|
+
/** Optional absolute working-directory filter. */
|
|
23
|
+
cwd?: string;
|
|
24
|
+
/** Opaque pagination cursor from the previous response. */
|
|
25
|
+
cursor?: string;
|
|
26
|
+
/** Generic ACP `_meta` passthrough for session/list. */
|
|
27
|
+
meta?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
/** Options for AcpAgentRunner.deleteSession(). */
|
|
30
|
+
export interface DeleteSessionOptions extends LifecycleRoutingOptions {
|
|
31
|
+
/** Session id returned by session/list or previously persisted by the backend. */
|
|
32
|
+
sessionId: string;
|
|
33
|
+
/** Generic ACP `_meta` passthrough for session/delete. */
|
|
34
|
+
meta?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
/** Options for AcpAgentRunner.loadSession() and resumeSession(). */
|
|
37
|
+
export interface ReattachSessionOptions extends InteractiveSessionOptions {
|
|
38
|
+
/** Existing backend session id to route before the lifecycle request is sent. */
|
|
39
|
+
sessionId: string;
|
|
40
|
+
/** Alias for onPermissionRequest for hosts that name the resolver by role. */
|
|
41
|
+
permissionResolver?: PermissionResolver;
|
|
42
|
+
}
|
|
9
43
|
/** Constructor options for the runner: pool sizing, client-side handlers, and the custom-backend
|
|
10
44
|
* registry. `backends` merges over (and wins against) env-declared AGENTPRISM_BACKENDS entries. */
|
|
11
45
|
export interface AcpRunnerOptions extends AcpPoolOptions {
|
|
@@ -60,10 +94,20 @@ export declare class AcpAgentRunner implements AgentRunner {
|
|
|
60
94
|
* is one).
|
|
61
95
|
*/
|
|
62
96
|
openSession(opts: InteractiveSessionOptions): Promise<InteractiveSession>;
|
|
97
|
+
/** List persisted ACP sessions from the selected backend. */
|
|
98
|
+
listSessions(opts?: ListSessionsOptions): Promise<ListSessionsResponse>;
|
|
99
|
+
/** Delete a persisted ACP session from the selected backend. */
|
|
100
|
+
deleteSession(opts: DeleteSessionOptions): Promise<void>;
|
|
101
|
+
/** Load an existing ACP session and return a live, routed InteractiveSession. */
|
|
102
|
+
loadSession(opts: ReattachSessionOptions): Promise<InteractiveSession>;
|
|
103
|
+
/** Resume an existing ACP session without replay and return a live, routed InteractiveSession. */
|
|
104
|
+
resumeSession(opts: ReattachSessionOptions): Promise<InteractiveSession>;
|
|
63
105
|
run<S extends TSchema | undefined = undefined>(prompt: string, options?: RunOptions<S>): Promise<AgentResult<S>>;
|
|
64
106
|
/** Tear down the whole pool (close every long-lived process). Call when the run ends / the
|
|
65
107
|
* runner is disposed. Beyond the AgentRunner seam (additive) — never enters the resume hash. */
|
|
66
108
|
dispose(): Promise<void>;
|
|
109
|
+
private createInteractiveSession;
|
|
110
|
+
private createDedicatedConnection;
|
|
67
111
|
/** Build the backend choice, model-selection spec, tool policy, and session/new options in one
|
|
68
112
|
* place for run() and openSession() so new AcpSessionOptions fields cannot drift by path. */
|
|
69
113
|
private prepareSession;
|
|
@@ -86,4 +130,5 @@ export declare function selectBackend(opts: {
|
|
|
86
130
|
model?: string;
|
|
87
131
|
tier?: string;
|
|
88
132
|
}, registry?: BackendRegistry): Backend;
|
|
133
|
+
export {};
|
|
89
134
|
//# sourceMappingURL=runner.d.ts.map
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAmBA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.js
CHANGED
|
@@ -91,67 +91,66 @@ export class AcpAgentRunner {
|
|
|
91
91
|
* is one).
|
|
92
92
|
*/
|
|
93
93
|
async openSession(opts) {
|
|
94
|
+
return this.createInteractiveSession(opts, "openSession", (connection, prepared) => connection.openSession(prepared.sessionOptions));
|
|
95
|
+
}
|
|
96
|
+
/** List persisted ACP sessions from the selected backend. */
|
|
97
|
+
async listSessions(opts = {}) {
|
|
94
98
|
if (this.disposed)
|
|
95
99
|
throw new Error("ACP agent runner is disposed");
|
|
96
|
-
|
|
100
|
+
validateOptionalLifecycleCwd(opts.cwd, opts.label, "listSessions");
|
|
97
101
|
opts.signal?.throwIfAborted();
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
schema: undefined,
|
|
101
|
-
registry: this.backends,
|
|
102
|
-
permissionResolver: opts.onPermissionRequest,
|
|
103
|
-
retainSessionLog: false,
|
|
104
|
-
});
|
|
105
|
-
this.installExitHook();
|
|
106
|
-
let interactive;
|
|
107
|
-
const connection = PooledConnection.create(prepared.backend, {
|
|
108
|
-
onDead: () => {
|
|
109
|
-
// Dedicated connections are not stored in pool arrays, so there is nothing to evict.
|
|
110
|
-
// Once the public wrapper exists, process death releases it through the normal path:
|
|
111
|
-
// subscriptions are removed, session_close is emitted, and future prompt() calls fail
|
|
112
|
-
// with the clean released-session error. Before then, openSession's catch tears down.
|
|
113
|
-
void interactive?.release();
|
|
114
|
-
},
|
|
115
|
-
onEvent: this.emitEvent,
|
|
116
|
-
permissionResolver: this.permissionResolver,
|
|
117
|
-
clientHandlers: this.clientHandlers,
|
|
118
|
-
});
|
|
119
|
-
let session;
|
|
102
|
+
const backend = selectBackend(opts, this.backends);
|
|
103
|
+
const connection = this.createDedicatedConnection(backend, () => undefined);
|
|
120
104
|
try {
|
|
121
|
-
|
|
105
|
+
const request = {
|
|
106
|
+
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
107
|
+
...(opts.cursor ? { cursor: opts.cursor } : {}),
|
|
108
|
+
...(opts.meta ? { _meta: opts.meta } : {}),
|
|
109
|
+
};
|
|
110
|
+
const response = await connection.listSessions(request, opts.label);
|
|
122
111
|
opts.signal?.throwIfAborted();
|
|
123
|
-
|
|
112
|
+
if (this.disposed)
|
|
113
|
+
throw new Error("ACP agent runner is disposed");
|
|
114
|
+
return response;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
await disposeBestEffort(connection);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Delete a persisted ACP session from the selected backend. */
|
|
121
|
+
async deleteSession(opts) {
|
|
122
|
+
if (this.disposed)
|
|
123
|
+
throw new Error("ACP agent runner is disposed");
|
|
124
|
+
if (typeof opts.sessionId !== "string" || opts.sessionId.trim() === "") {
|
|
125
|
+
throw new WorkflowError("deleteSession requires sessionId to be a non-empty string", WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: opts.label });
|
|
126
|
+
}
|
|
127
|
+
opts.signal?.throwIfAborted();
|
|
128
|
+
const backend = selectBackend(opts, this.backends);
|
|
129
|
+
const connection = this.createDedicatedConnection(backend, () => undefined);
|
|
130
|
+
try {
|
|
131
|
+
const request = {
|
|
132
|
+
sessionId: opts.sessionId,
|
|
133
|
+
...(opts.meta ? { _meta: opts.meta } : {}),
|
|
134
|
+
};
|
|
135
|
+
await connection.deleteSession(request, opts.label);
|
|
124
136
|
opts.signal?.throwIfAborted();
|
|
125
137
|
if (this.disposed)
|
|
126
138
|
throw new Error("ACP agent runner is disposed");
|
|
127
|
-
interactive = new InteractiveSession({
|
|
128
|
-
session,
|
|
129
|
-
connection,
|
|
130
|
-
backend: prepared.backend,
|
|
131
|
-
subscribe: (name, listener) => this.events.on(name, listener),
|
|
132
|
-
onRelease: (self) => this.interactiveSessions.delete(self),
|
|
133
|
-
signal: opts.signal,
|
|
134
|
-
label: opts.label,
|
|
135
|
-
});
|
|
136
|
-
this.interactiveSessions.set(interactive, connection);
|
|
137
|
-
return interactive;
|
|
138
139
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await session?.release();
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
// best-effort: openSession failed, so teardown must never mask the real error.
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
await connection.dispose();
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
// best-effort: same as pool teardown.
|
|
151
|
-
}
|
|
152
|
-
throw error;
|
|
140
|
+
finally {
|
|
141
|
+
await disposeBestEffort(connection);
|
|
153
142
|
}
|
|
154
143
|
}
|
|
144
|
+
/** Load an existing ACP session and return a live, routed InteractiveSession. */
|
|
145
|
+
async loadSession(opts) {
|
|
146
|
+
validateLifecycleSessionId(opts.sessionId, opts.label, "loadSession");
|
|
147
|
+
return this.createInteractiveSession(opts, "loadSession", (connection, prepared) => connection.loadSession(opts.sessionId, prepared.sessionOptions));
|
|
148
|
+
}
|
|
149
|
+
/** Resume an existing ACP session without replay and return a live, routed InteractiveSession. */
|
|
150
|
+
async resumeSession(opts) {
|
|
151
|
+
validateLifecycleSessionId(opts.sessionId, opts.label, "resumeSession");
|
|
152
|
+
return this.createInteractiveSession(opts, "resumeSession", (connection, prepared) => connection.resumeSession(opts.sessionId, prepared.sessionOptions));
|
|
153
|
+
}
|
|
155
154
|
async run(prompt, options = {}) {
|
|
156
155
|
const opts = options;
|
|
157
156
|
const schema = opts.schema;
|
|
@@ -183,6 +182,9 @@ export class AcpAgentRunner {
|
|
|
183
182
|
// model id: "browser" selects nothing; "browser/foo" selects "foo". Built-ins get the
|
|
184
183
|
// full spec unchanged (their catalogs match provider-prefixed and bare ids).
|
|
185
184
|
await applyModelSelection(session, prepared.modelSpec, opts);
|
|
185
|
+
opts.signal?.throwIfAborted();
|
|
186
|
+
if (opts.mode)
|
|
187
|
+
await session.setMode(opts.mode);
|
|
186
188
|
const text = buildRunPrompt(prompt, opts, schema, prepared.backend);
|
|
187
189
|
const initialPrompt = opts.images && opts.images.length > 0 ? promptWithImages(text, opts.images) : text;
|
|
188
190
|
// Generic turn-scoped _meta passthrough merged UNDER the backend-computed keys (e.g. the
|
|
@@ -260,11 +262,79 @@ export class AcpAgentRunner {
|
|
|
260
262
|
await this.pool.dispose();
|
|
261
263
|
this.events.removeAllListeners();
|
|
262
264
|
}
|
|
265
|
+
async createInteractiveSession(opts, methodName, open) {
|
|
266
|
+
if (this.disposed)
|
|
267
|
+
throw new Error("ACP agent runner is disposed");
|
|
268
|
+
validateInteractiveCwd(opts.cwd, opts.label, methodName);
|
|
269
|
+
opts.signal?.throwIfAborted();
|
|
270
|
+
const prepared = this.prepareSession(opts, {
|
|
271
|
+
cwd: opts.cwd,
|
|
272
|
+
schema: undefined,
|
|
273
|
+
registry: this.backends,
|
|
274
|
+
permissionResolver: opts.permissionResolver ?? opts.onPermissionRequest,
|
|
275
|
+
retainSessionLog: opts.retainSessionLog ?? false,
|
|
276
|
+
});
|
|
277
|
+
this.installExitHook();
|
|
278
|
+
let interactive;
|
|
279
|
+
const connection = this.createDedicatedConnection(prepared.backend, () => {
|
|
280
|
+
// Dedicated connections are not stored in pool arrays, so there is nothing to evict.
|
|
281
|
+
// Once the public wrapper exists, process death releases it through the normal path:
|
|
282
|
+
// subscriptions are removed, session_close is emitted, and future prompt() calls fail
|
|
283
|
+
// with the clean released-session error. Before then, this method's catch tears down.
|
|
284
|
+
void interactive?.release();
|
|
285
|
+
});
|
|
286
|
+
let session;
|
|
287
|
+
try {
|
|
288
|
+
session = await open(connection, prepared);
|
|
289
|
+
opts.signal?.throwIfAborted();
|
|
290
|
+
await applyModelSelection(session, prepared.modelSpec, opts);
|
|
291
|
+
opts.signal?.throwIfAborted();
|
|
292
|
+
if (opts.mode)
|
|
293
|
+
await session.setMode(opts.mode);
|
|
294
|
+
opts.signal?.throwIfAborted();
|
|
295
|
+
if (this.disposed)
|
|
296
|
+
throw new Error("ACP agent runner is disposed");
|
|
297
|
+
interactive = new InteractiveSession({
|
|
298
|
+
session,
|
|
299
|
+
connection,
|
|
300
|
+
backend: prepared.backend,
|
|
301
|
+
subscribe: (name, listener) => this.events.on(name, listener),
|
|
302
|
+
onRelease: (self) => this.interactiveSessions.delete(self),
|
|
303
|
+
signal: opts.signal,
|
|
304
|
+
label: opts.label,
|
|
305
|
+
});
|
|
306
|
+
this.interactiveSessions.set(interactive, connection);
|
|
307
|
+
return interactive;
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
try {
|
|
311
|
+
await session?.release();
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
// best-effort: lifecycle setup failed, so teardown must never mask the real error.
|
|
315
|
+
}
|
|
316
|
+
await disposeBestEffort(connection);
|
|
317
|
+
throw error;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
createDedicatedConnection(backend, onDead) {
|
|
321
|
+
return PooledConnection.create(backend, {
|
|
322
|
+
onDead,
|
|
323
|
+
onEvent: this.emitEvent,
|
|
324
|
+
permissionResolver: this.permissionResolver,
|
|
325
|
+
clientHandlers: this.clientHandlers,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
263
328
|
/** Build the backend choice, model-selection spec, tool policy, and session/new options in one
|
|
264
329
|
* place for run() and openSession() so new AcpSessionOptions fields cannot drift by path. */
|
|
265
330
|
prepareSession(opts, config) {
|
|
266
331
|
const backend = selectBackend(opts, config.registry);
|
|
267
|
-
const
|
|
332
|
+
const hasPermissionResolver = Boolean(config.permissionResolver ?? this.permissionResolver);
|
|
333
|
+
const policy = {
|
|
334
|
+
allow: opts.toolNames,
|
|
335
|
+
deny: opts.disallowedToolNames,
|
|
336
|
+
defaultOutcome: opts.mode && !hasPermissionResolver ? "deny" : undefined,
|
|
337
|
+
};
|
|
268
338
|
return {
|
|
269
339
|
backend,
|
|
270
340
|
modelSpec: innerModelSpec(opts.model ?? opts.tier, backend),
|
|
@@ -401,9 +471,27 @@ function innerModelSpec(spec, backend) {
|
|
|
401
471
|
}
|
|
402
472
|
/** Interactive sessions are public and long-lived, so fail before spawning a dedicated process
|
|
403
473
|
* when the required worktree root is absent or not absolute. */
|
|
404
|
-
function validateInteractiveCwd(cwd, label) {
|
|
474
|
+
function validateInteractiveCwd(cwd, label, methodName) {
|
|
405
475
|
if (typeof cwd !== "string" || cwd.trim() === "" || !isAbsolute(cwd)) {
|
|
406
|
-
throw new WorkflowError(
|
|
476
|
+
throw new WorkflowError(`${methodName} requires cwd to be a non-empty absolute path`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: label });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function validateOptionalLifecycleCwd(cwd, label, methodName) {
|
|
480
|
+
if (cwd === undefined || cwd === null)
|
|
481
|
+
return;
|
|
482
|
+
validateInteractiveCwd(cwd, label, methodName);
|
|
483
|
+
}
|
|
484
|
+
function validateLifecycleSessionId(sessionId, label, methodName) {
|
|
485
|
+
if (typeof sessionId !== "string" || sessionId.trim() === "") {
|
|
486
|
+
throw new WorkflowError(`${methodName} requires sessionId to be a non-empty string`, WorkflowErrorCode.SCRIPT_VALIDATION_ERROR, { recoverable: false, agentLabel: label });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
async function disposeBestEffort(connection) {
|
|
490
|
+
try {
|
|
491
|
+
await connection.dispose();
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
// Dedicated lifecycle processes are already no longer useful; never mask the request result.
|
|
407
495
|
}
|
|
408
496
|
}
|
|
409
497
|
function backendIdForSpec(spec) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automatalabs/acp-agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@agentclientprotocol/claude-agent-acp": "0.56.0",
|
|
32
32
|
"@automatalabs/codex-acp": "1.4.0",
|
|
33
33
|
"typebox": "1.3.2",
|
|
34
|
-
"@automatalabs/shared-types": "0.
|
|
34
|
+
"@automatalabs/shared-types": "0.9.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -b",
|