From 02daaee1f259cdbb8413de01d3198d4239bb1109 Mon Sep 17 00:00:00 2001 From: fancyboi999 <135568692+fancyboi999@users.noreply.github.com> Date: Thu, 21 May 2026 16:26:44 +0800 Subject: [PATCH] fix(frontend): export subtask prefix constants and document fallback intent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address review feedback on the previous BUG-007 commit: 1. `SUCCESS_PREFIX`, `FAILURE_PREFIX`, `TIMEOUT_PREFIX`, and the `ERROR_WRAPPER_PATTERN` regex are now exported. The JSDoc explicitly pins them as part of the backend↔frontend contract defined in `task_tool.py` and `tool_error_handling_middleware.py`, so any future structured-status migration (e.g. backend writing `additional_kwargs.subagent_status` instead of leading text) can reference these from one canonical place rather than redefine them. 2. The `in_progress` fallback now carries a docstring explaining the deliberate choice — LangChain only ever emits a `ToolMessage` once the tool itself has returned, so unrecognised content means the contract has drifted and "still running" is the right operator signal (eagerly marking it terminal-failed would mask the drift). No behaviour change; this is documentation and an API export. Refs: bytedance/deer-flow#3107 (BUG-007) --- frontend/src/core/tasks/subtask-result.ts | 28 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/frontend/src/core/tasks/subtask-result.ts b/frontend/src/core/tasks/subtask-result.ts index 914d71d15..505ed329d 100644 --- a/frontend/src/core/tasks/subtask-result.ts +++ b/frontend/src/core/tasks/subtask-result.ts @@ -8,9 +8,22 @@ export interface SubtaskResultUpdate { error?: string; } -const SUCCESS_PREFIX = "Task Succeeded. Result:"; -const FAILURE_PREFIX = "Task failed."; -const TIMEOUT_PREFIX = "Task timed out"; +/** + * Prefix strings the backend `task` tool writes into its result `content`. + * + * These values are not user-facing copy — they are part of the + * backend↔frontend contract defined in + * `backend/packages/harness/deerflow/tools/builtins/task_tool.py` (returned + * from the tool body) and in + * `backend/packages/harness/deerflow/agents/middlewares/tool_error_handling_middleware.py` + * (wrapper for tool exceptions). Any change here must be paired with the + * matching backend change. Exported so a future structured-status migration + * can reference the same values from one place. + */ +export const SUCCESS_PREFIX = "Task Succeeded. Result:"; +export const FAILURE_PREFIX = "Task failed."; +export const TIMEOUT_PREFIX = "Task timed out"; +export const ERROR_WRAPPER_PATTERN = /^Error\b/i; /** * Map a `task` tool result string to a {@link SubtaskStatus}. @@ -20,6 +33,13 @@ const TIMEOUT_PREFIX = "Task timed out"; * `ToolErrorHandlingMiddleware` wraps an exception as * `Error: Tool 'task' failed ...`). Treat any leading `Error:` token as a * terminal failure so subtask cards stop being stuck on "in_progress". + * + * Returning `in_progress` is the **deliberate** fallback for content that + * matches none of the known prefixes. LangChain only ever emits a + * `ToolMessage` once the tool itself has returned (success or wrapped + * exception), so an unknown shape means "the contract changed underneath us" + * — surfacing it as still-running prompts the operator to investigate, where + * eagerly marking it terminal-failed would mask the drift. */ export function parseSubtaskResult(text: string): SubtaskResultUpdate { const trimmed = text.trim(); @@ -44,7 +64,7 @@ export function parseSubtaskResult(text: string): SubtaskResultUpdate { // ToolErrorHandlingMiddleware-style wrapper, or any other terminal error // signal the backend forwards to the lead agent. - if (/^Error\b/i.test(trimmed)) { + if (ERROR_WRAPPER_PATTERN.test(trimmed)) { return { status: "failed", error: trimmed }; }