diff --git a/agents/matmaster_agent/flow_agents/agent.py b/agents/matmaster_agent/flow_agents/agent.py index a6d88f8f..1e818e7e 100644 --- a/agents/matmaster_agent/flow_agents/agent.py +++ b/agents/matmaster_agent/flow_agents/agent.py @@ -75,6 +75,7 @@ get_report_instruction, ) from agents.matmaster_agent.flow_agents.scene_agent.constant import SCENE_AGENT +from agents.matmaster_agent.flow_agents.scene_agent.model import SceneEnum from agents.matmaster_agent.flow_agents.scene_agent.prompt import SCENE_INSTRUCTION from agents.matmaster_agent.flow_agents.scene_agent.schema import SceneSchema from agents.matmaster_agent.flow_agents.schema import FlowStatusEnum @@ -406,8 +407,19 @@ async def _run_scene_agent( logger.info(f'{ctx.session.id} scenes = {scenes}') yield update_state_event(ctx, state_delta={'scenes': copy.deepcopy(scenes)}) + def _is_query_job_status_only(self, ctx: InvocationContext) -> bool: + """True when user intent is only to query task/job status (no thinking needed).""" + scenes = ctx.session.state.get('scenes') or [] + query_status_value = SceneEnum.QUERY_JOB_STATUS.value + return any(getattr(s, 'value', s) == query_status_value for s in scenes) + async def _run_plan_make_agent( - self, ctx: InvocationContext, UPDATE_USER_CONTENT, TOOLCHAIN_EXAMPLES_PROMPT + self, + ctx: InvocationContext, + UPDATE_USER_CONTENT, + TOOLCHAIN_EXAMPLES_PROMPT, + *, + skip_thinking: bool = False, ) -> AsyncGenerator[Event, None]: # 制定计划 if check_plan(ctx) == FlowStatusEnum.FAILED: @@ -471,41 +483,49 @@ async def _run_plan_make_agent( ) expanded_query = expand_state.get('update_user_content', '') - # Thinking: loop (and optional revision) is handled inside ThinkingAgent + # Thinking: skip for "query job status only" (e.g. 查看任务状态); run otherwise thinking_text = '' - try: - self._thinking_agent.set_thinking_params( - available_tools_with_info_str, - session_file_summary, - original_query, - expanded_query, - short_term_memory=short_term_memory_block, - ) - last_full_text = '' - async for thinking_event in self._thinking_agent.run_async(ctx): - yield thinking_event + if not skip_thinking: + try: + self._thinking_agent.set_thinking_params( + available_tools_with_info_str, + session_file_summary, + original_query, + expanded_query, + short_term_memory=short_term_memory_block, + ) + last_full_text = '' + async for thinking_event in self._thinking_agent.run_async(ctx): + yield thinking_event + if ( + not getattr(thinking_event, 'partial', True) + and getattr(thinking_event, 'content', None) + and getattr(thinking_event.content, 'parts', None) + ): + parts_text = ''.join( + p.text or '' + for p in thinking_event.content.parts + if getattr(p, 'text', None) + ) + if parts_text.strip(): + last_full_text = parts_text.strip() + thinking_text = (last_full_text or '').strip() if ( - not getattr(thinking_event, 'partial', True) - and getattr(thinking_event, 'content', None) - and getattr(thinking_event.content, 'parts', None) + getattr(self._thinking_agent, '_last_thinking_text', None) + is not None ): - parts_text = ''.join( - p.text or '' - for p in thinking_event.content.parts - if getattr(p, 'text', None) - ) - if parts_text.strip(): - last_full_text = parts_text.strip() - thinking_text = (last_full_text or '').strip() - if getattr(self._thinking_agent, '_last_thinking_text', None) is not None: - thinking_text = self._thinking_agent._last_thinking_text + thinking_text = self._thinking_agent._last_thinking_text + logger.info( + f'{ctx.session.id} reasoning_agent result length={len(thinking_text)}, ' + f'preview={repr(thinking_text[:300]) if thinking_text else "empty"}' + ) + except Exception as e: + logger.warning( + f'{ctx.session.id} reasoning_agent failed: {e}, proceed without thinking' + ) + else: logger.info( - f'{ctx.session.id} reasoning_agent result length={len(thinking_text)}, ' - f'preview={repr(thinking_text[:300]) if thinking_text else "empty"}' - ) - except Exception as e: - logger.warning( - f'{ctx.session.id} reasoning_agent failed: {e}, proceed without thinking' + f'{ctx.session.id} skip reasoning_agent (query_job_status_only)' ) self.plan_make_agent.instruction = get_plan_make_instruction( @@ -873,13 +893,18 @@ async def _run_research_flow( yield update_state_event(ctx, state_delta={PLAN: {}, MULTI_PLANS: {}}) # 制定计划(1. 无计划;2. 计划已完成;3. 计划失败;4. 用户未确认计划) + # 仅查询任务状态时跳过 thinking(查任务状态不 thinking) + skip_thinking = self._is_query_job_status_only(ctx) if check_plan(ctx) in [ FlowStatusEnum.NO_PLAN, FlowStatusEnum.COMPLETE, FlowStatusEnum.FAILED, ] or not is_plan_confirmed(ctx): async for _plan_make_event in self._run_plan_make_agent( - ctx, UPDATE_USER_CONTENT, TOOLCHAIN_EXAMPLES_PROMPT + ctx, + UPDATE_USER_CONTENT, + TOOLCHAIN_EXAMPLES_PROMPT, + skip_thinking=skip_thinking, ): yield _plan_make_event diff --git a/agents/matmaster_agent/flow_agents/utils.py b/agents/matmaster_agent/flow_agents/utils.py index 69f600a8..d36adc2e 100644 --- a/agents/matmaster_agent/flow_agents/utils.py +++ b/agents/matmaster_agent/flow_agents/utils.py @@ -163,20 +163,29 @@ def has_self_check(current_tool_name: str) -> bool: return tool.get('self_check', False) +def _scenes_contain_query_job_status(ctx: InvocationContext) -> bool: + """True when current scenes include query_job_status (e.g. 查询任务/查看任务状态).""" + scenes = ctx.session.state.get('scenes') or [] + query_value = SceneEnum.QUERY_JOB_STATUS.value + return any(getattr(s, 'value', s) == query_value for s in scenes) + + def is_plan_confirmed(ctx: InvocationContext) -> bool: # 1) 原有:前端状态里已确认 biz_state = ctx.session.state.get(FRONTEND_STATE_KEY, {}).get(BIZ, {}) if biz_state.get(PLAN_CONFIRM, False): return True - # 2) 新增:用户输入匹配“方案 + 数字”(方案和数字间允许空格) + # 2) 用户输入匹配“方案 + 数字”(方案和数字间允许空格) try: text = (ctx.user_content.parts[0].text or '').strip() except Exception: text = '' - - # 仅匹配纯数字:方案1 / 方案 1 / 方案 12 if re.match(r'^\s*方案\s*\d+\s*$', text): return True + # 3) 查询任务/任务状态场景:仅查任务状态或结果,无需用户点确认,直接视为已确认 + if _scenes_contain_query_job_status(ctx): + return True + return False