@rivus/agent 0.16.2 → 0.16.6

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.js CHANGED
@@ -1,768 +1,2 @@
1
- import { _ as createAgentLoopToolExecutionStart, c as toEffectAgentLoop, g as createAgentLoopToolExecutionEnd, h as createAgentLoopThinkingDelta, m as createAgentLoopTextDelta, o as fromEffectAgentLoop, s as toCompatibilityAgentLoopInput, v as createAgentLoopToolExecutionUpdate, y as createAgentLoopTurnStart } from "./chunks/agent-loop.js";
2
- import * as acp from "@agentclientprotocol/sdk";
3
- import { Effect, Stream } from "effect";
4
- import { randomUUID } from "node:crypto";
5
- import { Readable, Writable } from "node:stream";
6
- import { spawn } from "node:child_process";
7
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
8
- import { dirname } from "node:path";
9
- //#region src/adapters/acp/runtime/acp-agent-loop.ts
10
- function createAcpAgentLoop$1(options) {
11
- return {
12
- run: (input) => Stream.fromAsyncIterable(runAcpSession(input, options), (error) => error),
13
- supportsSteering: true
14
- };
15
- }
16
- async function* runAcpSession(input, options) {
17
- const session = await options.resolveSession(input);
18
- const updates = [];
19
- const tools = /* @__PURE__ */ new Map();
20
- let wake;
21
- let abortCancellation;
22
- let abortFailure;
23
- let abortSettled = false;
24
- let aborted = false;
25
- let currentTurn = startAcpTurn(input.text, session, input, updates, tools, () => {
26
- wake?.();
27
- wake = void 0;
28
- });
29
- const onAbort = () => {
30
- aborted = true;
31
- abortCancellation ??= settleCancelledTurn(session, currentTurn.promise, options.cancellationSettleTimeoutMs ?? 5e3);
32
- abortCancellation.then(() => {
33
- abortSettled = true;
34
- wake?.();
35
- wake = void 0;
36
- }, (error) => {
37
- abortFailure = error;
38
- wake?.();
39
- wake = void 0;
40
- });
41
- };
42
- input.abortSignal.addEventListener("abort", onAbort, { once: true });
43
- const takeSteering = () => input.steering ? Effect.runPromise(input.steering.next()) : void 0;
44
- let steering = takeSteering();
45
- try {
46
- if (input.abortSignal.aborted) onAbort();
47
- while (!currentTurn.completed || updates.length > 0) {
48
- if (abortFailure !== void 0) throw abortFailure;
49
- if (aborted && abortSettled) break;
50
- const event = updates.shift();
51
- if (event) yield event;
52
- else {
53
- const signal = await Promise.race([
54
- new Promise((resolve) => {
55
- wake = () => resolve({ type: "wake" });
56
- }),
57
- ...steering ? [steering.then((text) => ({
58
- text,
59
- type: "steer"
60
- }))] : [],
61
- currentTurn.promise.then(() => ({ type: "turn_completed" }), () => ({ type: "turn_completed" }))
62
- ]);
63
- if (signal.type === "steer") {
64
- await Promise.resolve(session.cancel({ preserveSession: true }));
65
- await currentTurn.promise;
66
- updates.push(createAgentLoopTurnStart());
67
- currentTurn = startAcpTurn(createSteeringTurnPrompt(signal.text), session, input, updates, tools, () => {
68
- wake?.();
69
- wake = void 0;
70
- });
71
- steering = takeSteering();
72
- }
73
- if (signal.type === "turn_completed" && currentTurn.completed) break;
74
- if (signal.type === "wake") wake = void 0;
75
- }
76
- }
77
- if (!aborted) {
78
- await currentTurn.promise;
79
- if (currentTurn.failure !== void 0) throw currentTurn.failure;
80
- }
81
- } finally {
82
- input.abortSignal.removeEventListener("abort", onAbort);
83
- if (abortCancellation) await abortCancellation;
84
- if (options.disposeSessionAfterRun !== false) await session.dispose?.();
85
- }
86
- }
87
- async function settleCancelledTurn(session, currentTurn, timeoutMs) {
88
- await Promise.resolve(session.cancel({ preserveSession: false }));
89
- if (await settlesWithin(currentTurn, timeoutMs)) return;
90
- if (session.invalidate) await session.invalidate();
91
- else await session.dispose?.();
92
- }
93
- async function settlesWithin(promise, timeoutMs) {
94
- let timeout;
95
- try {
96
- return await Promise.race([promise.then(() => true), new Promise((resolve) => {
97
- timeout = setTimeout(() => resolve(false), timeoutMs);
98
- })]);
99
- } finally {
100
- if (timeout) clearTimeout(timeout);
101
- }
102
- }
103
- function createSteeringTurnPrompt(text) {
104
- return [
105
- "用户刚刚在当前任务执行期间发送了一条 steering 消息。",
106
- "请先直接回答这条消息;如果它是关于当前任务的进度或概念问题,先给出清晰解释。",
107
- "只有消息明确要求改变任务时才执行动作;不要把用户自然语言当作 shell 命令。",
108
- "回答后基于当前会话已有状态继续任务;不得重放最初指令或重复已经完成的步骤。",
109
- "用户消息:",
110
- text
111
- ].join("\n");
112
- }
113
- function startAcpTurn(text, session, input, updates, tools, notify) {
114
- let completed = false;
115
- let failure;
116
- return {
117
- promise: session.prompt(text, (update) => {
118
- updates.push(...mapAcpSessionUpdate(update, tools));
119
- notify();
120
- }).then(() => void 0).catch((error) => {
121
- if (!input.abortSignal.aborted) failure = error;
122
- }).finally(() => {
123
- completed = true;
124
- notify();
125
- }),
126
- get completed() {
127
- return completed;
128
- },
129
- get failure() {
130
- return failure;
131
- }
132
- };
133
- }
134
- function mapAcpSessionUpdate(update, tools) {
135
- if (update.sessionUpdate === "agent_message_chunk") {
136
- const text = readTextContent(update.content);
137
- return text === void 0 ? [] : [createAgentLoopTextDelta(text)];
138
- }
139
- if (update.sessionUpdate === "agent_thought_chunk") {
140
- const text = readTextContent(update.content);
141
- return text === void 0 ? [] : [createAgentLoopThinkingDelta(text)];
142
- }
143
- if (update.sessionUpdate === "tool_call") {
144
- if (!update.toolCallId || !update.title) return [];
145
- const name = update.name?.trim() || update.title;
146
- const state = {
147
- input: update.rawInput,
148
- name
149
- };
150
- tools.set(update.toolCallId, state);
151
- const start = createAgentLoopToolExecutionStart({
152
- input: state.input,
153
- toolCallId: update.toolCallId,
154
- toolName: state.name
155
- });
156
- if (update.status === "completed" || update.status === "failed") {
157
- tools.delete(update.toolCallId);
158
- return [start, createAgentLoopToolExecutionEnd({
159
- isError: update.status === "failed",
160
- result: update.rawOutput,
161
- toolCallId: update.toolCallId,
162
- toolName: state.name
163
- })];
164
- }
165
- return [start];
166
- }
167
- if (update.sessionUpdate !== "tool_call_update") return [];
168
- if (!update.toolCallId) return [];
169
- const prior = tools.get(update.toolCallId);
170
- const state = {
171
- input: update.rawInput ?? prior?.input,
172
- name: update.name?.trim() || update.title?.trim() || prior?.name || update.toolCallId
173
- };
174
- tools.set(update.toolCallId, state);
175
- if (update.status === "completed" || update.status === "failed") {
176
- tools.delete(update.toolCallId);
177
- return [createAgentLoopToolExecutionEnd({
178
- isError: update.status === "failed",
179
- result: update.rawOutput,
180
- toolCallId: update.toolCallId,
181
- toolName: state.name
182
- })];
183
- }
184
- return [createAgentLoopToolExecutionUpdate({
185
- input: state.input,
186
- partialResult: update.rawOutput,
187
- toolCallId: update.toolCallId,
188
- toolName: state.name
189
- })];
190
- }
191
- function readTextContent(content) {
192
- if (!isRecord$1(content) || content.type !== "text" || typeof content.text !== "string") return void 0;
193
- return content.text;
194
- }
195
- function isRecord$1(value) {
196
- return typeof value === "object" && value !== null;
197
- }
198
- //#endregion
199
- //#region src/adapters/acp/runtime/acp-agent-server.ts
200
- function createAcpAgentServer$1(options) {
201
- const sessions = /* @__PURE__ */ new Set();
202
- const active = /* @__PURE__ */ new Map();
203
- return acp.agent({ name: options.agentName ?? "rivus" }).onRequest(acp.methods.agent.initialize, ({ params }) => ({
204
- agentCapabilities: {},
205
- agentInfo: {
206
- name: options.agentName ?? "rivus",
207
- version: "1"
208
- },
209
- protocolVersion: params.protocolVersion === acp.PROTOCOL_VERSION ? params.protocolVersion : acp.PROTOCOL_VERSION
210
- })).onRequest(acp.methods.agent.session.new, () => {
211
- const sessionId = randomUUID();
212
- sessions.add(sessionId);
213
- return { sessionId };
214
- }).onRequest(acp.methods.agent.session.prompt, async ({ client, params }) => {
215
- if (!sessions.has(params.sessionId)) throw new Error(`Unknown ACP session: ${params.sessionId}`);
216
- if (active.has(params.sessionId)) throw new Error(`ACP session is already active: ${params.sessionId}`);
217
- const controller = new AbortController();
218
- active.set(params.sessionId, controller);
219
- const sessionKey = `acp:${params.sessionId}`;
220
- const releasePermissionBridge = options.permissionBridge?.bind(sessionKey, async (request) => {
221
- const response = await client.request(acp.methods.client.session.requestPermission, {
222
- options: request.options.map((option) => ({ ...option })),
223
- sessionId: params.sessionId,
224
- toolCall: {
225
- ...request.toolCall.rawInput === void 0 ? {} : { rawInput: request.toolCall.rawInput },
226
- ...request.toolCall.title === void 0 ? {} : { title: request.toolCall.title },
227
- toolCallId: request.toolCall.toolCallId
228
- }
229
- });
230
- return response.outcome.outcome === "selected" ? { optionId: response.outcome.optionId } : void 0;
231
- });
232
- try {
233
- await Effect.runPromise(options.loop.run({
234
- abortSignal: controller.signal,
235
- runId: randomUUID(),
236
- sessionKey,
237
- text: readPromptText(params.prompt)
238
- }).pipe(Stream.runForEach((event) => Effect.tryPromise({
239
- catch: (cause) => cause,
240
- try: async () => {
241
- const update = mapAgentLoopEvent(event);
242
- if (update) await client.notify(acp.methods.client.session.update, {
243
- sessionId: params.sessionId,
244
- update
245
- });
246
- }
247
- }))));
248
- return { stopReason: controller.signal.aborted ? "cancelled" : "end_turn" };
249
- } finally {
250
- releasePermissionBridge?.();
251
- active.delete(params.sessionId);
252
- }
253
- }).onNotification(acp.methods.agent.session.cancel, ({ params }) => {
254
- active.get(params.sessionId)?.abort();
255
- });
256
- }
257
- async function serveAcpAgentOnStdio$1(app) {
258
- const stream = acp.ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
259
- await app.connect(stream).closed;
260
- }
261
- function readPromptText(prompt) {
262
- const parts = prompt.flatMap((content) => content.type === "text" ? [content.text] : []);
263
- if (parts.length !== prompt.length) throw new Error("Rivus ACP facade currently accepts text prompt content only");
264
- return parts.join("\n");
265
- }
266
- function mapAgentLoopEvent(event) {
267
- if (event.type === "assistant_text_delta") return {
268
- content: {
269
- text: event.delta,
270
- type: "text"
271
- },
272
- sessionUpdate: "agent_message_chunk"
273
- };
274
- if (event.type === "assistant_thinking_delta") return {
275
- content: {
276
- text: event.delta,
277
- type: "text"
278
- },
279
- sessionUpdate: "agent_thought_chunk"
280
- };
281
- if (event.type === "tool_execution_start") return {
282
- name: event.toolName,
283
- rawInput: event.input,
284
- sessionUpdate: "tool_call",
285
- status: "in_progress",
286
- title: event.toolName,
287
- toolCallId: event.toolCallId
288
- };
289
- if (event.type === "tool_execution_update") return {
290
- name: event.toolName,
291
- rawInput: event.input,
292
- rawOutput: event.partialResult,
293
- sessionUpdate: "tool_call_update",
294
- status: "in_progress",
295
- title: event.toolName,
296
- toolCallId: event.toolCallId
297
- };
298
- if (event.type === "tool_execution_end") return {
299
- name: event.toolName,
300
- rawOutput: event.result,
301
- sessionUpdate: "tool_call_update",
302
- status: event.isError ? "failed" : "completed",
303
- title: event.toolName,
304
- toolCallId: event.toolCallId
305
- };
306
- }
307
- //#endregion
308
- //#region src/adapters/acp/runtime/acp-permission-policy.ts
309
- async function decideAcpPermission(request, policy) {
310
- const selection = await policy?.(request);
311
- if (!selection || !request.options.some((option) => option.optionId === selection.optionId)) return { outcome: "cancelled" };
312
- return {
313
- optionId: selection.optionId,
314
- outcome: "selected"
315
- };
316
- }
317
- //#endregion
318
- //#region src/adapters/acp/runtime/acp-stdio-agent-loop.ts
319
- async function buildAcpSession(processConnection, options, input) {
320
- const mcpServers = createMcpServers(options, input);
321
- const persisted = await options.sessionStore?.load(input.sessionKey);
322
- if (persisted) return restoreAcpSession(processConnection, options, persisted.sessionId, mcpServers);
323
- const session = await processConnection.connection.agent.buildSession({
324
- cwd: options.workingDirectory,
325
- mcpServers
326
- }).start();
327
- await options.sessionStore?.save(input.sessionKey, { sessionId: session.sessionId });
328
- return session;
329
- }
330
- function createMcpServers(options, input) {
331
- return (options.mcpServers?.(input) ?? []).map((server) => ({
332
- args: [...server.args],
333
- command: server.command,
334
- env: server.env.map(({ name, value }) => ({
335
- name,
336
- value
337
- })),
338
- name: server.name,
339
- type: "stdio"
340
- }));
341
- }
342
- async function restoreAcpSession(processConnection, options, sessionId, mcpServers) {
343
- const session = new ResumedAcpSession(processConnection, sessionId);
344
- try {
345
- if (processConnection.agentCapabilities?.loadSession) await processConnection.connection.agent.request(acp.methods.agent.session.load, {
346
- cwd: options.workingDirectory,
347
- mcpServers,
348
- sessionId
349
- });
350
- else if (processConnection.agentCapabilities?.sessionCapabilities?.resume) await processConnection.connection.agent.request(acp.methods.agent.session.resume, {
351
- cwd: options.workingDirectory,
352
- mcpServers,
353
- sessionId
354
- });
355
- else throw new AcpSessionResumeUnavailable(sessionId);
356
- session.clearReplay();
357
- return session;
358
- } catch (error) {
359
- session.dispose();
360
- throw new AcpSessionResumeFailed(sessionId, error);
361
- }
362
- }
363
- function createAcpStdioAgentLoop$1(options) {
364
- let pendingConnection;
365
- let activeConnection;
366
- let ownedChild;
367
- const sessionKeys = /* @__PURE__ */ new Map();
368
- const resolveConnection = () => {
369
- if (pendingConnection) return pendingConnection;
370
- let current;
371
- current = openConnection(options, sessionKeys, (child) => {
372
- ownedChild = child;
373
- });
374
- pendingConnection = current;
375
- current.then((processConnection) => {
376
- if (pendingConnection !== current) {
377
- processConnection.connection.close();
378
- terminateChild(processConnection.child, options.terminationTimeoutMs);
379
- return;
380
- }
381
- activeConnection = processConnection;
382
- processConnection.connection.closed.finally(() => {
383
- if (pendingConnection !== current) return;
384
- pendingConnection = void 0;
385
- activeConnection = void 0;
386
- if (ownedChild === processConnection.child) ownedChild = void 0;
387
- sessionKeys.clear();
388
- for (const session of processConnection.sessions.values()) session.dispose();
389
- processConnection.sessions.clear();
390
- processConnection.sessionUpdateHandlers.clear();
391
- terminateChild(processConnection.child, options.terminationTimeoutMs);
392
- });
393
- }, () => {
394
- if (pendingConnection === current) {
395
- pendingConnection = void 0;
396
- activeConnection = void 0;
397
- ownedChild = void 0;
398
- sessionKeys.clear();
399
- }
400
- });
401
- return current;
402
- };
403
- return {
404
- dispose: async () => {
405
- const current = pendingConnection;
406
- pendingConnection = void 0;
407
- const processConnection = activeConnection;
408
- activeConnection = void 0;
409
- if (processConnection) {
410
- for (const session of processConnection.sessions.values()) session.dispose();
411
- processConnection.sessions.clear();
412
- processConnection.sessionUpdateHandlers.clear();
413
- processConnection.connection.close();
414
- }
415
- sessionKeys.clear();
416
- const child = ownedChild;
417
- ownedChild = void 0;
418
- if (child) await terminateChild(child, options.terminationTimeoutMs);
419
- await current?.catch(() => void 0);
420
- },
421
- loop: createAcpAgentLoop$1({
422
- disposeSessionAfterRun: false,
423
- resolveSession: async (input) => {
424
- const processConnection = await resolveConnection();
425
- const current = processConnection.sessions.get(input.sessionKey);
426
- if (current?.isReusable) return current;
427
- if (current) {
428
- current.dispose();
429
- processConnection.sessions.delete(input.sessionKey);
430
- }
431
- const session = new SdkAcpAgentSession(await buildAcpSession(processConnection, options, input), processConnection.connection.agent, input.sessionKey, options.sessionStore);
432
- sessionKeys.set(session.sessionId, input.sessionKey);
433
- processConnection.sessions.set(input.sessionKey, session);
434
- return session;
435
- }
436
- })
437
- };
438
- }
439
- var SdkAcpAgentSession = class {
440
- session;
441
- agent;
442
- sessionKey;
443
- sessionStore;
444
- reusable = true;
445
- constructor(session, agent, sessionKey, sessionStore) {
446
- this.session = session;
447
- this.agent = agent;
448
- this.sessionKey = sessionKey;
449
- this.sessionStore = sessionStore;
450
- }
451
- get sessionId() {
452
- return this.session.sessionId;
453
- }
454
- get isReusable() {
455
- return this.reusable;
456
- }
457
- cancel(options) {
458
- if (options?.preserveSession !== true) this.reusable = false;
459
- return this.agent.notify(acp.methods.agent.session.cancel, { sessionId: this.session.sessionId });
460
- }
461
- dispose() {
462
- this.reusable = false;
463
- this.session.dispose();
464
- }
465
- async invalidate() {
466
- this.reusable = false;
467
- this.session.dispose();
468
- await this.sessionStore?.delete(this.sessionKey);
469
- }
470
- async prompt(text, onUpdate) {
471
- const failure = this.session.prompt(text).then(() => new Promise(() => void 0), (error) => Promise.reject(error));
472
- for (;;) {
473
- const message = await Promise.race([this.session.nextUpdate(), failure]);
474
- if (message.kind === "stop") return { stopReason: message.stopReason };
475
- onUpdate(message.update);
476
- }
477
- }
478
- };
479
- var ResumedAcpSession = class {
480
- processConnection;
481
- sessionId;
482
- updates = [];
483
- waiters = [];
484
- disposed = false;
485
- failure;
486
- constructor(processConnection, sessionId) {
487
- this.processConnection = processConnection;
488
- this.sessionId = sessionId;
489
- processConnection.sessionUpdateHandlers.set(sessionId, (notification) => {
490
- this.enqueue({
491
- kind: "session_update",
492
- update: notification.update
493
- });
494
- });
495
- }
496
- clearReplay() {
497
- this.updates.splice(0);
498
- }
499
- dispose() {
500
- if (this.disposed) return;
501
- this.disposed = true;
502
- this.processConnection.sessionUpdateHandlers.delete(this.sessionId);
503
- const error = /* @__PURE__ */ new Error(`ACP session ${this.sessionId} observer disposed`);
504
- for (const waiter of this.waiters.splice(0)) waiter.reject(error);
505
- this.updates.splice(0);
506
- }
507
- nextUpdate() {
508
- if (this.updates.length > 0) return Promise.resolve(this.updates.shift());
509
- if (this.failure !== void 0) return Promise.reject(this.failure);
510
- if (this.disposed) return Promise.reject(/* @__PURE__ */ new Error(`ACP session ${this.sessionId} observer disposed`));
511
- return new Promise((resolve, reject) => this.waiters.push({
512
- reject,
513
- resolve
514
- }));
515
- }
516
- prompt(text) {
517
- if (this.disposed) return Promise.reject(/* @__PURE__ */ new Error(`ACP session ${this.sessionId} observer disposed`));
518
- const response = this.processConnection.connection.agent.request(acp.methods.agent.session.prompt, {
519
- prompt: [{
520
- text,
521
- type: "text"
522
- }],
523
- sessionId: this.sessionId
524
- });
525
- response.then((result) => this.enqueue({
526
- kind: "stop",
527
- stopReason: result.stopReason
528
- }), (error) => this.fail(error));
529
- return response;
530
- }
531
- enqueue(message) {
532
- if (this.disposed) return;
533
- const waiter = this.waiters.shift();
534
- if (waiter) waiter.resolve(message);
535
- else this.updates.push(message);
536
- }
537
- fail(error) {
538
- if (this.failure !== void 0 || this.disposed) return;
539
- this.failure = error;
540
- for (const waiter of this.waiters.splice(0)) waiter.reject(error);
541
- }
542
- };
543
- var AcpSessionResumeUnavailable = class extends Error {
544
- sessionId;
545
- name = "AcpSessionResumeUnavailable";
546
- constructor(sessionId) {
547
- super(`ACP Agent cannot load or resume persisted session ${sessionId}`);
548
- this.sessionId = sessionId;
549
- }
550
- };
551
- var AcpSessionResumeFailed = class extends Error {
552
- sessionId;
553
- cause;
554
- name = "AcpSessionResumeFailed";
555
- constructor(sessionId, cause) {
556
- super(`ACP Agent failed to restore persisted session ${sessionId}`);
557
- this.sessionId = sessionId;
558
- this.cause = cause;
559
- }
560
- };
561
- async function openConnection(options, sessionKeys, onSpawn) {
562
- const child = spawn(options.command, [...options.arguments ?? []], {
563
- cwd: options.workingDirectory,
564
- env: { ...options.environment },
565
- stdio: [
566
- "pipe",
567
- "pipe",
568
- "pipe"
569
- ]
570
- });
571
- onSpawn(child);
572
- child.stderr.setEncoding("utf8");
573
- if (options.onStderr) child.stderr.on("data", options.onStderr);
574
- else child.stderr.resume();
575
- const sessionUpdateHandlers = /* @__PURE__ */ new Map();
576
- const app = acp.client({ name: options.clientName ?? "rivus" }).onRequest(acp.methods.client.session.requestPermission, async ({ params }) => {
577
- const sessionKey = sessionKeys.get(params.sessionId);
578
- return { outcome: await decideAcpPermission(toPermissionRequest(params), sessionKey && options.permissionPolicy ? (request) => options.permissionPolicy?.(request, { sessionKey }) : void 0) };
579
- }).onNotification(acp.methods.client.session.update, ({ params }) => {
580
- sessionUpdateHandlers.get(params.sessionId)?.(params);
581
- });
582
- const stream = acp.ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
583
- const connection = app.connect(stream);
584
- try {
585
- const initialized = await withTimeout(connection.agent.request(acp.methods.agent.initialize, {
586
- clientCapabilities: {},
587
- clientInfo: {
588
- name: options.clientName ?? "rivus",
589
- version: "1"
590
- },
591
- protocolVersion: acp.PROTOCOL_VERSION
592
- }), options.initializationTimeoutMs ?? 1e4, "ACP initialization timed out");
593
- if (initialized.protocolVersion !== acp.PROTOCOL_VERSION) throw new Error(`ACP protocol version ${initialized.protocolVersion} is not supported`);
594
- return {
595
- ...initialized.agentCapabilities ? { agentCapabilities: initialized.agentCapabilities } : {},
596
- child,
597
- connection,
598
- sessionUpdateHandlers,
599
- sessions: /* @__PURE__ */ new Map()
600
- };
601
- } catch (error) {
602
- connection.close(error);
603
- await terminateChild(child, options.terminationTimeoutMs);
604
- throw error;
605
- }
606
- }
607
- function toPermissionRequest(request) {
608
- return {
609
- options: request.options,
610
- sessionId: request.sessionId,
611
- toolCall: {
612
- ...request.toolCall.rawInput === void 0 ? {} : { rawInput: request.toolCall.rawInput },
613
- ...request.toolCall.title == null ? {} : { title: request.toolCall.title },
614
- toolCallId: request.toolCall.toolCallId
615
- }
616
- };
617
- }
618
- async function terminateChild(child, timeoutMs = 2e3) {
619
- if (child.exitCode !== null || child.signalCode !== null) return;
620
- child.kill("SIGTERM");
621
- if (await waitForChildExit(child, timeoutMs)) return;
622
- child.kill("SIGKILL");
623
- if (!await waitForChildExit(child, timeoutMs)) throw new Error(`ACP child did not exit after SIGKILL within ${timeoutMs}ms`);
624
- }
625
- function waitForChildExit(child, timeoutMs) {
626
- if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve(true);
627
- return new Promise((resolve) => {
628
- const onExit = () => {
629
- clearTimeout(timeout);
630
- resolve(true);
631
- };
632
- const timeout = setTimeout(() => {
633
- child.removeListener("exit", onExit);
634
- resolve(false);
635
- }, timeoutMs);
636
- timeout.unref();
637
- child.once("exit", onExit);
638
- });
639
- }
640
- function withTimeout(promise, timeoutMs, message) {
641
- return new Promise((resolve, reject) => {
642
- const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`${message} after ${timeoutMs}ms`)), timeoutMs);
643
- promise.then((value) => {
644
- clearTimeout(timeout);
645
- resolve(value);
646
- }, (error) => {
647
- clearTimeout(timeout);
648
- reject(error);
649
- });
650
- });
651
- }
652
- //#endregion
653
- //#region src/adapters/compatibility/agent-execution/acp/acp-runtime.ts
654
- function createAcpAgentLoop(options) {
655
- return fromEffectAgentLoop(createAcpAgentLoop$1({
656
- ...options.cancellationSettleTimeoutMs === void 0 ? {} : { cancellationSettleTimeoutMs: options.cancellationSettleTimeoutMs },
657
- ...options.disposeSessionAfterRun === void 0 ? {} : { disposeSessionAfterRun: options.disposeSessionAfterRun },
658
- resolveSession: (input) => options.resolveSession(toCompatibilityAgentLoopInput(input))
659
- }));
660
- }
661
- function createAcpAgentServer(options) {
662
- return createAcpAgentServer$1({
663
- ...options.agentName === void 0 ? {} : { agentName: options.agentName },
664
- loop: toEffectAgentLoop(options.loop),
665
- ...options.permissionBridge ? { permissionBridge: options.permissionBridge } : {},
666
- workingDirectory: options.workingDirectory
667
- });
668
- }
669
- function serveAcpAgentOnStdio(app) {
670
- return serveAcpAgentOnStdio$1(app);
671
- }
672
- function createAcpStdioAgentLoop(options) {
673
- const handle = createAcpStdioAgentLoop$1({
674
- ...options.arguments ? { arguments: options.arguments } : {},
675
- ...options.clientName === void 0 ? {} : { clientName: options.clientName },
676
- command: options.command,
677
- ...options.environment ? { environment: options.environment } : {},
678
- ...options.initializationTimeoutMs === void 0 ? {} : { initializationTimeoutMs: options.initializationTimeoutMs },
679
- ...options.mcpServers ? { mcpServers: (input) => options.mcpServers(toCompatibilityAgentLoopInput(input)) } : {},
680
- ...options.onStderr ? { onStderr: options.onStderr } : {},
681
- ...options.permissionPolicy ? { permissionPolicy: options.permissionPolicy } : {},
682
- ...options.sessionStore ? { sessionStore: options.sessionStore } : {},
683
- ...options.terminationTimeoutMs === void 0 ? {} : { terminationTimeoutMs: options.terminationTimeoutMs },
684
- workingDirectory: options.workingDirectory
685
- });
686
- return {
687
- dispose: () => handle.dispose(),
688
- loop: fromEffectAgentLoop(handle.loop)
689
- };
690
- }
691
- //#endregion
692
- //#region src/adapters/acp/runtime/acp-permission-bridge.ts
693
- function createAcpPermissionBridge() {
694
- const policies = /* @__PURE__ */ new Map();
695
- return {
696
- bind: (sessionKey, policy) => {
697
- if (policies.has(sessionKey)) throw new Error(`ACP permission bridge is already bound: ${sessionKey}`);
698
- policies.set(sessionKey, policy);
699
- return () => {
700
- if (policies.get(sessionKey) === policy) policies.delete(sessionKey);
701
- };
702
- },
703
- policy: async (request, context) => policies.get(context.sessionKey)?.(request)
704
- };
705
- }
706
- //#endregion
707
- //#region src/adapters/acp/runtime/acp-session-store.ts
708
- /**
709
- * A small deployment-owned store for ACP provider session identities.
710
- * The file contains no prompts or credentials, only session-key bindings.
711
- */
712
- function createJsonAcpSessionStore(options) {
713
- let recordsPromise;
714
- let writeChain = Promise.resolve();
715
- const readRecords = async () => {
716
- try {
717
- const raw = await readFile(options.filePath, "utf8");
718
- const parsed = JSON.parse(raw);
719
- if (!isRecord(parsed)) throw new Error("ACP session store must contain an object");
720
- const records = /* @__PURE__ */ new Map();
721
- for (const [sessionKey, value] of Object.entries(parsed)) {
722
- if (!isRecord(value) || typeof value.sessionId !== "string" || value.sessionId.trim() === "") throw new Error(`invalid ACP session record for ${sessionKey}`);
723
- records.set(sessionKey, { sessionId: value.sessionId });
724
- }
725
- return records;
726
- } catch (error) {
727
- if (isMissingFile(error)) return /* @__PURE__ */ new Map();
728
- throw error;
729
- }
730
- };
731
- const records = async () => {
732
- recordsPromise ??= readRecords();
733
- return recordsPromise;
734
- };
735
- const persist = async (value) => {
736
- const temporaryPath = `${options.filePath}.tmp-${process.pid}-${Date.now()}`;
737
- await mkdir(dirname(options.filePath), { recursive: true });
738
- await writeFile(temporaryPath, `${JSON.stringify(Object.fromEntries(value), null, 2)}\n`, "utf8");
739
- await rename(temporaryPath, options.filePath);
740
- };
741
- return {
742
- delete: async (sessionKey) => {
743
- writeChain = writeChain.then(async () => {
744
- const current = await records();
745
- if (!current.delete(sessionKey)) return;
746
- await persist(current);
747
- });
748
- await writeChain;
749
- },
750
- load: async (sessionKey) => (await records()).get(sessionKey),
751
- save: async (sessionKey, record) => {
752
- writeChain = writeChain.then(async () => {
753
- const current = await records();
754
- current.set(sessionKey, { sessionId: record.sessionId });
755
- await persist(current);
756
- });
757
- await writeChain;
758
- }
759
- };
760
- }
761
- function isMissingFile(error) {
762
- return isRecord(error) && error.code === "ENOENT";
763
- }
764
- function isRecord(value) {
765
- return value !== null && typeof value === "object" && !Array.isArray(value);
766
- }
767
- //#endregion
1
+ import { AcpSessionResumeFailed, AcpSessionResumeUnavailable, createAcpPermissionBridge, createJsonAcpSessionStore, createLegacyAcpAgentLoop as createAcpAgentLoop, createLegacyAcpAgentServer as createAcpAgentServer, createLegacyAcpStdioAgentLoop as createAcpStdioAgentLoop, decideAcpPermission, serveLegacyAcpAgentOnStdio as serveAcpAgentOnStdio } from "@rivus/runtime/acp";
768
2
  export { AcpSessionResumeFailed, AcpSessionResumeUnavailable, createAcpAgentLoop, createAcpAgentServer, createAcpPermissionBridge, createAcpStdioAgentLoop, createJsonAcpSessionStore, decideAcpPermission, serveAcpAgentOnStdio };