@gotgenes/pi-subagents 10.0.0 → 10.1.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.
@@ -1,6 +1,6 @@
1
1
  import { debugLog } from "#src/debug";
2
2
  import { getLifetimeTotal, getSessionContextPercent } from "#src/lifecycle/usage";
3
- import type { AgentRecord } from "#src/types";
3
+ import type { Agent } from "#src/types";
4
4
  import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
5
5
 
6
6
  /** Details attached to custom notification messages for visual rendering. */
@@ -42,7 +42,7 @@ export function getStatusLabel(status: string, error?: string): string {
42
42
  }
43
43
 
44
44
  /** Format a structured task notification matching Claude Code's <task-notification> XML. */
45
- export function formatTaskNotification(record: AgentRecord, resultMaxLen: number): string {
45
+ export function formatTaskNotification(record: Agent, resultMaxLen: number): string {
46
46
  const status = getStatusLabel(record.status, record.error);
47
47
  const durationMs = record.completedAt ? record.completedAt - record.startedAt : 0;
48
48
  const totalTokens = getLifetimeTotal(record.lifetimeUsage);
@@ -75,7 +75,7 @@ export function formatTaskNotification(record: AgentRecord, resultMaxLen: number
75
75
 
76
76
  /** Build notification details for the custom message renderer. */
77
77
  export function buildNotificationDetails(
78
- record: AgentRecord,
78
+ record: Agent,
79
79
  resultMaxLen: number,
80
80
  activity?: AgentActivityTracker,
81
81
  ): NotificationDetails {
@@ -100,8 +100,8 @@ export function buildNotificationDetails(
100
100
  };
101
101
  }
102
102
 
103
- /** Build event data for lifecycle events from an AgentRecord. */
104
- export function buildEventData(record: AgentRecord) {
103
+ /** Build event data for lifecycle events from an Agent. */
104
+ export function buildEventData(record: Agent) {
105
105
  const durationMs = record.completedAt ? record.completedAt - record.startedAt : Date.now() - record.startedAt;
106
106
  const u = record.lifetimeUsage;
107
107
  const total = getLifetimeTotal(u);
@@ -126,7 +126,7 @@ export function buildEventData(record: AgentRecord) {
126
126
 
127
127
  export interface NotificationSystem {
128
128
  cancelNudge: (key: string) => void;
129
- sendCompletion: (record: AgentRecord) => void;
129
+ sendCompletion: (record: Agent) => void;
130
130
  cleanupCompleted: (id: string) => void;
131
131
  dispose: () => void;
132
132
  }
@@ -154,7 +154,7 @@ export class NotificationManager implements NotificationSystem {
154
154
  }
155
155
  }
156
156
 
157
- sendCompletion(record: AgentRecord): void {
157
+ sendCompletion(record: Agent): void {
158
158
  this.agentActivity.delete(record.id);
159
159
  this.markFinished(record.id);
160
160
  this.scheduleNudge(record.id, () => this.emitIndividualNudge(record));
@@ -187,7 +187,7 @@ export class NotificationManager implements NotificationSystem {
187
187
  );
188
188
  }
189
189
 
190
- private emitIndividualNudge(record: AgentRecord): void {
190
+ private emitIndividualNudge(record: Agent): void {
191
191
  if (record.notification?.resultConsumed) return;
192
192
 
193
193
  const notification = formatTaskNotification(record, 500);
@@ -1,16 +1,16 @@
1
1
  /**
2
- * record-observer.ts — Subscribes to session events and updates AgentRecord stats.
2
+ * record-observer.ts — Subscribes to session events and updates Agent stats.
3
3
  *
4
4
  * Replaces the scattered callback-wrapping logic in AgentManager's startAgent()
5
5
  * and resume() with a single direct subscription.
6
6
  */
7
7
 
8
+ import type { Agent } from "#src/lifecycle/agent";
8
9
  import type { CompactionInfo } from "#src/lifecycle/agent-manager";
9
- import type { AgentRecord } from "#src/lifecycle/agent-record";
10
10
  import type { SubscribableSession } from "#src/types";
11
11
 
12
- export interface RecordObserverOptions {
13
- onCompact?: (record: AgentRecord, info: CompactionInfo) => void;
12
+ export interface AgentObserverOptions {
13
+ onCompact?: (record: Agent, info: CompactionInfo) => void;
14
14
  }
15
15
 
16
16
  /**
@@ -23,10 +23,10 @@ export interface RecordObserverOptions {
23
23
  *
24
24
  * @returns An unsubscribe function.
25
25
  */
26
- export function subscribeRecordObserver(
26
+ export function subscribeAgentObserver(
27
27
  session: SubscribableSession,
28
- record: AgentRecord,
29
- options?: RecordObserverOptions,
28
+ record: Agent,
29
+ options?: AgentObserverOptions,
30
30
  ): () => void {
31
31
  return session.subscribe((event) => {
32
32
  if (event.type === "tool_execution_end") {
@@ -8,17 +8,16 @@
8
8
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
9
9
  import type { SpawnOptions, SubagentRecord, SubagentsService } from "#src/service/service";
10
10
  import type { ModelRegistry } from "#src/session/model-resolver";
11
- import type { AgentRecord, SessionContext } from "#src/types";
11
+ import type { Agent, SessionContext } from "#src/types";
12
12
 
13
13
  /** Narrow interface for the AgentManager — avoids coupling to the concrete class. */
14
14
  export interface AgentManagerLike {
15
15
  spawn(snapshot: ParentSnapshot, type: string, prompt: string, options: unknown): string;
16
- getRecord(id: string): AgentRecord | undefined;
17
- listAgents(): AgentRecord[];
16
+ getRecord(id: string): Agent | undefined;
17
+ listAgents(): Agent[];
18
18
  abort(id: string): boolean;
19
19
  waitForAll(): Promise<void>;
20
20
  hasRunning(): boolean;
21
- queueSteer(id: string, message: string): boolean;
22
21
  }
23
22
 
24
23
  /**
@@ -93,8 +92,9 @@ export class SubagentsServiceAdapter implements SubagentsService {
93
92
  }
94
93
  const session = record.session;
95
94
  if (!session) {
96
- // Session not ready yet — queue via manager for delivery once initialized
97
- return this.manager.queueSteer(id, message);
95
+ // Session not ready yet — buffer on the agent for delivery once initialized
96
+ record.queueSteer(message);
97
+ return true;
98
98
  }
99
99
  await session.steer(message);
100
100
  return true;
@@ -110,10 +110,10 @@ export class SubagentsServiceAdapter implements SubagentsService {
110
110
  }
111
111
 
112
112
  /**
113
- * Convert an internal AgentRecord to a serializable SubagentRecord.
113
+ * Convert an internal Agent to a serializable SubagentRecord.
114
114
  * Uses an explicit allowlist — new fields must be opted in.
115
115
  */
116
- export function toSubagentRecord(record: AgentRecord): SubagentRecord {
116
+ export function toSubagentRecord(record: Agent): SubagentRecord {
117
117
  const out: SubagentRecord = {
118
118
  id: record.id,
119
119
  type: record.type,
@@ -18,19 +18,6 @@ import type { AgentPromptConfig, SubagentType, ThinkingLevel } from "#src/types"
18
18
 
19
19
  // ── Public interfaces ────────────────────────────────────────────────────────
20
20
 
21
- /**
22
- * Tool filtering configuration — consumed by `filterActiveTools` in `agent-runner.ts`.
23
- *
24
- * Groups the two fields that travel together through the assembly→runner boundary:
25
- * the built-in tool allowlist and the extensions setting.
26
- */
27
- export interface ToolFilterConfig {
28
- /** Built-in tool name allowlist for this agent type. */
29
- toolNames: string[];
30
- /** Resolved extensions setting: true = inherit all, false = none. */
31
- extensions: boolean;
32
- }
33
-
34
21
  /**
35
22
  * IO collaborators injected into `assembleSessionConfig`.
36
23
  *
@@ -98,8 +85,10 @@ export interface SessionConfig {
98
85
  effectiveCwd: string;
99
86
  /** Fully-assembled system prompt string (ready for `systemPromptOverride`). */
100
87
  systemPrompt: string;
101
- /** Tool filtering cluster — tool allowlist, denylist, and extensions setting. */
102
- toolFilter: ToolFilterConfig;
88
+ /** Built-in tool name allowlist for this agent type. */
89
+ toolNames: string[];
90
+ /** Resolved extensions setting: true = inherit all, false = none. */
91
+ extensions: boolean;
103
92
  /**
104
93
  * Resolved model instance (undefined → use parent model as passed to SDK).
105
94
  * Opaque handle — the assembler passes it through without inspection.
@@ -222,7 +211,8 @@ export function assembleSessionConfig(
222
211
  return {
223
212
  effectiveCwd,
224
213
  systemPrompt,
225
- toolFilter: { toolNames, extensions },
214
+ toolNames,
215
+ extensions,
226
216
  model,
227
217
  thinkingLevel,
228
218
  noSkills,
@@ -11,7 +11,7 @@ import { runForeground } from "#src/tools/foreground-runner";
11
11
  import { buildDetails, buildTypeListText, textResult } from "#src/tools/helpers";
12
12
  import { renderAgentResult } from "#src/tools/result-renderer";
13
13
  import { type ModelInfo, resolveSpawnConfig } from "#src/tools/spawn-config";
14
- import type { AgentRecord } from "#src/types";
14
+ import type { Agent } from "#src/types";
15
15
  import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
16
16
  import { type UICtx } from "#src/ui/agent-widget";
17
17
  import { type AgentDetails, getDisplayName } from "#src/ui/display";
@@ -33,9 +33,9 @@ export interface AgentActivityAccess {
33
33
  /** Narrow manager interface — only the methods the Agent tool calls. */
34
34
  export interface AgentToolManager {
35
35
  spawn: (snapshot: ParentSnapshot, type: string, prompt: string, opts: AgentSpawnConfig) => string;
36
- spawnAndWait: (snapshot: ParentSnapshot, type: string, prompt: string, opts: Omit<AgentSpawnConfig, "isBackground">) => Promise<AgentRecord>;
37
- resume: (id: string, prompt: string, signal: AbortSignal) => Promise<AgentRecord | undefined>;
38
- getRecord: (id: string) => AgentRecord | undefined;
36
+ spawnAndWait: (snapshot: ParentSnapshot, type: string, prompt: string, opts: Omit<AgentSpawnConfig, "isBackground">) => Promise<Agent>;
37
+ resume: (id: string, prompt: string, signal: AbortSignal) => Promise<Agent | undefined>;
38
+ getRecord: (id: string) => Agent | undefined;
39
39
  }
40
40
 
41
41
  /** Narrow runtime interface — the Agent tool's slice of SubagentRuntime. */
@@ -3,14 +3,14 @@ import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
3
3
  import type { AgentActivityAccess } from "#src/tools/agent-tool";
4
4
  import { textResult } from "#src/tools/helpers";
5
5
  import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
6
- import type { AgentRecord } from "#src/types";
6
+ import type { Agent } from "#src/types";
7
7
  import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
8
8
  import { subscribeUIObserver } from "#src/ui/ui-observer";
9
9
 
10
10
  /** Narrow manager interface for the background spawner. */
11
11
  export interface BackgroundManagerDeps {
12
12
  spawn(snapshot: ParentSnapshot, type: string, prompt: string, opts: AgentSpawnConfig): string;
13
- getRecord(id: string): AgentRecord | undefined;
13
+ getRecord(id: string): Agent | undefined;
14
14
  }
15
15
 
16
16
  /** Narrow widget interface for the background spawner. */
@@ -9,7 +9,7 @@ import {
9
9
  textResult,
10
10
  } from "#src/tools/helpers";
11
11
  import type { ResolvedSpawnConfig } from "#src/tools/spawn-config";
12
- import type { AgentRecord } from "#src/types";
12
+ import type { Agent } from "#src/types";
13
13
  import { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
14
14
  import {
15
15
  type AgentDetails,
@@ -26,7 +26,7 @@ export interface ForegroundManagerDeps {
26
26
  type: string,
27
27
  prompt: string,
28
28
  opts: Omit<AgentSpawnConfig, "isBackground">,
29
- ): Promise<AgentRecord>;
29
+ ): Promise<Agent>;
30
30
  }
31
31
 
32
32
  /** Narrow widget interface for the foreground runner. */
@@ -62,7 +62,7 @@ export async function runForeground(
62
62
 
63
63
  const fgState = new AgentActivityTracker(execution.effectiveMaxTurns);
64
64
  let unsubUI: (() => void) | undefined;
65
- let recordRef: AgentRecord | undefined;
65
+ let recordRef: Agent | undefined;
66
66
 
67
67
  const streamUpdate = () => {
68
68
  const toolUses = recordRef?.toolUses ?? 0;
@@ -92,7 +92,7 @@ export async function runForeground(
92
92
 
93
93
  streamUpdate();
94
94
 
95
- let record: AgentRecord;
95
+ let record: Agent;
96
96
  try {
97
97
  record = await manager.spawnAndWait(
98
98
  params.snapshot,
@@ -4,13 +4,13 @@ import type { AgentConfigLookup } from "#src/config/agent-types";
4
4
  import { getAgentConversation } from "#src/lifecycle/agent-runner";
5
5
  import { getSessionContextPercent } from "#src/lifecycle/usage";
6
6
  import { formatLifetimeTokens, textResult } from "#src/tools/helpers";
7
- import type { AgentRecord } from "#src/types";
7
+ import type { Agent } from "#src/types";
8
8
  import { formatDuration, getDisplayName } from "#src/ui/display";
9
9
 
10
10
  // ---- Deps interfaces ----
11
11
 
12
12
  export interface GetResultToolManager {
13
- getRecord(id: string): AgentRecord | undefined;
13
+ getRecord(id: string): Agent | undefined;
14
14
  }
15
15
 
16
16
  export interface GetResultToolNotifications {
@@ -2,13 +2,12 @@ import { defineTool } from "@earendil-works/pi-coding-agent";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  import { getSessionContextPercent } from "#src/lifecycle/usage";
4
4
  import { formatLifetimeTokens, textResult } from "#src/tools/helpers";
5
- import type { AgentRecord } from "#src/types";
5
+ import type { Agent } from "#src/types";
6
6
 
7
7
  // ---- Deps interfaces ----
8
8
 
9
9
  export interface SteerToolManager {
10
- getRecord(id: string): AgentRecord | undefined;
11
- queueSteer(id: string, message: string): boolean;
10
+ getRecord(id: string): Agent | undefined;
12
11
  }
13
12
 
14
13
  export interface SteerToolEvents {
@@ -43,8 +42,8 @@ export class SteerTool {
43
42
  }
44
43
  const session = record.session;
45
44
  if (!session) {
46
- // Session not ready yet — queue via manager for delivery once initialized
47
- this.manager.queueSteer(record.id, params.message);
45
+ // Session not ready yet — buffer on the agent for delivery once initialized
46
+ record.queueSteer(params.message);
48
47
  this.events.emit("subagents:steered", { id: record.id, message: params.message });
49
48
  return textResult(
50
49
  `Steering message queued for agent ${record.id}. It will be delivered once the session initializes.`,
package/src/types.ts CHANGED
@@ -7,7 +7,7 @@ import type { AgentSessionEvent } from "@earendil-works/pi-coding-agent";
7
7
  import type { ModelRegistry } from "#src/session/model-resolver";
8
8
 
9
9
 
10
- export { AgentRecord } from "#src/lifecycle/agent-record";
10
+ export { Agent } from "#src/lifecycle/agent";
11
11
  export type { AgentSessionEvent, ThinkingLevel };
12
12
 
13
13
  /**
@@ -9,7 +9,7 @@ import { join } from "node:path";
9
9
 
10
10
  import { BUILTIN_TOOL_NAMES } from "#src/config/agent-types";
11
11
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
12
- import type { AgentRecord } from "#src/types";
12
+ import type { Agent } from "#src/types";
13
13
  import type { AgentFileOps } from "#src/ui/agent-file-ops";
14
14
  import { writeAgentFile } from "#src/ui/agent-file-writer";
15
15
  import type { MenuUI } from "#src/ui/agent-menu";
@@ -23,7 +23,7 @@ export interface WizardManager {
23
23
  type: string,
24
24
  prompt: string,
25
25
  opts: { description: string; maxTurns: number },
26
- ) => Promise<AgentRecord>;
26
+ ) => Promise<Agent>;
27
27
  }
28
28
 
29
29
  /** Narrow registry interface for reloading after creation. */
@@ -4,7 +4,7 @@ import { AgentTypeRegistry } from "#src/config/agent-types";
4
4
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
5
5
  import { type ModelRegistry, resolveModel } from "#src/session/model-resolver";
6
6
  import { getModelLabelFromConfig } from "#src/tools/helpers";
7
- import type { AgentConfig, AgentRecord } from "#src/types";
7
+ import type { Agent, AgentConfig } from "#src/types";
8
8
  import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
9
9
  import { AgentConfigEditor } from "#src/ui/agent-config-editor";
10
10
  import { AgentCreationWizard } from "#src/ui/agent-creation-wizard";
@@ -15,15 +15,15 @@ import { formatDuration, getDisplayName } from "#src/ui/display";
15
15
 
16
16
  /** Narrow manager interface for menu operations. */
17
17
  export interface AgentMenuManager {
18
- listAgents: () => AgentRecord[];
19
- getRecord: (id: string) => AgentRecord | undefined;
18
+ listAgents: () => Agent[];
19
+ getRecord: (id: string) => Agent | undefined;
20
20
  /** Used by generate wizard to spawn an agent that writes the .md file. */
21
21
  spawnAndWait: (
22
22
  parentSnapshot: ParentSnapshot,
23
23
  type: string,
24
24
  prompt: string,
25
25
  opts: { description: string; maxTurns: number },
26
- ) => Promise<AgentRecord>;
26
+ ) => Promise<Agent>;
27
27
  }
28
28
 
29
29
  /** Narrow settings interface required by the agent menu. */
@@ -251,7 +251,7 @@ export class AgentsMenuHandler {
251
251
  await this.showRunningAgents(ui);
252
252
  }
253
253
 
254
- private async viewAgentConversation(ui: MenuUI, record: AgentRecord): Promise<void> {
254
+ private async viewAgentConversation(ui: MenuUI, record: Agent): Promise<void> {
255
255
  const session = record.session;
256
256
  if (!session) {
257
257
  ui.notify(
@@ -9,7 +9,7 @@ import type { AgentSession } from "@earendil-works/pi-coding-agent";
9
9
  import { type Component, matchesKey, type TUI, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
10
  import type { AgentConfigLookup } from "#src/config/agent-types";
11
11
  import { getLifetimeTotal, getSessionContextPercent } from "#src/lifecycle/usage";
12
- import type { AgentRecord } from "#src/types";
12
+ import type { Agent } from "#src/types";
13
13
  import type { AgentActivityTracker } from "#src/ui/agent-activity-tracker";
14
14
  import { buildInvocationTags, formatDuration, formatSessionTokens, getDisplayName, getPromptModeLabel, type Theme } from "#src/ui/display";
15
15
  import { formatMessage, formatStreamingIndicator } from "#src/ui/message-formatters";
@@ -25,7 +25,7 @@ export const VIEWPORT_HEIGHT_PCT = 70;
25
25
  export interface ConversationViewerOptions {
26
26
  tui: TUI;
27
27
  session: AgentSession;
28
- record: AgentRecord;
28
+ record: Agent;
29
29
  activity: AgentActivityTracker | undefined;
30
30
  theme: Theme;
31
31
  done: (result: undefined) => void;
@@ -42,7 +42,7 @@ export class ConversationViewer implements Component {
42
42
 
43
43
  private tui: TUI;
44
44
  private session: AgentSession;
45
- private record: AgentRecord;
45
+ private record: Agent;
46
46
  private activity: AgentActivityTracker | undefined;
47
47
  private theme: Theme;
48
48
  private done: (result: undefined) => void;