@bytetrue/byspace 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.
Files changed (54) hide show
  1. package/node_modules/@bytetrue/client/package.json +3 -3
  2. package/node_modules/@bytetrue/highlight/package.json +1 -1
  3. package/node_modules/@bytetrue/protocol/package.json +1 -1
  4. package/node_modules/@bytetrue/relay/package.json +1 -1
  5. package/node_modules/@bytetrue/server/dist/server/server/agent/agent-manager.d.ts +30 -0
  6. package/node_modules/@bytetrue/server/dist/server/server/agent/agent-manager.js +118 -8
  7. package/node_modules/@bytetrue/server/dist/server/server/agent/mcp-shared.d.ts +1 -1
  8. package/node_modules/@bytetrue/server/dist/server/server/agent/{providers/claude/subagents → provider-subagents}/observation.d.ts +2 -2
  9. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/claude/agent.js +1 -1
  10. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +1 -1
  11. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +1 -1
  12. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/claude/subagents/workflow-replay-source.d.ts +1 -1
  13. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/omp/rpc-types.d.ts +6 -6
  14. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/agent-subagents.d.ts +45 -0
  15. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/agent-subagents.js +159 -0
  16. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/agent.d.ts +2 -2
  17. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/agent.js +86 -151
  18. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/runtime.d.ts +0 -2
  19. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/runtime.js +0 -4
  20. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/session-descriptor.d.ts +2 -0
  21. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/session-descriptor.js +2 -2
  22. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/subagent-session-tailer.d.ts +47 -0
  23. package/node_modules/@bytetrue/server/dist/server/server/agent/providers/pi/subagent-session-tailer.js +212 -0
  24. package/node_modules/@bytetrue/server/dist/server/server/bootstrap.d.ts +6 -0
  25. package/node_modules/@bytetrue/server/dist/server/server/bootstrap.js +49 -0
  26. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{index-8d553cf4f8b1937dcd7c1da125243e39.js → index-5762beef0f3c7a285c88f6cb383d0f16.js} +485 -484
  27. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-5762beef0f3c7a285c88f6cb383d0f16.js.br +0 -0
  28. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-5762beef0f3c7a285c88f6cb383d0f16.js.gz +0 -0
  29. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-9f3696181e42915ed4f9cb01f7595007.js → indexeddb-attachment-store-433f8ff1c621845eba95cc633f47b72d.js} +1 -1
  30. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-433f8ff1c621845eba95cc633f47b72d.js.br +0 -0
  31. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-433f8ff1c621845eba95cc633f47b72d.js.gz +0 -0
  32. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-f829a425d0a064f4a9b4b153d185a3fb.js → native-file-attachment-store-6ed537a199e954caec287e6d28945868.js} +3 -3
  33. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-6ed537a199e954caec287e6d28945868.js.br +0 -0
  34. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-6ed537a199e954caec287e6d28945868.js.gz +0 -0
  35. package/node_modules/@bytetrue/server/dist/server/web-ui/index.html +1 -1
  36. package/node_modules/@bytetrue/server/dist/server/web-ui/index.html.br +0 -0
  37. package/node_modules/@bytetrue/server/dist/server/web-ui/index.html.gz +0 -0
  38. package/node_modules/@bytetrue/server/dist/src/server/agent/agent-manager.js +118 -8
  39. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/claude/agent.js +1 -1
  40. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/pi/agent-subagents.js +159 -0
  41. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/pi/agent.js +86 -151
  42. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/pi/runtime.js +0 -4
  43. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/pi/session-descriptor.js +2 -2
  44. package/node_modules/@bytetrue/server/dist/src/server/agent/providers/pi/subagent-session-tailer.js +212 -0
  45. package/node_modules/@bytetrue/server/package.json +5 -5
  46. package/package.json +7 -7
  47. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-8d553cf4f8b1937dcd7c1da125243e39.js.br +0 -0
  48. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/index-8d553cf4f8b1937dcd7c1da125243e39.js.gz +0 -0
  49. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-9f3696181e42915ed4f9cb01f7595007.js.br +0 -0
  50. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-9f3696181e42915ed4f9cb01f7595007.js.gz +0 -0
  51. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-f829a425d0a064f4a9b4b153d185a3fb.js.br +0 -0
  52. package/node_modules/@bytetrue/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-f829a425d0a064f4a9b4b153d185a3fb.js.gz +0 -0
  53. /package/node_modules/@bytetrue/server/dist/server/server/agent/{providers/claude/subagents → provider-subagents}/observation.js +0 -0
  54. /package/node_modules/@bytetrue/server/dist/src/server/agent/{providers/claude/subagents → provider-subagents}/observation.js +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytetrue/client",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "BySpace client SDK package",
