@oh-my-pi/pi-coding-agent 15.10.12 → 15.11.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 (125) hide show
  1. package/CHANGELOG.md +60 -3
  2. package/dist/cli.js +841 -803
  3. package/dist/types/async/index.d.ts +0 -1
  4. package/dist/types/cli/gallery-fixtures/types.d.ts +5 -0
  5. package/dist/types/config/keybindings.d.ts +6 -1
  6. package/dist/types/config/settings-schema.d.ts +56 -33
  7. package/dist/types/export/html/template.generated.d.ts +1 -1
  8. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  9. package/dist/types/extensibility/shared-events.d.ts +2 -2
  10. package/dist/types/internal-urls/history-protocol.d.ts +14 -0
  11. package/dist/types/internal-urls/index.d.ts +1 -0
  12. package/dist/types/internal-urls/types.d.ts +1 -1
  13. package/dist/types/irc/bus.d.ts +66 -0
  14. package/dist/types/modes/components/agent-hub.d.ts +30 -0
  15. package/dist/types/modes/components/compaction-summary-message.d.ts +10 -4
  16. package/dist/types/modes/components/custom-editor.d.ts +2 -0
  17. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  18. package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
  19. package/dist/types/modes/components/welcome.d.ts +3 -9
  20. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  21. package/dist/types/modes/interactive-mode.d.ts +3 -2
  22. package/dist/types/modes/theme/theme.d.ts +2 -1
  23. package/dist/types/modes/types.d.ts +3 -2
  24. package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
  25. package/dist/types/registry/agent-lifecycle.d.ts +51 -0
  26. package/dist/types/registry/agent-registry.d.ts +16 -5
  27. package/dist/types/session/agent-session.d.ts +35 -30
  28. package/dist/types/session/messages.d.ts +2 -4
  29. package/dist/types/session/session-history-format.d.ts +12 -0
  30. package/dist/types/session/session-manager.d.ts +21 -3
  31. package/dist/types/session/streaming-output.d.ts +23 -0
  32. package/dist/types/task/executor.d.ts +11 -2
  33. package/dist/types/task/index.d.ts +11 -4
  34. package/dist/types/task/output-manager.d.ts +0 -7
  35. package/dist/types/task/repair-args.d.ts +8 -7
  36. package/dist/types/task/types.d.ts +55 -51
  37. package/dist/types/tools/browser/tab-worker.d.ts +3 -1
  38. package/dist/types/tools/find.d.ts +0 -11
  39. package/dist/types/tools/grouped-file-output.d.ts +0 -49
  40. package/dist/types/tools/index.d.ts +1 -3
  41. package/dist/types/tools/irc.d.ts +76 -38
  42. package/dist/types/tools/job.d.ts +7 -1
  43. package/examples/extensions/with-deps/package.json +1 -0
  44. package/package.json +11 -10
  45. package/scripts/bundle-dist.ts +28 -19
  46. package/src/async/index.ts +0 -1
  47. package/src/cli/gallery-cli.ts +1 -1
  48. package/src/cli/gallery-fixtures/agentic.ts +230 -115
  49. package/src/cli/gallery-fixtures/types.ts +5 -0
  50. package/src/cli.ts +20 -6
  51. package/src/commit/agentic/tools/analyze-file.ts +38 -19
  52. package/src/config/keybindings.ts +6 -1
  53. package/src/config/settings-schema.ts +56 -40
  54. package/src/config/settings.ts +7 -0
  55. package/src/eval/__tests__/agent-bridge.test.ts +5 -3
  56. package/src/eval/agent-bridge.ts +3 -16
  57. package/src/eval/js/shared/prelude.txt +1 -1
  58. package/src/eval/py/prelude.py +5 -6
  59. package/src/export/html/template.generated.ts +1 -1
  60. package/src/export/html/template.js +38 -13
  61. package/src/extensibility/custom-tools/types.ts +2 -2
  62. package/src/extensibility/shared-events.ts +2 -2
  63. package/src/internal-urls/docs-index.generated.ts +8 -8
  64. package/src/internal-urls/history-protocol.ts +113 -0
  65. package/src/internal-urls/index.ts +1 -0
  66. package/src/internal-urls/router.ts +3 -1
  67. package/src/internal-urls/types.ts +1 -1
  68. package/src/irc/bus.ts +292 -0
  69. package/src/main.ts +8 -60
  70. package/src/modes/components/{session-observer-overlay.ts → agent-hub.ts} +586 -367
  71. package/src/modes/components/compaction-summary-message.ts +68 -32
  72. package/src/modes/components/custom-editor.ts +10 -0
  73. package/src/modes/components/tool-execution.ts +31 -1
  74. package/src/modes/components/ttsr-notification.ts +72 -30
  75. package/src/modes/components/welcome.ts +9 -33
  76. package/src/modes/controllers/event-controller.ts +65 -0
  77. package/src/modes/controllers/extension-ui-controller.ts +8 -8
  78. package/src/modes/controllers/input-controller.ts +18 -2
  79. package/src/modes/controllers/selector-controller.ts +21 -17
  80. package/src/modes/interactive-mode.ts +8 -13
  81. package/src/modes/theme/theme.ts +18 -5
  82. package/src/modes/types.ts +3 -5
  83. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  84. package/src/modes/utils/ui-helpers.ts +51 -49
  85. package/src/prompts/system/irc-incoming.md +3 -4
  86. package/src/prompts/system/orchestrate-notice.md +2 -2
  87. package/src/prompts/system/subagent-system-prompt.md +0 -5
  88. package/src/prompts/system/system-prompt.md +1 -0
  89. package/src/prompts/system/workflow-notice.md +2 -2
  90. package/src/prompts/tools/eval.md +3 -3
  91. package/src/prompts/tools/irc.md +29 -19
  92. package/src/prompts/tools/read.md +2 -2
  93. package/src/prompts/tools/task-summary.md +5 -16
  94. package/src/prompts/tools/task.md +38 -29
  95. package/src/registry/agent-lifecycle.ts +218 -0
  96. package/src/registry/agent-registry.ts +16 -5
  97. package/src/sdk.ts +29 -9
  98. package/src/session/agent-session.ts +243 -237
  99. package/src/session/messages.ts +11 -78
  100. package/src/session/session-history-format.ts +246 -0
  101. package/src/session/session-manager.ts +59 -5
  102. package/src/session/streaming-output.ts +60 -0
  103. package/src/task/executor.ts +855 -466
  104. package/src/task/index.ts +718 -794
  105. package/src/task/output-manager.ts +0 -11
  106. package/src/task/render.ts +133 -63
  107. package/src/task/repair-args.ts +21 -9
  108. package/src/task/types.ts +73 -66
  109. package/src/tools/ask.ts +4 -2
  110. package/src/tools/bash.ts +15 -5
  111. package/src/tools/browser/tab-worker.ts +26 -7
  112. package/src/tools/browser.ts +28 -1
  113. package/src/tools/find.ts +2 -27
  114. package/src/tools/grouped-file-output.ts +1 -118
  115. package/src/tools/index.ts +4 -12
  116. package/src/tools/irc.ts +596 -171
  117. package/src/tools/job.ts +41 -7
  118. package/src/tools/read.ts +57 -1
  119. package/src/tools/renderers.ts +2 -0
  120. package/src/tools/resolve.ts +4 -1
  121. package/dist/types/async/support.d.ts +0 -2
  122. package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
  123. package/dist/types/task/simple-mode.d.ts +0 -8
  124. package/src/async/support.ts +0 -5
  125. package/src/task/simple-mode.ts +0 -27
