From f63082fb9c3ae62a18d9be999fbb1f3cb794fa55 Mon Sep 17 00:00:00 2001 From: Chiguyong Date: Mon, 6 Jul 2026 21:20:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(iq):=20apply=20code=20review=20fixes=20?= =?UTF-8?q?=E2=80=94=20P1=20trigger=5Freason=20+=20P2=20autonomy=20UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P1-1: _rebalance 路径传入 trigger_reason="loop_detection",使 retrieve_prompt_reflection 在重新规划时检索历史反思(原先两个 调用方都不传 trigger_reason,导致 retrieve_prompt_reflection 在生产中是死代码)。verify_retry / schema_validation 触发路径 待 verify/schema 重试路径与 team re-planning 集成后接入。 P2-1: 会话切换时如果有 autonomyPaused,先发送 cancel 消息通知 后端取消暂停的执行,避免 _resume_handler future 挂起最多 30 分钟。 P2-2: resumeAutonomy 中更新 "自主执行已暂停" milestone 状态为 "success",避免 streaming step 列表残留 "running" 状态。 --- src/agentkit/experts/orchestrator.py | 14 ++++++++++- .../server/frontend/src/stores/chatStore.ts | 23 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/agentkit/experts/orchestrator.py b/src/agentkit/experts/orchestrator.py index 7f15a6f..c3d894d 100644 --- a/src/agentkit/experts/orchestrator.py +++ b/src/agentkit/experts/orchestrator.py @@ -589,9 +589,21 @@ class TeamOrchestrator( f"where natural." ) # Temporarily wrap task with hint — call _decompose_task with augmented task. + # U4/KTD5: re-decomposition is a re-planning signal — pass trigger_reason + # so retrieve_prompt_reflection can inform the new plan with historical + # reflection. "loop_detection" is the closest KTD5 trigger: the original + # plan hit a structural limit (too many independent subtasks) and needs + # re-planning, analogous to detecting a planning loop. + # ponytail: verify_retry / schema_validation triggers belong to the + # verify-failed / schema-failed retry paths (plan_exec_engine.py / + # verification_loop.py), which do not call _decompose_task today; + # wiring those is deferred until those paths are integrated with + # team re-planning. augmented_task = f"{task}\n\n[Re-decomposition hint]: {original_hint}" try: - new_phases = await self._decompose_task(lead, augmented_task) + new_phases = await self._decompose_task( + lead, augmented_task, trigger_reason="loop_detection" + ) except (LLMProviderError, asyncio.TimeoutError, ConnectionError, ValueError) as e: logger.warning(f"U4 re-decompose failed: {e}, keeping original phases") return phases diff --git a/src/agentkit/server/frontend/src/stores/chatStore.ts b/src/agentkit/server/frontend/src/stores/chatStore.ts index 4e5a54a..8b4a6d3 100644 --- a/src/agentkit/server/frontend/src/stores/chatStore.ts +++ b/src/agentkit/server/frontend/src/stores/chatStore.ts @@ -5,7 +5,7 @@ import { useTeamStore } from "@/stores/team"; import { useDocumentsStore } from "@/stores/documents"; import { useCalendarStore } from "@/stores/calendar"; import { useChatSocket } from "@/stores/chatSocket"; -import { useChatStream } from "@/stores/chatStream"; +import { useChatStream, updateLastStep } from "@/stores/chatStream"; import type { BoardState } from "@/stores/chatStream"; import { pickExpertIdentity } from "@/components/chat/helpers/expertIdentity"; import type { @@ -222,6 +222,16 @@ export const useChatStore = defineStore("chat", () => { // 会话隔离 — 切换会话时重置三个 transient state,避免跨会话数据泄漏。 // force-reload 同一会话时不重置,防止误清空。 if (prevConvId !== id) { + // U1/P2-1: if the previous conversation had an autonomy-paused execution + // waiting for resume, cancel it server-side so the engine's + // _resume_handler future does not hang for up to 30 minutes. + if (stream.autonomyPaused.value && socket.ws.value?.readyState === WebSocket.OPEN) { + try { + socket.ws.value.send(JSON.stringify({ type: "cancel" } as WsClientMessage)); + } catch { + // swallow — socket teardown will cancel the future server-side + } + } stream.boardState.value = null; stream.debateState.value = null; stream.collaborationState.value = null; @@ -543,6 +553,17 @@ export const useChatStore = defineStore("chat", () => { */ function resumeAutonomy(resumeToken: string): void { stream.autonomyPaused.value = null; + // U1/P2-2: mark the "自主执行已暂停" milestone as completed so the + // streaming step list does not leave a perpetual "running" entry. + const cid = currentConversationId.value; + if (cid) { + updateLastStep( + stream.streamingStepsByConv, + (s) => s.type === "milestone" && s.label === "自主执行已暂停", + { status: "success" }, + cid, + ); + } if (!socket.ws.value || socket.ws.value.readyState !== WebSocket.OPEN) { return; }