@oh-my-pi/pi-coding-agent 15.10.11 → 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.
- package/CHANGELOG.md +103 -2
- package/dist/cli.js +5790 -5731
- package/dist/types/async/index.d.ts +0 -1
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +5 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +1 -0
- package/dist/types/config/model-resolver.d.ts +18 -0
- package/dist/types/config/settings-schema.d.ts +85 -34
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +3 -0
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/internal-urls/history-protocol.d.ts +14 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/irc/bus.d.ts +66 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/modes/components/agent-hub.d.ts +30 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +10 -4
- package/dist/types/modes/components/custom-editor.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
- package/dist/types/modes/components/welcome.d.ts +3 -9
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +10 -4
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +2 -1
- package/dist/types/modes/types.d.ts +5 -2
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
- package/dist/types/registry/agent-lifecycle.d.ts +51 -0
- package/dist/types/registry/agent-registry.d.ts +16 -5
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +49 -32
- package/dist/types/session/messages.d.ts +2 -4
- package/dist/types/session/session-history-format.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +21 -3
- package/dist/types/session/streaming-output.d.ts +46 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +12 -2
- package/dist/types/task/index.d.ts +13 -6
- package/dist/types/task/output-manager.d.ts +0 -7
- package/dist/types/task/repair-args.d.ts +8 -7
- package/dist/types/task/types.d.ts +63 -51
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/browser/tab-worker.d.ts +3 -1
- package/dist/types/tools/find.d.ts +0 -11
- package/dist/types/tools/grouped-file-output.d.ts +0 -49
- package/dist/types/tools/index.d.ts +7 -3
- package/dist/types/tools/irc.d.ts +76 -38
- package/dist/types/tools/job.d.ts +7 -1
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/examples/extensions/with-deps/package.json +1 -0
- package/package.json +11 -10
- package/scripts/bundle-dist.ts +28 -19
- package/src/async/index.ts +0 -1
- package/src/auto-thinking/classifier.ts +1 -0
- package/src/cli/args.ts +3 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/agentic.ts +230 -115
- package/src/cli/gallery-fixtures/types.ts +5 -0
- package/src/cli-commands.ts +29 -0
- package/src/cli.ts +28 -15
- package/src/commands/launch.ts +4 -0
- package/src/commit/agentic/tools/analyze-file.ts +38 -19
- package/src/commit/model-selection.ts +3 -2
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/keybindings.ts +6 -1
- package/src/config/model-registry.ts +97 -30
- package/src/config/model-resolver.ts +60 -0
- package/src/config/settings-schema.ts +99 -55
- package/src/config/settings.ts +68 -3
- package/src/edit/hashline/execute.ts +39 -2
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/eval/__tests__/agent-bridge.test.ts +5 -3
- package/src/eval/agent-bridge.ts +3 -16
- package/src/eval/completion-bridge.ts +1 -0
- package/src/eval/js/shared/prelude.txt +1 -1
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -1
- package/src/eval/py/kernel.ts +31 -11
- package/src/eval/py/prelude.py +5 -6
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +82 -3
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +38 -13
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +3 -0
- package/src/extensibility/shared-events.ts +2 -2
- package/src/hindsight/bank.ts +17 -2
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/router.ts +3 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/irc/bus.ts +292 -0
- package/src/main.ts +26 -66
- package/src/memories/index.ts +2 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +151 -4
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/{session-observer-overlay.ts → agent-hub.ts} +586 -367
- package/src/modes/components/assistant-message.ts +19 -21
- package/src/modes/components/compaction-summary-message.ts +68 -32
- package/src/modes/components/custom-editor.ts +10 -0
- package/src/modes/components/footer.ts +3 -1
- package/src/modes/components/status-line/component.ts +118 -34
- package/src/modes/components/tool-execution.ts +31 -1
- package/src/modes/components/ttsr-notification.ts +72 -30
- package/src/modes/components/welcome.ts +9 -33
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +65 -0
- package/src/modes/controllers/extension-ui-controller.ts +8 -8
- package/src/modes/controllers/input-controller.ts +19 -2
- package/src/modes/controllers/mcp-command-controller.ts +38 -3
- package/src/modes/controllers/selector-controller.ts +21 -17
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +47 -22
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/theme/theme.ts +18 -5
- package/src/modes/types.ts +5 -5
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +51 -49
- package/src/prompts/system/irc-incoming.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +0 -5
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +2 -2
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/irc.md +29 -19
- package/src/prompts/tools/read.md +2 -2
- package/src/prompts/tools/task-summary.md +5 -16
- package/src/prompts/tools/task.md +38 -29
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +16 -5
- package/src/sdk.ts +37 -10
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +422 -291
- package/src/session/messages.ts +11 -78
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-manager.ts +59 -5
- package/src/session/streaming-output.ts +226 -10
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/system-prompt.ts +14 -0
- package/src/task/executor.ts +851 -461
- package/src/task/index.ts +721 -796
- package/src/task/output-manager.ts +0 -11
- package/src/task/render.ts +148 -63
- package/src/task/repair-args.ts +21 -9
- package/src/task/types.ts +82 -66
- package/src/thinking.ts +7 -0
- package/src/tiny/title-client.ts +34 -5
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/ask.ts +4 -2
- package/src/tools/bash.ts +61 -10
- package/src/tools/browser/tab-worker.ts +26 -7
- package/src/tools/browser.ts +28 -1
- package/src/tools/find.ts +2 -27
- package/src/tools/grouped-file-output.ts +1 -118
- package/src/tools/image-gen.ts +11 -4
- package/src/tools/index.ts +17 -13
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +596 -171
- package/src/tools/job.ts +41 -7
- package/src/tools/read.ts +57 -1
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resolve.ts +4 -1
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
- package/dist/types/async/support.d.ts +0 -2
- package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
- package/dist/types/task/simple-mode.d.ts +0 -8
- package/src/async/support.ts +0 -5
- package/src/task/simple-mode.ts +0 -27
|
@@ -85,15 +85,4 @@ export class AgentOutputManager {
|
|
|
85
85
|
await this.#ensureInitialized();
|
|
86
86
|
return this.#allocateUnique(id);
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Allocate unique IDs for a batch of tasks.
|
|
91
|
-
*
|
|
92
|
-
* @param ids Array of requested IDs
|
|
93
|
-
* @returns Array of unique IDs in same order
|
|
94
|
-
*/
|
|
95
|
-
async allocateBatch(ids: string[]): Promise<string[]> {
|
|
96
|
-
await this.#ensureInitialized();
|
|
97
|
-
return ids.map(id => this.#allocateUnique(id));
|
|
98
|
-
}
|
|
99
88
|
}
|
package/src/task/render.ts
CHANGED
|
@@ -62,6 +62,7 @@ function appendAgentStats(
|
|
|
62
62
|
line: string,
|
|
63
63
|
opts: {
|
|
64
64
|
toolCount?: number;
|
|
65
|
+
requests?: number;
|
|
65
66
|
tokens: number;
|
|
66
67
|
contextTokens?: number;
|
|
67
68
|
contextWindow?: number;
|
|
@@ -74,6 +75,9 @@ function appendAgentStats(
|
|
|
74
75
|
if (opts.toolCount) {
|
|
75
76
|
line += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(opts.toolCount)} ${theme.icon.extensionTool}`)}`;
|
|
76
77
|
}
|
|
78
|
+
if (opts.requests) {
|
|
79
|
+
line += `${theme.sep.dot}${theme.fg("dim", `${formatNumber(opts.requests)} req`)}`;
|
|
80
|
+
}
|
|
77
81
|
// Current per-turn context — match the status line's `<pct>%/<window>` gauge (e.g. `5.1%/1M`).
|
|
78
82
|
if (opts.contextTokens && opts.contextTokens > 0) {
|
|
79
83
|
const ctx =
|
|
@@ -505,65 +509,106 @@ function formatOutputInline(data: unknown, theme: Theme, maxWidth = 80): string
|
|
|
505
509
|
}
|
|
506
510
|
|
|
507
511
|
/**
|
|
508
|
-
* Render the
|
|
509
|
-
*
|
|
510
|
-
* trailing entries may be partially parsed — every field access is defensive.
|
|
512
|
+
* Render the call preview lines for the single spawned agent. The
|
|
513
|
+
* args stream in token by token, so every field access is defensive.
|
|
511
514
|
*/
|
|
512
|
-
function
|
|
513
|
-
|
|
514
|
-
if (items.length === 0) return [];
|
|
515
|
-
|
|
515
|
+
function renderTaskCallLines(args: Partial<TaskParams> | undefined, theme: Theme): string[] {
|
|
516
|
+
if (!args) return [];
|
|
516
517
|
const bullet = theme.fg("dim", "•");
|
|
517
|
-
const
|
|
518
|
-
const truncated = cap < items.length;
|
|
518
|
+
const lines: string[] = [];
|
|
519
519
|
|
|
520
|
+
const rawId = typeof args.id === "string" ? args.id.trim() : "";
|
|
521
|
+
const idLabel = rawId ? formatTaskId(rawId) : "";
|
|
522
|
+
const desc = typeof args.description === "string" ? args.description.trim() : "";
|
|
523
|
+
if (idLabel || desc) {
|
|
524
|
+
let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel || "agent"))}`;
|
|
525
|
+
if (desc) {
|
|
526
|
+
line += `: ${theme.fg("muted", truncateToWidth(replaceTabs(desc), 64))}`;
|
|
527
|
+
}
|
|
528
|
+
lines.push(line);
|
|
529
|
+
}
|
|
530
|
+
lines.push(...renderTaskItemLines(args.tasks, theme));
|
|
531
|
+
return lines;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Render the per-item list (`id` + ui `description`) for a batch call's
|
|
536
|
+
* streaming preview. The args stream in token by token, so the array grows
|
|
537
|
+
* over time and trailing entries may be partially parsed — every field access
|
|
538
|
+
* is defensive.
|
|
539
|
+
*/
|
|
540
|
+
function renderTaskItemLines(tasks: TaskItem[] | undefined, theme: Theme): string[] {
|
|
541
|
+
if (!Array.isArray(tasks) || tasks.length === 0) return [];
|
|
542
|
+
|
|
543
|
+
const bullet = theme.fg("dim", "•");
|
|
544
|
+
const cap = Math.min(tasks.length, 12);
|
|
520
545
|
const lines: string[] = [];
|
|
521
546
|
for (let i = 0; i < cap; i++) {
|
|
522
|
-
const task =
|
|
523
|
-
const rawId = task?.id
|
|
547
|
+
const task = tasks[i] as Partial<TaskItem> | undefined;
|
|
548
|
+
const rawId = typeof task?.id === "string" ? task.id.trim() : "";
|
|
524
549
|
const idLabel = rawId ? formatTaskId(rawId) : `#${i + 1}`;
|
|
525
550
|
let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel))}`;
|
|
526
|
-
const desc = task?.description
|
|
551
|
+
const desc = typeof task?.description === "string" ? task.description.trim() : "";
|
|
527
552
|
if (desc) {
|
|
528
553
|
line += `: ${theme.fg("muted", truncateToWidth(replaceTabs(desc), 64))}`;
|
|
529
554
|
}
|
|
555
|
+
if (task?.isolated === true) {
|
|
556
|
+
line += theme.fg("dim", " [isolated]");
|
|
557
|
+
}
|
|
530
558
|
lines.push(line);
|
|
531
559
|
}
|
|
532
|
-
if (
|
|
533
|
-
lines.push(`${bullet} ${theme.fg("dim", formatMoreItems(
|
|
560
|
+
if (cap < tasks.length) {
|
|
561
|
+
lines.push(`${bullet} ${theme.fg("dim", formatMoreItems(tasks.length - cap, "agent"))}`);
|
|
534
562
|
}
|
|
535
563
|
return lines;
|
|
536
564
|
}
|
|
537
565
|
|
|
538
|
-
/**
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
* the merged result frame so the brief stays visible for the whole task
|
|
542
|
-
* lifecycle — not just until the first progress snapshot replaces the call view.
|
|
543
|
-
*/
|
|
544
|
-
type TaskRenderSection = { lines: readonly string[] };
|
|
545
|
-
type ContextSectionRenderer = (width: number) => TaskRenderSection;
|
|
566
|
+
/** One renderable frame section: optional label, body rows, leading divider. */
|
|
567
|
+
type TaskRenderSection = { label?: string; lines: readonly string[]; separator?: boolean };
|
|
568
|
+
type AssignmentSectionRenderer = (width: number) => TaskRenderSection;
|
|
546
569
|
|
|
547
570
|
// Default output-block layout is: left border + one-cell content inset + right
|
|
548
571
|
// border. Render markdown at that inner width so the output block does not need
|
|
549
|
-
// to rewrap already-rendered
|
|
550
|
-
const
|
|
572
|
+
// to rewrap already-rendered assignment lines.
|
|
573
|
+
const ASSIGNMENT_FRAME_INSET = 3;
|
|
551
574
|
|
|
552
|
-
|
|
553
|
-
|
|
575
|
+
/**
|
|
576
|
+
* Build the assignment section (the markdown brief handed to the subagent).
|
|
577
|
+
* Rendered in both the streaming call preview and the result frame so the
|
|
578
|
+
* brief stays visible for the whole task lifecycle — not just until the first
|
|
579
|
+
* progress snapshot replaces the call view.
|
|
580
|
+
*/
|
|
581
|
+
function createAssignmentSectionRenderer(
|
|
582
|
+
args: Partial<TaskParams> | undefined,
|
|
583
|
+
theme: Theme,
|
|
584
|
+
): AssignmentSectionRenderer | undefined {
|
|
585
|
+
// `renderResult` receives the raw tool args (unlike `renderCall`, which is
|
|
586
|
+
// fed through `repairTaskParams`), so undo any per-field double-encoding
|
|
587
|
+
// here too. The repair is idempotent on already-clean text.
|
|
588
|
+
const assignment = repairDoubleEncodedJsonString(typeof args?.assignment === "string" ? args.assignment : "").trim();
|
|
589
|
+
if (!assignment) return undefined;
|
|
590
|
+
return createMarkdownSectionRenderer(assignment, theme);
|
|
554
591
|
}
|
|
555
592
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
593
|
+
/**
|
|
594
|
+
* Build the shared-context section (the `# Goal / # Constraints` background a
|
|
595
|
+
* batch call hands every subagent). Rendered like the assignment brief so the
|
|
596
|
+
* shared background stays visible for the whole task lifecycle.
|
|
597
|
+
*/
|
|
598
|
+
function createContextSectionRenderer(
|
|
599
|
+
args: Partial<TaskParams> | undefined,
|
|
600
|
+
theme: Theme,
|
|
601
|
+
): AssignmentSectionRenderer | undefined {
|
|
602
|
+
const context = repairDoubleEncodedJsonString(typeof args?.context === "string" ? args.context : "").trim();
|
|
561
603
|
if (!context) return undefined;
|
|
604
|
+
return createMarkdownSectionRenderer(context, theme);
|
|
605
|
+
}
|
|
562
606
|
|
|
563
|
-
|
|
564
|
-
|
|
607
|
+
function createMarkdownSectionRenderer(text: string, theme: Theme): AssignmentSectionRenderer {
|
|
608
|
+
const markdown = new Markdown(text, 0, 0, getMarkdownTheme(), {
|
|
609
|
+
color: line => theme.fg("muted", line),
|
|
565
610
|
});
|
|
566
|
-
return width => ({ lines: markdown.render(
|
|
611
|
+
return width => ({ lines: markdown.render(Math.max(1, width - ASSIGNMENT_FRAME_INSET)) });
|
|
567
612
|
}
|
|
568
613
|
|
|
569
614
|
/**
|
|
@@ -576,21 +621,22 @@ export function renderCall(
|
|
|
576
621
|
): Component {
|
|
577
622
|
const showIsolated = "isolated" in args && args.isolated === true;
|
|
578
623
|
const header = renderStatusLine({ icon: "pending", title: "Task", description: args.agent }, theme);
|
|
579
|
-
const
|
|
624
|
+
const assignmentSection = createAssignmentSectionRenderer(args, theme);
|
|
625
|
+
const contextSection = createContextSectionRenderer(args, theme);
|
|
580
626
|
return framedBlock(theme, width => {
|
|
581
627
|
const sections: Array<{ label?: string; lines: readonly string[]; separator?: boolean }> = [];
|
|
582
628
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
//
|
|
586
|
-
//
|
|
587
|
-
// draws the same agents as progress/result lines, so showing the Tasks
|
|
588
|
-
// section here would just repeat the count the result frame already shows.
|
|
629
|
+
// The call preview only exists to surface the dispatched agent while the
|
|
630
|
+
// args stream in. Once a result snapshot exists, `renderResult` draws the
|
|
631
|
+
// same agent (and the assignment brief) itself, so showing it here would
|
|
632
|
+
// repeat what the result frame already shows.
|
|
589
633
|
if (!options.renderContext?.hasResult) {
|
|
590
634
|
sections.push({
|
|
591
635
|
separator: true,
|
|
592
|
-
lines:
|
|
636
|
+
lines: renderTaskCallLines(args, theme),
|
|
593
637
|
});
|
|
638
|
+
if (contextSection) sections.push(contextSection(width));
|
|
639
|
+
if (assignmentSection) sections.push(assignmentSection(width));
|
|
594
640
|
}
|
|
595
641
|
|
|
596
642
|
return {
|
|
@@ -631,8 +677,12 @@ function renderAgentProgress(
|
|
|
631
677
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
632
678
|
const indent = prefix ? `${prefix} ` : "";
|
|
633
679
|
let statusLine: string;
|
|
634
|
-
if (progress.status === "running") {
|
|
635
|
-
|
|
680
|
+
if (progress.status === "running" || progress.status === "pending") {
|
|
681
|
+
// Live (or queued) agents shimmer their description so the row reads as
|
|
682
|
+
// in-flight even after the block freezes — the async spawn result keeps
|
|
683
|
+
// the agent on "pending" while the detached job runs.
|
|
684
|
+
const bullet =
|
|
685
|
+
progress.status === "running" ? theme.styledSymbol("status.done", "text") : theme.fg(iconColor, icon);
|
|
636
686
|
const name = theme.fg("accent", description ? theme.bold(displayId) : displayId);
|
|
637
687
|
statusLine = `${indent}${bullet} ${name}`;
|
|
638
688
|
if (description) {
|
|
@@ -945,6 +995,7 @@ function renderAgentResult(
|
|
|
945
995
|
statusLine,
|
|
946
996
|
{
|
|
947
997
|
tokens: result.tokens,
|
|
998
|
+
requests: result.requests,
|
|
948
999
|
contextTokens: result.contextTokens,
|
|
949
1000
|
contextWindow: result.contextWindow,
|
|
950
1001
|
cost: result.usage?.cost.total ?? 0,
|
|
@@ -1072,6 +1123,32 @@ function renderAgentResult(
|
|
|
1072
1123
|
return lines;
|
|
1073
1124
|
}
|
|
1074
1125
|
|
|
1126
|
+
/**
|
|
1127
|
+
* Order live progress entries so finished agents render first — sorted by
|
|
1128
|
+
* runtime ascending, matching {@link orderResultsForDisplay} — while
|
|
1129
|
+
* unfinished (pending/running) ones stay pinned at the bottom in dispatch
|
|
1130
|
+
* order. Because a finished agent's runtime is fixed, finalization renders
|
|
1131
|
+
* the same order and rows never reshuffle.
|
|
1132
|
+
*/
|
|
1133
|
+
function orderProgressForDisplay(progress: readonly AgentProgress[]): AgentProgress[] {
|
|
1134
|
+
const finished: AgentProgress[] = [];
|
|
1135
|
+
const unfinished: AgentProgress[] = [];
|
|
1136
|
+
for (const p of progress) {
|
|
1137
|
+
(p.status === "pending" || p.status === "running" ? unfinished : finished).push(p);
|
|
1138
|
+
}
|
|
1139
|
+
finished.sort((a, b) => a.durationMs - b.durationMs || a.index - b.index);
|
|
1140
|
+
return finished.concat(unfinished);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/**
|
|
1144
|
+
* Order finalized results by runtime ascending (tie-break: dispatch index) so
|
|
1145
|
+
* the finalized list matches the live-progress order produced by
|
|
1146
|
+
* {@link orderProgressForDisplay}.
|
|
1147
|
+
*/
|
|
1148
|
+
function orderResultsForDisplay(results: readonly SingleResult[]): SingleResult[] {
|
|
1149
|
+
return [...results].sort((a, b) => a.durationMs - b.durationMs || a.index - b.index);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1075
1152
|
/**
|
|
1076
1153
|
* Render the tool result.
|
|
1077
1154
|
*/
|
|
@@ -1083,25 +1160,28 @@ export function renderResult(
|
|
|
1083
1160
|
): Component {
|
|
1084
1161
|
const fallbackText = result.content.find(c => c.type === "text")?.text ?? "";
|
|
1085
1162
|
const details = result.details;
|
|
1086
|
-
const
|
|
1163
|
+
const agentLabel = args?.agent?.trim() || undefined;
|
|
1164
|
+
const assignmentSection = createAssignmentSectionRenderer(args, theme);
|
|
1165
|
+
const contextSection = createContextSectionRenderer(args, theme);
|
|
1087
1166
|
|
|
1088
1167
|
if (!details) {
|
|
1089
1168
|
const text = result.content.find(c => c.type === "text")?.text || "";
|
|
1090
1169
|
const errored = result.isError === true;
|
|
1091
1170
|
const header = errored
|
|
1092
|
-
? renderStatusLine({ icon: "error", title: "Task", description:
|
|
1171
|
+
? renderStatusLine({ icon: "error", title: "Task", description: agentLabel }, theme)
|
|
1093
1172
|
: renderStatusLine(
|
|
1094
1173
|
{
|
|
1095
1174
|
iconOverride: theme.styledSymbol("status.done", "accent"),
|
|
1096
1175
|
title: "Task",
|
|
1097
|
-
description:
|
|
1176
|
+
description: agentLabel,
|
|
1098
1177
|
},
|
|
1099
1178
|
theme,
|
|
1100
1179
|
);
|
|
1101
1180
|
return framedBlock(theme, width => ({
|
|
1102
1181
|
header,
|
|
1103
1182
|
sections: [
|
|
1104
|
-
...(
|
|
1183
|
+
...(contextSection ? [contextSection(width)] : []),
|
|
1184
|
+
...(assignmentSection ? [assignmentSection(width)] : []),
|
|
1105
1185
|
...(text ? [{ separator: true, lines: [theme.fg("dim", truncateToWidth(text, width))] }] : []),
|
|
1106
1186
|
],
|
|
1107
1187
|
state: errored ? "error" : "success",
|
|
@@ -1117,12 +1197,10 @@ export function renderResult(
|
|
|
1117
1197
|
const isError = aborted || failed;
|
|
1118
1198
|
const agentCount = hasResults ? details.results.length : (details.progress?.length ?? 0);
|
|
1119
1199
|
const icon: ToolUIStatus = options.isPartial ? "running" : isError ? "error" : mergeFailed ? "warning" : "success";
|
|
1120
|
-
// Surface the dispatched agent type (e.g. `Reviewer`) alongside the count
|
|
1121
|
-
// the header reads `Task
|
|
1122
|
-
// single `agent` type (top-level param), so one label covers the whole batch.
|
|
1123
|
-
const agentName = args?.agent?.trim();
|
|
1200
|
+
// Surface the dispatched agent type (e.g. `Reviewer`) alongside the count
|
|
1201
|
+
// so the header reads `Task 1 agent: Reviewer`.
|
|
1124
1202
|
const countLabel = agentCount > 0 ? `${agentCount} ${agentCount === 1 ? "agent" : "agents"}` : undefined;
|
|
1125
|
-
const metaLabel = countLabel ? (
|
|
1203
|
+
const metaLabel = countLabel ? (agentLabel ? `${countLabel}: ${agentLabel}` : countLabel) : agentLabel;
|
|
1126
1204
|
const header = renderStatusLine(
|
|
1127
1205
|
{
|
|
1128
1206
|
icon: icon === "success" ? undefined : icon,
|
|
@@ -1140,11 +1218,11 @@ export function renderResult(
|
|
|
1140
1218
|
const shouldRenderProgress =
|
|
1141
1219
|
Boolean(details.progress && details.progress.length > 0) && (isPartial || details.results.length === 0);
|
|
1142
1220
|
if (shouldRenderProgress && details.progress) {
|
|
1143
|
-
details.progress.forEach(progress => {
|
|
1221
|
+
orderProgressForDisplay(details.progress).forEach(progress => {
|
|
1144
1222
|
lines.push(...renderAgentProgress(progress, "", " ", expanded, theme, spinnerFrame));
|
|
1145
1223
|
});
|
|
1146
1224
|
} else if (details.results && details.results.length > 0) {
|
|
1147
|
-
details.results.forEach(res => {
|
|
1225
|
+
orderResultsForDisplay(details.results).forEach(res => {
|
|
1148
1226
|
lines.push(...renderAgentResult(res, "", " ", expanded, theme));
|
|
1149
1227
|
});
|
|
1150
1228
|
|
|
@@ -1157,6 +1235,8 @@ export function renderResult(
|
|
|
1157
1235
|
if (successCount > 0) summaryParts.push(theme.fg("success", `${successCount} succeeded`));
|
|
1158
1236
|
if (mergeFailedCount > 0) summaryParts.push(theme.fg("warning", `${mergeFailedCount} merge failed`));
|
|
1159
1237
|
if (failCount > 0) summaryParts.push(theme.fg("error", `${failCount} failed`));
|
|
1238
|
+
const totalRequests = details.results.reduce((sum, r) => sum + (r.requests ?? 0), 0);
|
|
1239
|
+
if (totalRequests > 0) summaryParts.push(theme.fg("dim", `${formatNumber(totalRequests)} req`));
|
|
1160
1240
|
summaryParts.push(theme.fg("dim", formatDuration(details.totalDurationMs)));
|
|
1161
1241
|
// Wrap the run summary in the theme's bracket glyphs (dim chrome, colored
|
|
1162
1242
|
// counts) to match the bash tool's `[Wall: … | Exit: …]` footer.
|
|
@@ -1175,7 +1255,8 @@ export function renderResult(
|
|
|
1175
1255
|
return {
|
|
1176
1256
|
header,
|
|
1177
1257
|
sections: [
|
|
1178
|
-
...(
|
|
1258
|
+
...(contextSection ? [contextSection(width)] : []),
|
|
1259
|
+
...(assignmentSection ? [assignmentSection(width)] : []),
|
|
1179
1260
|
{ separator: true, lines: [theme.fg("dim", truncateToWidth(text, width))] },
|
|
1180
1261
|
],
|
|
1181
1262
|
state,
|
|
@@ -1205,7 +1286,8 @@ export function renderResult(
|
|
|
1205
1286
|
return {
|
|
1206
1287
|
header,
|
|
1207
1288
|
sections: [
|
|
1208
|
-
...(
|
|
1289
|
+
...(contextSection ? [contextSection(width)] : []),
|
|
1290
|
+
...(assignmentSection ? [assignmentSection(width)] : []),
|
|
1209
1291
|
...(lines.length > 0 ? [{ separator: true, lines }] : []),
|
|
1210
1292
|
],
|
|
1211
1293
|
state,
|
|
@@ -1238,8 +1320,9 @@ function renderNestedTaskResults(detailsList: TaskToolDetails[], expanded: boole
|
|
|
1238
1320
|
const lines: string[] = [];
|
|
1239
1321
|
for (const details of detailsList) {
|
|
1240
1322
|
if (!details.results || details.results.length === 0) continue;
|
|
1241
|
-
details.results
|
|
1242
|
-
|
|
1323
|
+
const ordered = orderResultsForDisplay(details.results);
|
|
1324
|
+
ordered.forEach((result, index) => {
|
|
1325
|
+
const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
|
|
1243
1326
|
lines.push(...renderAgentResult(result, prefix, continuePrefix, expanded, theme));
|
|
1244
1327
|
});
|
|
1245
1328
|
}
|
|
@@ -1261,16 +1344,18 @@ function renderNestedTaskTree(
|
|
|
1261
1344
|
for (const details of detailsList) {
|
|
1262
1345
|
const hasResults = Boolean(details.results && details.results.length > 0);
|
|
1263
1346
|
if (hasResults) {
|
|
1264
|
-
details.results
|
|
1265
|
-
|
|
1347
|
+
const ordered = orderResultsForDisplay(details.results);
|
|
1348
|
+
ordered.forEach((result, index) => {
|
|
1349
|
+
const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
|
|
1266
1350
|
lines.push(...renderAgentResult(result, prefix, continuePrefix, expanded, theme));
|
|
1267
1351
|
});
|
|
1268
1352
|
continue;
|
|
1269
1353
|
}
|
|
1270
1354
|
const inflight = details.progress;
|
|
1271
1355
|
if (inflight && inflight.length > 0) {
|
|
1272
|
-
|
|
1273
|
-
|
|
1356
|
+
const ordered = orderProgressForDisplay(inflight);
|
|
1357
|
+
ordered.forEach((prog, index) => {
|
|
1358
|
+
const { prefix, continuePrefix } = nestedMarkers(index === ordered.length - 1, theme);
|
|
1274
1359
|
lines.push(...renderAgentProgress(prog, prefix, continuePrefix, expanded, theme, spinnerFrame));
|
|
1275
1360
|
});
|
|
1276
1361
|
}
|
package/src/task/repair-args.ts
CHANGED
|
@@ -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
|
|
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
|
-
* (`
|
|
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
|
*/
|
|
@@ -90,15 +90,20 @@ function repairTaskItem(task: TaskItem): TaskItem {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Repair double-encoded prose in task-tool params (`
|
|
94
|
-
* `
|
|
95
|
-
* so callers can cheaply skip
|
|
96
|
-
* (missing/undefined fields,
|
|
97
|
-
* path as well as on
|
|
93
|
+
* Repair double-encoded prose in task-tool params (`assignment`,
|
|
94
|
+
* `description`, shared `context`, and each batch task item's prose fields).
|
|
95
|
+
* Returns the same reference when nothing changed so callers can cheaply skip
|
|
96
|
+
* work. Defensive against partially-streamed args (missing/undefined fields,
|
|
97
|
+
* partial task arrays) so it is safe on the render path as well as on
|
|
98
|
+
* execution.
|
|
98
99
|
*/
|
|
99
100
|
export function repairTaskParams(params: TaskParams): TaskParams {
|
|
100
101
|
if (params === null || typeof params !== "object") return params;
|
|
101
102
|
|
|
103
|
+
const assignment =
|
|
104
|
+
typeof params.assignment === "string" ? repairDoubleEncodedJsonString(params.assignment) : params.assignment;
|
|
105
|
+
const description =
|
|
106
|
+
typeof params.description === "string" ? repairDoubleEncodedJsonString(params.description) : params.description;
|
|
102
107
|
const context = typeof params.context === "string" ? repairDoubleEncodedJsonString(params.context) : params.context;
|
|
103
108
|
|
|
104
109
|
let tasks = params.tasks;
|
|
@@ -112,6 +117,13 @@ export function repairTaskParams(params: TaskParams): TaskParams {
|
|
|
112
117
|
if (changed) tasks = repaired;
|
|
113
118
|
}
|
|
114
119
|
|
|
115
|
-
if (
|
|
116
|
-
|
|
120
|
+
if (
|
|
121
|
+
assignment === params.assignment &&
|
|
122
|
+
description === params.description &&
|
|
123
|
+
context === params.context &&
|
|
124
|
+
tasks === params.tasks
|
|
125
|
+
) {
|
|
126
|
+
return params;
|
|
127
|
+
}
|
|
128
|
+
return { ...params, assignment, description, context, tasks };
|
|
117
129
|
}
|
package/src/task/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
|
2
2
|
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
4
4
|
import * as z from "zod/v4";
|
|
5
|
-
import {
|
|
5
|
+
import type { AgentSessionEvent } from "../session/agent-session";
|
|
6
6
|
import type { NestedRepoPatch } from "./worktree";
|
|
7
7
|
|
|
8
8
|
/** Source of an agent definition */
|
|
@@ -41,11 +41,18 @@ export interface SubagentProgressPayload {
|
|
|
41
41
|
agent: string;
|
|
42
42
|
agentSource: AgentSource;
|
|
43
43
|
task: string;
|
|
44
|
+
parentToolCallId?: string;
|
|
44
45
|
assignment?: string;
|
|
45
46
|
progress: AgentProgress;
|
|
46
47
|
sessionFile?: string;
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
/** Payload emitted on TASK_SUBAGENT_EVENT_CHANNEL */
|
|
51
|
+
export interface SubagentEventPayload {
|
|
52
|
+
id: string;
|
|
53
|
+
event: AgentSessionEvent;
|
|
54
|
+
}
|
|
55
|
+
|
|
49
56
|
/** Payload emitted on TASK_SUBAGENT_LIFECYCLE_CHANNEL */
|
|
50
57
|
export interface SubagentLifecyclePayload {
|
|
51
58
|
id: string;
|
|
@@ -54,87 +61,92 @@ export interface SubagentLifecyclePayload {
|
|
|
54
61
|
description?: string;
|
|
55
62
|
status: "started" | "completed" | "failed" | "aborted";
|
|
56
63
|
sessionFile?: string;
|
|
64
|
+
parentToolCallId?: string;
|
|
57
65
|
index: number;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
if (contextEnabled) {
|
|
82
|
-
schema = schema.extend({
|
|
83
|
-
context: z.string().optional().describe("shared background prepended to each assignment"),
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (customSchemaEnabled) {
|
|
88
|
-
schema = schema.extend({
|
|
89
|
-
schema: z.string().optional().describe("jtd schema for expected response shape"),
|
|
90
|
-
});
|
|
91
|
-
}
|
|
68
|
+
/**
|
|
69
|
+
* One unit of work. The single-spawn schema is `{ agent, ...taskItemSchema }`;
|
|
70
|
+
* the batch schema (`task.batch`) is `{ agent, context, tasks: taskItemSchema[] }`.
|
|
71
|
+
* When task isolation is enabled, `isolated` joins the item shape (per-item in
|
|
72
|
+
* batch form, top-level in the flat form via the spread).
|
|
73
|
+
*/
|
|
74
|
+
const taskItemShape = {
|
|
75
|
+
id: z.string().max(48).optional().describe("stable agent id; default generated"),
|
|
76
|
+
description: z.string().optional().describe("ui label, not seen by subagent"),
|
|
77
|
+
assignment: z.string().describe("the work; self-contained instructions"),
|
|
78
|
+
};
|
|
79
|
+
const isolatedShape = {
|
|
80
|
+
isolated: z.boolean().optional().describe("run in isolated env; returns patches"),
|
|
81
|
+
};
|
|
82
|
+
const agentShape = {
|
|
83
|
+
agent: z.string().describe("agent type to spawn"),
|
|
84
|
+
};
|
|
85
|
+
const contextShape = {
|
|
86
|
+
context: z.string().describe("shared background prepended to each assignment"),
|
|
87
|
+
};
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
isolated: z.boolean().optional().describe("run in isolated env; returns patches"),
|
|
96
|
-
});
|
|
97
|
-
}
|
|
89
|
+
export const taskItemSchema = z.object(taskItemShape);
|
|
90
|
+
const taskItemSchemaIsolated = z.object({ ...taskItemShape, ...isolatedShape });
|
|
98
91
|
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
/** Single task item. Fields are optional defensively: args stream in token by token. */
|
|
93
|
+
export interface TaskItem {
|
|
94
|
+
/** Stable agent id; default = generated AdjectiveNoun. */
|
|
95
|
+
id?: string;
|
|
96
|
+
/** UI label, not seen by the subagent. */
|
|
97
|
+
description?: string;
|
|
98
|
+
/** The work; required by the schema. */
|
|
99
|
+
assignment?: string;
|
|
100
|
+
/** Run this spawn in an isolated worktree (batch form; flat form carries it top-level). */
|
|
101
|
+
isolated?: boolean;
|
|
102
|
+
}
|
|
101
103
|
|
|
102
|
-
export const taskSchema =
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
] as const;
|
|
104
|
+
export const taskSchema = z.object({ ...agentShape, ...taskItemShape, ...isolatedShape });
|
|
105
|
+
const taskSchemaNoIsolation = z.object({ ...agentShape, ...taskItemShape });
|
|
106
|
+
const taskSchemaBatch = z.object({
|
|
107
|
+
...agentShape,
|
|
108
|
+
...contextShape,
|
|
109
|
+
tasks: z.array(taskItemSchemaIsolated).describe("tasks to spawn; one subagent per item"),
|
|
110
|
+
});
|
|
111
|
+
const taskSchemaBatchNoIsolation = z.object({
|
|
112
|
+
...agentShape,
|
|
113
|
+
...contextShape,
|
|
114
|
+
tasks: z.array(taskItemSchema).describe("tasks to spawn; one subagent per item"),
|
|
115
|
+
});
|
|
116
|
+
const ALL_TASK_SCHEMAS = [taskSchema, taskSchemaNoIsolation, taskSchemaBatch, taskSchemaBatchNoIsolation] as const;
|
|
116
117
|
|
|
117
118
|
type DynamicTaskSchema = (typeof ALL_TASK_SCHEMAS)[number];
|
|
118
119
|
export type TaskSchema = typeof taskSchema;
|
|
119
|
-
/** Active task tool parameter schema for the current
|
|
120
|
+
/** Active task tool parameter schema for the current isolation / batch flags */
|
|
120
121
|
export type TaskToolSchemaInstance = DynamicTaskSchema;
|
|
121
122
|
|
|
122
|
-
export function getTaskSchema(options: { isolationEnabled: boolean;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return options.isolationEnabled ? taskSchemaSchemaFree : taskSchemaSchemaFreeNoIsolation;
|
|
126
|
-
case "independent":
|
|
127
|
-
return options.isolationEnabled ? taskSchemaIndependent : taskSchemaIndependentNoIsolation;
|
|
128
|
-
default:
|
|
129
|
-
return options.isolationEnabled ? taskSchema : taskSchemaNoIsolation;
|
|
123
|
+
export function getTaskSchema(options: { isolationEnabled: boolean; batchEnabled: boolean }): DynamicTaskSchema {
|
|
124
|
+
if (options.batchEnabled) {
|
|
125
|
+
return options.isolationEnabled ? taskSchemaBatch : taskSchemaBatchNoIsolation;
|
|
130
126
|
}
|
|
127
|
+
return options.isolationEnabled ? taskSchema : taskSchemaNoIsolation;
|
|
131
128
|
}
|
|
132
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Runtime params union over both wire shapes. The model sees exactly one shape
|
|
132
|
+
* (`{ agent, context, tasks[] }` when `task.batch` is on, `{ agent, ...item }`
|
|
133
|
+
* otherwise); runtime stays permissive so internal callers and stale
|
|
134
|
+
* transcripts using the flat form keep working under either setting.
|
|
135
|
+
*/
|
|
133
136
|
export interface TaskParams {
|
|
134
|
-
|
|
137
|
+
/** Agent type; required. */
|
|
138
|
+
agent?: string;
|
|
139
|
+
/** Stable agent id (flat form); default = generated AdjectiveNoun. */
|
|
140
|
+
id?: string;
|
|
141
|
+
/** UI label (flat form), not seen by the subagent. */
|
|
142
|
+
description?: string;
|
|
143
|
+
/** The work (flat form). */
|
|
144
|
+
assignment?: string;
|
|
145
|
+
/** Batch form (`task.batch`): one subagent per item. */
|
|
146
|
+
tasks?: TaskItem[];
|
|
147
|
+
/** Batch form: shared background prepended to every assignment; required by the batch schema. */
|
|
135
148
|
context?: string;
|
|
136
|
-
|
|
137
|
-
tasks: TaskItem[];
|
|
149
|
+
/** Run in an isolated worktree (flat form; per-item in batch form). */
|
|
138
150
|
isolated?: boolean;
|
|
139
151
|
}
|
|
140
152
|
|
|
@@ -197,6 +209,8 @@ export interface AgentProgress {
|
|
|
197
209
|
recentTools: Array<{ tool: string; args: string; endMs: number }>;
|
|
198
210
|
recentOutput: string[];
|
|
199
211
|
toolCount: number;
|
|
212
|
+
/** Count of assistant requests (assistant message_end events) across the run. Drives the soft request budget guard. */
|
|
213
|
+
requests: number;
|
|
200
214
|
/** Cumulative input + output + cacheWrite tokens across all turns. Excludes cacheRead (re-reads cached context every turn, making cumulative sum misleading). */
|
|
201
215
|
tokens: number;
|
|
202
216
|
/**
|
|
@@ -267,6 +281,8 @@ export interface SingleResult {
|
|
|
267
281
|
durationMs: number;
|
|
268
282
|
/** Cumulative input + output + cacheWrite tokens across all turns. Excludes cacheRead (re-reads cached context every turn, making cumulative sum misleading). */
|
|
269
283
|
tokens: number;
|
|
284
|
+
/** Count of assistant requests (assistant message_end events) across the run. */
|
|
285
|
+
requests: number;
|
|
270
286
|
/** Latest per-turn context size at task completion. See `AgentProgress.contextTokens`. */
|
|
271
287
|
contextTokens?: number;
|
|
272
288
|
/** Model's context window in tokens, when known. */
|