@@ -214,14 +214,31 @@ export declare function migrateSessionEntries(entries: FileEntry[]): void;
214
214
  /** Exported for compaction.test.ts */
215
215
  export declare function parseSessionEntries(content: string): FileEntry[];
216
216
  export declare function getLatestCompactionEntry(entries: SessionEntry[]): CompactionEntry | null;
217
+ export interface BuildSessionContextOptions {
218
+ /**
219
+ * Build the full-history display transcript instead of the LLM context:
220
+ * every path entry in chronological order, with each compaction emitted
221
+ * inline as a `compactionSummary` message at the position it fired rather
222
+ * than replacing the history before it. Display-only — never send the
223
+ * result to a provider.
224
+ */
225
+ transcript?: boolean;
226
+ }
217
227
  /**
218
228
  * Build the session context from entries using tree traversal.
219
229
  * If leafId is provided, walks from that entry to root.
220
230
  * Handles compaction and branch summaries along the path.
221
231
  */
222
- export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>): SessionContext;
232
+ export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>, options?: BuildSessionContextOptions): SessionContext;
223
233
  /** Exported for testing */
224
234
  export declare function loadEntriesFromFile(filePath: string, storage?: SessionStorage): Promise<FileEntry[]>;
235
+ /**
236
+ * Read-only message view of a session file: load entries, migrate to the
237
+ * current version, resolve blob refs, and build the context along the
238
+ * persisted leaf path (last entry). Does NOT create a writer or take the
239
+ * session lock — safe to call against a file another session is writing.
240
+ */
241
+ export declare function loadSessionMessagesReadOnly(filePath: string): Promise<AgentMessage[]>;
225
242
  declare class RecentSessionInfo {
226
243
  #private;
227
244
  readonly path: string;
@@ -507,10 +524,11 @@ export declare class SessionManager {
507
524
  */
508
525
  getBranch(fromId?: string): SessionEntry[];
509
526
  /**
510
- * Build the session context (what gets sent to the LLM).
527
+ * Build the session context (what gets sent to the LLM), or — with
528
+ * `{ transcript: true }` — the full-history display transcript.
511
529
  * Uses tree traversal from current leaf.
512
530
  */
513
- buildSessionContext(): SessionContext;
531
+ buildSessionContext(options?: BuildSessionContextOptions): SessionContext;
514
532
  /** Strip stale OpenAI Responses assistant replay metadata from loaded in-memory entries. */
515
533
  sanitizeLoadedOpenAIResponsesReplayMetadata(): boolean;
516
534
  /**
@@ -159,6 +159,29 @@ export declare function formatMiddleElisionMarker(elidedLines: number, elidedByt
159
159
  * budget is empty or the content already fits.
160
160
  */
161
161
  export declare function truncateMiddle(content: string, options?: TruncationOptions): TruncationResult;
162
+ /** Options for {@link enforceInlineByteCap}. */
163
+ export interface InlineByteCapOptions {
164
+ /** Inline byte budget. Defaults to {@link DEFAULT_MAX_BYTES}. */
165
+ maxBytes?: number;
166
+ /** What the text is, for the elision marker (e.g. "bash output"). */
167
+ label: string;
168
+ /**
169
+ * Persist the full text as a session artifact. When an artifact id is
170
+ * returned, a `[raw output: artifact://<id>]` footer is appended so the
171
+ * elided bytes stay recoverable.
172
+ */
173
+ saveArtifact?: (full: string) => string | undefined | Promise<string | undefined>;
174
+ }
175
+ /**
176
+ * Final-defense inline size guard for tool results.
177
+ *
178
+ * No-op when `text` fits within `maxBytes` (the common path). Otherwise keeps
179
+ * ~60% of the budget from the head and ~25% from the tail — cut on line
180
+ * boundaries, never splitting a multi-byte UTF-8 sequence — with an elision
181
+ * marker between. The remaining ~15% is slack for the marker and the optional
182
+ * `[raw output: artifact://<id>]` footer, so the result stays under `maxBytes`.
183
+ */
184
+ export declare function enforceInlineByteCap(text: string, options: InlineByteCapOptions): Promise<string>;
162
185
  export declare class TailBuffer {
163
186
  #private;
164
187
  readonly maxBytes: number;
@@ -22,6 +22,16 @@ import type { ContextFileEntry } from "../tools";
22
22
  import type { EventBus } from "../utils/event-bus";
23
23
  import type { WorkspaceTree } from "../workspace-tree";
24
24
  import { type AgentDefinition, type AgentProgress, type ReviewFinding, type SingleResult } from "./types";
25
+ /**
26
+ * Soft per-agent request budgets (assistant requests per run). When a subagent
27
+ * crosses its budget it receives ONE steering notice asking it to wrap up; at
28
+ * 1.5x the budget the run is aborted gracefully so partial output is salvaged.
29
+ * The `default` key applies to agents without an explicit entry and can be
30
+ * overridden via the `task.softRequestBudget` setting (0 disables the guard).
31
+ */
32
+ export declare const SOFT_REQUEST_BUDGET: Record<string, number>;
33
+ /** Steering notice injected once when a subagent crosses its soft request budget. */
34
+ export declare function buildBudgetNotice(requests: number): string;
25
35
  /** Options for subagent execution */
26
36
  export interface ExecutorOptions {
27
37
  cwd: string;
@@ -29,6 +39,7 @@ export interface ExecutorOptions {
29
39
  agent: AgentDefinition;
30
40
  task: string;
31
41
  assignment?: string;
42
+ /** Shared background from the task call (`task.batch`), rendered into the subagent's system prompt. */
32
43
  context?: string;
33
44
  /**
34
45
  * The session's active overall plan, handed off so subagents spawned during
@@ -66,8 +77,6 @@ export interface ExecutorOptions {
66
77
  sessionFile?: string | null;
67
78
  persistArtifacts?: boolean;
68
79
  artifactsDir?: string;
69
- /** Path to parent conversation context file */
70
- contextFile?: string;
71
80
  eventBus?: EventBus;
72
81
  contextFiles?: ContextFileEntry[];
73
82
  skills?: Skill[];
@@ -1,7 +1,7 @@
1
1
  import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
2
2
  import type { ToolSession } from "..";
3
3
  import type { Theme } from "../modes/theme/theme";
4
- import { type AgentDefinition, type TaskToolDetails, type TaskToolSchemaInstance } from "./types";
4
+ import { type AgentDefinition, type SingleResult, type TaskToolDetails, type TaskToolSchemaInstance } from "./types";
5
5
  import "../tools/review";
6
6
  import { renderResult, renderCall as renderTaskCall } from "./render";
7
7
  export { loadBundledAgents as BUNDLED_AGENTS } from "./agents";
@@ -12,11 +12,18 @@ export type { AgentDefinition, AgentProgress, SingleResult, SubagentEventPayload
12
12
  export { TASK_SUBAGENT_EVENT_CHANNEL, TASK_SUBAGENT_LIFECYCLE_CHANNEL, TASK_SUBAGENT_PROGRESS_CHANNEL, taskSchema, } from "./types";
13
13
  export declare const READ_ONLY_TOOL_NAMES: ReadonlySet<string>;
14
14
  export declare function isReadOnlyAgent(agent: AgentDefinition): boolean;
15
+ /**
16
+ * Preview text for a child result. Falls back to "(no output)" — annotated
17
+ * with the request count when the child actually did work, so the parent can
18
+ * tell a no-op child from one that burned requests before being cancelled.
19
+ */
20
+ export declare function formatResultOutputFallback(result: Pick<SingleResult, "output" | "stderr" | "requests">): string;
15
21
  /**
16
22
  * Task tool - Delegate tasks to specialized agents.
17
23
  *
18
- * Requires async initialization to discover available agents.
19
- * Use `TaskTool.create(session)` to instantiate.
24
+ * Each call spawns one subagent or, with `task.batch`, one per `tasks[]`
25
+ * item. Spawning is non-blocking: the call registers AsyncJobManager jobs and
26
+ * returns immediately; each result is delivered when that agent yields.
20
27
  */
21
28
  export declare class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetails, Theme> {
22
29
  #private;
@@ -25,7 +32,7 @@ export declare class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskT
25
32
  readonly approval: "exec";
26
33
  readonly formatApprovalDetails: (args: unknown) => string[];
27
34
  readonly label = "Task";
28
- readonly summary = "Spawn a subagent to complete a parallel task";
35
+ readonly summary = "Spawn a subagent to complete a task in the background";
29
36
  readonly strict = true;
30
37
  readonly loadMode = "discoverable";
31
38
  readonly renderResult: typeof renderResult;
@@ -17,11 +17,4 @@ export declare class AgentOutputManager {
17
17
  * @returns Unique ID ("Anna" first, then "Anna-2", "Anna-3", …)
18
18
  */
19
19
  allocate(id: string): Promise<string>;
20
- /**
21
- * Allocate unique IDs for a batch of tasks.
22
- *
23
- * @param ids Array of requested IDs
24
- * @returns Array of unique IDs in same order
25
- */
26
- allocateBatch(ids: string[]): Promise<string[]>;
27
20
  }
@@ -2,7 +2,7 @@
2
2
  * Repair double-encoded JSON string arguments for the task tool.
3
3
  *
4
4
  * Models occasionally JSON-escape a string value twice when emitting a
5
- * `task` tool call, so a `context`/`assignment` that should read
5
+ * `task` tool call, so an `assignment` that should read
6
6
  *
7
7
  * # Role
8
8
  * You are a judge … "describe this" … return —
@@ -24,7 +24,7 @@
24
24
  * string.
25
25
  *
26
26
  * This is deliberately scoped to the task tool's natural-language fields
27
- * (`context`, `assignment`, `description`). It is NOT applied to code-bearing
27
+ * (`assignment`, `description`). It is NOT applied to code-bearing
28
28
  * tools (write/edit/bash/search), where a backslash or quote is load-bearing
29
29
  * and a false-positive unescape would silently corrupt a file or command.
30
30
  */
@@ -43,10 +43,11 @@ import type { TaskParams } from "./types";
43
43
  */
44
44
  export declare function repairDoubleEncodedJsonString(value: string): string;
45
45
  /**
46
- * Repair double-encoded prose in task-tool params (`context` and each task's
47
- * `assignment`/`description`). Returns the same reference when nothing changed
48
- * so callers can cheaply skip work. Defensive against partially-streamed args
49
- * (missing/undefined fields, partial task arrays) so it is safe on the render
50
- * path as well as on execution.
46
+ * Repair double-encoded prose in task-tool params (`assignment`,
47
+ * `description`, shared `context`, and each batch task item's prose fields).
48
+ * Returns the same reference when nothing changed so callers can cheaply skip
49
+ * work. Defensive against partially-streamed args (missing/undefined fields,
50
+ * partial task arrays) so it is safe on the render path as well as on
51
+ * execution.
51
52
  */
52
53
  export declare function repairTaskParams(params: TaskParams): TaskParams;
@@ -2,7 +2,6 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
2
  import type { Usage } from "@oh-my-pi/pi-ai";
3
3
  import * as z from "zod/v4";
4
4
  import type { AgentSessionEvent } from "../session/agent-session";
5
- import { type TaskSimpleMode } from "./simple-mode";
6
5
  import type { NestedRepoPatch } from "./worktree";
7
6
  /** Source of an agent definition */
8
7
  export type AgentSource = "bundled" | "user" | "project";
@@ -43,85 +42,86 @@ export interface SubagentLifecyclePayload {
43
42
  parentToolCallId?: string;
44
43
  index: number;
45
44
  }
46
- /** Single task item for parallel execution (default shape with context enabled). */
47
45
  export declare const taskItemSchema: z.ZodObject<{
48
- id: z.ZodString;
49
- description: z.ZodString;
46
+ id: z.ZodOptional<z.ZodString>;
47
+ description: z.ZodOptional<z.ZodString>;
50
48
  assignment: z.ZodString;
51
49
  }, z.core.$strip>;
52
- export type TaskItem = z.infer<typeof taskItemSchema>;
50
+ /** Single task item. Fields are optional defensively: args stream in token by token. */
51
+ export interface TaskItem {
52
+ /** Stable agent id; default = generated AdjectiveNoun. */
53
+ id?: string;
54
+ /** UI label, not seen by the subagent. */
55
+ description?: string;
56
+ /** The work; required by the schema. */
57
+ assignment?: string;
58
+ /** Run this spawn in an isolated worktree (batch form; flat form carries it top-level). */
59
+ isolated?: boolean;
60
+ }
53
61
  export declare const taskSchema: z.ZodObject<{
62
+ id: z.ZodOptional<z.ZodString>;
63
+ description: z.ZodOptional<z.ZodString>;
64
+ assignment: z.ZodString;
65
+ isolated: z.ZodOptional<z.ZodBoolean>;
54
66
  agent: z.ZodString;
55
- tasks: z.ZodArray<z.ZodObject<{
56
- id: z.ZodString;
57
- description: z.ZodString;
58
- assignment: z.ZodString;
59
- }, z.core.$strip>>;
60
- }, z.core.$strip>;
61
- export declare const taskSchemaNoIsolation: z.ZodObject<{
62
- agent: z.ZodString;
63
- tasks: z.ZodArray<z.ZodObject<{
64
- id: z.ZodString;
65
- description: z.ZodString;
66
- assignment: z.ZodString;
67
- }, z.core.$strip>>;
68
67
  }, z.core.$strip>;
69
68
  declare const ALL_TASK_SCHEMAS: readonly [z.ZodObject<{
69
+ id: z.ZodOptional<z.ZodString>;
70
+ description: z.ZodOptional<z.ZodString>;
71
+ assignment: z.ZodString;
72
+ isolated: z.ZodOptional<z.ZodBoolean>;
70
73
  agent: z.ZodString;
71
- tasks: z.ZodArray<z.ZodObject<{
72
- id: z.ZodString;
73
- description: z.ZodString;
74
- assignment: z.ZodString;
75
- }, z.core.$strip>>;
76
- }, z.core.$strip>, z.ZodObject<{
77
- agent: z.ZodString;
78
- tasks: z.ZodArray<z.ZodObject<{
79
- id: z.ZodString;
80
- description: z.ZodString;
81
- assignment: z.ZodString;
82
- }, z.core.$strip>>;
83
- }, z.core.$strip>, z.ZodObject<{
84
- agent: z.ZodString;
85
- tasks: z.ZodArray<z.ZodObject<{
86
- id: z.ZodString;
87
- description: z.ZodString;
88
- assignment: z.ZodString;
89
- }, z.core.$strip>>;
90
74
  }, z.core.$strip>, z.ZodObject<{
75
+ id: z.ZodOptional<z.ZodString>;
76
+ description: z.ZodOptional<z.ZodString>;
77
+ assignment: z.ZodString;
91
78
  agent: z.ZodString;
92
- tasks: z.ZodArray<z.ZodObject<{
93
- id: z.ZodString;
94
- description: z.ZodString;
95
- assignment: z.ZodString;
96
- }, z.core.$strip>>;
97
79
  }, z.core.$strip>, z.ZodObject<{
98
80
  agent: z.ZodString;
81
+ context: z.ZodString;
99
82
  tasks: z.ZodArray<z.ZodObject<{
100
- id: z.ZodString;
101
- description: z.ZodString;
83
+ id: z.ZodOptional<z.ZodString>;
84
+ description: z.ZodOptional<z.ZodString>;
102
85
  assignment: z.ZodString;
86
+ isolated: z.ZodOptional<z.ZodBoolean>;
103
87
  }, z.core.$strip>>;
104
88
  }, z.core.$strip>, z.ZodObject<{
105
89
  agent: z.ZodString;
90
+ context: z.ZodString;
106
91
  tasks: z.ZodArray<z.ZodObject<{
107
- id: z.ZodString;
108
- description: z.ZodString;
92
+ id: z.ZodOptional<z.ZodString>;
93
+ description: z.ZodOptional<z.ZodString>;
109
94
  assignment: z.ZodString;
110
95
  }, z.core.$strip>>;
111
96
  }, z.core.$strip>];
112
97
  type DynamicTaskSchema = (typeof ALL_TASK_SCHEMAS)[number];
113
98
  export type TaskSchema = typeof taskSchema;
114
- /** Active task tool parameter schema for the current simple-mode / isolation flags */
99
+ /** Active task tool parameter schema for the current isolation / batch flags */
115
100
  export type TaskToolSchemaInstance = DynamicTaskSchema;
116
101
  export declare function getTaskSchema(options: {
117
102
  isolationEnabled: boolean;
118
- simpleMode: TaskSimpleMode;
103
+ batchEnabled: boolean;
119
104
  }): DynamicTaskSchema;
105
+ /**
106
+ * Runtime params union over both wire shapes. The model sees exactly one shape
107
+ * (`{ agent, context, tasks[] }` when `task.batch` is on, `{ agent, ...item }`
108
+ * otherwise); runtime stays permissive so internal callers and stale
109
+ * transcripts using the flat form keep working under either setting.
110
+ */
120
111
  export interface TaskParams {
121
- agent: string;
112
+ /** Agent type; required. */
113
+ agent?: string;
114
+ /** Stable agent id (flat form); default = generated AdjectiveNoun. */
115
+ id?: string;
116
+ /** UI label (flat form), not seen by the subagent. */
117
+ description?: string;
118
+ /** The work (flat form). */
119
+ assignment?: string;
120
+ /** Batch form (`task.batch`): one subagent per item. */
121
+ tasks?: TaskItem[];
122
+ /** Batch form: shared background prepended to every assignment; required by the batch schema. */
122
123
  context?: string;
123
- schema?: string;
124
- tasks: TaskItem[];
124
+ /** Run in an isolated worktree (flat form; per-item in batch form). */
125
125
  isolated?: boolean;
126
126
  }
127
127
  /** A code review finding reported by the reviewer agent */
@@ -183,6 +183,8 @@ export interface AgentProgress {
183
183
  }>;
184
184
  recentOutput: string[];
185
185
  toolCount: number;
186
+ /** Count of assistant requests (assistant message_end events) across the run. Drives the soft request budget guard. */
187
+ requests: number;
186
188
  /** Cumulative input + output + cacheWrite tokens across all turns. Excludes cacheRead (re-reads cached context every turn, making cumulative sum misleading). */
187
189
  tokens: number;
188
190
  /**
@@ -252,6 +254,8 @@ export interface SingleResult {
252
254
  durationMs: number;
253
255
  /** Cumulative input + output + cacheWrite tokens across all turns. Excludes cacheRead (re-reads cached context every turn, making cumulative sum misleading). */
254
256
  tokens: number;
257
+ /** Count of assistant requests (assistant message_end events) across the run. */
258
+ requests: number;
255
259
  /** Latest per-turn context size at task completion. See `AgentProgress.contextTokens`. */
256
260
  contextTokens?: number;
257
261
  /** Model's context window in tokens, when known. */
@@ -1,5 +1,5 @@
1
1
  import type { HTMLElement } from "linkedom";
2
- import type { ElementHandle } from "puppeteer-core";
2
+ import type { ElementHandle, ImageFormat } from "puppeteer-core";
3
3
  import type { Transport } from "./tab-protocol";
4
4
  declare global {
5
5
  interface Element extends HTMLElement {
@@ -23,6 +23,8 @@ export interface InflightOp {
23
23
  }
24
24
  /** Human-readable label for a screenshot op, used in op tracking + timeout errors. */
25
25
  export declare function describeScreenshot(opts?: ScreenshotOptions): string;
26
+ /** Map an explicit save path's extension to a puppeteer capture format (default png). */
27
+ export declare function imageFormatForPath(filePath: string): ImageFormat;
26
28
  /** Summarize still-running helpers (oldest first) so a cell timeout names what stalled. */
27
29
  export declare function describeInflight(inflight: Map<number, InflightOp>): string;
28
30
  export declare class WorkerCore {
@@ -14,17 +14,6 @@ declare const findSchema: z.ZodObject<{
14
14
  timeout: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
15
15
  }, z.core.$strict>;
16
16
  export type FindToolInput = z.infer<typeof findSchema>;
17
- /**
18
- * Group find matches into a multi-level directory tree so the model doesn't pay
19
- * repeated tokens for shared path prefixes. Single-child directory chains fold
20
- * into one header (`# a/b/c/`), so a common prefix — including an absolute root
21
- * for out-of-cwd results — collapses to a single line. Each level adds one `#`;
22
- * files are listed bare under the deepest directory header that owns them.
23
- *
24
- * Order follows the input (mtime-desc for native glob): a directory appears when
25
- * its first member is emitted, and a node's own files precede its subdirectories.
26
- */
27
- export declare function formatFindGroupedOutput(paths: readonly string[]): string;
28
17
  export interface FindToolDetails {
29
18
  truncation?: TruncationResult;
30
19
  resultLimitReached?: number;
@@ -1,51 +1,3 @@
1
- interface PathTreeNode {
2
- /** Direct file leaves, in first-seen order. */
3
- files: Array<{
4
- name: string;
5
- key: string;
6
- }>;
7
- /** Dedup set for `files` (a glob can surface the same path twice on retry). */
8
- fileNames: Set<string>;
9
- /** Child directories, in first-seen order. */
10
- subdirs: Array<{
11
- name: string;
12
- node: PathTreeNode;
13
- }>;
14
- /** Dedup index for `subdirs`. */
15
- dirIndex: Map<string, PathTreeNode>;
16
- }
17
- export interface PathTreeInput {
18
- /** Path string; absolute, cwd-relative, or url-like. Backslashes are normalized. */
19
- path: string;
20
- /** Whether the leaf itself is a directory (trailing-slash match from find). */
21
- isDir: boolean;
22
- /** Opaque key carried onto file events for section lookup. Defaults to `path`. */
23
- key?: string;
24
- }
25
- /** One node emitted while walking the tree: a folded directory or a file leaf. */
26
- export interface GroupedTreeEvent {
27
- kind: "dir" | "file";
28
- /** 0-based nesting depth (root children are depth 0). */
29
- depth: number;
30
- /** Folded chain for dirs (e.g. `a/b/c`, no trailing slash); basename for files. */
31
- name: string;
32
- /** File key for `kind === "file"`; empty string for directories. */
33
- key: string;
34
- }
35
- /**
36
- * Build a directory tree from a flat list of paths. URL-like entries are kept
37
- * whole as root-level file leaves (they have no meaningful directory structure).
38
- * Absolute paths carry a leading empty segment so they share a common `/` root
39
- * and fold like any other prefix.
40
- */
41
- export declare function buildPathTree(entries: Iterable<PathTreeInput>): PathTreeNode;
42
- /**
43
- * Depth-first walk yielding directory and file events. Directories collapse their
44
- * single-child chains (`a` → `a/b` → `a/b/c`) so a shared prefix becomes one
45
- * header. Each node's direct files are emitted before its subdirectories, keeping
46
- * a file unambiguously attached to the header above it.
47
- */
48
- export declare function walkPathTree(node: PathTreeNode, depth?: number): Generator<GroupedTreeEvent>;
49
1
  /**
50
2
  * One file's contribution to a grouped file output. The header itself is generated
51
3
  * by `formatGroupedFiles` (one `#` per nesting level); use `headerSuffix` to tack
@@ -116,4 +68,3 @@ export declare function classifyGroupedLines(lines: readonly string[], headerBas
116
68
  * indices lets callers slice parallel arrays (raw lines, styled lines, contexts).
117
69
  */
118
70
  export declare function groupLineIndicesByBlank(rawLines: readonly string[]): number[][];
119
- export {};
@@ -13,7 +13,7 @@ import type { LocalProtocolOptions } from "../internal-urls";
13
13
  import type { MCPManager } from "../mcp";
14
14
  import type { MnemopiSessionState } from "../mnemopi/state";
15
15
  import type { PlanModeState } from "../plan-mode/state";
16
- import { type AgentRegistry } from "../registry/agent-registry";
16
+ import type { AgentRegistry } from "../registry/agent-registry";
17
17
  import type { ArtifactManager } from "../session/artifacts";
18
18
  import type { ClientBridge } from "../session/client-bridge";
19
19
  import type { CustomMessage } from "../session/messages";
@@ -220,8 +220,6 @@ export interface ToolSession {
220
220
  recordEvalSubagentUsage?: (output: number) => void;
221
221
  /** Bridge to the connected client (e.g. ACP editor host). Tools should route fs/terminal/permission requests through this when available. */
222
222
  getClientBridge?: () => ClientBridge | undefined;
223
- /** Get compact conversation context for subagents (excludes tool results, system prompts) */
224
- getCompactContext?: () => string;
225
223
  /** Get cached todo phases for this session. */
226
224
  getTodoPhases?: () => TodoPhase[];
227
225
  /** Replace cached todo phases for this session. */
@@ -1,58 +1,62 @@
1
1
  /**
2
- * IRC tool — agent-to-agent messaging.
2
+ * IRC tool — agent-to-agent messaging over the process-global IrcBus.
3
3
  *
4
- * Lets any live agent send a short prose message to any other live agent in
5
- * this process and (optionally) get a prose reply.
6
- *
7
- * Routing happens via the global AgentRegistry. Replies are produced by an
8
- * ephemeral side-channel call (`AgentSession.respondAsBackground`) that
9
- * mirrors `/btw`: the recipient's current model, system prompt, and message
10
- * history are used to compute a reply without persisting it through the
11
- * normal stream path. After the reply is generated, both the incoming
12
- * message and the auto-reply are queued for injection into the recipient's
13
- * persisted history (deferred until the recipient is idle), so the model
14
- * sees the exchange on its next turn.
15
- *
16
- * This avoids the deadlock that arises when the recipient is blocked on a
17
- * long-running tool call: the side-channel call does not depend on the
18
- * recipient's main agent loop being free.
4
+ * `send` is fire-and-forget: the bus routes the message to the recipient
5
+ * (waking idle agents with a real turn, reviving parked ones via the
6
+ * lifecycle manager, injecting a non-interrupting aside into busy ones) and
7
+ * returns delivery receipts immediately. Replies are real turns by the
8
+ * recipient, observed with `wait` (or the `await: true` send sugar). `inbox`
9
+ * drains pending messages; `list` shows every addressable peer.
19
10
  */
20
11
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
12
+ import { type Component } from "@oh-my-pi/pi-tui";
21
13
  import * as z from "zod/v4";
14
+ import type { Settings } from "../config/settings";
15
+ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
16
+ import { type IrcDeliveryReceipt, type IrcMessage } from "../irc/bus";
17
+ import type { Theme } from "../modes/theme/theme";
22
18
  import type { ToolSession } from ".";
19
+ /**
20
+ * IRC availability: there must be someone to chat with. True for every
21
+ * subagent (it always has a parent, and possibly siblings) and for any
22
+ * session that can still spawn subagents through the task tool. Only a
23
+ * top-level session with task spawning unavailable has no peers — no irc.
24
+ */
25
+ export declare function isIrcEnabled(settings: Settings, taskDepth: number): boolean;
23
26
  declare const ircSchema: z.ZodObject<{
24
27
  op: z.ZodEnum<{
28
+ inbox: "inbox";
25
29
  list: "list";
26
30
  send: "send";
31
+ wait: "wait";
27
32
  }>;
28
33
  to: z.ZodOptional<z.ZodString>;
29
34
  message: z.ZodOptional<z.ZodString>;
30
- awaitReply: z.ZodOptional<z.ZodBoolean>;
35
+ replyTo: z.ZodOptional<z.ZodString>;
36
+ await: z.ZodOptional<z.ZodBoolean>;
37
+ from: z.ZodOptional<z.ZodString>;
38
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
39
+ peek: z.ZodOptional<z.ZodBoolean>;
31
40
  }, z.core.$strip>;
32
41
  type IrcParams = z.infer<typeof ircSchema>;
33
- interface IrcReply {
34
- from: string;
35
- text: string;
42
+ interface IrcPeerInfo {
43
+ id: string;
44
+ displayName: string;
45
+ kind: string;
46
+ status: string;
47
+ parentId?: string;
48
+ unread: number;
49
+ lastActivity: number;
36
50
  }
37
51
  export interface IrcDetails {
38
- op: "send" | "list";
52
+ op: "send" | "wait" | "inbox" | "list";
39
53
  from?: string;
40
54
  to?: string;
41
- delivered?: string[];
42
- replies?: IrcReply[];
43
- failed?: Array<{
44
- id: string;
45
- error: string;
46
- }>;
47
- notFound?: string[];
48
- peers?: Array<{
49
- id: string;
50
- displayName: string;
51
- kind: string;
52
- status: string;
53
- parentId?: string;
54
- }>;
55
- channels?: string[];
55
+ receipts?: IrcDeliveryReceipt[];
56
+ /** Message consumed by `wait` / `send await:true`; null when the wait timed out. */
57
+ waited?: IrcMessage | null;
58
+ inbox?: IrcMessage[];
59
+ peers?: IrcPeerInfo[];
56
60
  }
57
61
  export declare class IrcTool implements AgentTool<typeof ircSchema, IrcDetails> {
58
62
  #private;
@@ -60,16 +64,22 @@ export declare class IrcTool implements AgentTool<typeof ircSchema, IrcDetails>
60
64
  readonly name = "irc";
61
65
  readonly approval: "read";
62
66
  readonly label = "IRC";
63
- readonly summary = "Send and receive messages between agents over IRC-like channels";
67
+ readonly summary = "Send and receive messages between agents";
64
68
  readonly description: string;
65
69
  readonly parameters: z.ZodObject<{
66
70
  op: z.ZodEnum<{
71
+ inbox: "inbox";
67
72
  list: "list";
68
73
  send: "send";
74
+ wait: "wait";
69
75
  }>;
70
76
  to: z.ZodOptional<z.ZodString>;
71
77
  message: z.ZodOptional<z.ZodString>;
72
- awaitReply: z.ZodOptional<z.ZodBoolean>;
78
+ replyTo: z.ZodOptional<z.ZodString>;
79
+ await: z.ZodOptional<z.ZodBoolean>;
80
+ from: z.ZodOptional<z.ZodString>;
81
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
82
+ peek: z.ZodOptional<z.ZodBoolean>;
73
83
  }, z.core.$strip>;
74
84
  readonly strict = true;
75
85
  readonly loadMode = "discoverable";
@@ -77,4 +87,32 @@ export declare class IrcTool implements AgentTool<typeof ircSchema, IrcDetails>
77
87
  static createIf(session: ToolSession): IrcTool | null;
78
88
  execute(_toolCallId: string, params: IrcParams, signal?: AbortSignal, _onUpdate?: AgentToolUpdateCallback<IrcDetails>, _context?: AgentToolContext): Promise<AgentToolResult<IrcDetails>>;
79
89
  }
90
+ type IrcRenderArgs = Partial<IrcParams>;
91
+ /**
92
+ * Display-only transcript card for live IRC traffic: `irc:incoming` DMs
93
+ * delivered to this session and `irc:relay` observations of agent↔agent
94
+ * traffic. Shares the tool renderer's glyph + quote-border conventions so
95
+ * cards and `irc` tool output look identical in the transcript.
96
+ */
97
+ export declare function createIrcMessageCard(card: {
98
+ kind: "incoming" | "relay";
99
+ from?: string;
100
+ to?: string;
101
+ body?: string;
102
+ replyTo?: string;
103
+ timestamp?: number;
104
+ }, getExpanded: () => boolean, uiTheme: Theme): Component;
105
+ export declare const ircToolRenderer: {
106
+ inline: boolean;
107
+ mergeCallAndResult: boolean;
108
+ renderCall(args: IrcRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component;
109
+ renderResult(result: {
110
+ content: Array<{
111
+ type: string;
112
+ text?: string;
113
+ }>;
114
+ details?: IrcDetails;
115
+ isError?: boolean;
116
+ }, options: RenderResultOptions, uiTheme: Theme, args?: IrcRenderArgs): Component;
117
+ };
80
118
  export {};
@@ -27,6 +27,13 @@ export interface JobToolDetails {
27
27
  status: CancelStatus;
28
28
  }[];
29
29
  }
30
+ /**
31
+ * A poll snapshot where every watched job is still running and nothing was
32
+ * cancelled — pure "still waiting" noise once a newer poll exists. The TUI
33
+ * keeps such a block un-finalized (displaceable) so a follow-up `job` call
34
+ * replaces it instead of stacking another waiting frame in the transcript.
35
+ */
36
+ export declare function isWaitingPollDetails(details: unknown): boolean;
30
37
  export declare class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
31
38
  #private;
32
39
  private readonly session;
@@ -43,7 +50,6 @@ export declare class JobTool implements AgentTool<typeof jobSchema, JobToolDetai
43
50
  readonly strict = true;
44
51
  readonly loadMode = "discoverable";
45
52
  constructor(session: ToolSession);
46
- static createIf(session: ToolSession): JobTool | null;
47
53
  execute(_toolCallId: string, params: JobParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<JobToolDetails>, _context?: AgentToolContext): Promise<AgentToolResult<JobToolDetails>>;
48
54
  }
49
55
  interface JobRenderArgs {
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "version": "1.0.0",
4
+ "homepage": "https://omp.sh",
4
5
  "type": "module",
5
6
  "omp": {
6
7
  "extensions": [