@dougbots/avenor-pi 0.17.0 → 0.18.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, MessageProvider, StatusResult, Supervisor, answerPermissionTool, attachOwner, brokerReceiveTool, dial, eventsTool, getSupervisorClient, inspectTool, killTool, messageTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, workflowCancelTool, workflowCompleteTool, workflowControllerStatusTool, workflowEventsTool, workflowGateTool, workflowInspectTool, workflowReadyTool, workflowStatusTool, workflowWaitTool } from "@dougbots/avenor-core";
1
+ import { InspectResult, MessageProvider, RunObserver, StatusResult, Supervisor, answerPermissionTool, attachOwner, brokerReceiveTool, dial, eventsTool, getSupervisorClient, inspectTool, killTool, messageTool, observeRun, resultTool, shutdownTool, spawnTool, statusTool, workflowCancelTool, 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
@@ -173,7 +173,9 @@ interface ExtensionDeps {
173
173
  hostProviderFor?: (supervisorId: string | undefined) => Promise<MessageProvider>;
174
174
  /** Dial a supervisor for the default host provider; tests inject a fake client. */
175
175
  getSupervisorClient?: typeof getSupervisorClient;
176
- observeRun: typeof observeRun;
176
+ /** A watch transport may decline to observe (no runtime id yet), so a test
177
+ * double that only asserts the call can answer null. */
178
+ observeRun: (client: Parameters<typeof observeRun>[0], options?: Parameters<typeof observeRun>[1]) => RunObserver | null;
177
179
  dial: typeof dial;
178
180
  attachOwner: typeof attachOwner;
179
181
  Supervisor: typeof Supervisor;
package/dist/index.js CHANGED
@@ -1987,6 +1987,18 @@ function spawnIdentityMetadata(params, status) {
1987
1987
  function sleep(ms) {
1988
1988
  return new Promise((resolve) => setTimeout(resolve, ms));
1989
1989
  }
1990
+ /** The text of a tool result's first text part; image parts carry none. */
1991
+ function firstTextPart(content) {
1992
+ return content?.find((part) => part.type === "text")?.text ?? "";
1993
+ }
1994
+ /** The status a tool result records; a stored transcript record may carry no details. */
1995
+ function resultStatus(details) {
1996
+ return details && typeof details === "object" && "status" in details ? String(details.status ?? "") : "";
1997
+ }
1998
+ /** Close an observer a concurrent watch assigned, ignoring a close failure. */
1999
+ async function closeObserverQuietly(observer) {
2000
+ await observer?.close().catch(() => {});
2001
+ }
1990
2002
  function normalizeMultilinePreview(text, limit = COMPLETION_OUTPUT_CHARS) {
1991
2003
  if (!text) return void 0;
1992
2004
  const clean = sanitizeText(text).trim();
@@ -2270,7 +2282,7 @@ function createExtension(deps = defaultDeps, options = {}) {
2270
2282
  refusedSessionName = null;
2271
2283
  } catch (error) {
2272
2284
  if (error instanceof BrokerHttpError && error.status === 400 && error.code === "invalid-name") {
2273
- refusedSessionName = name;
2285
+ refusedSessionName = name ?? null;
2274
2286
  console.error("[avenor] session_name_set refused:", error.message);
2275
2287
  return;
2276
2288
  }
@@ -2911,7 +2923,7 @@ function createExtension(deps = defaultDeps, options = {}) {
2911
2923
  const outcome = abortPromise ? await Promise.race([waitPromise, abortPromise]) : await waitPromise;
2912
2924
  if (signal && abortListener) signal.removeEventListener("abort", abortListener);
2913
2925
  unsubscribe?.();
2914
- await observer?.close().catch(() => {});
2926
+ await closeObserverQuietly(observer);
2915
2927
  if (outcome === "aborted") return { aborted: true };
2916
2928
  try {
2917
2929
  return {
@@ -3221,10 +3233,13 @@ function createExtension(deps = defaultDeps, options = {}) {
3221
3233
  wait: Type.Optional(Type.Boolean({ description: "Block until complete (default true)" }))
3222
3234
  }),
3223
3235
  async execute(_toolCallId, params, signal, onUpdate, ctx) {
3224
- if (signal?.aborted) return { content: [{
3225
- type: "text",
3226
- text: "Cancelled"
3227
- }] };
3236
+ if (signal?.aborted) return {
3237
+ content: [{
3238
+ type: "text",
3239
+ text: "Cancelled"
3240
+ }],
3241
+ details: {}
3242
+ };
3228
3243
  validateSpawnSelection({
3229
3244
  agent: params.agent,
3230
3245
  model: params.model,
@@ -3303,10 +3318,11 @@ function createExtension(deps = defaultDeps, options = {}) {
3303
3318
  if (waitResult.aborted) {
3304
3319
  const stop = blockingWait.stopped;
3305
3320
  if (stop && !stop.synthetic) {
3306
- const probed = asStatusResult(await deps.statusTool({
3321
+ const raw = await deps.statusTool({
3307
3322
  runId: result.run_id,
3308
3323
  supervisorId
3309
- }).catch(() => void 0));
3324
+ }).catch(() => void 0);
3325
+ const probed = raw ? asStatusResult(raw) : void 0;
3310
3326
  if (probed && (isTerminalStatus(probed.status) || probed.status === "waiting")) waitStatus = probed;
3311
3327
  else {
3312
3328
  const tracked = getTrackedRunById(result.run_id, supervisorId);
@@ -3390,7 +3406,7 @@ function createExtension(deps = defaultDeps, options = {}) {
3390
3406
  run: tracked,
3391
3407
  runtimeId: status.runtime_id ?? runRef.runtimeId,
3392
3408
  label,
3393
- agent: params.agent,
3409
+ agent: tracked?.agent ?? params.agent ?? "unknown",
3394
3410
  status: status.status,
3395
3411
  nestedCount: tracked?.nestedCount,
3396
3412
  backend: status.backend
@@ -3436,17 +3452,11 @@ function createExtension(deps = defaultDeps, options = {}) {
3436
3452
  return new Text(agent + agentName + label + wait, 0, 0);
3437
3453
  },
3438
3454
  renderResult(result, { isPartial }, theme) {
3439
- if (isPartial) {
3440
- const status = result.details?.status ?? "running";
3441
- const emoji = statusEmoji(String(status));
3442
- return new Text(theme.fg("accent", `${emoji} ${result.content?.[0]?.text ?? "Running…"}`), 0, 0);
3443
- }
3444
- const status = String(result.details?.status ?? "");
3445
- if (status && isTerminalStatus(status)) {
3446
- const emoji = statusEmoji(status);
3447
- return new Text(`${theme.fg(status === "done" ? "success" : "error", `${emoji} ${status}`)}\n${(result.content?.[0]?.text ?? "").split("\n").map((line) => theme.fg("muted", ` ${line}`)).join("\n")}`, 0, 0);
3448
- }
3449
- return new Text((result.content?.[0]?.text ?? "").split("\n").map((line) => theme.fg("muted", line)).join("\n"), 0, 0);
3455
+ const status = resultStatus(result.details);
3456
+ const text = firstTextPart(result.content);
3457
+ if (isPartial) return new Text(theme.fg("accent", `${statusEmoji(status || "running")} ${text || "Running…"}`), 0, 0);
3458
+ if (status && isTerminalStatus(status)) return new Text(`${theme.fg(status === "done" ? "success" : "error", `${statusEmoji(status)} ${status}`)}\n${text.split("\n").map((line) => theme.fg("muted", ` ${line}`)).join("\n")}`, 0, 0);
3459
+ return new Text(text.split("\n").map((line) => theme.fg("muted", line)).join("\n"), 0, 0);
3450
3460
  }
3451
3461
  });
3452
3462
  pi.registerTool({
@@ -3639,7 +3649,7 @@ function createExtension(deps = defaultDeps, options = {}) {
3639
3649
  pi.registerTool({
3640
3650
  name: "avenor_message",
3641
3651
  label: "Avenor Message",
3642
- description: "Send a message to another agent run, answer an inbound ask, withdraw a pending ask, or resume a completed run. Every action is explicit and the result states whether a failed ask can still be withdrawn. `control_reply` is available only on the claude-channel surface.",
3652
+ description: "Send a message to another agent run, answer an inbound ask, withdraw a pending ask, or resume a completed run. Every action is explicit and the result states whether a failed ask can still be withdrawn. `control_reply` is retained in the contract but no surface can deliver one.",
3643
3653
  parameters: Type.Object({
3644
3654
  action: Type.Union([
3645
3655
  Type.Literal("tell"),
@@ -3719,7 +3729,7 @@ function createExtension(deps = defaultDeps, options = {}) {
3719
3729
  workflow_id: params.workflow_id,
3720
3730
  actor: params.actor,
3721
3731
  reason: params.reason,
3722
- supervisor_id: params.supervisor_id
3732
+ supervisorId: params.supervisor_id
3723
3733
  });
3724
3734
  return {
3725
3735
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dougbots/avenor-pi",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -31,11 +31,12 @@
31
31
  },
32
32
  "scripts": {
33
33
  "build": "tsdown",
34
+ "typecheck": "tsc --noEmit",
34
35
  "test": "bun test",
35
36
  "dev": "tsdown --watch"
36
37
  },
37
38
  "dependencies": {
38
- "@dougbots/avenor-core": "^0.17.0"
39
+ "@dougbots/avenor-core": "^0.18.0"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "@earendil-works/pi-coding-agent": ">=1.4.0",