@oh-my-pi/pi-coding-agent 17.0.2 → 17.0.3

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 (73) hide show
  1. package/CHANGELOG.md +70 -20
  2. package/dist/cli.js +4087 -4108
  3. package/dist/types/config/settings-schema.d.ts +7 -3
  4. package/dist/types/eval/agent-bridge.d.ts +7 -19
  5. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +15 -1
  6. package/dist/types/lsp/client.d.ts +2 -0
  7. package/dist/types/lsp/types.d.ts +3 -0
  8. package/dist/types/mcp/transports/stdio.d.ts +29 -0
  9. package/dist/types/modes/components/agent-hub.d.ts +15 -0
  10. package/dist/types/registry/persisted-agents.d.ts +3 -0
  11. package/dist/types/sdk.d.ts +14 -3
  12. package/dist/types/session/session-entries.d.ts +6 -1
  13. package/dist/types/session/session-manager.d.ts +5 -0
  14. package/dist/types/task/executor.d.ts +26 -1
  15. package/dist/types/task/index.d.ts +1 -1
  16. package/dist/types/task/parallel.d.ts +14 -0
  17. package/dist/types/task/structured-subagent.d.ts +111 -0
  18. package/dist/types/task/types.d.ts +51 -0
  19. package/dist/types/tools/fetch.d.ts +4 -5
  20. package/dist/types/tools/hub/messaging.d.ts +5 -1
  21. package/dist/types/tools/index.d.ts +16 -1
  22. package/dist/types/tools/todo.d.ts +31 -0
  23. package/dist/types/tui/tree-list.d.ts +7 -0
  24. package/dist/types/utils/markit.d.ts +11 -0
  25. package/package.json +12 -12
  26. package/src/cli/file-processor.ts +1 -2
  27. package/src/config/settings-schema.ts +4 -3
  28. package/src/eval/__tests__/agent-bridge.test.ts +133 -47
  29. package/src/eval/__tests__/prelude-agent.test.ts +29 -0
  30. package/src/eval/agent-bridge.ts +104 -477
  31. package/src/eval/jl/prelude.jl +7 -6
  32. package/src/eval/js/shared/prelude.txt +5 -4
  33. package/src/eval/py/prelude.py +11 -39
  34. package/src/eval/rb/prelude.rb +5 -6
  35. package/src/extensibility/legacy-pi-coding-agent-shim.ts +53 -7
  36. package/src/lsp/client.ts +57 -0
  37. package/src/lsp/index.ts +62 -6
  38. package/src/lsp/types.ts +3 -0
  39. package/src/mcp/oauth-flow.ts +20 -0
  40. package/src/mcp/transports/stdio.test.ts +269 -1
  41. package/src/mcp/transports/stdio.ts +152 -1
  42. package/src/modes/components/agent-hub.ts +1 -72
  43. package/src/modes/components/bash-execution.ts +7 -3
  44. package/src/modes/components/eval-execution.ts +3 -1
  45. package/src/modes/interactive-mode.ts +30 -8
  46. package/src/prompts/system/system-prompt.md +1 -1
  47. package/src/prompts/tools/eval.md +5 -2
  48. package/src/prompts/tools/read.md +1 -1
  49. package/src/prompts/tools/task.md +12 -8
  50. package/src/prompts/tools/write.md +1 -1
  51. package/src/registry/persisted-agents.ts +74 -0
  52. package/src/sdk.ts +129 -87
  53. package/src/session/agent-session.ts +75 -21
  54. package/src/session/session-entries.ts +6 -1
  55. package/src/session/session-manager.ts +9 -0
  56. package/src/session/streaming-output.ts +41 -1
  57. package/src/system-prompt.ts +7 -2
  58. package/src/task/executor.ts +99 -21
  59. package/src/task/index.ts +258 -429
  60. package/src/task/parallel.ts +43 -0
  61. package/src/task/persisted-revive.ts +19 -7
  62. package/src/task/structured-subagent.ts +642 -0
  63. package/src/task/types.ts +58 -0
  64. package/src/tools/__tests__/eval-description.test.ts +1 -1
  65. package/src/tools/fetch.ts +28 -105
  66. package/src/tools/hub/messaging.ts +16 -3
  67. package/src/tools/index.ts +47 -14
  68. package/src/tools/path-utils.ts +1 -0
  69. package/src/tools/read.ts +14 -26
  70. package/src/tools/todo.ts +126 -13
  71. package/src/tui/tree-list.ts +39 -0
  72. package/src/utils/markit.ts +12 -0
  73. package/src/utils/zip.ts +16 -1
@@ -5126,14 +5126,18 @@ export declare const SETTINGS_SCHEMA: {
5126
5126
  };
