mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-28 03:30:40 +00:00
refactor(core): generalize task_stop and send_message framing to "task"
Today every BackgroundTaskRegistry entry is a subagent, but the control-plane tools were named and described as agent-only. Generalize so future task kinds (e.g. backgrounded shells, monitors) can share the same registry without a model-facing rename. - task_stop / send_message: descriptions, error messages, and ToolError enum values drop the "agent" framing in favor of "task". - send_message: parameter to -> task_id, matching task_stop for a uniform control-plane contract. - BackgroundTaskRegistry.hasUnfinalizedAgents -> hasUnfinalizedTasks. - agent-transcript: add a TODO at getSubagentSessionDir flagging that <projectDir>/subagents/ is part of the model-facing contract via <output-file>; future kinds should migrate to <projectDir>/tasks/. - Add a test for complete()-after-finalizeCancelled no-op to pin the one-notification-per-task SDK contract through the post-notified re-entry path.
This commit is contained in:
parent
cb513119d1
commit
57c89e425f
10 changed files with 110 additions and 81 deletions
|
|
@ -167,7 +167,7 @@ describe('runNonInteractive', () => {
|
|||
setNotificationCallback: vi.fn(),
|
||||
setRegisterCallback: vi.fn(),
|
||||
getRunning: vi.fn().mockReturnValue([]),
|
||||
hasUnfinalizedAgents: vi.fn().mockReturnValue(false),
|
||||
hasUnfinalizedTasks: vi.fn().mockReturnValue(false),
|
||||
abortAll: vi.fn(),
|
||||
}),
|
||||
} as unknown as Config;
|
||||
|
|
|
|||
|
|
@ -714,11 +714,11 @@ export async function runNonInteractive(
|
|||
await handleCancellationError(config);
|
||||
}
|
||||
await drainLocalQueue();
|
||||
// Wait for every agent's terminal notification, not just the
|
||||
// Wait for every task's terminal notification, not just the
|
||||
// running ones: cancel() marks status 'cancelled' synchronously
|
||||
// but the notification is emitted later by the natural handler,
|
||||
// and SDK consumers need every task_started paired with one.
|
||||
if (!registry.hasUnfinalizedAgents() && localQueue.length === 0)
|
||||
if (!registry.hasUnfinalizedTasks() && localQueue.length === 0)
|
||||
break;
|
||||
await new Promise((r) => setTimeout(r, 100));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ function sanitizeFilenameComponent(value: string): string {
|
|||
/**
|
||||
* Returns the directory holding all subagent transcripts for a given session.
|
||||
* Layout: `<projectDir>/subagents/<sessionId>/`.
|
||||
*
|
||||
* TODO: this path is part of the model-facing contract via `<output-file>` in
|
||||
* the task-notification XML. When a second background task kind lands (e.g. a
|
||||
* shell pool), migrate to `<projectDir>/tasks/<sessionId>/<kind>-<id>.jsonl`
|
||||
* so the namespace generalizes. Update `read-file.ts` auto-allow accordingly.
|
||||
*/
|
||||
export function getSubagentSessionDir(
|
||||
projectDir: string,
|
||||
|
|
|
|||
|
|
@ -120,14 +120,14 @@ describe('BackgroundTaskRegistry', () => {
|
|||
expect(callback).not.toHaveBeenCalled();
|
||||
|
||||
// Pathological tool case: bgBody never emits. After the grace period
|
||||
// the fallback fires so hasUnfinalizedAgents() stops reporting true
|
||||
// the fallback fires so hasUnfinalizedTasks() stops reporting true
|
||||
// and the headless wait loop can exit.
|
||||
vi.runAllTimers();
|
||||
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
const [, modelText] = callback.mock.calls[0] as [string, string];
|
||||
expect(modelText).toContain('<status>cancelled</status>');
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(false);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(false);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
|
|
@ -182,6 +182,34 @@ describe('BackgroundTaskRegistry', () => {
|
|||
expect(modelText).toContain('<status>cancelled</status>');
|
||||
});
|
||||
|
||||
it('complete() after the cancellation has already been notified is a no-op', () => {
|
||||
// Once finalizeCancelled has emitted the terminal notification, a
|
||||
// late-arriving complete() must not double-fire — the SDK contract
|
||||
// is one notification per task_started.
|
||||
const callback = vi.fn();
|
||||
registry.setNotificationCallback(callback);
|
||||
|
||||
registry.register({
|
||||
agentId: 'test-1',
|
||||
description: 'test agent',
|
||||
status: 'running',
|
||||
startTime: Date.now(),
|
||||
abortController: new AbortController(),
|
||||
});
|
||||
|
||||
registry.cancel('test-1');
|
||||
registry.finalizeCancelled('test-1', 'partial');
|
||||
expect(callback).toHaveBeenCalledOnce();
|
||||
callback.mockClear();
|
||||
|
||||
registry.complete('test-1', 'late result');
|
||||
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
// Status stays cancelled — the notified terminal state wins.
|
||||
expect(registry.get('test-1')!.status).toBe('cancelled');
|
||||
expect(registry.get('test-1')!.result).toBe('partial');
|
||||
});
|
||||
|
||||
it('does not cancel a non-running agent', () => {
|
||||
const abortController = new AbortController();
|
||||
|
||||
|
|
@ -257,7 +285,7 @@ describe('BackgroundTaskRegistry', () => {
|
|||
expect(callback).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('hasUnfinalizedAgents reports cancelled-but-not-notified entries', () => {
|
||||
it('hasUnfinalizedTasks reports cancelled-but-not-notified entries', () => {
|
||||
// Headless runs rely on this to keep the event loop alive after a
|
||||
// task_stop until the agent's natural handler has emitted the
|
||||
// terminal task-notification — otherwise the matching notification
|
||||
|
|
@ -269,17 +297,17 @@ describe('BackgroundTaskRegistry', () => {
|
|||
startTime: Date.now(),
|
||||
abortController: new AbortController(),
|
||||
});
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(true);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(true);
|
||||
|
||||
registry.cancel('test-1');
|
||||
expect(registry.get('test-1')!.status).toBe('cancelled');
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(true);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(true);
|
||||
|
||||
registry.finalizeCancelled('test-1', '');
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(false);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(false);
|
||||
});
|
||||
|
||||
it('hasUnfinalizedAgents clears once every entry has been notified', () => {
|
||||
it('hasUnfinalizedTasks clears once every entry has been notified', () => {
|
||||
registry.register({
|
||||
agentId: 'a',
|
||||
description: 'agent a',
|
||||
|
|
@ -295,11 +323,11 @@ describe('BackgroundTaskRegistry', () => {
|
|||
abortController: new AbortController(),
|
||||
});
|
||||
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(true);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(true);
|
||||
registry.complete('a', 'done');
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(true);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(true);
|
||||
registry.fail('b', 'boom');
|
||||
expect(registry.hasUnfinalizedAgents()).toBe(false);
|
||||
expect(registry.hasUnfinalizedTasks()).toBe(false);
|
||||
});
|
||||
|
||||
it('complete after cancellation surfaces the real result', () => {
|
||||
|
|
|
|||
|
|
@ -221,14 +221,14 @@ export class BackgroundTaskRegistry {
|
|||
}
|
||||
|
||||
/**
|
||||
* True if any registered agent has not yet emitted its terminal
|
||||
* True if any registered task has not yet emitted its terminal
|
||||
* task-notification. Covers `running` (still executing) and
|
||||
* `cancelled`-but-not-finalized (cancel requested, but the natural
|
||||
* handler hasn't fired finalizeCancelled() yet). Headless callers
|
||||
* must keep their event loop alive while this returns true, so every
|
||||
* task_started is paired with a matching task_notification.
|
||||
*/
|
||||
hasUnfinalizedAgents(): boolean {
|
||||
hasUnfinalizedTasks(): boolean {
|
||||
for (const entry of this.agents.values()) {
|
||||
if (!entry.notified) return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('SendMessageTool', () => {
|
|||
tool = new SendMessageTool(config);
|
||||
});
|
||||
|
||||
it('queues a message for a running agent', async () => {
|
||||
it('queues a message for a running task', async () => {
|
||||
registry.register({
|
||||
agentId: 'agent-1',
|
||||
description: 'test agent',
|
||||
|
|
@ -33,7 +33,7 @@ describe('SendMessageTool', () => {
|
|||
});
|
||||
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'do more work' },
|
||||
{ task_id: 'agent-1', message: 'do more work' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
|
|
@ -52,11 +52,11 @@ describe('SendMessageTool', () => {
|
|||
});
|
||||
|
||||
await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'first' },
|
||||
{ task_id: 'agent-1', message: 'first' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'second' },
|
||||
{ task_id: 'agent-1', message: 'second' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
|
|
@ -66,17 +66,17 @@ describe('SendMessageTool', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('returns error for non-existent agent', async () => {
|
||||
it('returns error for non-existent task', async () => {
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ to: 'nope', message: 'hello' },
|
||||
{ task_id: 'nope', message: 'hello' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(result.error?.type).toBe(ToolErrorType.SEND_MESSAGE_AGENT_NOT_FOUND);
|
||||
expect(result.llmContent).toContain('No background agent found');
|
||||
expect(result.error?.type).toBe(ToolErrorType.SEND_MESSAGE_NOT_FOUND);
|
||||
expect(result.llmContent).toContain('No background task found');
|
||||
});
|
||||
|
||||
it('returns error for non-running agent', async () => {
|
||||
it('returns error for non-running task', async () => {
|
||||
registry.register({
|
||||
agentId: 'agent-1',
|
||||
description: 'test agent',
|
||||
|
|
@ -87,17 +87,15 @@ describe('SendMessageTool', () => {
|
|||
registry.complete('agent-1', 'done');
|
||||
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'hello' },
|
||||
{ task_id: 'agent-1', message: 'hello' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(result.error?.type).toBe(
|
||||
ToolErrorType.SEND_MESSAGE_AGENT_NOT_RUNNING,
|
||||
);
|
||||
expect(result.error?.type).toBe(ToolErrorType.SEND_MESSAGE_NOT_RUNNING);
|
||||
expect(result.llmContent).toContain('not running');
|
||||
});
|
||||
|
||||
it('rejects messages for a cancelled agent', async () => {
|
||||
it('rejects messages for a cancelled task', async () => {
|
||||
// Once task_stop fires, the reasoning loop is winding down — there is
|
||||
// no next tool-round boundary to drain into, so the message would be
|
||||
// silently dropped. Reject instead of accepting a message that will
|
||||
|
|
@ -112,17 +110,15 @@ describe('SendMessageTool', () => {
|
|||
registry.cancel('agent-1');
|
||||
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'too late' },
|
||||
{ task_id: 'agent-1', message: 'too late' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(result.error?.type).toBe(
|
||||
ToolErrorType.SEND_MESSAGE_AGENT_NOT_RUNNING,
|
||||
);
|
||||
expect(result.error?.type).toBe(ToolErrorType.SEND_MESSAGE_NOT_RUNNING);
|
||||
expect(registry.get('agent-1')!.pendingMessages).toEqual([]);
|
||||
});
|
||||
|
||||
it('includes agent description in success display', async () => {
|
||||
it('includes task description in success display', async () => {
|
||||
registry.register({
|
||||
agentId: 'agent-1',
|
||||
description: 'Search for auth code',
|
||||
|
|
@ -132,7 +128,7 @@ describe('SendMessageTool', () => {
|
|||
});
|
||||
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ to: 'agent-1', message: 'focus on login' },
|
||||
{ task_id: 'agent-1', message: 'focus on login' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
/**
|
||||
* @fileoverview SendMessage tool — lets the model send a text message to
|
||||
* a running background agent. The message is injected into the agent's
|
||||
* a running background task. The message is injected into the task's
|
||||
* reasoning loop at the next tool-round boundary.
|
||||
*/
|
||||
|
||||
|
|
@ -22,9 +22,9 @@ import {
|
|||
} from './tools.js';
|
||||
|
||||
export interface SendMessageParams {
|
||||
/** The ID of the background agent to send the message to. */
|
||||
to: string;
|
||||
/** The text message to deliver to the agent. */
|
||||
/** The ID of the background task to send the message to. */
|
||||
task_id: string;
|
||||
/** The text message to deliver to the task. */
|
||||
message: string;
|
||||
}
|
||||
|
||||
|
|
@ -40,39 +40,39 @@ class SendMessageInvocation extends BaseToolInvocation<
|
|||
}
|
||||
|
||||
getDescription(): string {
|
||||
return `Send message to agent ${this.params.to}`;
|
||||
return `Send message to task ${this.params.task_id}`;
|
||||
}
|
||||
|
||||
async execute(_signal: AbortSignal): Promise<ToolResult> {
|
||||
const registry = this.config.getBackgroundTaskRegistry();
|
||||
const entry = registry.get(this.params.to);
|
||||
const entry = registry.get(this.params.task_id);
|
||||
|
||||
if (!entry) {
|
||||
return {
|
||||
llmContent: `Error: No background agent found with ID "${this.params.to}".`,
|
||||
returnDisplay: 'Agent not found.',
|
||||
llmContent: `Error: No background task found with ID "${this.params.task_id}".`,
|
||||
returnDisplay: 'Task not found.',
|
||||
error: {
|
||||
message: `Agent not found: ${this.params.to}`,
|
||||
type: ToolErrorType.SEND_MESSAGE_AGENT_NOT_FOUND,
|
||||
message: `Task not found: ${this.params.task_id}`,
|
||||
type: ToolErrorType.SEND_MESSAGE_NOT_FOUND,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (entry.status !== 'running') {
|
||||
return {
|
||||
llmContent: `Error: Background agent "${this.params.to}" is not running (status: ${entry.status}). Cannot send messages to stopped agents.`,
|
||||
returnDisplay: `Agent not running (${entry.status}).`,
|
||||
llmContent: `Error: Background task "${this.params.task_id}" is not running (status: ${entry.status}). Cannot send messages to stopped tasks.`,
|
||||
returnDisplay: `Task not running (${entry.status}).`,
|
||||
error: {
|
||||
message: `Agent is ${entry.status}: ${this.params.to}`,
|
||||
type: ToolErrorType.SEND_MESSAGE_AGENT_NOT_RUNNING,
|
||||
message: `Task is ${entry.status}: ${this.params.task_id}`,
|
||||
type: ToolErrorType.SEND_MESSAGE_NOT_RUNNING,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
registry.queueMessage(this.params.to, this.params.message);
|
||||
registry.queueMessage(this.params.task_id, this.params.message);
|
||||
|
||||
return {
|
||||
llmContent: `Message queued for delivery to background agent "${this.params.to}". The agent will receive it at the next tool-round boundary.`,
|
||||
llmContent: `Message queued for delivery to background task "${this.params.task_id}". The task will receive it at the next tool-round boundary.`,
|
||||
returnDisplay: `Message queued for ${entry.description}`,
|
||||
};
|
||||
}
|
||||
|
|
@ -88,22 +88,22 @@ export class SendMessageTool extends BaseDeclarativeTool<
|
|||
super(
|
||||
SendMessageTool.Name,
|
||||
ToolDisplayNames.SEND_MESSAGE,
|
||||
'Send a text message to a running background agent. The message is delivered at the next tool-round boundary. Use this to provide additional instructions or context to a background agent.',
|
||||
'Send a text message to a running background task. The message is delivered at the next tool-round boundary. Use this to provide additional instructions or context to a background task.',
|
||||
Kind.Other,
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
to: {
|
||||
task_id: {
|
||||
type: 'string',
|
||||
description:
|
||||
'The ID of the running background agent (from the launch response).',
|
||||
'The ID of the running background task (from the launch response).',
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'The text message to send to the agent.',
|
||||
description: 'The text message to send to the task.',
|
||||
},
|
||||
},
|
||||
required: ['to', 'message'],
|
||||
required: ['task_id', 'message'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,17 +45,17 @@ describe('TaskStopTool', () => {
|
|||
expect(ac.signal.aborted).toBe(true);
|
||||
});
|
||||
|
||||
it('returns error for non-existent agent', async () => {
|
||||
it('returns error for non-existent task', async () => {
|
||||
const result = await tool.validateBuildAndExecute(
|
||||
{ task_id: 'nope' },
|
||||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(result.error?.type).toBe(ToolErrorType.TASK_STOP_AGENT_NOT_FOUND);
|
||||
expect(result.llmContent).toContain('No background agent found');
|
||||
expect(result.error?.type).toBe(ToolErrorType.TASK_STOP_NOT_FOUND);
|
||||
expect(result.llmContent).toContain('No background task found');
|
||||
});
|
||||
|
||||
it('returns error for non-running agent', async () => {
|
||||
it('returns error for non-running task', async () => {
|
||||
registry.register({
|
||||
agentId: 'agent-1',
|
||||
description: 'test agent',
|
||||
|
|
@ -70,7 +70,7 @@ describe('TaskStopTool', () => {
|
|||
new AbortController().signal,
|
||||
);
|
||||
|
||||
expect(result.error?.type).toBe(ToolErrorType.TASK_STOP_AGENT_NOT_RUNNING);
|
||||
expect(result.error?.type).toBe(ToolErrorType.TASK_STOP_NOT_RUNNING);
|
||||
expect(result.llmContent).toContain('not running');
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview TaskStop tool — lets the model cancel a running background agent.
|
||||
* @fileoverview TaskStop tool — lets the model cancel a running background task.
|
||||
*/
|
||||
|
||||
import type { Config } from '../config/config.js';
|
||||
|
|
@ -20,7 +20,7 @@ import {
|
|||
} from './tools.js';
|
||||
|
||||
export interface TaskStopParams {
|
||||
/** The ID of the background agent to stop. */
|
||||
/** The ID of the background task to stop. */
|
||||
task_id: string;
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ class TaskStopInvocation extends BaseToolInvocation<
|
|||
}
|
||||
|
||||
getDescription(): string {
|
||||
return `Stop background agent ${this.params.task_id}`;
|
||||
return `Stop background task ${this.params.task_id}`;
|
||||
}
|
||||
|
||||
async execute(_signal: AbortSignal): Promise<ToolResult> {
|
||||
|
|
@ -45,35 +45,35 @@ class TaskStopInvocation extends BaseToolInvocation<
|
|||
|
||||
if (!entry) {
|
||||
return {
|
||||
llmContent: `Error: No background agent found with ID "${this.params.task_id}".`,
|
||||
returnDisplay: 'Agent not found.',
|
||||
llmContent: `Error: No background task found with ID "${this.params.task_id}".`,
|
||||
returnDisplay: 'Task not found.',
|
||||
error: {
|
||||
message: `Agent not found: ${this.params.task_id}`,
|
||||
type: ToolErrorType.TASK_STOP_AGENT_NOT_FOUND,
|
||||
message: `Task not found: ${this.params.task_id}`,
|
||||
type: ToolErrorType.TASK_STOP_NOT_FOUND,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (entry.status !== 'running') {
|
||||
return {
|
||||
llmContent: `Error: Background agent "${this.params.task_id}" is not running (status: ${entry.status}).`,
|
||||
returnDisplay: `Agent not running (${entry.status}).`,
|
||||
llmContent: `Error: Background task "${this.params.task_id}" is not running (status: ${entry.status}).`,
|
||||
returnDisplay: `Task not running (${entry.status}).`,
|
||||
error: {
|
||||
message: `Agent is ${entry.status}: ${this.params.task_id}`,
|
||||
type: ToolErrorType.TASK_STOP_AGENT_NOT_RUNNING,
|
||||
message: `Task is ${entry.status}: ${this.params.task_id}`,
|
||||
type: ToolErrorType.TASK_STOP_NOT_RUNNING,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
registry.cancel(this.params.task_id);
|
||||
|
||||
// The terminal task-notification is emitted by the agent's own handler
|
||||
// The terminal task-notification is emitted by the task's own handler
|
||||
// (via registry.complete/fail) rather than cancel(), so the parent model
|
||||
// still receives the agent's real partial/final result — not just a bare
|
||||
// still receives the task's real partial/final result — not just a bare
|
||||
// "cancelled" message — once the reasoning loop unwinds.
|
||||
const desc = entry.description;
|
||||
return {
|
||||
llmContent: `Cancellation requested for background agent "${this.params.task_id}". A final task-notification carrying the agent's last result will follow.\nDescription: ${desc}`,
|
||||
llmContent: `Cancellation requested for background task "${this.params.task_id}". A final task-notification carrying the task's last result will follow.\nDescription: ${desc}`,
|
||||
returnDisplay: `Cancelled: ${desc}`,
|
||||
};
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ export class TaskStopTool extends BaseDeclarativeTool<
|
|||
super(
|
||||
TaskStopTool.Name,
|
||||
ToolDisplayNames.TASK_STOP,
|
||||
'Cancel a running background agent by its ID. The agent ID is returned when you launch a background agent.',
|
||||
'Cancel a running background task by its ID. The task ID is returned when the task is launched.',
|
||||
Kind.Other,
|
||||
{
|
||||
type: 'object',
|
||||
|
|
@ -97,7 +97,7 @@ export class TaskStopTool extends BaseDeclarativeTool<
|
|||
task_id: {
|
||||
type: 'string',
|
||||
description:
|
||||
'The ID of the background agent to stop (from the launch response or notification).',
|
||||
'The ID of the background task to stop (from the launch response or notification).',
|
||||
},
|
||||
},
|
||||
required: ['task_id'],
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ export enum ToolErrorType {
|
|||
OUTPUT_TRUNCATED = 'output_truncated',
|
||||
|
||||
// TaskStop-specific Errors
|
||||
TASK_STOP_AGENT_NOT_FOUND = 'task_stop_agent_not_found',
|
||||
TASK_STOP_AGENT_NOT_RUNNING = 'task_stop_agent_not_running',
|
||||
TASK_STOP_NOT_FOUND = 'task_stop_not_found',
|
||||
TASK_STOP_NOT_RUNNING = 'task_stop_not_running',
|
||||
|
||||
// SendMessage-specific Errors
|
||||
SEND_MESSAGE_AGENT_NOT_FOUND = 'send_message_agent_not_found',
|
||||
SEND_MESSAGE_AGENT_NOT_RUNNING = 'send_message_agent_not_running',
|
||||
SEND_MESSAGE_NOT_FOUND = 'send_message_not_found',
|
||||
SEND_MESSAGE_NOT_RUNNING = 'send_message_not_running',
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue