feat(web): degrade stage-blocked task runs to chat confirmation
Keep weak write verbs off the task shortcut path, and once-only fall back to chat when TASK_SCOPE_UNRESOLVED or DOC_TASK_NOT_IN_ACTIVE_STAGE. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@ import { DeliverableItem } from '../types/workbench';
|
||||
const READ_ONLY_INTENT =
|
||||
/(?:总结|概括|查看|看看|展示|读取|介绍|解释|分析|评价|检查|查询|当前状态|进度|谁在编辑|是否在编辑)/;
|
||||
const WRITE_INTENT =
|
||||
// 弱写动词(整理/梳理/汇总等)故意不含:走聊天通道,由后端阶段感知 + 确认门禁引导。
|
||||
/(?:开始|编写|编制|生成|起草|创建|撰写|重写|更新|修改|完善|补充|刷新|重做|改写)/;
|
||||
const CURRENT_DOC_DEIXIS = /当前受控文档|当前文档|本文件|这份文档|本文档|本受控文档/;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { isBlockedGovernanceStatus } from '../lib/blockedGovernanceCopy';
|
||||
import {
|
||||
buildFailedTaskErrorInfo,
|
||||
buildNetworkErrorInfo,
|
||||
isTaskStageDegradeCode,
|
||||
readRemoteTaskRun,
|
||||
} from '../lib/taskRunErrorInfo';
|
||||
|
||||
@@ -22,6 +23,15 @@ test('chat and task attempts live in one hook', () => {
|
||||
assert.equal(hook.includes('chatWindow.allMessages.find'), true);
|
||||
assert.equal(hook.includes('buildFailedTaskErrorInfo'), true);
|
||||
assert.equal(hook.includes('buildCancelledTaskErrorInfo'), true);
|
||||
assert.equal(hook.includes('isTaskStageDegradeCode'), true);
|
||||
assert.equal(hook.includes('改由对话确认引导'), true);
|
||||
});
|
||||
|
||||
test('stage unresolved and not-in-active-stage degrade to chat once', () => {
|
||||
assert.equal(isTaskStageDegradeCode('TASK_SCOPE_UNRESOLVED'), true);
|
||||
assert.equal(isTaskStageDegradeCode('DOC_TASK_NOT_IN_ACTIVE_STAGE'), true);
|
||||
assert.equal(isTaskStageDegradeCode('DOC_BUSY'), false);
|
||||
assert.equal(isTaskStageDegradeCode(''), false);
|
||||
});
|
||||
|
||||
test('failed run with error_message surfaces TASK_FAILED not NETWORK_ERROR', () => {
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
buildFailedTaskErrorInfo,
|
||||
buildInterruptedTaskErrorInfo,
|
||||
buildNetworkErrorInfo,
|
||||
isTaskStageDegradeCode,
|
||||
readRemoteTaskRun,
|
||||
} from '../lib/taskRunErrorInfo';
|
||||
import {
|
||||
@@ -790,6 +791,27 @@ export function useTaskRunAttempts(input: TaskRunAttemptsInput) {
|
||||
? Number((_err as { httpStatus?: number }).httpStatus)
|
||||
: undefined;
|
||||
const errMeta = _err as { errorCode?: string; detail?: string; message?: string };
|
||||
// 阶段/作用域未解析:降级聊天一次,由后端意图确认引导,替代仅弹错误气泡。
|
||||
if (
|
||||
mode === 'run' &&
|
||||
attemptIndex === 0 &&
|
||||
isTaskStageDegradeCode(errMeta.errorCode) &&
|
||||
task.userMessage?.trim()
|
||||
) {
|
||||
settled = true;
|
||||
patchAsst({
|
||||
status: 'pending',
|
||||
livePhaseLabel: '改由对话确认引导…',
|
||||
errorInfo: undefined,
|
||||
taskRequest: undefined,
|
||||
content: '',
|
||||
});
|
||||
taskRunStream.setThinking(sessionId, false);
|
||||
runStreamAttempt(task.userMessage.trim(), asstId, 0, {
|
||||
clientTurnId: task.clientTurnId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
failOrRetry(
|
||||
buildNetworkErrorInfo(httpStatus, {
|
||||
errorCode: errMeta.errorCode,
|
||||
|
||||
@@ -35,6 +35,11 @@ const fatalDenialCopy: Record<string, string> = {
|
||||
TASK_SCOPE_UNRESOLVED: '无法定位该文档任务的工作流阶段,请检查任务名或联系管理员',
|
||||
};
|
||||
|
||||
/** 任务直通道失败后应降级到聊天确认引导的错误码(仅降级一次,防循环)。 */
|
||||
export function isTaskStageDegradeCode(code: string | undefined | null): boolean {
|
||||
return code === 'TASK_SCOPE_UNRESOLVED' || code === 'DOC_TASK_NOT_IN_ACTIVE_STAGE';
|
||||
}
|
||||
|
||||
export function buildNetworkErrorInfo(
|
||||
httpStatus?: number,
|
||||
opts?: { errorCode?: string; detail?: string },
|
||||
|
||||
Reference in New Issue
Block a user