Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 58 additions & 33 deletions agents/matmaster_agent/flow_agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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

Expand Down
15 changes: 12 additions & 3 deletions agents/matmaster_agent/flow_agents/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading