@automatalabs/pi-acp 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/session.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import { methods, } from "@agentclientprotocol/sdk";
2
2
  import { adapterError, classifyPreflight, isRequestError, unexpectedError } from "./errors.js";
3
- import { applyConfig, thinkingLevelOption } from "./config.js";
3
+ import { applyConfig, modelOption, thinkingLevelOption } from "./config.js";
4
4
  import { convertPromptContent } from "./prompt-content.js";
5
5
  import { replayEntry } from "./replay.js";
6
6
  import { stopReasonFor } from "./stop-reason.js";
7
7
  import { translateEvent } from "./translate.js";
8
8
  import { agentMessages, promptUsage, terminalAssistant, usageUpdate, } from "./usage.js";
9
9
  import { installPermissionWrapper } from "./permissions.js";
10
- import { disposeMcpBridge, } from "./mcp-bridge.js";
10
+ import { ChildCleanupFailure } from "./child-process-registry.js";
11
11
  export class PiSession {
12
12
  sessionId;
13
13
  pi;
14
14
  manager;
15
15
  client;
16
16
  deps;
17
- mcpClients;
17
+ mcpBridge;
18
18
  failedMcpResults;
19
- structured;
19
+ availableModels;
20
+ childRegistry;
21
+ lifecycleController;
20
22
  onWedged;
21
23
  pending = [];
22
24
  pump;
@@ -26,15 +28,22 @@ export class PiSession {
26
28
  disposed = false;
27
29
  unsubscribe;
28
30
  activeTurn;
31
+ configReserved = false;
32
+ cleanupDirty = false;
33
+ cleanupGeneration;
34
+ resourceDisposePromise;
35
+ bridgeClosePromise;
29
36
  constructor(options) {
30
37
  this.sessionId = options.sessionId;
31
38
  this.pi = options.session;
32
39
  this.manager = options.manager;
33
40
  this.client = options.client;
34
41
  this.deps = options.deps;
35
- this.mcpClients = options.mcpClients;
42
+ this.mcpBridge = options.mcpBridge;
36
43
  this.failedMcpResults = options.failedMcpResults;
37
- this.structured = options.structured;
44
+ this.availableModels = options.availableModels;
45
+ this.childRegistry = options.childRegistry;
46
+ this.lifecycleController = options.lifecycleController;
38
47
  this.onWedged = options.onWedged;
39
48
  installPermissionWrapper(this.pi, {
40
49
  sessionId: this.sessionId,
@@ -66,10 +75,24 @@ export class PiSession {
66
75
  });
67
76
  }
68
77
  get busy() {
69
- return this.activeTurn !== undefined || this.closing;
78
+ return this.activeTurn !== undefined || this.configReserved || this.closing;
70
79
  }
71
80
  configOptions() {
72
- return [thinkingLevelOption(this.pi)];
81
+ return [thinkingLevelOption(this.pi), modelOption(this.pi, this.availableModels)];
82
+ }
83
+ publishAvailableModels(models) {
84
+ this.availableModels = [...models];
85
+ }
86
+ activeTurnSignal() { return this.activeTurn?.controller.signal; }
87
+ emitMcpDiagnostic(text) {
88
+ if (this.disposed)
89
+ return;
90
+ if (this.activeTurn && !this.activeTurn.completed && this.activeTurn.diagnosticOpen) {
91
+ this.enqueue({ sessionUpdate: "agent_thought_chunk", content: { type: "text", text } });
92
+ }
93
+ else {
94
+ console.error(text);
95
+ }
73
96
  }
74
97
  enqueue(update) {
75
98
  if (this.stopped)
@@ -125,34 +148,44 @@ export class PiSession {
125
148
  async setConfig(configId, value) {
126
149
  if (this.busy)
127
150
  throw adapterError("session_busy");
128
- return applyConfig(this.pi, this.deps.modelRuntime, configId, value);
129
- }
130
- disarm(turn) {
131
- if (!turn.structured)
132
- return;
151
+ // Reserve synchronously before the corrective catalog refresh. Prompt,
152
+ // config, fork, and refresh commit all share the same admission boundary.
153
+ this.configReserved = true;
154
+ let release;
133
155
  try {
134
- this.structured.disarm(this.pi);
156
+ release = await this.mcpBridge.acquireTurnBoundary();
157
+ if (this.closing)
158
+ throw adapterError("session_busy");
159
+ const result = await applyConfig(this.pi, this.deps.modelRuntime, this.availableModels, configId, value);
160
+ this.availableModels = result.availableModels;
161
+ return result.configOptions;
135
162
  }
136
- catch (error) {
137
- console.error("pi-acp structured-output disarm error:", error);
163
+ finally {
164
+ release?.();
165
+ this.configReserved = false;
138
166
  }
139
167
  }
140
- finish(turn, outcome, keepBackstop = false) {
168
+ finish(turn, outcome) {
141
169
  if (turn.completed)
142
170
  return;
171
+ turn.diagnosticOpen = false;
143
172
  turn.completed = true;
144
173
  turn.removeRequestAbort?.();
145
174
  turn.removeRequestAbort = undefined;
146
- this.disarm(turn);
147
- if (!keepBackstop)
148
- turn.settledController.abort();
149
- if (this.activeTurn === turn)
150
- this.activeTurn = undefined;
151
175
  if ("response" in outcome)
152
176
  turn.resolve(outcome.response);
153
177
  else
154
178
  turn.reject(outcome.error);
155
179
  turn.resolveSettlement();
180
+ turn.releaseBoundary?.();
181
+ turn.releaseBoundary = undefined;
182
+ if (this.activeTurn === turn)
183
+ this.activeTurn = undefined;
184
+ const generation = this.cleanupGeneration;
185
+ if (generation?.resumeRefreshesOnSettlement && generation.mode === "cancel-only") {
186
+ this.cleanupGeneration = undefined;
187
+ this.mcpBridge.resumeRefreshes();
188
+ }
156
189
  }
157
190
  notificationFailure() {
158
191
  const turn = this.activeTurn;
@@ -160,17 +193,135 @@ export class PiSession {
160
193
  return;
161
194
  turn.notificationFailed = true;
162
195
  this.abortTurn(turn);
163
- this.finish(turn, { error: adapterError("notification_error") }, true);
196
+ void turn.cleanup?.then(() => this.finish(turn, { error: adapterError("notification_error") }), (error) => this.finish(turn, { error }));
164
197
  }
165
198
  abortTurn(turn) {
166
199
  if (turn.completed)
167
200
  return;
168
- if (!turn.controller.signal.aborted)
201
+ turn.cleanup ??= this.cleanupTurn("cancel-only");
202
+ turn.cleanup.catch((error) => {
203
+ if (!turn.completed)
204
+ this.turnError(turn, error);
205
+ void this.cleanupWedged();
206
+ });
207
+ }
208
+ startDisposal() {
209
+ this.closing = true;
210
+ // The contract's disposal prefix is intentionally split: transport close
211
+ // admission starts first, then incoming handlers observe session disposal,
212
+ // and only then are refresh/turn signals aborted.
213
+ this.mcpBridge.startDisposal();
214
+ if (!this.lifecycleController.signal.aborted) {
215
+ this.lifecycleController.abort(new Error("session disposed"));
216
+ }
217
+ this.mcpBridge.abortRefreshes();
218
+ this.bridgeClosePromise ??= this.mcpBridge.close();
219
+ this.bridgeClosePromise.catch(() => undefined);
220
+ }
221
+ cleanupTurn(mode) {
222
+ const current = this.cleanupGeneration;
223
+ if (current?.status === "pending") {
224
+ if (mode === "disposal" && current.mode === "cancel-only") {
225
+ current.mode = "disposal";
226
+ this.startDisposal();
227
+ }
228
+ return current.promise;
229
+ }
230
+ if (current?.status === "succeeded" && current.mode === "disposal") {
231
+ return current.promise;
232
+ }
233
+ const deadlineController = new AbortController();
234
+ const timerController = new AbortController();
235
+ const generation = {
236
+ mode,
237
+ status: "pending",
238
+ promise: Promise.resolve(),
239
+ deadlineController,
240
+ timerController,
241
+ };
242
+ this.cleanupGeneration = generation;
243
+ const expiry = this.deps.sleep(this.deps.graceMs, timerController.signal).then(() => {
244
+ const failure = new ChildCleanupFailure(this.childRegistry.remainingChildren);
245
+ deadlineController.abort(failure);
246
+ throw failure;
247
+ });
248
+ expiry.catch(() => undefined);
249
+ // Closing the captured epoch is the synchronous admission barrier. It
250
+ // must precede Pi abort, because abort can yield while a bash spawn is
251
+ // between its filesystem check and lease acquisition.
252
+ const captured = this.childRegistry.closeEpoch(deadlineController.signal);
253
+ captured.drain.catch(() => undefined);
254
+ if (mode === "disposal")
255
+ this.startDisposal();
256
+ else
257
+ this.mcpBridge.abortRefreshes();
258
+ const turn = this.activeTurn;
259
+ if (turn && !turn.controller.signal.aborted)
169
260
  turn.controller.abort();
261
+ let abortPi;
262
+ try {
263
+ abortPi = this.pi.abort();
264
+ }
265
+ catch (error) {
266
+ abortPi = Promise.reject(error);
267
+ }
268
+ abortPi.catch(() => undefined);
269
+ const operations = Promise.allSettled([abortPi, captured.drain]);
270
+ generation.promise = new Promise((resolve, reject) => {
271
+ let claimed = false;
272
+ const fail = (error) => {
273
+ if (claimed)
274
+ return;
275
+ claimed = true;
276
+ generation.status = "failed";
277
+ this.cleanupDirty = true;
278
+ generation.mode = "disposal";
279
+ this.startDisposal();
280
+ const remaining = error instanceof ChildCleanupFailure
281
+ ? error.remainingChildren
282
+ : this.childRegistry.remainingChildren;
283
+ generation.error = adapterError("child_cleanup_error", { details: { remainingChildren: remaining } });
284
+ timerController.abort();
285
+ reject(generation.error);
286
+ };
287
+ expiry.then(() => undefined, (error) => {
288
+ if (timerController.signal.aborted && !deadlineController.signal.aborted)
289
+ return;
290
+ fail(error);
291
+ });
292
+ operations.then((results) => {
293
+ if (claimed)
294
+ return;
295
+ const failure = results.find((result) => result.status === "rejected");
296
+ if (failure) {
297
+ fail(failure.reason);
298
+ return;
299
+ }
300
+ claimed = true;
301
+ generation.status = "succeeded";
302
+ this.cleanupDirty = false;
303
+ timerController.abort();
304
+ if (generation.mode === "cancel-only" && this.cleanupGeneration === generation) {
305
+ this.childRegistry.commitRotation(captured.epoch);
306
+ if (turn?.completed) {
307
+ this.cleanupGeneration = undefined;
308
+ this.mcpBridge.resumeRefreshes();
309
+ }
310
+ else {
311
+ generation.resumeRefreshesOnSettlement = true;
312
+ }
313
+ }
314
+ resolve();
315
+ });
316
+ });
317
+ generation.promise.catch(() => undefined);
318
+ return generation.promise;
170
319
  }
171
320
  turnError(turn, error) {
172
- if (turn.completed)
321
+ if (turn.completed || turn.errorSettlementStarted)
173
322
  return;
323
+ turn.errorSettlementStarted = true;
324
+ turn.diagnosticOpen = false;
174
325
  let terminal;
175
326
  try {
176
327
  terminal = terminalAssistant(agentMessages(this.pi).slice(turn.startMessageIndex));
@@ -178,7 +329,8 @@ export class PiSession {
178
329
  catch {
179
330
  terminal = undefined;
180
331
  }
181
- this.finish(turn, { error: isRequestError(error) ? error : unexpectedError(error, terminal) });
332
+ const mapped = isRequestError(error) ? error : unexpectedError(error, terminal);
333
+ void this.drain().then(() => this.finish(turn, { error: mapped }), () => this.notificationFailure());
182
334
  }
183
335
  runTurnTask(turn, task) {
184
336
  void task.catch((error) => {
@@ -190,61 +342,22 @@ export class PiSession {
190
342
  }
191
343
  async cleanupWedged() {
192
344
  try {
193
- await this.onWedged(this.sessionId, this);
345
+ await this.onWedged(this.sessionId, this, true);
194
346
  }
195
347
  catch (error) {
196
348
  console.error("pi-acp wedged-session cleanup error:", error);
197
349
  }
198
350
  }
199
- startBackstop(turn) {
200
- if (turn.backstopStarted)
201
- return;
202
- turn.backstopStarted = true;
203
- const backstop = this.deps.sleep(this.deps.graceMs, turn.settledController.signal).then(async () => {
204
- try {
205
- if (!turn.completed) {
206
- const messages = agentMessages(this.pi).slice(turn.startMessageIndex);
207
- if (!this.pumpFailure) {
208
- this.enqueue(usageUpdate(this.pi));
209
- await this.drain();
210
- }
211
- if (!turn.completed) {
212
- this.finish(turn, {
213
- response: { stopReason: "cancelled", usage: promptUsage(messages) },
214
- });
215
- }
216
- }
217
- }
218
- catch (error) {
219
- if (this.pumpFailure !== undefined) {
220
- turn.notificationFailed = true;
221
- this.finish(turn, { error: adapterError("notification_error") }, true);
222
- }
223
- else {
224
- this.turnError(turn, error);
225
- }
226
- }
227
- if (turn.completed)
228
- await this.cleanupWedged();
229
- }, async (error) => {
230
- if (turn.settledController.signal.aborted || turn.completed)
231
- return;
232
- this.turnError(turn, error);
233
- await this.cleanupWedged();
234
- });
235
- this.runTurnTask(turn, backstop);
236
- }
237
351
  async handlePiResolved(turn) {
238
352
  if (turn.completed)
239
353
  return;
240
354
  try {
355
+ if (this.childRegistry.childCleanupFailed)
356
+ turn.cleanup ??= this.cleanupTurn("disposal");
241
357
  const messages = agentMessages(this.pi).slice(turn.startMessageIndex);
242
- if (turn.structured) {
243
- const json = this.structured.takeJson();
244
- if (json !== undefined) {
245
- this.enqueue({ sessionUpdate: "agent_message_chunk", content: { type: "text", text: json } });
246
- }
247
- }
358
+ if (turn.cleanup)
359
+ await turn.cleanup;
360
+ turn.diagnosticOpen = false;
248
361
  this.enqueue(usageUpdate(this.pi));
249
362
  await this.drain();
250
363
  if (turn.completed)
@@ -264,11 +377,21 @@ export class PiSession {
264
377
  if (turn.completed)
265
378
  return;
266
379
  if (!turn.controller.signal.aborted) {
267
- this.finish(turn, { error: classifyPreflight(error) });
380
+ turn.diagnosticOpen = false;
381
+ try {
382
+ await this.drain();
383
+ this.finish(turn, { error: classifyPreflight(error) });
384
+ }
385
+ catch {
386
+ this.notificationFailure();
387
+ }
268
388
  return;
269
389
  }
270
390
  try {
391
+ if (turn.cleanup)
392
+ await turn.cleanup;
271
393
  const messages = agentMessages(this.pi).slice(turn.startMessageIndex);
394
+ turn.diagnosticOpen = false;
272
395
  this.enqueue(usageUpdate(this.pi));
273
396
  await this.drain();
274
397
  this.finish(turn, { response: { stopReason: "cancelled", usage: promptUsage(messages) } });
@@ -284,35 +407,12 @@ export class PiSession {
284
407
  if (this.busy)
285
408
  throw adapterError("session_busy");
286
409
  const converted = convertPromptContent(params.prompt);
287
- const schema = params._meta?.outputSchema;
288
- let text = converted.text;
289
- let structured = false;
290
- if (schema !== undefined) {
291
- let instruction;
292
- try {
293
- instruction = this.structured.arm(this.pi, schema);
294
- }
295
- catch (error) {
296
- if (isRequestError(error))
297
- throw error;
298
- throw unexpectedError(error);
299
- }
300
- text = text ? `${instruction}\n\n${text}` : instruction;
301
- structured = true;
302
- }
410
+ const text = converted.text;
303
411
  let startMessageIndex;
304
412
  try {
305
413
  startMessageIndex = agentMessages(this.pi).length;
306
414
  }
307
415
  catch (error) {
308
- if (structured) {
309
- try {
310
- this.structured.disarm(this.pi);
311
- }
312
- catch (disarmError) {
313
- console.error("pi-acp structured-output disarm error:", disarmError);
314
- }
315
- }
316
416
  throw unexpectedError(error);
317
417
  }
318
418
  let resolve;
@@ -327,29 +427,17 @@ export class PiSession {
327
427
  });
328
428
  const turn = {
329
429
  controller: new AbortController(),
330
- settledController: new AbortController(),
331
430
  settlement,
332
431
  resolveSettlement,
333
432
  completed: false,
433
+ diagnosticOpen: true,
434
+ errorSettlementStarted: false,
334
435
  notificationFailed: false,
335
- backstopStarted: false,
336
436
  resolve,
337
437
  reject,
338
438
  startMessageIndex,
339
- structured,
340
439
  };
341
440
  this.activeTurn = turn;
342
- turn.controller.signal.addEventListener("abort", () => {
343
- try {
344
- this.pi.agent.abort();
345
- }
346
- catch (error) {
347
- console.error("pi-acp abort error:", error);
348
- }
349
- finally {
350
- this.startBackstop(turn);
351
- }
352
- }, { once: true });
353
441
  const abortFromRequest = () => this.abortTurn(turn);
354
442
  if (requestSignal.aborted)
355
443
  abortFromRequest();
@@ -357,58 +445,126 @@ export class PiSession {
357
445
  requestSignal.addEventListener("abort", abortFromRequest, { once: true });
358
446
  turn.removeRequestAbort = () => requestSignal.removeEventListener("abort", abortFromRequest);
359
447
  }
360
- let piPromise;
361
- try {
362
- piPromise = this.pi.prompt(text, { images: converted.images });
363
- }
364
- catch (error) {
365
- this.runTurnTask(turn, this.handlePiRejected(turn, error));
366
- return result;
367
- }
368
- void piPromise.then(() => this.runTurnTask(turn, this.handlePiResolved(turn)), (error) => this.runTurnTask(turn, this.handlePiRejected(turn, error)));
448
+ this.runTurnTask(turn, (async () => {
449
+ turn.releaseBoundary = await this.mcpBridge.acquireTurnBoundary();
450
+ if (turn.controller.signal.aborted) {
451
+ try {
452
+ if (turn.cleanup)
453
+ await turn.cleanup;
454
+ turn.diagnosticOpen = false;
455
+ this.enqueue(usageUpdate(this.pi));
456
+ await this.drain();
457
+ this.finish(turn, {
458
+ response: {
459
+ stopReason: "cancelled",
460
+ usage: { inputTokens: 0, outputTokens: 0, cachedReadTokens: 0, cachedWriteTokens: 0, totalTokens: 0 },
461
+ },
462
+ });
463
+ }
464
+ catch (error) {
465
+ this.turnError(turn, error);
466
+ }
467
+ return;
468
+ }
469
+ let piPromise;
470
+ try {
471
+ piPromise = this.pi.prompt(text, { images: converted.images });
472
+ }
473
+ catch (error) {
474
+ await this.handlePiRejected(turn, error);
475
+ return;
476
+ }
477
+ await piPromise.then(() => this.handlePiResolved(turn), (error) => this.handlePiRejected(turn, error));
478
+ })());
369
479
  return result;
370
480
  }
371
481
  cancel() {
372
482
  if (this.activeTurn)
373
483
  this.abortTurn(this.activeTurn);
374
484
  }
485
+ childCleanupFailure() {
486
+ const turn = this.activeTurn;
487
+ if (turn && !turn.completed) {
488
+ this.abortTurn(turn);
489
+ return;
490
+ }
491
+ void this.cleanupWedged();
492
+ }
375
493
  async dispose() {
376
- if (this.disposed)
494
+ if (this.disposed && !this.cleanupDirty && this.childRegistry.remainingChildren === 0 && !this.childRegistry.childCleanupFailed)
377
495
  return;
378
- this.closing = true;
496
+ const cleanup = this.cleanupTurn("disposal");
379
497
  const turn = this.activeTurn;
498
+ let cleanupError;
380
499
  if (turn) {
381
500
  this.abortTurn(turn);
382
501
  await turn.settlement;
502
+ try {
503
+ await cleanup;
504
+ }
505
+ catch (error) {
506
+ cleanupError = error;
507
+ }
383
508
  }
509
+ else {
510
+ try {
511
+ await cleanup;
512
+ }
513
+ catch (error) {
514
+ cleanupError = error;
515
+ }
516
+ }
517
+ await this.disposeResources();
518
+ if (cleanupError)
519
+ throw cleanupError;
520
+ }
521
+ async disposeAfterCleanupFailure() {
522
+ this.startDisposal();
384
523
  await this.disposeResources();
385
524
  }
525
+ get remainingChildren() { return this.childRegistry.remainingChildren; }
526
+ get cleanupRetryRequired() {
527
+ return this.cleanupDirty || this.childRegistry.remainingChildren > 0 || this.childRegistry.childCleanupFailed;
528
+ }
386
529
  async disposeResources() {
387
- if (this.disposed)
530
+ this.resourceDisposePromise ??= (async () => {
531
+ if (this.disposed)
532
+ return;
533
+ this.closing = true;
534
+ this.disposed = true;
535
+ this.stopped = true;
536
+ this.pending.length = 0;
537
+ this.failedMcpResults.clear();
538
+ try {
539
+ this.unsubscribe?.();
540
+ }
541
+ catch (error) {
542
+ console.error("pi-acp unsubscribe error:", error);
543
+ }
544
+ this.unsubscribe = undefined;
545
+ this.startDisposal();
546
+ await this.mcpBridge.drainRefreshes().catch((error) => {
547
+ console.error("pi-acp MCP refresh drain error:", error);
548
+ });
549
+ const results = await Promise.allSettled([
550
+ Promise.resolve().then(() => this.pi.dispose()),
551
+ this.bridgeClosePromise ?? Promise.resolve(),
552
+ ]);
553
+ if (results[0]?.status === "rejected") {
554
+ console.error("pi-acp session dispose error:", results[0].reason);
555
+ }
556
+ if (results[1]?.status === "rejected") {
557
+ console.error("pi-acp MCP disposal error:", results[1].reason);
558
+ }
559
+ })();
560
+ return this.resourceDisposePromise;
561
+ }
562
+ poison() {
563
+ if (this.closing || this.disposed)
388
564
  return;
389
565
  this.closing = true;
390
- this.disposed = true;
391
- this.stopped = true;
392
- this.pending.length = 0;
393
- this.failedMcpResults.clear();
394
- try {
395
- this.unsubscribe?.();
396
- }
397
- catch (error) {
398
- console.error("pi-acp unsubscribe error:", error);
399
- }
400
- this.unsubscribe = undefined;
401
- try {
402
- await this.pi.dispose();
403
- }
404
- catch (error) {
405
- console.error("pi-acp session dispose error:", error);
406
- }
407
- try {
408
- await disposeMcpBridge(this.mcpClients, this.deps);
409
- }
410
- catch (error) {
411
- console.error("pi-acp MCP disposal error:", error);
412
- }
566
+ void this.onWedged(this.sessionId, this, false).catch((error) => {
567
+ console.error("pi-acp poisoned-session cleanup error:", error);
568
+ });
413
569
  }
414
570
  }
@@ -1 +1 @@
1
- {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,UAAU,QAAQ;IAChB,OAAO,CAAC,EAAE,KAAK,CACX;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CACpD,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAgBlD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,EAAE,GAAG,SAAS,CAI3E;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,YAAY,EAAE,CAM7D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,EAAE,CAE7D;AA4BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,iBAAiB,EAAE,YAAY,CAAC,EAAE,QAAQ,GAAG,aAAa,EAAE,CAsDjG"}
1
+ {"version":3,"file":"translate.d.ts","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEzE,UAAU,QAAQ;IAChB,OAAO,CAAC,EAAE,KAAK,CACX;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC9B;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CACpD,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAgBlD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,EAAE,GAAG,SAAS,CAI3E;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,YAAY,EAAE,CAM7D;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,EAAE,CAE7D;AA4BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,iBAAiB,EAAE,YAAY,CAAC,EAAE,QAAQ,GAAG,aAAa,EAAE,CAyDjG"}
package/dist/translate.js CHANGED
@@ -68,12 +68,16 @@ export function translateEvent(event, failedResult) {
68
68
  _meta: { toolName: event.toolName },
69
69
  }];
70
70
  case "tool_execution_update":
71
- return [{
72
- sessionUpdate: "tool_call_update",
73
- toolCallId: event.toolCallId,
74
- status: "in_progress",
75
- content: toContent(event.partialResult),
76
- }];
71
+ const update = {
72
+ sessionUpdate: "tool_call_update",
73
+ toolCallId: event.toolCallId,
74
+ status: "in_progress",
75
+ content: toContent(event.partialResult),
76
+ };
77
+ const partial = event.partialResult;
78
+ if (partial.details !== undefined)
79
+ update.rawOutput = partial.details;
80
+ return [update];
77
81
  case "tool_execution_end": {
78
82
  const result = failedResult ?? event.result;
79
83
  const update = {
@@ -0,0 +1,2 @@
1
+ export declare const PKG_VERSION: string;
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,QAEvB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { readFileSync } from "node:fs";
2
+ export const PKG_VERSION = String(JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automatalabs/pi-acp",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": ">=22.19.0"
@@ -31,13 +31,13 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@agentclientprotocol/sdk": "1.2.1",
34
+ "@earendil-works/pi-ai": "0.80.10",
34
35
  "@earendil-works/pi-coding-agent": "0.80.10",
35
36
  "@modelcontextprotocol/sdk": "1.29.0",
36
37
  "typebox": "1.3.2"
37
38
  },
38
39
  "devDependencies": {
39
- "@earendil-works/pi-agent-core": "0.80.10",
40
- "@earendil-works/pi-ai": "0.80.10"
40
+ "@earendil-works/pi-agent-core": "0.80.10"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsc -b",