feat(coding-agent/task): added optional assignment field to track raw task text separately from templates
- Added optional `assignment` field to task result and progress interfaces to track raw per-task assignment text separately from full templated task. - Updated task rendering to display assignment text instead of full task template when available, improving clarity of task display. - Modified task section rendering to show trimmed assignment text with fallback to task field if assignment is not available. - Propagated assignment field through task executor, template renderer, and result objects to maintain consistency across task processing pipeline.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Added `assignment` field to task progress and result objects to track the raw per-task assignment text separately from the full templated task
|
||||
- Added `details` field to todo items for storing implementation specifics, file paths, and edge cases (shown only when task is active)
|
||||
- Added support for multi-line details in todo items with automatic indentation in interactive and reminder displays
|
||||
- Added `todo.eager` setting to automatically create a comprehensive todo list after the first user message
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated task rendering to display assignment text instead of full task template when available, reducing noise in progress and result displays
|
||||
- Modified task section rendering to show trimmed assignment text without stripping context blocks, simplifying the display logic
|
||||
- Updated todo item display to show `details` field indented below active tasks in both interactive mode and todo reminder component
|
||||
- Modified tool choice resolution to support per-turn tool choice overrides via `consumeNextToolChoiceOverride()`
|
||||
- Updated tool documentation to clarify that `path` parameter accepts files, directories, glob patterns, or comma/space-separated path lists
|
||||
|
||||
@@ -123,6 +123,7 @@ export interface ExecutorOptions {
|
||||
worktree?: string;
|
||||
agent: AgentDefinition;
|
||||
task: string;
|
||||
assignment?: string;
|
||||
description?: string;
|
||||
index: number;
|
||||
id: string;
|
||||
@@ -442,6 +443,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
cwd,
|
||||
agent,
|
||||
task,
|
||||
assignment,
|
||||
index,
|
||||
id,
|
||||
worktree,
|
||||
@@ -462,6 +464,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
agentSource: agent.source,
|
||||
status: "running",
|
||||
task,
|
||||
assignment,
|
||||
description: options.description,
|
||||
lastIntent: undefined,
|
||||
recentTools: [],
|
||||
@@ -480,6 +483,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
agent: agent.name,
|
||||
agentSource: agent.source,
|
||||
task,
|
||||
assignment,
|
||||
description: options.description,
|
||||
exitCode: 1,
|
||||
output: "",
|
||||
@@ -622,6 +626,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
agent: agent.name,
|
||||
agentSource: agent.source,
|
||||
task,
|
||||
assignment,
|
||||
progress: { ...progress },
|
||||
});
|
||||
}
|
||||
@@ -711,6 +716,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
agent: agent.name,
|
||||
agentSource: agent.source,
|
||||
task,
|
||||
assignment,
|
||||
event,
|
||||
});
|
||||
}
|
||||
@@ -1231,6 +1237,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
|
||||
agent: agent.name,
|
||||
agentSource: agent.source,
|
||||
task,
|
||||
assignment,
|
||||
description: options.description,
|
||||
lastIntent: progress.lastIntent,
|
||||
exitCode,
|
||||
|
||||
@@ -224,6 +224,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
agentSource: fallbackAgentSource,
|
||||
status: "pending",
|
||||
task: renderedTask.task,
|
||||
assignment: renderedTask.assignment,
|
||||
description: renderedTask.description,
|
||||
recentTools: [],
|
||||
recentOutput: [],
|
||||
@@ -732,6 +733,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
agentSource: agent.source,
|
||||
status: "pending",
|
||||
task: t.task,
|
||||
assignment: t.assignment,
|
||||
recentTools: [],
|
||||
recentOutput: [],
|
||||
toolCount: 0,
|
||||
@@ -749,6 +751,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
cwd: this.session.cwd,
|
||||
agent,
|
||||
task: task.task,
|
||||
assignment: task.assignment,
|
||||
description: task.description,
|
||||
index,
|
||||
id: task.id,
|
||||
@@ -801,6 +804,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
worktree: isolationDir,
|
||||
agent,
|
||||
task: task.task,
|
||||
assignment: task.assignment,
|
||||
description: task.description,
|
||||
index,
|
||||
id: task.id,
|
||||
@@ -886,6 +890,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
agent: agent.name,
|
||||
agentSource: agent.source,
|
||||
task: task.task,
|
||||
assignment: task.assignment,
|
||||
description: task.description,
|
||||
exitCode: 1,
|
||||
output: "",
|
||||
@@ -929,6 +934,7 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
||||
agent: agentName,
|
||||
agentSource: agent.source,
|
||||
task: task.task,
|
||||
assignment: task.assignment,
|
||||
description: task.description,
|
||||
exitCode: 1,
|
||||
output: "",
|
||||
|
||||
@@ -374,16 +374,11 @@ function renderTaskSection(
|
||||
maxExpanded = 20,
|
||||
): string[] {
|
||||
const lines: string[] = [];
|
||||
const trimmed = task.trimEnd();
|
||||
const trimmed = task.trim();
|
||||
if (!expanded || !trimmed) return lines;
|
||||
|
||||
// Strip the shared <context>...</context> block — it's the same
|
||||
// across all tasks and just adds noise when expanded.
|
||||
const stripped = trimmed.replace(/<context>[\s\S]*?<\/context>\s*/, "").trimStart();
|
||||
if (!stripped) return lines;
|
||||
|
||||
lines.push(`${continuePrefix}${theme.fg("dim", "Task")}`);
|
||||
const taskLines = stripped.split("\n");
|
||||
const taskLines = trimmed.split("\n");
|
||||
for (const line of taskLines.slice(0, maxExpanded)) {
|
||||
lines.push(`${continuePrefix} ${theme.fg("dim", truncateToWidth(replaceTabs(line), 70))}`);
|
||||
}
|
||||
@@ -526,7 +521,7 @@ function renderAgentProgress(
|
||||
|
||||
if (progress.status === "running") {
|
||||
if (!description) {
|
||||
const taskPreview = truncateToWidth(progress.task, 40);
|
||||
const taskPreview = truncateToWidth(progress.assignment ?? progress.task, 40);
|
||||
statusLine += ` ${theme.fg("muted", taskPreview)}`;
|
||||
}
|
||||
if (progress.toolCount > 0) {
|
||||
@@ -546,7 +541,7 @@ function renderAgentProgress(
|
||||
|
||||
lines.push(statusLine);
|
||||
|
||||
lines.push(...renderTaskSection(progress.task, continuePrefix, expanded, theme));
|
||||
lines.push(...renderTaskSection(progress.assignment ?? progress.task, continuePrefix, expanded, theme));
|
||||
|
||||
// Current tool (if running) or most recent completed tool
|
||||
if (progress.status === "running") {
|
||||
@@ -781,7 +776,7 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
||||
|
||||
lines.push(statusLine);
|
||||
|
||||
lines.push(...renderTaskSection(result.task, continuePrefix, expanded, theme));
|
||||
lines.push(...renderTaskSection(result.assignment ?? result.task, continuePrefix, expanded, theme));
|
||||
|
||||
if (aborted && result.abortReason) {
|
||||
lines.push(
|
||||
|
||||
@@ -5,6 +5,8 @@ import type { TaskItem } from "./types";
|
||||
interface RenderResult {
|
||||
/** Full task text sent to the subagent */
|
||||
task: string;
|
||||
/** Raw per-task assignment text, without prompt template boilerplate */
|
||||
assignment: string;
|
||||
id: string;
|
||||
description: string;
|
||||
}
|
||||
@@ -20,10 +22,11 @@ export function renderTemplate(context: string | undefined, task: TaskItem): Ren
|
||||
context = context?.trim();
|
||||
|
||||
if (!context || !assignment) {
|
||||
return { task: assignment || context!, id, description };
|
||||
return { task: assignment || context!, assignment: assignment || context!, id, description };
|
||||
}
|
||||
return {
|
||||
task: renderPromptTemplate(subagentUserPromptTemplate, { context, assignment }),
|
||||
assignment,
|
||||
id,
|
||||
description,
|
||||
};
|
||||
|
||||
@@ -136,6 +136,7 @@ export interface AgentProgress {
|
||||
agentSource: AgentSource;
|
||||
status: "pending" | "running" | "completed" | "failed" | "aborted";
|
||||
task: string;
|
||||
assignment?: string;
|
||||
description?: string;
|
||||
lastIntent?: string;
|
||||
currentTool?: string;
|
||||
@@ -158,6 +159,7 @@ export interface SingleResult {
|
||||
agent: string;
|
||||
agentSource: AgentSource;
|
||||
task: string;
|
||||
assignment?: string;
|
||||
description?: string;
|
||||
lastIntent?: string;
|
||||
exitCode: number;
|
||||
|
||||
Reference in New Issue
Block a user