5127
5127
  readonly "providers.kimiApiFormat": {
5128
5128
  readonly type: "enum";
5129
- readonly values: readonly ["openai", "anthropic"];
5130
- readonly default: "anthropic";
5129
+ readonly values: readonly ["auto", "openai", "anthropic"];
5130
+ readonly default: "auto";
5131
5131
  readonly ui: {
5132
5132
  readonly tab: "providers";
5133
5133
  readonly group: "Protocol";
5134
5134
  readonly label: "Kimi API Format";
5135
- readonly description: "API format for Kimi Code provider";
5135
+ readonly description: "API format for Kimi Code provider (auto follows live model metadata)";
5136
5136
  readonly options: readonly [{
5137
+ readonly value: "auto";
5138
+ readonly label: "Auto";
5139
+ readonly description: "Use the model's server-declared protocol";
5140
+ }, {
5137
5141
  readonly value: "openai";
5138
5142
  readonly label: "OpenAI";
5139
5143
  readonly description: "api.kimi.com";
@@ -1,15 +1,10 @@
1
- import { type NestedRepoPatch } from "../task/worktree.js";
1
+ import { type StructuredSubagentSchemaMode } from "../task/structured-subagent.js";
2
+ import type { NestedRepoPatch } from "../task/worktree.js";
2
3
  import type { ToolSession } from "../tools/index.js";
3
4
  import type { JsStatusEvent } from "./js/shared/types.js";
4
5
  import "../tools/review.js";
5
6
  /** Synthetic bridge name reserved for the `agent()` helper across both runtimes. */
6
7
  export declare const EVAL_AGENT_BRIDGE_NAME = "__agent__";
7
- /**
8
- * Hard recursion ceiling for eval-driven subagents. The user setting
9
- * `task.maxRecursionDepth` is honored on top of this — whichever is tighter
10
- * wins, so a maintainer-friendly cap can't get raised by a user setting.
11
- */
12
- export declare const EVAL_AGENT_MAX_DEPTH = 3;
13
8
  export interface EvalAgentBridgeOptions {
14
9
  session: ToolSession;
15
10
  signal?: AbortSignal;
@@ -17,28 +12,21 @@ export interface EvalAgentBridgeOptions {
17
12
  }
18
13
  export interface EvalAgentResult {
19
14
  text: string;
15
+ /** Parsed structured data returned by the child executor. */
16
+ data?: unknown;
20
17
  details: {
21
18
  agent: string;
22
19
  id: string;
23
20
  model?: string | string[];
24
21
  structured: boolean;
25
- /** True iff this run executed inside an isolation worktree. */
22
+ schemaSource?: "caller" | "agent" | "session";
23
+ schemaMode?: StructuredSubagentSchemaMode;
24
+ schemaStatus?: "valid" | "invalid";
26
25
  isolated?: boolean;
27
- /** Captured patch artifact (patch mode) — surfaced regardless of `apply`. */
28
26
  patchPath?: string;
29
- /** Captured branch (branch mode) — surfaced regardless of `apply`. */
30
27
  branchName?: string;
31
- /** Captured nested repository patches — surfaced for isolated `apply=false` manual application. */
32
28
  nestedPatches?: NestedRepoPatch[];
33
- /**
34
- * Tri-state apply outcome for isolated runs:
35
- * - `true` — apply ran (or had nothing to do) and left the repo clean.
36
- * - `false` — apply attempted and failed; artifacts preserved.
37
- * - `null` — caller opted out via `apply=false`.
38
- * Omitted for non-isolated runs.
39
- */
40
29
  changesApplied?: boolean | null;
41
- /** Human-readable isolation apply/merge summary; kept out of schema-backed `text`. */
42
30
  isolationSummary?: string;
43
31
  };
44
32
  }
@@ -11,7 +11,7 @@
11
11
  * entry, while still re-exporting the canonical surface so plugins observe
12
12
  * the same module identity as a direct `@oh-my-pi/pi-coding-agent` import.
13
13
  */
14
- import type { TSchema } from "@oh-my-pi/pi-ai";
14
+ import { type AuthCredential, type TSchema } from "@oh-my-pi/pi-ai";
15
15
  import type { PromptTemplate } from "../config/prompt-templates.js";
16
16
  import { Settings } from "../config/settings.js";
17
17
  import type { CreateAgentSessionOptions, CreateAgentSessionResult, LoadExtensionsResult } from "../sdk.js";
@@ -339,6 +339,20 @@ export type LegacyPiCreateAgentSessionOptions = CreateAgentSessionOptions & {
339
339
  resourceLoader?: ResourceLoader;
340
340
  };
341
341
  export declare function createAgentSession(options?: LegacyPiCreateAgentSessionOptions): Promise<CreateAgentSessionResult>;
342
+ /**
343
+ * Synchronous auth storage surface retained for legacy extensions.
344
+ *
345
+ * Modern OMP auth storage is asynchronous, while older provider extensions
346
+ * call `AuthStorage.create().get()` during module initialization.
347
+ */
348
+ export declare class AuthStorage {
349
+ constructor();
350
+ static create(): AuthStorage;
351
+ get(provider: string): AuthCredential | undefined;
352
+ set(provider: string, credential: AuthCredential): void;
353
+ }
354
+ /** Read the first active credential for a legacy extension provider. */
355
+ export declare function readStoredCredential(provider: string): AuthCredential | undefined;
342
356
  export * from "../index.js";
343
357
  export { formatBytes as formatSize } from "../tools/render-utils.js";
344
358
  export { Type } from "./typebox.js";
@@ -15,6 +15,8 @@ export interface WatchedFileChange {
15
15
  filePath: string;
16
16
  type: FileChangeType;
17
17
  }
18
+ /** Whether the server advertised LSP 3.17 document diagnostic pulls statically or through registration. */
19
+ export declare function supportsDocumentDiagnostics(client: LspClient): boolean;
18
20
  /** Timeout for warmup initialize requests (5 seconds) */
19
21
  export declare const WARMUP_TIMEOUT_MS = 5000;
20
22
  /**
@@ -248,6 +248,7 @@ export interface LspServerCapabilities {
248
248
  referencesProvider?: boolean;
249
249
  documentSymbolProvider?: boolean;
250
250
  workspaceSymbolProvider?: boolean;
251
+ diagnosticProvider?: boolean | Record<string, unknown>;
251
252
  [key: string]: unknown;
252
253
  }
253
254
  export interface LspClient {
@@ -258,6 +259,8 @@ export interface LspClient {
258
259
  requestId: number;
259
260
  diagnostics: Map<string, PublishedDiagnostics>;
260
261
  diagnosticsVersion: number;
262
+ /** Dynamic capability registrations keyed by the server-provided registration ID. */
263
+ dynamicCapabilityRegistrations?: Map<string, string>;
261
264
  openFiles: Map<string, OpenFile>;
262
265
  pendingRequests: Map<number | string, PendingRequest>;
263
266
  messageBuffer: Uint8Array;
@@ -97,6 +97,35 @@ interface FrameSink {
97
97
  * the dead transport is detected by the read loop / request timeout instead.
98
98
  */
99
99
  export declare function writeFrame(stdin: FrameSink, frame: string): boolean;
100
+ /**
101
+ * The subset of `Subprocess` that termination needs. Decoupled from the
102
+ * `Subprocess<In, Out, Err>` stdio generics — `#process`'s pipes are
103
+ * irrelevant to signaling — so tests can exercise it against a plain
104
+ * `Bun.spawn(cmd, { stdio: "ignore" })` child without fighting the generics.
105
+ */
106
+ interface KillableSubprocess {
107
+ readonly pid: number;
108
+ readonly exited: Promise<number>;
109
+ kill(signal?: number | NodeJS.Signals): void;
110
+ }
111
+ /**
112
+ * Terminate an MCP stdio subprocess: SIGTERM (process-group when `detached`
113
+ * on POSIX, direct child otherwise), wait up to `TERM_GRACE_MS` for a
114
+ * cooperative exit, then escalate to SIGKILL — waiting up to `KILL_GRACE_MS`
115
+ * more only when the leader itself hadn't already exited. A detached
116
+ * leader's cooperative exit does not prove the whole process group is gone
117
+ * (a grandchild can outlive it and ignore SIGTERM), so detached transports
118
+ * always fire the group SIGKILL sweep, even after a clean SIGTERM exit.
119
+ * Every step is a no-op-safe signal against an already-exited target, so
120
+ * repeat calls (idempotent `close()`) never throw.
121
+ *
122
+ * Exported so tests can exercise group-signal escalation with an explicit
123
+ * `detached`/`platform` pair: `StdioTransport.connect()` derives `detached`
124
+ * from `resolveStdioSpawnCommand()`, which is tied to the host's real
125
+ * `process.platform`, so a POSIX detached session cannot be reproduced
126
+ * end-to-end through `connect()` on a non-Linux dev/CI host.
127
+ */
128
+ export declare function terminateStdioProcess(proc: KillableSubprocess, detached: boolean, platform?: NodeJS.Platform): Promise<void>;
100
129
  /**
101
130
  * Stdio transport for MCP servers.
102
131
  * Spawns a subprocess and communicates via stdin/stdout.
@@ -1,3 +1,18 @@
1
+ /**
2
+ * Agent Hub overlay component.
3
+ *
4
+ * One overlay, two views:
5
+ * - Table view: every registered agent except Main (Main IS the ambient
6
+ * chat), live from the global AgentRegistry — status, unread irc count,
7
+ * current/last task, last activity. Select with j/k, Enter opens a chat,
8
+ * `r` revives a parked agent, `x` aborts + releases one.
9
+ * - Chat view: per-agent transcript (incremental session-file tail, absorbed
10
+ * from the old session observer overlay) plus an input line. Submitting
11
+ * revives a parked agent, then prompts/steers it; the message lands in the
12
+ * agent's persisted history via the normal prompt path.
13
+ *
14
+ * Replaces the old SessionObserverOverlayComponent (ctrl+s observer).
15
+ */
1
16
  import { type AgentTool } from "@oh-my-pi/pi-agent-core";
2
17
  import { Container, type TUI } from "@oh-my-pi/pi-tui";
3
18
  import type { KeyId } from "../../config/keybindings.js";
@@ -0,0 +1,3 @@
1
+ import { type AgentRegistry } from "./agent-registry.js";
2
+ /** Register persisted subagent and advisor transcripts as parked registry refs. */
3
+ export declare function registerPersistedSubagents(registry: AgentRegistry, sessionFile: string | null | undefined): Promise<void>;
@@ -21,6 +21,7 @@ import { AgentSession, type PlanYolo, type Prewalk } from "./session/agent-sessi
21
21
  import type { AuthStorage } from "./session/auth-storage.js";
22
22
  import { SessionManager } from "./session/session-manager.js";
23
23
  import { type BuildSystemPromptResult } from "./system-prompt.js";
24
+ import type { StructuredSubagentSchemaMode } from "./task/types.js";
24
25
  import { type ConfiguredThinkingLevel } from "./thinking.js";
25
26
  import { BashTool, BUILTIN_TOOLS, createTools, EditTool, EvalTool, GlobTool, GrepTool, HIDDEN_TOOLS, type LspStartupServerInfo, ReadTool, type Tool, type ToolSession, WebSearchTool, WriteTool } from "./tools/index.js";
26
27
  import { EventBus } from "./utils/event-bus.js";
@@ -141,18 +142,28 @@ export interface CreateAgentSessionOptions {
141
142
  promptTemplates?: PromptTemplate[];
142
143
  /** File-based slash commands. Default: discovered from commands/ directories */
143
144
  slashCommands?: FileSlashCommand[];
144
- /** Enable MCP server discovery from .mcp.json files. Default: true */
145
+ /**
146
+ * Enable MCP capabilities. `false` skips MCP discovery and ignores
147
+ * `mcpManager`, preventing process-global or inherited MCP access. Default:
148
+ * true.
149
+ */
145
150
  enableMCP?: boolean;
146
- /** Existing MCP manager to reuse (skips discovery, propagates to toolSession). */
151
+ /** Existing MCP manager to reuse when MCP is enabled (skips discovery, propagates to toolSession). */
147
152
  mcpManager?: MCPManager;
148
153
  /** Enable LSP integration (tool, formatting, diagnostics, warmup). Default: true */
149
154
  enableLsp?: boolean;
155
+ /** Whether this invocation may expose IRC. `false` removes it even for subagents. */
156
+ enableIrc?: boolean;
150
157
  /** Skip subprocess-kernel availability checks and prelude warmup */
151
158
  skipPythonPreflight?: boolean;
152
159
  /** Tool names explicitly requested (enables disabled-by-default tools) */
153
160
  toolNames?: string[];
154
- /** Output schema for structured completion (subagents) */
161
+ /** Limit the session to explicitly supplied tool names, without discovered extras. */
162
+ restrictToolNames?: boolean;
163
+ /** Output schema for structured completion (subagents). */
155
164
  outputSchema?: unknown;
165
+ /** Enforcement policy for {@link outputSchema}; defaults to legacy permissive behavior. */
166
+ outputSchemaMode?: StructuredSubagentSchemaMode;
156
167
  /** Whether to include the yield tool by default */
157
168
  requireYieldTool?: boolean;
158
169
  /** Task recursion depth (for subagent sessions). Default: 0 */
@@ -1,5 +1,6 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
2
  import type { ImageContent, MessageAttribution, ServiceTierByFamily, TextContent } from "@oh-my-pi/pi-ai";
3
+ import type { StructuredSubagentSchemaMode } from "../task/types.js";
3
4
  export declare const CURRENT_SESSION_VERSION = 3;
4
5
  export declare const SESSION_TITLE_SLOT_BYTES = 256;
5
6
  export declare const SESSION_TITLE_SLOT_ENTRY_TYPE = "title";
@@ -142,8 +143,12 @@ export interface SessionInitEntry extends SessionEntryBase {
142
143
  task: string;
143
144
  /** Tools available to the agent */
144
145
  tools: string[];
145
- /** Output schema if structured output was requested */
146
+ /** Output schema if structured output was requested. */
146
147
  outputSchema?: unknown;
148
+ /** Enforcement policy recorded with the output schema for faithful revival. */
149
+ outputSchemaMode?: StructuredSubagentSchemaMode;
150
+ /** Whether revival must retain only the explicitly persisted tool names. */
151
+ restrictToolNames?: boolean;
147
152
  /** Spawn allowlist the subagent ran with ("" = none, "*" = any, else CSV); absent on pre-spawns files. */
148
153
  spawns?: string;
149
154
  /** The agent's `readSummarize` setting (`false` = read summarization disabled); absent uses the session default. */
@@ -1,4 +1,5 @@
1
1
  import type { ImageContent, Message, MessageAttribution, ServiceTierByFamily, TextContent } from "@oh-my-pi/pi-ai";
2
+ import type { StructuredSubagentSchemaMode } from "../task/types.js";
2
3
  import { ArtifactManager } from "./artifacts.js";
3
4
  import { type BlobPutOptions, type BlobPutResult } from "./blob-store.js";
4
5
  import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages.js";
@@ -169,6 +170,8 @@ export declare class SessionManager {
169
170
  task: string;
170
171
  tools: string[];
171
172
  outputSchema?: unknown;
173
+ outputSchemaMode?: StructuredSubagentSchemaMode;
174
+ restrictToolNames?: boolean;
172
175
  spawns?: string;
173
176
  readSummarize?: boolean;
174
177
  }): string;
@@ -293,6 +296,8 @@ export declare class SessionManager {
293
296
  task: string;
294
297
  tools: string[];
295
298
  outputSchema?: unknown;
299
+ outputSchemaMode?: StructuredSubagentSchemaMode;
300
+ restrictToolNames?: boolean;
296
301
  spawns?: string;
297
302
  readSummarize?: boolean;
298
303
  } | null;
@@ -24,7 +24,7 @@ import type { ConfiguredThinkingLevel } from "../thinking.js";
24
24
  import type { ContextFileEntry } from "../tools/index.js";
25
25
  import type { EventBus } from "../utils/event-bus.js";
26
26
  import type { WorkspaceTree } from "../workspace-tree.js";
27
- import { type AgentDefinition, type AgentProgress, type SingleResult, type YieldItem } from "./types.js";
27
+ import { type AgentDefinition, type AgentProgress, type SingleResult, type StructuredSubagentOutput, type StructuredSubagentSchemaMode, type StructuredSubagentSchemaSource, type YieldItem } from "./types.js";
28
28
  export type { YieldItem } from "./types.js";
29
29
  /**
30
30
  * Soft per-agent request budgets (assistant requests per run). Crossing the
@@ -78,7 +78,12 @@ export interface ExecutorOptions {
78
78
  */
79
79
  parentActiveModelPattern?: string;
80
80
  thinkingLevel?: ConfiguredThinkingLevel;
81
+ /** Schema used to validate the final structured completion. */
81
82
  outputSchema?: unknown;
83
+ /** Enforcement policy for {@link outputSchema}; defaults to legacy permissive behavior. */
84
+ outputSchemaMode?: StructuredSubagentSchemaMode;
85
+ /** Origin of the selected schema, preserved in {@link SingleResult.structuredOutput}. */
86
+ outputSchemaSource?: StructuredSubagentSchemaSource;
82
87
  /**
83
88
  * Caller supplied a schema that supersedes the agent's native output prompt.
84
89
  * Eval `agent(..., schema=...)` sets this so built-in agents ignore stale yield labels.
@@ -93,7 +98,20 @@ export interface ExecutorOptions {
93
98
  * watchdog is already suspended for the call's duration.
94
99
  */
95
100
  maxRuntimeMs?: number;
101
+ /** Include IRC only when the invocation policy permits collaboration. */
102
+ enableIrc?: boolean;
96
103
  enableLsp?: boolean;
104
+ /**
105
+ * Enable MCP capabilities for this child. `false` suppresses both inherited
106
+ * MCP proxy tools and session MCP discovery; it never consults the
107
+ * process-global MCP manager. Defaults to `true`.
108
+ */
109
+ enableMCP?: boolean;
110
+ /**
111
+ * Limit the child to its explicit host tool names and the required yield
112
+ * tool, suppressing discovered and always-included capabilities.
113
+ */
114
+ restrictToolNames?: boolean;
97
115
  signal?: AbortSignal;
98
116
  onProgress?: (progress: AgentProgress) => void;
99
117
  /**
@@ -183,6 +201,8 @@ interface FinalizeSubprocessOutputArgs {
183
201
  signalAborted: boolean;
184
202
  yieldItems?: YieldItem[];
185
203
  outputSchema: unknown;
204
+ outputSchemaMode?: StructuredSubagentSchemaMode;
205
+ outputSchemaSource?: StructuredSubagentSchemaSource;
186
206
  lastAssistantText?: string;
187
207
  }
188
208
  interface FinalizeSubprocessOutputResult {
@@ -191,6 +211,7 @@ interface FinalizeSubprocessOutputResult {
191
211
  stderr: string;
192
212
  abortedViaYield: boolean;
193
213
  hasYield: boolean;
214
+ structuredOutput?: StructuredSubagentOutput;
194
215
  }
195
216
  export declare const SUBAGENT_WARNING_SCHEMA_OVERRIDDEN = "SYSTEM WARNING: Subagent exhausted schema-retry budget; result was accepted despite failing the output schema.";
196
217
  export declare const SUBAGENT_WARNING_NULL_YIELD = "SYSTEM WARNING: Subagent called yield with null data.";
@@ -230,6 +251,10 @@ export interface FollowUpTurnOptions {
230
251
  message: string;
231
252
  index?: number;
232
253
  description?: string;
254
+ /** Structured-output state retained from the original invocation. */
255
+ outputSchema?: unknown;
256
+ outputSchemaMode?: StructuredSubagentSchemaMode;
257
+ outputSchemaSource?: StructuredSubagentSchemaSource;
233
258
  signal?: AbortSignal;
234
259
  onProgress?: (progress: AgentProgress) => void;
235
260
  eventBus?: EventBus;
@@ -64,7 +64,7 @@ export declare class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskT
64
64
  readonly formatApprovalDetails: (args: unknown) => string[];
65
65
  readonly label = "Task";
66
66
  readonly summary = "Spawn subagents to complete delegated tasks";
67
- readonly strict = true;
67
+ readonly strict = false;
68
68
  readonly loadMode = "essential";
69
69
  readonly renderResult: typeof renderResult;
70
70
  readonly mergeCallAndResult = true;
@@ -23,6 +23,20 @@ export interface ParallelResult<R> {
23
23
  * @param signal - Optional abort signal to stop scheduling new work
24
24
  */
25
25
  export declare function mapWithConcurrencyLimit<T, R>(items: T[], concurrency: number, fn: (item: T, index: number, signal: AbortSignal) => Promise<R>, signal?: AbortSignal): Promise<ParallelResult<R>>;
26
+ /** Result of a concurrency-limited operation that waits for every launched item. */
27
+ export interface ParallelSettledResult<R> {
28
+ /** Settled results in original input order; absent entries were never launched after cancellation. */
29
+ results: (PromiseSettledResult<R> | undefined)[];
30
+ /** Whether cancellation prevented scheduling all items. */
31
+ aborted: boolean;
32
+ }
33
+ /**
34
+ * Execute items with a concurrency limit without failing fast. Rejections are
35
+ * captured at their input position and already launched siblings always settle
36
+ * before this function returns. Cancellation stops new launches but preserves
37
+ * the settled state of every item that began.
38
+ */
39
+ export declare function mapWithConcurrencyLimitAllSettled<T, R>(items: T[], concurrency: number, fn: (item: T, index: number, signal: AbortSignal) => Promise<R>, signal?: AbortSignal): Promise<ParallelSettledResult<R>>;
26
40
  /**
27
41
  * Simple counting semaphore for limiting concurrency across independently-scheduled async work.
28
42
  *
@@ -0,0 +1,111 @@
1
+ import type { ToolSession } from "../tools/index.js";
2
+ import { type DiscoveryResult } from "./discovery.js";
3
+ import { type AgentDefinition, type AgentProgress, type SingleResult, type StructuredSubagentOutput } from "./types.js";
4
+ /** Validation behavior requested for an effective output schema. */
5
+ export type StructuredSubagentSchemaMode = "permissive" | "strict";
6
+ /** Where an effective output schema came from. */
7
+ export type StructuredSubagentSchemaSource = "caller" | "agent" | "session" | "none";
8
+ /** Final structured completion metadata returned for a schema-bearing run. */
9
+ export type StructuredSubagentSchemaResult = StructuredSubagentOutput;
10
+ /** A schema validation or extraction error attached to structured completion metadata. */
11
+ export type StructuredSubagentSchemaError = NonNullable<StructuredSubagentOutput["error"]>;
12
+ /** A selected schema paired with its source and enforcement mode. */
13
+ export interface StructuredSubagentSchemaResolution {
14
+ schema: unknown;
15
+ source: StructuredSubagentSchemaSource;
16
+ mode: StructuredSubagentSchemaMode;
17
+ outputSchemaOverridesAgent: boolean;
18
+ }
19
+ /** Isolation controls shared by the task and eval surfaces. */
20
+ export interface StructuredSubagentIsolationControls {
21
+ requested?: boolean;
22
+ merge?: "patch" | "branch";
23
+ apply?: boolean;
24
+ }
25
+ /** Identity and presentation metadata supplied by the calling surface. */
26
+ export interface StructuredSubagentIdentity {
27
+ /** A previously reserved output/registry id. */
28
+ id?: string;
29
+ /** Stable user-facing label used when allocating a new id. */
30
+ label?: string;
31
+ }
32
+ /** One normalized child invocation. */
33
+ export interface StructuredSubagentRequest {
34
+ session: ToolSession;
35
+ invocationKind: "task" | "eval";
36
+ assignment: string;
37
+ context?: string;
38
+ agent?: string;
39
+ model?: string | string[];
40
+ /** Presence, rather than truthiness, makes this the highest-priority schema. */
41
+ outputSchema?: unknown;
42
+ schemaMode?: StructuredSubagentSchemaMode;
43
+ identity?: StructuredSubagentIdentity;
44
+ index?: number;
45
+ parentToolCallId?: string;
46
+ detached?: boolean;
47
+ invokedAt?: number;
48
+ acquiredAt?: number;
49
+ isolation?: StructuredSubagentIsolationControls;
50
+ /** The parent agent name forbidden from recursively spawning itself. */
51
+ blockedAgent?: string;
52
+ /** Preserve a completed temporary artifacts directory for an agent:// handle. */
53
+ retainArtifacts?: boolean;
54
+ /** Task UI agents keep live registry references; eval one-shots normally do not. */
55
+ keepAlive?: boolean;
56
+ /** Task subagents share their parent's eval kernel; eval bridge children must not. */
57
+ shareEvalSession?: boolean;
58
+ /** Task frontends may inherit LSP; eval frontends normally set this false. */
59
+ enableLsp?: boolean;
60
+ /** Explicitly pass false for plan mode or invocation kinds that must not use IRC. */
61
+ enableIrc?: boolean;
62
+ /** `0` disables executor wall-clock timeout. Undefined inherits settings. */
63
+ maxRuntimeMs?: number;
64
+ signal?: AbortSignal;
65
+ onProgress?: (progress: AgentProgress) => void;
66
+ }
67
+ /** A normalized preflight result, reusable by tests and adapters. */
68
+ export interface EffectiveSubagentPolicy {
69
+ discovery: DiscoveryResult;
70
+ agentName: string;
71
+ agent: AgentDefinition;
72
+ effectiveAgent: AgentDefinition;
73
+ modelOverride?: string | string[];
74
+ parentActiveModelPattern?: string;
75
+ schema: StructuredSubagentSchemaResolution;
76
+ planMode: boolean;
77
+ isIsolated: boolean;
78
+ mergeMode: "patch" | "branch";
79
+ applyChanges: boolean;
80
+ enableLsp: boolean;
81
+ enableIrc: boolean;
82
+ }
83
+ /** Settled child execution plus data needed by the frontends' own rendering. */
84
+ export interface StructuredSubagentResult {
85
+ result: SingleResult;
86
+ policy: EffectiveSubagentPolicy;
87
+ mergeSummary: string;
88
+ changesApplied: boolean | null;
89
+ artifactsDir: string;
90
+ temporaryArtifacts: boolean;
91
+ }
92
+ /** Machine-readable failure category so adapters can retain their native errors. */
93
+ export declare class StructuredSubagentError extends Error {
94
+ readonly kind: "preflight" | "isolation" | "execution";
95
+ constructor(kind: "preflight" | "isolation" | "execution", message: string, options?: ErrorOptions);
96
+ }
97
+ /**
98
+ * Resolve every policy shared by task and eval before allocating artifacts or
99
+ * dispatching work. Callers translate {@link StructuredSubagentError} into
100
+ * their own wire-level error surface.
101
+ */
102
+ export declare function resolveEffectiveSubagentPolicy(request: StructuredSubagentRequest): Promise<EffectiveSubagentPolicy>;
103
+ /** Reserve a session-global agent id only after preflight has succeeded. */
104
+ export declare function reserveStructuredSubagentId(session: ToolSession, identity: StructuredSubagentIdentity | undefined): Promise<string>;
105
+ /**
106
+ * Execute a validated subagent. Preflight errors occur before any artifact
107
+ * lease or child dispatch; callers keep responsibility for their result text.
108
+ */
109
+ export declare function runStructuredSubagent(request: StructuredSubagentRequest): Promise<StructuredSubagentResult>;
110
+ /** Build the recovery suffix used by adapters after an isolated failure. */
111
+ export declare function buildStructuredSubagentRecoveryHint(result: SingleResult, artifactsDir: string): Promise<string>;
@@ -5,6 +5,32 @@ import type { ConfiguredThinkingLevel } from "../thinking.js";
5
5
  import type { NestedRepoPatch } from "./worktree.js";
6
6
  /** Source of an agent definition */
7
7
  export type AgentSource = "bundled" | "user" | "project";
8
+ /**
9
+ * Enforcement policy for a structured subagent output schema.
10
+ *
11
+ * `permissive` preserves legacy retry-budget overrides; `strict` turns every
12
+ * invalid final payload, including an exhausted retry override, into a failed
13
+ * `schema_violation` result.
14
+ */
15
+ export type StructuredSubagentSchemaMode = "permissive" | "strict";
16
+ /** Origin of the schema selected for a structured subagent invocation. */
17
+ export type StructuredSubagentSchemaSource = "caller" | "agent" | "session" | "none";
18
+ /** Final validation state of a structured subagent invocation. */
19
+ export type StructuredSubagentValidationStatus = "valid" | "invalid" | "unavailable";
20
+ /**
21
+ * Parsed structured completion and its schema-validation metadata.
22
+ *
23
+ * `data` is present whenever a payload could be assembled or parsed, even when
24
+ * strict validation rejects it. `error` explains unavailable or invalid
25
+ * validation without requiring consumers to parse presentation text.
26
+ */
27
+ export interface StructuredSubagentOutput {
28
+ source: StructuredSubagentSchemaSource;
29
+ mode: StructuredSubagentSchemaMode;
30
+ status: StructuredSubagentValidationStatus;
31
+ data?: unknown;
32
+ error?: string;
33
+ }
8
34
  /** Maximum output bytes per agent */
9
35
  export declare const MAX_OUTPUT_BYTES: number;
10
36
  /** Maximum output lines per agent */
@@ -57,6 +83,8 @@ export declare const taskItemSchema: import("arktype/internal/variants/object.ts
57
83
  name?: string | undefined;
58
84
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
59
85
  task: string;
86
+ outputSchema?: unknown;
87
+ schemaMode?: "permissive" | "strict" | undefined;
60
88
  }, {}>;
61
89
  /** Single task item. Fields are optional defensively: args stream in token by token. */
62
90
  export interface TaskItem {
@@ -66,6 +94,10 @@ export interface TaskItem {
66
94
  agent?: string;
67
95
  /** The work; required by the schema. */
68
96
  task?: string;
97
+ /** Caller-provided output schema; its presence overrides the selected agent's schema. */
98
+ outputSchema?: unknown;
99
+ /** Validation behavior for a caller-provided or inherited output schema. */
100
+ schemaMode?: "permissive" | "strict";
69
101
  /** Run this spawn in an isolated worktree (batch form; flat form carries it top-level). */
70
102
  isolated?: boolean;
71
103
  }
@@ -73,23 +105,31 @@ export declare const taskSchema: import("arktype/internal/variants/object.ts").O
73
105
  name?: string | undefined;
74
106
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
75
107
  task: string;
108
+ outputSchema?: unknown;
109
+ schemaMode?: "permissive" | "strict" | undefined;
76
110
  isolated?: boolean | undefined;
77
111
  }, {}>;
78
112
  declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/object.ts").ObjectType<{
79
113
  name?: string | undefined;
80
114
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
81
115
  task: string;
116
+ outputSchema?: unknown;
117
+ schemaMode?: "permissive" | "strict" | undefined;
82
118
  isolated?: boolean | undefined;
83
119
  }, {}>, import("arktype/internal/variants/object.ts").ObjectType<{
84
120
  name?: string | undefined;
85
121
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
86
122
  task: string;
123
+ outputSchema?: unknown;
124
+ schemaMode?: "permissive" | "strict" | undefined;
87
125
  }, {}>, import("arktype/internal/variants/object.ts").ObjectType<{
88
126
  context: string;
89
127
  tasks: {
90
128
  name?: string | undefined;
91
129
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
92
130
  task: string;
131
+ outputSchema?: unknown;
132
+ schemaMode?: "permissive" | "strict" | undefined;
93
133
  isolated?: boolean | undefined;
94
134
  }[];
95
135
  }, {}>, import("arktype/internal/variants/object.ts").ObjectType<{
@@ -98,6 +138,8 @@ declare const ALL_TASK_SCHEMAS: readonly [import("arktype/internal/variants/obje
98
138
  name?: string | undefined;
99
139
  agent: import("arktype/internal/attributes.ts").Default<string, "task">;
100
140
  task: string;
141
+ outputSchema?: unknown;
142
+ schemaMode?: "permissive" | "strict" | undefined;
101
143
  }[];
102
144
  }, {}>];
103
145
  type DynamicTaskSchema = (typeof ALL_TASK_SCHEMAS)[number];
@@ -126,6 +168,10 @@ export interface TaskParams {
126
168
  agent?: string;
127
169
  /** The work (flat form). */
128
170
  task?: string;
171
+ /** Caller-provided output schema; its presence overrides the selected agent's schema. */
172
+ outputSchema?: unknown;
173
+ /** Validation behavior for a caller-provided or inherited output schema. */
174
+ schemaMode?: "permissive" | "strict";
129
175
  /** Batch form (`task.batch`): one subagent per item. */
130
176
  tasks?: TaskItem[];
131
177
  /** Batch form: shared background prepended to every assignment; required by the batch schema. */
@@ -294,6 +340,11 @@ export interface SingleResult {
294
340
  output: string;
295
341
  stderr: string;
296
342
  truncated: boolean;
343
+ /**
344
+ * Parsed structured completion and validation metadata, when this invocation
345
+ * selected an output schema or strict schema mode.
346
+ */
347
+ structuredOutput?: StructuredSubagentOutput;
297
348
  durationMs: number;
298
349
  /** Cumulative input + output + cacheWrite tokens across all turns. Excludes cacheRead (re-reads cached context every turn, making cumulative sum misleading). */
299
350
  tokens: number;
@@ -53,22 +53,21 @@ export interface ReadUrlToolDetails {
53
53
  notes: string[];
54
54
  meta?: OutputMeta;
55
55
  }
56
- interface ReadUrlCacheEntry {
56
+ interface ReadUrlEntry {
57
57
  artifactId?: string;
58
58
  artifactPath?: string;
59
- contentPath?: string;
60
59
  details: ReadUrlToolDetails;
61
60
  image?: FetchImagePayload;
62
61
  output: string;
63
62
  content: string;
64
63
  }
65
- export declare function loadReadUrlCacheEntry(session: ToolSession, params: {
64
+ /** Fetch and render a URL for a read or search operation. */
65
+ export declare function fetchReadUrl(session: ToolSession, params: {
66
66
  path: string;
67
67
  raw?: boolean;
68
68
  }, signal?: AbortSignal, options?: {
69
69
  ensureArtifact?: boolean;
70
- preferCached?: boolean;
71
- }): Promise<ReadUrlCacheEntry>;
70
+ }): Promise<ReadUrlEntry>;
72
71
  /** Materialize rendered URL body text to a local file for tools that require filesystem paths. */
73
72
  export declare function materializeReadUrlToFile(session: ToolSession, params: {
74
73
  path: string;
@@ -32,7 +32,11 @@ export declare function resolveMessageTimeoutMs(settings: Settings, explicit?: n
32
32
  export declare function drainPendingInbox(registry: AgentRegistry, senderId: string, from?: string): IrcMessage | undefined;
33
33
  /** `wait` result carrying a consumed message. */
34
34
  export declare function messageResult(senderId: string, waited: IrcMessage): AgentToolResult<CoordinationDetails>;
35
- export declare function executeList(registry: AgentRegistry, senderId: string): AgentToolResult<CoordinationDetails>;
35
+ /**
36
+ * List every addressable peer, restoring parked refs from disk when a resumed
37
+ * session has no in-memory roster.
38
+ */
39
+ export declare function executeList(registry: AgentRegistry, senderId: string): Promise<AgentToolResult<CoordinationDetails>>;
36
40
  export interface HubSendParams {
37
41
  to?: string;
38
42
  message?: string;