5
5
  "files": [
6
6
  "dist",
@@ -39,8 +39,8 @@
39
39
  "test": "vitest run"
40
40
  },
41
41
  "dependencies": {
42
- "@bytetrue/protocol": "0.17.0",
43
- "@bytetrue/relay": "0.17.0"
42
+ "@bytetrue/protocol": "0.18.0",
43
+ "@bytetrue/relay": "0.18.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^20.9.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytetrue/highlight",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.map",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytetrue/protocol",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "BySpace shared protocol schemas and wire types",
5
5
  "files": [
6
6
  "dist",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytetrue/relay",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "BySpace relay for bridging daemon and client connections",
5
5
  "files": [
6
6
  "dist",
@@ -11,6 +11,7 @@ import { type ForegroundTurnWaiter } from "./agent-run-state.js";
11
11
  import { type RewindMode } from "./rewind/rewind.js";
12
12
  import type { BySpaceToolCatalogFactory } from "./tools/types.js";
13
13
  import { type ProviderSubagentDescriptor, type ProviderSubagentStoreEvent } from "./provider-subagents/store.js";
14
+ import { type SubagentObservation } from "./provider-subagents/observation.js";
14
15
  export declare class AgentManagerShuttingDownError extends Error {
15
16
  constructor();
16
17
  }
@@ -244,6 +245,9 @@ export declare class AgentManager {
244
245
  private readonly agents;
245
246
  private readonly timelineStore;
246
247
  private readonly providerSubagents;
248
+ private readonly piSubagentReportTokens;
249
+ private piSubagentReportBaseUrl;
250
+ private readonly piSubagentTailers;
247
251
  private readonly agentsAwaitingInitialSnapshotPersist;
248
252
  private readonly sessionEventTails;
249
253
  private readonly steerEventBarriers;
@@ -287,6 +291,32 @@ export declare class AgentManager {
287
291
  setAgentAttentionCallback(callback: AgentAttentionCallback): void;
288
292
  setAgentArchivedCallback(callback: AgentArchivedCallback): void;
289
293
  setMcpBaseUrl(url: string | null): void;
294
+ setPiSubagentReportBaseUrl(url: string | null): void;
295
+ /**
296
+ * Resolve the agent a pi-subagent report token was minted for. Tokens are random
297
+ * per pi launch, so the token alone identifies the agent — the reporter extension
298
+ * never needs to know its own BySpace agent id.
299
+ */
300
+ resolvePiSubagentReportAgentId(token: string): string | null;
301
+ /**
302
+ * Apply a provider-subagent store event with the terminal latch: a running upsert for an
303
+ * already-terminal subagent is dropped. HTTP reports and transcript replays have no ordering
304
+ * guarantee, so a stale running snapshot must not reopen a finished subagent. New launches
305
+ * get fresh ids and are unaffected.
306
+ */
307
+ private applyProviderSubagentEvent;
308
+ /**
309
+ * Apply a provider-subagent observation reported from outside the agent stream (the pi
310
+ * subagent extension POSTs progress snapshots over loopback) and dispatch the resulting
311
+ * store event.
312
+ */
313
+ applyExternalProviderSubagentObservation(agentId: string, provider: AgentProvider, observation: SubagentObservation): boolean;
314
+ /**
315
+ * Apply a pi-subagent progress report POSTed by the pi-subagent extension over loopback:
316
+ * verify the per-launch token, fold each record into a provider-subagent observation, and
317
+ * feed session references to the jsonl tailers that stream child-session timelines.
318
+ */
319
+ applyPiSubagentReport(token: string, records: readonly unknown[]): "ok" | "unauthorized";
290
320
  prepareForShutdown(): void;
291
321
  setBySpaceToolsEnabled(enabled: boolean): void;
292
322
  setBySpaceToolCatalogFactory(factory: BySpaceToolCatalogFactory | null): void;
@@ -1,4 +1,4 @@
1
- import { randomUUID } from "node:crypto";
1
+ import { randomBytes, randomUUID } from "node:crypto";
2
2
  import { basename, resolve } from "node:path";
3
3
  import { stat } from "node:fs/promises";
4
4
  import { AGENT_LIFECYCLE_STATUSES, } from "@bytetrue/protocol/agent-lifecycle";
@@ -17,6 +17,9 @@ import { stripInternalBySpaceMcpServer, withRuntimeBySpaceMcpServer, } from "./r
17
17
  import { resolveCreateAgentTitles } from "./create-agent-title.js";
18
18
  import { isBySpaceToolPolicyEnabled } from "./byspace-tool-policy.js";
19
19
  import { ProviderSubagentStore, } from "./provider-subagents/store.js";
20
+ import { foldSubagentObservations, } from "./provider-subagents/observation.js";
21
+ import { observePiSubagentRecord } from "./providers/pi/agent-subagents.js";
22
+ import { PI_SUBAGENT_TERMINAL_STATUSES, parsePiSubagentTailerSnapshot, PiSubagentSessionTailers, } from "./providers/pi/subagent-session-tailer.js";
20
23
  import { withTimeout } from "../../utils/promise-timeout.js";
21
24
  const RELOAD_SESSION_CLOSE_TIMEOUT_MS = 3000;
22
25
  const INTERRUPT_SESSION_TIMEOUT_MS = 2000;
@@ -263,6 +266,13 @@ export class AgentManager {
263
266
  this.agents = new Map();
264
267
  this.timelineStore = new InMemoryAgentTimelineStore();
265
268
  this.providerSubagents = new ProviderSubagentStore();
269
+ this.piSubagentReportTokens = new Map();
270
+ this.piSubagentReportBaseUrl = null;
271
+ this.piSubagentTailers = new PiSubagentSessionTailers({
272
+ emit: (agentId, observation) => {
273
+ this.applyExternalProviderSubagentObservation(agentId, "pi", observation);
274
+ },
275
+ });
266
276
  this.agentsAwaitingInitialSnapshotPersist = new Set();
267
277
  this.sessionEventTails = new Map();
268
278
  this.steerEventBarriers = new Map();
@@ -353,8 +363,87 @@ export class AgentManager {
353
363
  setMcpBaseUrl(url) {
354
364
  this.mcpBaseUrl = url;
355
365
  }
366
+ setPiSubagentReportBaseUrl(url) {
367
+ this.piSubagentReportBaseUrl = url;
368
+ if (!url) {
369
+ this.piSubagentReportTokens.clear();
370
+ }
371
+ }
372
+ /**
373
+ * Resolve the agent a pi-subagent report token was minted for. Tokens are random
374
+ * per pi launch, so the token alone identifies the agent — the reporter extension
375
+ * never needs to know its own BySpace agent id.
376
+ */
377
+ resolvePiSubagentReportAgentId(token) {
378
+ if (!token)
379
+ return null;
380
+ for (const [agentId, minted] of this.piSubagentReportTokens) {
381
+ if (minted === token && this.agents.has(agentId))
382
+ return agentId;
383
+ }
384
+ return null;
385
+ }
386
+ /**
387
+ * Apply a provider-subagent store event with the terminal latch: a running upsert for an
388
+ * already-terminal subagent is dropped. HTTP reports and transcript replays have no ordering
389
+ * guarantee, so a stale running snapshot must not reopen a finished subagent. New launches
390
+ * get fresh ids and are unaffected.
391
+ */
392
+ applyProviderSubagentEvent(agentId, provider, event) {
393
+ if (event.type === "upsert" && event.status === "running") {
394
+ const current = this.providerSubagents.get(agentId, event.id)?.status;
395
+ if (current && PI_SUBAGENT_TERMINAL_STATUSES.includes(current)) {
396
+ return null;
397
+ }
398
+ }
399
+ return this.providerSubagents.apply(agentId, provider, event);
400
+ }
401
+ /**
402
+ * Apply a provider-subagent observation reported from outside the agent stream (the pi
403
+ * subagent extension POSTs progress snapshots over loopback) and dispatch the resulting
404
+ * store event.
405
+ */
406
+ applyExternalProviderSubagentObservation(agentId, provider, observation) {
407
+ const agent = this.agents.get(agentId);
408
+ if (!agent) {
409
+ return false;
410
+ }
411
+ const [event] = foldSubagentObservations([observation]);
412
+ if (!event) {
413
+ return false;
414
+ }
415
+ const update = this.applyProviderSubagentEvent(agentId, provider, event);
416
+ if (!update) {
417
+ return false;
418
+ }
419
+ this.dispatch({ type: "provider_subagent", event: update });
420
+ return true;
421
+ }
422
+ /**
423
+ * Apply a pi-subagent progress report POSTed by the pi-subagent extension over loopback:
424
+ * verify the per-launch token, fold each record into a provider-subagent observation, and
425
+ * feed session references to the jsonl tailers that stream child-session timelines.
426
+ */
427
+ applyPiSubagentReport(token, records) {
428
+ const agentId = this.resolvePiSubagentReportAgentId(token);
429
+ if (!agentId) {
430
+ return "unauthorized";
431
+ }
432
+ for (const record of records) {
433
+ const observation = observePiSubagentRecord(record);
434
+ if (observation) {
435
+ this.applyExternalProviderSubagentObservation(agentId, "pi", observation);
436
+ }
437
+ const snapshot = parsePiSubagentTailerSnapshot(record);
438
+ if (snapshot) {
439
+ this.piSubagentTailers.update(agentId, snapshot);
440
+ }
441
+ }
442
+ return "ok";
443
+ }
356
444
  prepareForShutdown() {
357
445
  this.acceptingAgentRegistrations = false;
446
+ this.piSubagentTailers.dispose();
358
447
  }
359
448
  setBySpaceToolsEnabled(enabled) {
360
449
  this.byspaceToolsEnabled = enabled;
@@ -778,8 +867,10 @@ export class AgentManager {
778
867
  publishWhenReady: true,
779
868
  });
780
869
  for (const event of imported.providerSubagentEvents ?? []) {
781
- const update = this.providerSubagents.apply(agent.id, event.provider, event.event);
782
- this.dispatch({ type: "provider_subagent", event: update });
870
+ const update = this.applyProviderSubagentEvent(agent.id, event.provider, event.event);
871
+ if (update) {
872
+ this.dispatch({ type: "provider_subagent", event: update });
873
+ }
783
874
  }
784
875
  return agent;
785
876
  }
@@ -2511,6 +2602,10 @@ export class AgentManager {
2511
2602
  this.agentStreamCoalescer.flushAndDiscard(agent.id);
2512
2603
  this.agents.delete(agent.id);
2513
2604
  this.previousStatuses.delete(agent.id);
2605
+ // Child-session tailers and report tokens are live-process state: on close (and reload,
2606
+ // whose new process re-reports) they have no owner and would poll until daemon shutdown.
2607
+ this.piSubagentReportTokens.delete(agent.id);
2608
+ this.piSubagentTailers.removeAgent(agent.id);
2514
2609
  if (agent.unsubscribeSession) {
2515
2610
  agent.unsubscribeSession();
2516
2611
  agent.unsubscribeSession = null;
@@ -2541,6 +2636,8 @@ export class AgentManager {
2541
2636
  discardRetainedAgentState(agentId) {
2542
2637
  this.timelineStore.delete(agentId);
2543
2638
  this.byspaceToolPolicies.delete(agentId);
2639
+ this.piSubagentReportTokens.delete(agentId);
2640
+ this.piSubagentTailers.removeAgent(agentId);
2544
2641
  for (const event of this.providerSubagents.deleteParent(agentId)) {
2545
2642
  this.dispatch({ type: "provider_subagent", event });
2546
2643
  }
@@ -2627,8 +2724,10 @@ export class AgentManager {
2627
2724
  }
2628
2725
  async dispatchSessionEvent(agent, event) {
2629
2726
  if (event.type === "provider_subagent") {
2630
- const update = this.providerSubagents.apply(agent.id, event.provider, event.event);
2631
- this.dispatch({ type: "provider_subagent", event: update });
2727
+ const update = this.applyProviderSubagentEvent(agent.id, event.provider, event.event);
2728
+ if (update) {
2729
+ this.dispatch({ type: "provider_subagent", event: update });
2730
+ }
2632
2731
  return;
2633
2732
  }
2634
2733
  const turnId = getAgentStreamEventTurnId(event);
@@ -2766,8 +2865,8 @@ export class AgentManager {
2766
2865
  }
2767
2866
  }
2768
2867
  for (const event of providerSubagentEvents) {
2769
- const update = this.providerSubagents.apply(agent.id, event.provider, event.event);
2770
- if (broadcast) {
2868
+ const update = this.applyProviderSubagentEvent(agent.id, event.provider, event.event);
2869
+ if (update && broadcast) {
2771
2870
  this.dispatch({ type: "provider_subagent", event: update });
2772
2871
  }
2773
2872
  }
@@ -2793,7 +2892,9 @@ export class AgentManager {
2793
2892
  for await (const rawEvent of agent.session.streamHistory()) {
2794
2893
  const event = limitAgentStreamEventContent(rawEvent);
2795
2894
  if (event.type === "provider_subagent") {
2796
- const update = this.providerSubagents.apply(agent.id, event.provider, event.event);
2895
+ const update = this.applyProviderSubagentEvent(agent.id, event.provider, event.event);
2896
+ if (!update)
2897
+ continue;
2797
2898
  const managerEvent = { type: "provider_subagent", event: update };
2798
2899
  if (deferredBroadcast) {
2799
2900
  providerSubagentEvents.push(managerEvent);
@@ -3625,6 +3726,15 @@ export class AgentManager {
3625
3726
  BYSPACE_AGENT_CWD: cwd,
3626
3727
  },
3627
3728
  };
3729
+ if (client.provider === "pi" && this.piSubagentReportBaseUrl) {
3730
+ const reportToken = randomBytes(32).toString("base64url");
3731
+ this.piSubagentReportTokens.set(agentId, reportToken);
3732
+ context.env = {
3733
+ ...context.env,
3734
+ BYSPACE_SUBAGENT_REPORT_URL: `${this.piSubagentReportBaseUrl}/api/subagent-report`,
3735
+ BYSPACE_SUBAGENT_REPORT_TOKEN: reportToken,
3736
+ };
3737
+ }
3628
3738
  if (this.byspaceToolsEnabled &&
3629
3739
  isBySpaceToolPolicyEnabled(byspaceToolPolicy) &&
3630
3740
  client.capabilities.supportsNativeBySpaceTools &&
@@ -164,7 +164,7 @@ export declare function toScheduleSummary(schedule: z.infer<typeof StoredSchedul
164
164
  mcpServers?: Record<string, unknown> | undefined;
165
165
  };
166
166
  };
167
- status: "completed" | "active" | "paused";
167
+ status: "completed" | "paused" | "active";
168
168
  createdAt: string;
169
169
  updatedAt: string;
170
170
  nextRunAt: string | null;
@@ -1,5 +1,5 @@
1
- import type { AgentTimelineItem } from "../../../agent-sdk-types.js";
2
- import type { ProviderSubagentInputEvent, ProviderSubagentStatus } from "../../../provider-subagents/store.js";
1
+ import type { AgentTimelineItem } from "../agent-sdk-types.js";
2
+ import type { ProviderSubagentInputEvent, ProviderSubagentStatus } from "./store.js";
3
3
  /**
4
4
  * A single fact a provider observed about one subagent.
5
5
  *
@@ -12,7 +12,7 @@ import { ClaudeSidechainTracker } from "./sidechain-tracker.js";
12
12
  import { ClaudeTaskState } from "./task-state.js";
13
13
  import { ClaudeTaskProtocolSource, } from "./subagents/live-source.js";
14
14
  import { observeReplaySubagents, parseClaudeSubagentMeta, } from "./subagents/replay-source.js";
15
- import { foldSubagentObservations } from "./subagents/observation.js";
15
+ import { foldSubagentObservations, } from "../../provider-subagents/observation.js";
16
16
  import { observeReplayWorkflows, parseClaudeWorkflowRun, } from "./subagents/workflow-replay-source.js";
17
17
  import { readClaudeWorkflowResultFile } from "./subagents/workflow-output.js";
18
18
  import { buildClaudeFeatures, claudeModelSupportsFastMode } from "./feature-definitions.js";
@@ -1,6 +1,6 @@
1
1
  import type { SDKMessage } from "@anthropic-ai/claude-agent-sdk";
2
2
  import type { AgentMetadata } from "../../../agent-sdk-types.js";
3
- import type { SubagentObservation } from "./observation.js";
3
+ import type { SubagentObservation } from "../../../provider-subagents/observation.js";
4
4
  /**
5
5
  * The subset of a hook input this source reads. Every hook shares these base fields: `agent_id`
6
6
  * is set when the hook fires from inside a subagent, and `effort.level` is the ACTIVE level for
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { AgentTimelineItem } from "../../../agent-sdk-types.js";
3
- import type { SubagentObservation } from "./observation.js";
3
+ import type { SubagentObservation } from "../../../provider-subagents/observation.js";
4
4
  /**
5
5
  * Rebuilds subagent observations from a persisted session, producing the same vocabulary the
6
6
  * live task-protocol source produces. Identical observations in means identical descriptor
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import type { AgentTimelineItem } from "../../../agent-sdk-types.js";
3
- import type { SubagentObservation } from "./observation.js";
3
+ import type { SubagentObservation } from "../../../provider-subagents/observation.js";
4
4
  import type { ClaudeReplayEntry } from "./replay-source.js";
5
5
  declare const ClaudeWorkflowRunSchema: z.ZodObject<{
6
6
  runId: z.ZodString;
@@ -1,12 +1,12 @@
1
1
  import { z } from "zod";
2
2
  export declare const OmpThinkingLevelSchema: z.ZodEnum<{
3
3
  off: "off";
4
- high: "high";
4
+ minimal: "minimal";
5
5
  low: "low";
6
6
  medium: "medium";
7
+ high: "high";
7
8
  xhigh: "xhigh";
8
9
  max: "max";
9
- minimal: "minimal";
10
10
  }>;
11
11
  export declare const OmpImageContentSchema: z.ZodObject<{
12
12
  type: z.ZodLiteral<"image">;
@@ -144,12 +144,12 @@ export declare const OmpSessionStateSchema: z.ZodObject<{
144
144
  }, z.core.$loose>>>;
145
145
  thinkingLevel: z.ZodOptional<z.ZodEnum<{
146
146
  off: "off";
147
- high: "high";
147
+ minimal: "minimal";
148
148
  low: "low";
149
149
  medium: "medium";
150
+ high: "high";
150
151
  xhigh: "xhigh";
151
152
  max: "max";
152
- minimal: "minimal";
153
153
  }>>;
154
154
  isStreaming: z.ZodBoolean;
155
155
  isCompacting: z.ZodBoolean;
@@ -1868,12 +1868,12 @@ export declare const OmpRpcCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1868
1868
  type: z.ZodLiteral<"set_thinking_level">;
1869
1869
  level: z.ZodEnum<{
1870
1870
  off: "off";
1871
- high: "high";
1871
+ minimal: "minimal";
1872
1872
  low: "low";
1873
1873
  medium: "medium";
1874
+ high: "high";
1874
1875
  xhigh: "xhigh";
1875
1876
  max: "max";
1876
- minimal: "minimal";
1877
1877
  }>;
1878
1878
  id: z.ZodOptional<z.ZodString>;
1879
1879
  }, z.core.$strip>, z.ZodObject<{
@@ -0,0 +1,45 @@
1
+ import type { SubagentObservation } from "../../provider-subagents/observation.js";
2
+ import type { ProviderSubagentStatus } from "../../provider-subagents/store.js";
3
+ import type { PiAgentMessage } from "./rpc-types.js";
4
+ export declare function isPiSubagentToolName(toolName: string): boolean;
5
+ /**
6
+ * The descriptor has no paused state and paused is not terminal, so it reads as running.
7
+ * Unknown statuses map to undefined: the caller's upsert then preserves the stored status.
8
+ */
9
+ export declare function mapPiSubagentStatus(status: unknown): ProviderSubagentStatus | undefined;
10
+ interface PiSubagentRecordDetails {
11
+ id: string;
12
+ status?: string;
13
+ description?: string;
14
+ agent?: string;
15
+ }
16
+ /**
17
+ * The subset of `toMessageDetails` this source reads. Every field is optional except the
18
+ * id: the extension adds fields across releases and older runtimes omit newer ones, so a
19
+ * wrong-typed field reads as absent rather than failing the record.
20
+ */
21
+ export declare function parsePiSubagentRecordDetails(details: unknown): PiSubagentRecordDetails | null;
22
+ /** Launch observation from the `subagent` tool result plus its call arguments. */
23
+ export declare function observePiSubagentLaunch(input: {
24
+ toolCallId: string;
25
+ args: unknown;
26
+ details: unknown;
27
+ }): SubagentObservation | null;
28
+ /** Status observation from a full task record (status/stop tool result or exit message). */
29
+ export declare function observePiSubagentRecord(details: unknown): SubagentObservation | null;
30
+ /**
31
+ * Exit custom messages carry one record, or an array when several children finished before
32
+ * the extension could deliver the notification (its exit-batch path).
33
+ */
34
+ export declare function observePiSubagentExit(details: unknown): SubagentObservation[];
35
+ /**
36
+ * Rebuilds subagent observations from a persisted session, producing the same vocabulary the
37
+ * live source produces. Identical observations in means identical descriptor state out.
38
+ *
39
+ * The transcript carries all three origins: assistant toolCall blocks with their toolResult
40
+ * messages (launch and record results), and `subagent-exit` custom messages. Tool calls
41
+ * precede their results in an assistant turn, so a single pass with a pending map pairs them.
42
+ */
43
+ export declare function replayPiSubagentObservations(messages: readonly PiAgentMessage[]): SubagentObservation[];
44
+ export {};
45
+ //# sourceMappingURL=agent-subagents.d.ts.map
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Pi announces background subagents through the @bytetrue/pi-subagent extension. Three wire
3
+ * origins carry the facts, and all three reduce to the shared observation vocabulary:
4
+ *
5
+ * - the `subagent` tool result (launch): details `{ id, status: "running" }`, the task
6
+ * description lives on the tool call arguments;
7
+ * - `subagent_status` / `subagent_stop` tool results and `subagent-exit` custom
8
+ * messages: details are the extension's full task record (`toMessageDetails`).
9
+ *
10
+ * The extension strips live objects before details cross the wire, so every field here is
11
+ * clone-safe JSON. Both the live event stream and the persisted session replay read through
12
+ * these functions, so a fact is derived once for both paths.
13
+ */
14
+ /** Tool the extension registers to launch a background child. */
15
+ const PI_SUBAGENT_LAUNCH_TOOL = "subagent";
16
+ /** Tools whose results carry the full task record. */
17
+ const PI_SUBAGENT_RECORD_TOOLS = new Set(["subagent_status", "subagent_stop"]);
18
+ /** Custom message type the extension sends when a child finishes. */
19
+ const PI_SUBAGENT_EXIT_CUSTOM_TYPE = "subagent-exit";
20
+ export function isPiSubagentToolName(toolName) {
21
+ return toolName === PI_SUBAGENT_LAUNCH_TOOL || PI_SUBAGENT_RECORD_TOOLS.has(toolName);
22
+ }
23
+ /**
24
+ * The descriptor has no paused state and paused is not terminal, so it reads as running.
25
+ * Unknown statuses map to undefined: the caller's upsert then preserves the stored status.
26
+ */
27
+ export function mapPiSubagentStatus(status) {
28
+ switch (status) {
29
+ case "running":
30
+ case "pending":
31
+ case "paused":
32
+ return "running";
33
+ case "succeeded":
34
+ return "completed";
35
+ case "failed":
36
+ return "failed";
37
+ case "cancelled":
38
+ return "canceled";
39
+ default:
40
+ return undefined;
41
+ }
42
+ }
43
+ /**
44
+ * The subset of `toMessageDetails` this source reads. Every field is optional except the
45
+ * id: the extension adds fields across releases and older runtimes omit newer ones, so a
46
+ * wrong-typed field reads as absent rather than failing the record.
47
+ */
48
+ export function parsePiSubagentRecordDetails(details) {
49
+ if (typeof details !== "object" || details === null || Array.isArray(details)) {
50
+ return null;
51
+ }
52
+ const record = details;
53
+ if (typeof record.id !== "string" || record.id.length === 0) {
54
+ return null;
55
+ }
56
+ return {
57
+ id: record.id,
58
+ ...(typeof record.status === "string" ? { status: record.status } : {}),
59
+ ...(typeof record.description === "string" ? { description: record.description } : {}),
60
+ ...(typeof record.agent === "string" && record.agent.length > 0 ? { agent: record.agent } : {}),
61
+ };
62
+ }
63
+ function readStringArg(value) {
64
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
65
+ }
66
+ /** Launch observation from the `subagent` tool result plus its call arguments. */
67
+ export function observePiSubagentLaunch(input) {
68
+ const record = parsePiSubagentRecordDetails(input.details);
69
+ if (!record) {
70
+ return null;
71
+ }
72
+ const args = typeof input.args === "object" && input.args !== null
73
+ ? input.args
74
+ : {};
75
+ const agent = readStringArg(args.agent);
76
+ const task = readStringArg(args.task) ?? record.description;
77
+ return {
78
+ kind: "declared",
79
+ id: record.id,
80
+ toolCallId: input.toolCallId,
81
+ ...(agent ? { title: agent } : {}),
82
+ ...(task ? { description: task } : {}),
83
+ };
84
+ }
85
+ /** Status observation from a full task record (status/stop tool result or exit message). */
86
+ export function observePiSubagentRecord(details) {
87
+ const record = parsePiSubagentRecordDetails(details);
88
+ if (!record) {
89
+ return null;
90
+ }
91
+ const status = mapPiSubagentStatus(record.status);
92
+ if (!status) {
93
+ return null;
94
+ }
95
+ return { kind: "status", id: record.id, status };
96
+ }
97
+ /**
98
+ * Exit custom messages carry one record, or an array when several children finished before
99
+ * the extension could deliver the notification (its exit-batch path).
100
+ */
101
+ export function observePiSubagentExit(details) {
102
+ if (Array.isArray(details)) {
103
+ return details
104
+ .map((entry) => observePiSubagentRecord(entry))
105
+ .filter((observation) => observation !== null);
106
+ }
107
+ const observation = observePiSubagentRecord(details);
108
+ return observation ? [observation] : [];
109
+ }
110
+ /**
111
+ * Rebuilds subagent observations from a persisted session, producing the same vocabulary the
112
+ * live source produces. Identical observations in means identical descriptor state out.
113
+ *
114
+ * The transcript carries all three origins: assistant toolCall blocks with their toolResult
115
+ * messages (launch and record results), and `subagent-exit` custom messages. Tool calls
116
+ * precede their results in an assistant turn, so a single pass with a pending map pairs them.
117
+ */
118
+ export function replayPiSubagentObservations(messages) {
119
+ const observations = [];
120
+ const pendingLaunches = new Map();
121
+ for (const message of messages) {
122
+ if (message.role === "assistant") {
123
+ for (const content of message.content) {
124
+ if (content.type === "toolCall" && isPiSubagentToolName(content.name)) {
125
+ pendingLaunches.set(content.id, { name: content.name, args: content.arguments });
126
+ }
127
+ }
128
+ continue;
129
+ }
130
+ if (message.role === "toolResult") {
131
+ const launch = pendingLaunches.get(message.toolCallId);
132
+ pendingLaunches.delete(message.toolCallId);
133
+ if (!launch) {
134
+ continue;
135
+ }
136
+ if (launch.name === PI_SUBAGENT_LAUNCH_TOOL) {
137
+ const observation = observePiSubagentLaunch({
138
+ toolCallId: message.toolCallId,
139
+ args: launch.args,
140
+ details: message.details,
141
+ });
142
+ if (observation) {
143
+ observations.push(observation);
144
+ }
145
+ continue;
146
+ }
147
+ const observation = observePiSubagentRecord(message.details);
148
+ if (observation) {
149
+ observations.push(observation);
150
+ }
151
+ continue;
152
+ }
153
+ if (message.role === "custom" && message.customType === PI_SUBAGENT_EXIT_CUSTOM_TYPE) {
154
+ observations.push(...observePiSubagentExit(message.details));
155
+ }
156
+ }
157
+ return observations;
158
+ }
159
+ //# sourceMappingURL=agent-subagents.js.map
@@ -128,6 +128,8 @@ export declare class PiRpcAgentSession implements AgentSession {
128
128
  private handleSessionEvent;
129
129
  private handleTurnBoundaryEvent;
130
130
  private handleToolExecutionEnd;
131
+ /** Background subagents announce themselves through tool result details, not the stream. */
132
+ private emitPiSubagentToolObservations;
131
133
  private emitCompactionTimeline;
132
134
  private handleMessageUpdate;
133
135
  private handleMessageStart;
@@ -171,8 +173,6 @@ export declare class PiRpcAgentClient implements AgentClient {
171
173
  */
172
174
  private resolveLaunchModel;
173
175
  private fetchAvailableProviders;
174
- private prepareMcpConfig;
175
- private detectMcpAdapter;
176
176
  private resolvePiLaunch;
177
177
  }
178
178
  export {};