Skip to content
Merged
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
85 changes: 52 additions & 33 deletions agents/matmaster_agent/flow_agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
check_plan,
get_tools_list,
is_plan_confirmed,
scenes_contain_query_job_status,
should_bypass_confirmation,
)
from agents.matmaster_agent.llm_config import MatMasterLlmConfig
Expand Down Expand Up @@ -407,7 +408,12 @@ async def _run_scene_agent(
yield update_state_event(ctx, state_delta={'scenes': copy.deepcopy(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 +477,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 +887,18 @@ async def _run_research_flow(
yield update_state_event(ctx, state_delta={PLAN: {}, MULTI_PLANS: {}})

# 制定计划(1. 无计划;2. 计划已完成;3. 计划失败;4. 用户未确认计划)
# 仅查询任务状态时跳过 thinking(查任务状态不 thinking)
skip_thinking = scenes_contain_query_job_status(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
6 changes: 6 additions & 0 deletions agents/matmaster_agent/flow_agents/scene_agent/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,9 @@ class SceneEnum(DescriptiveEnum):
'perovskite_research',
'Research, literature/database search, and semantic mining focused on perovskite solar cells (efficiency, stability, additives, architectures, new molecules).',
)

# job/task status only (no planning/thinking needed)
QUERY_JOB_STATUS = (
'query_job_status',
'User only asks to check task/job status or get task results. e.g. 查询任务, 查看任务, 查看任务状态, 查看任务结果, 任务怎么样了, 任务进度, check task status, check task results. Use this when the sole intent is to query status or retrieve results of submitted jobs, not to create a new plan.',
)
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