@dougbots/avenor-pi 0.12.0 → 0.13.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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { InspectResult, StatusResult, Supervisor, answerPermissionTool, brokerReceiveTool, brokerReplyTool, dial, eventsTool, followUpTool, inspectTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
1
+ import { InspectResult, StatusResult, Supervisor, answerPermissionTool, brokerReceiveTool, brokerReplyTool, dial, eventsTool, followUpTool, inspectTool, killTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
2
2
  import { EventBus, ExtensionAPI } from "@earendil-works/pi-coding-agent";
3
3
 
4
4
  //#region src/subagent-broker.d.ts
@@ -128,6 +128,7 @@ interface ExtensionDeps {
128
128
  brokerReceiveTool: typeof brokerReceiveTool;
129
129
  brokerReplyTool: typeof brokerReplyTool;
130
130
  shutdownTool: typeof shutdownTool;
131
+ killTool: typeof killTool;
131
132
  workflowStatusTool: typeof workflowStatusTool;
132
133
  workflowWaitTool: typeof workflowWaitTool;
133
134
  workflowInspectTool: typeof workflowInspectTool;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Input, Key, Text, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
2
2
  import { Type } from "typebox";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
- import { Supervisor, THINKING_LEVELS, answerPermissionTool, askTool, brokerReceiveTool, brokerReplyTool, cancelTool, dial, eventsTool, extractEventText, followUpTool, inspectTool, observeRun, peersTool, resultTool, shutdownTool, socketsRoot, spawnTool, statusTool, validateSpawnSelection, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
4
+ import { Supervisor, THINKING_LEVELS, answerPermissionTool, askTool, brokerReceiveTool, brokerReplyTool, cancelTool, dial, eventsTool, extractEventText, followUpTool, inspectTool, killTool, observeRun, peersTool, resultTool, shutdownTool, socketsRoot, spawnTool, statusTool, validateSpawnSelection, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
7
7
  //#region src/subagent-broker.ts
@@ -1393,6 +1393,9 @@ function renderWorkflowControllerStatusResult(result, options, theme, args) {
1393
1393
  }
1394
1394
  //#endregion
1395
1395
  //#region src/index.ts
1396
+ function asStatusResult(raw) {
1397
+ return raw;
1398
+ }
1396
1399
  const POLL_INTERVAL_MS = 3e3;
1397
1400
  const INSPECT_LIMIT = 128;
1398
1401
  const COMPLETION_OUTPUT_CHARS = 600;
@@ -1412,6 +1415,7 @@ const defaultDeps = {
1412
1415
  brokerReceiveTool,
1413
1416
  brokerReplyTool,
1414
1417
  shutdownTool,
1418
+ killTool,
1415
1419
  workflowStatusTool,
1416
1420
  workflowWaitTool,
1417
1421
  workflowInspectTool,
@@ -1597,6 +1601,88 @@ function createExtension(deps = defaultDeps, options = {}) {
1597
1601
  let pollingErrorCount = 0;
1598
1602
  const pollingErrors = [];
1599
1603
  let lastStatusEntries = [];
1604
+ const pendingWaits = /* @__PURE__ */ new Set();
1605
+ function interruptPendingWaits(stop, excludeRunKey) {
1606
+ for (const wait of [...pendingWaits]) {
1607
+ if (wait.runKey === excludeRunKey) continue;
1608
+ pendingWaits.delete(wait);
1609
+ wait.interrupt(stop);
1610
+ }
1611
+ }
1612
+ function registerPendingWait(runKey, interrupt) {
1613
+ const wait = {
1614
+ runKey,
1615
+ interrupt
1616
+ };
1617
+ pendingWaits.add(wait);
1618
+ return wait;
1619
+ }
1620
+ function createInterruptibleWait(runKey, signal) {
1621
+ const controller = new AbortController();
1622
+ let stopped;
1623
+ const onSignalAbort = () => controller.abort();
1624
+ if (signal?.aborted) controller.abort();
1625
+ else signal?.addEventListener("abort", onSignalAbort);
1626
+ const pending = registerPendingWait(runKey, (stop) => {
1627
+ if (controller.signal.aborted) return;
1628
+ stopped = stop;
1629
+ controller.abort();
1630
+ });
1631
+ return {
1632
+ signal: controller.signal,
1633
+ get stopped() {
1634
+ return stopped;
1635
+ },
1636
+ dispose() {
1637
+ pendingWaits.delete(pending);
1638
+ signal?.removeEventListener("abort", onSignalAbort);
1639
+ }
1640
+ };
1641
+ }
1642
+ /** Build the early return for a wait interrupted by a sibling stopping
1643
+ * point. When the awaited run itself has since reached a stopping point
1644
+ * (possible when the caller omitted supervisor_id and the registry key
1645
+ * diverged), deliver its real state instead of an interruption notice. */
1646
+ async function resultAfterInterrupt(params, stop, tracked) {
1647
+ const runId = tracked?.runId ?? params.run_id;
1648
+ const supervisorId = tracked?.supervisorId ?? params.supervisor_id;
1649
+ let current;
1650
+ try {
1651
+ current = asStatusResult(await deps.statusTool({
1652
+ runId,
1653
+ supervisorId,
1654
+ view: "full"
1655
+ }));
1656
+ } catch {}
1657
+ if (current !== void 0 && (isTerminalStatus(current.status) || current.status === "waiting")) try {
1658
+ return {
1659
+ ...await deps.resultTool({
1660
+ runId,
1661
+ supervisorId,
1662
+ wait: true,
1663
+ timeout: params.timeout,
1664
+ signal: params.signal
1665
+ }),
1666
+ interrupted_by: {
1667
+ run_id: stop.runId,
1668
+ label: stop.label,
1669
+ status: stop.status
1670
+ }
1671
+ };
1672
+ } catch {}
1673
+ return {
1674
+ run_id: current?.run_id ?? runId,
1675
+ label: current?.label ?? runId,
1676
+ status: current?.status ?? "running",
1677
+ ready: current !== void 0 && isTerminalStatus(current.status),
1678
+ ...current?.pending_permission && { pending_permission: current.pending_permission },
1679
+ interrupted_by: {
1680
+ run_id: stop.runId,
1681
+ label: stop.label,
1682
+ status: stop.status
1683
+ }
1684
+ };
1685
+ }
1600
1686
  const subAgentEnv = options.subAgentEnv !== void 0 ? options.subAgentEnv : readSubAgentEnv();
1601
1687
  const isSubAgentBrokerMode = subAgentEnv !== null;
1602
1688
  let subAgentPollTimer = null;
@@ -1714,7 +1800,7 @@ function createExtension(deps = defaultDeps, options = {}) {
1714
1800
  const liveMap = /* @__PURE__ */ new Map();
1715
1801
  try {
1716
1802
  const allLive = await deps.statusTool({});
1717
- const liveList = Array.isArray(allLive) ? allLive : [allLive];
1803
+ const liveList = "runs" in allLive ? allLive.runs : [allLive];
1718
1804
  for (const result of liveList) liveMap.set(result.run_id, result);
1719
1805
  } catch (err) {
1720
1806
  recordPollingError("singleton-list", "failed to list singleton runs", err);
@@ -1744,11 +1830,10 @@ function createExtension(deps = defaultDeps, options = {}) {
1744
1830
  continue;
1745
1831
  }
1746
1832
  try {
1747
- const raw = await deps.statusTool({
1833
+ const result = asStatusResult(await deps.statusTool({
1748
1834
  runId: run.runId,
1749
1835
  supervisorId: run.supervisorId
1750
- });
1751
- const result = Array.isArray(raw) ? raw[0] : raw;
1836
+ }));
1752
1837
  if (!result) throw new Error("status response was empty");
1753
1838
  run.lastStatus = result;
1754
1839
  run.agent = result.agent ?? run.agent;
@@ -1831,7 +1916,10 @@ function createExtension(deps = defaultDeps, options = {}) {
1831
1916
  const tick = async () => {
1832
1917
  if (!pollingActive || generation !== pollingGeneration) return;
1833
1918
  const prevStatuses = /* @__PURE__ */ new Map();
1834
- for (const [id, run] of trackedRuns) prevStatuses.set(id, run.lastStatus?.status);
1919
+ for (const [id, run] of trackedRuns) prevStatuses.set(id, {
1920
+ status: run.lastStatus?.status,
1921
+ pendingPermission: !!run.lastStatus?.pending_permission
1922
+ });
1835
1923
  const currentPoll = pollRuns();
1836
1924
  pollInFlight = currentPoll;
1837
1925
  const entries = await currentPoll.finally(() => {
@@ -1844,13 +1932,19 @@ function createExtension(deps = defaultDeps, options = {}) {
1844
1932
  const entryKey = trackedRunKey(entry.supervisorId, entry.runId);
1845
1933
  const run = trackedRuns.get(entryKey);
1846
1934
  if (!run) continue;
1935
+ const prevStatus = prevStatuses.get(entryKey);
1936
+ const wasStopped = prevStatus?.status !== void 0 && isTerminalStatus(prevStatus.status) || !!prevStatus?.pendingPermission;
1937
+ if ((entry.pendingPermission || isTerminalStatus(entry.status)) && !wasStopped) interruptPendingWaits({
1938
+ runId: entry.runId,
1939
+ label: entry.label,
1940
+ status: isTerminalStatus(entry.status) ? entry.status : "waiting"
1941
+ }, entryKey);
1847
1942
  if (isTerminalStatus(entry.status)) {
1848
1943
  if (decideCompletion(run) === "skip") {
1849
1944
  if (run.consumed) trackedRuns.delete(entryKey);
1850
1945
  continue;
1851
1946
  }
1852
- const prevStatus = prevStatuses.get(entryKey);
1853
- if (!(prevStatus && isTerminalStatus(prevStatus))) sessionCtx?.ui.notify(`Sub-agent "${entry.label}" finished: ${entry.status}`, entry.status === "done" ? "info" : "warning");
1947
+ if (!(prevStatus?.status !== void 0 && isTerminalStatus(prevStatus.status))) sessionCtx?.ui.notify(`Sub-agent "${entry.label}" finished: ${entry.status}`, entry.status === "done" ? "info" : "warning");
1854
1948
  const finalOutput = await resolveFinalOutput(run, run.lastStatus);
1855
1949
  try {
1856
1950
  pi.sendUserMessage(buildCompletionText({
@@ -1970,11 +2064,10 @@ function createExtension(deps = defaultDeps, options = {}) {
1970
2064
  supervisorId: run.supervisorId
1971
2065
  });
1972
2066
  try {
1973
- const rawStatus = await deps.statusTool({
2067
+ const status = asStatusResult(await deps.statusTool({
1974
2068
  runId: result.run_id,
1975
2069
  supervisorId: run.supervisorId
1976
- });
1977
- const status = Array.isArray(rawStatus) ? rawStatus[0] : rawStatus;
2070
+ }));
1978
2071
  upsertTrackedRun({
1979
2072
  runId: result.run_id,
1980
2073
  label: result.label,
@@ -2052,12 +2145,11 @@ function createExtension(deps = defaultDeps, options = {}) {
2052
2145
  await observer?.close().catch(() => {});
2053
2146
  if (outcome === "aborted") return { aborted: true };
2054
2147
  try {
2055
- const raw = await deps.statusTool({
2056
- runId: run.runId,
2057
- supervisorId: run.supervisorId
2058
- });
2059
2148
  return {
2060
- status: Array.isArray(raw) ? raw[0] : raw,
2149
+ status: asStatusResult(await deps.statusTool({
2150
+ runId: run.runId,
2151
+ supervisorId: run.supervisorId
2152
+ })),
2061
2153
  aborted: false
2062
2154
  };
2063
2155
  } catch {
@@ -2070,11 +2162,10 @@ function createExtension(deps = defaultDeps, options = {}) {
2070
2162
  if (!firstPoll) await sleep(pollIntervalMs);
2071
2163
  firstPoll = false;
2072
2164
  try {
2073
- const raw = await deps.statusTool({
2165
+ const status = asStatusResult(await deps.statusTool({
2074
2166
  runId: run.runId,
2075
2167
  supervisorId: run.supervisorId
2076
- });
2077
- const status = Array.isArray(raw) ? raw[0] : raw;
2168
+ }));
2078
2169
  if (!status) continue;
2079
2170
  const text = status.pending_permission ? `[blocked] ${run.label ?? run.runId} — permission: ${status.pending_permission.description}` : `${run.label ?? run.runId}${status.phase_label ? ` (${status.phase_label})` : ""}`;
2080
2171
  onUpdate?.({
@@ -2116,6 +2207,14 @@ function createExtension(deps = defaultDeps, options = {}) {
2116
2207
  stopSubAgentPoll();
2117
2208
  hostPendingAsks.clear();
2118
2209
  subAgentPendingAsks.clear();
2210
+ for (const wait of [...pendingWaits]) {
2211
+ pendingWaits.delete(wait);
2212
+ wait.interrupt({
2213
+ runId: "",
2214
+ status: "shutdown",
2215
+ synthetic: true
2216
+ });
2217
+ }
2119
2218
  sessionCtx = null;
2120
2219
  });
2121
2220
  pi.on("before_agent_start", async () => {
@@ -2144,12 +2243,12 @@ function createExtension(deps = defaultDeps, options = {}) {
2144
2243
  pi.registerTool({
2145
2244
  name: "avenor_spawn",
2146
2245
  label: "Avenor Spawn",
2147
- description: `Dispatch an agent run via avenor. Optional thinking accepts ${[...THINKING_LEVELS].slice(0, -1).join(", ")}, or ${THINKING_LEVELS[THINKING_LEVELS.length - 1]}; unsupported backends reject explicit values. Blocks by default, showing live progress. Set wait=false for fire-and-forget.`,
2246
+ description: `Dispatch an agent run via avenor. Optional thinking accepts ${[...THINKING_LEVELS].slice(0, -1).join(", ")}, or ${THINKING_LEVELS[THINKING_LEVELS.length - 1]}; unsupported backends reject explicit values. Blocks by default, showing live progress. Set wait=false for fire-and-forget. With several blocking spawns in parallel, the first stopping point (permission or completion) interrupts the other waits.`,
2148
2247
  promptSnippet: "Dispatch sub-agent runs via avenor (spawn, status, result, inspect, events, follow-up, shutdown)",
2149
2248
  promptGuidelines: [
2150
2249
  "Use avenor_spawn to delegate well-defined tasks to sub-agents.",
2151
2250
  "Use avenor_status (view \"lifecycle\") only to check progress or pending permissions.",
2152
- "Use avenor_result to retrieve the final result of a sub-agent; it waits by default, but set wait=false for runs that already completed.",
2251
+ "Use avenor_result to retrieve the final result of a sub-agent; it waits by default, but set wait=false for runs that already completed. When awaiting multiple runs, the first stopping point (permission or completion) interrupts the other waits.",
2153
2252
  "Use avenor_inspect to review a bounded transcript and tool activity from a run.",
2154
2253
  "Use avenor_events only when you specifically need raw event payloads.",
2155
2254
  "Use avenor_follow_up to iterate on a completed run.",
@@ -2251,21 +2350,56 @@ function createExtension(deps = defaultDeps, options = {}) {
2251
2350
  run_id: result.run_id
2252
2351
  }
2253
2352
  });
2254
- const waitResult = await waitForRun(runRef, signal, onUpdate);
2353
+ const blockingWait = createInterruptibleWait(trackedRunKey(supervisorId, result.run_id), signal);
2354
+ let waitResult;
2355
+ try {
2356
+ waitResult = await waitForRun(runRef, blockingWait.signal, onUpdate);
2357
+ } finally {
2358
+ blockingWait.dispose();
2359
+ }
2360
+ let waitStatus = waitResult.status;
2255
2361
  if (waitResult.aborted) {
2256
- trackedRuns.delete(trackedRunKey(supervisorId, result.run_id));
2257
- return {
2258
- content: [{
2259
- type: "text",
2260
- text: `Monitoring of "${label}" (run_id: ${result.run_id}) was interrupted. Use avenor_status or avenor_inspect to check.`
2261
- }],
2262
- details: {
2263
- run_id: result.run_id,
2264
- ...spawnIdentityMetadata(hostParams)
2362
+ const stop = blockingWait.stopped;
2363
+ if (stop && !stop.synthetic) {
2364
+ const probed = asStatusResult(await deps.statusTool({
2365
+ runId: result.run_id,
2366
+ supervisorId
2367
+ }).catch(() => void 0));
2368
+ if (probed && (isTerminalStatus(probed.status) || probed.status === "waiting")) waitStatus = probed;
2369
+ else {
2370
+ const tracked = getTrackedRun(result.run_id, supervisorId);
2371
+ if (tracked) tracked.blocking = false;
2372
+ return {
2373
+ content: [{
2374
+ type: "text",
2375
+ text: `Monitoring of "${label}" (run_id: ${result.run_id}) was interrupted: "${stop.label ?? stop.runId}" reached ${stop.status === "waiting" ? "a permission request" : stop.status}. Handle that first; this run's final result is delivered automatically.`
2376
+ }],
2377
+ details: {
2378
+ run_id: result.run_id,
2379
+ interrupted_by: {
2380
+ run_id: stop.runId,
2381
+ label: stop.label,
2382
+ status: stop.status
2383
+ },
2384
+ ...spawnIdentityMetadata(hostParams)
2385
+ }
2386
+ };
2265
2387
  }
2266
- };
2388
+ } else {
2389
+ trackedRuns.delete(trackedRunKey(supervisorId, result.run_id));
2390
+ return {
2391
+ content: [{
2392
+ type: "text",
2393
+ text: `Monitoring of "${label}" (run_id: ${result.run_id}) was interrupted. Use avenor_status or avenor_inspect to check.`
2394
+ }],
2395
+ details: {
2396
+ run_id: result.run_id,
2397
+ ...spawnIdentityMetadata(hostParams)
2398
+ }
2399
+ };
2400
+ }
2267
2401
  }
2268
- const status = waitResult.status;
2402
+ const status = waitStatus;
2269
2403
  if (!status) return {
2270
2404
  content: [{
2271
2405
  type: "text",
@@ -2404,7 +2538,7 @@ function createExtension(deps = defaultDeps, options = {}) {
2404
2538
  pi.registerTool({
2405
2539
  name: "avenor_result",
2406
2540
  label: "Avenor Result",
2407
- description: "Retrieve the complete final output of a run without transcript or event details. Waits by default; set wait=false to retrieve an already-completed run without blocking.",
2541
+ description: `Retrieve the complete final output of a run without transcript or event details. Waits by default; set wait=false to retrieve an already-completed run without blocking. When several runs are pending, the first stopping point (a permission request or completion on any run) interrupts other blocking waits so they can be handled; re-issue the interrupted wait afterwards.`,
2408
2542
  parameters: Type.Object({
2409
2543
  run_id: Type.String({ description: "Run ID or label" }),
2410
2544
  wait: Type.Optional(Type.Boolean({ description: "Wait for a terminal result (default true); false retrieves the current state without blocking" })),
@@ -2416,14 +2550,21 @@ function createExtension(deps = defaultDeps, options = {}) {
2416
2550
  const previousBlocking = tracked?.blocking;
2417
2551
  if (tracked) tracked.blocking = true;
2418
2552
  let completed = false;
2553
+ const blockingWait = params.wait ?? true ? createInterruptibleWait(trackedRunKey(tracked?.supervisorId ?? params.supervisor_id, tracked?.runId ?? params.run_id), signal) : void 0;
2419
2554
  try {
2420
- const result = await deps.resultTool({
2421
- runId: params.run_id,
2422
- supervisorId: params.supervisor_id,
2423
- wait: params.wait,
2424
- timeout: params.timeout,
2425
- signal
2426
- });
2555
+ let result;
2556
+ try {
2557
+ result = await deps.resultTool({
2558
+ runId: params.run_id,
2559
+ supervisorId: params.supervisor_id,
2560
+ wait: params.wait,
2561
+ timeout: params.timeout,
2562
+ signal: blockingWait?.signal ?? signal
2563
+ });
2564
+ } catch (err) {
2565
+ if (!blockingWait?.stopped || blockingWait.stopped.synthetic) throw err;
2566
+ result = await resultAfterInterrupt(params, blockingWait.stopped, tracked);
2567
+ }
2427
2568
  completed = result.ready;
2428
2569
  if (completed) {
2429
2570
  if (tracked) tracked.consumed = true;
@@ -2445,6 +2586,7 @@ function createExtension(deps = defaultDeps, options = {}) {
2445
2586
  details: result
2446
2587
  };
2447
2588
  } finally {
2589
+ blockingWait?.dispose();
2448
2590
  if (!completed && tracked && getTrackedRun(params.run_id, params.supervisor_id) === tracked) tracked.blocking = previousBlocking ?? false;
2449
2591
  }
2450
2592
  },
@@ -2548,11 +2690,10 @@ function createExtension(deps = defaultDeps, options = {}) {
2548
2690
  supervisorId: params.supervisor_id
2549
2691
  });
2550
2692
  try {
2551
- const rawStatus = await deps.statusTool({
2693
+ const status = asStatusResult(await deps.statusTool({
2552
2694
  runId: result.run_id,
2553
2695
  supervisorId: params.supervisor_id
2554
- });
2555
- const status = Array.isArray(rawStatus) ? rawStatus[0] : rawStatus;
2696
+ }));
2556
2697
  upsertTrackedRun({
2557
2698
  runId: result.run_id,
2558
2699
  label: result.label,
@@ -2589,16 +2730,18 @@ function createExtension(deps = defaultDeps, options = {}) {
2589
2730
  pi.registerTool({
2590
2731
  name: "avenor_ask",
2591
2732
  label: "Avenor Ask",
2592
- description: "Ask another agent run a question and block until it replies.",
2733
+ description: "Ask another agent run a question and block until it replies. An optional timeout_ms bounds the wait; a failed ask reports its message_id and whether it is still pending (withdrawable via avenor_cancel) or already withdrawn.",
2593
2734
  parameters: Type.Object({
2594
2735
  to_run_id: Type.String({ description: "Target run ID" }),
2595
2736
  message: Type.String({ description: "Question to ask the other agent" }),
2737
+ timeout_ms: Type.Optional(Type.Integer({ description: "Optional timeout in milliseconds for the ask" })),
2596
2738
  supervisor_id: Type.Optional(Type.String({ description: "Reuse an existing supervisor by socket path" }))
2597
2739
  }),
2598
2740
  async execute(_toolCallId, params) {
2599
2741
  return askTool({
2600
2742
  toRunId: params.to_run_id,
2601
2743
  message: params.message,
2744
+ timeoutMs: params.timeout_ms,
2602
2745
  supervisorId: params.supervisor_id
2603
2746
  });
2604
2747
  }
@@ -2789,6 +2932,31 @@ function createExtension(deps = defaultDeps, options = {}) {
2789
2932
  }, theme, context.args);
2790
2933
  }
2791
2934
  });
2935
+ pi.registerTool({
2936
+ name: "avenor_kill",
2937
+ label: "Avenor Kill",
2938
+ description: "Terminate a run without shutting down the supervisor. Other runs and the supervisor itself keep running.",
2939
+ parameters: Type.Object({
2940
+ run_id: Type.String({
2941
+ minLength: 1,
2942
+ description: "Run ID or label to terminate"
2943
+ }),
2944
+ supervisor_id: Type.Optional(Type.String({ description: "Reuse an existing supervisor by socket path" }))
2945
+ }),
2946
+ async execute(_toolCallId, params) {
2947
+ const result = await deps.killTool({
2948
+ runId: params.run_id,
2949
+ supervisorId: params.supervisor_id
2950
+ });
2951
+ return {
2952
+ content: [{
2953
+ type: "text",
2954
+ text: JSON.stringify(result, null, 2)
2955
+ }],
2956
+ details: result
2957
+ };
2958
+ }
2959
+ });
2792
2960
  pi.registerTool({
2793
2961
  name: "avenor_workflow_status",
2794
2962
  label: "Avenor Workflow Status",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dougbots/avenor-pi",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -35,7 +35,7 @@
35
35
  "dev": "tsdown --watch"
36
36
  },
37
37
  "dependencies": {
38
- "@dougbots/avenor-core": "^0.12.0"
38
+ "@dougbots/avenor-core": "^0.13.0"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@earendil-works/pi-coding-agent": ">=0.74.0",