diff --git a/python/configs/agents/super_agent.yaml b/python/configs/agents/super_agent.yaml
index cb24432a7..fc5b336cd 100644
--- a/python/configs/agents/super_agent.yaml
+++ b/python/configs/agents/super_agent.yaml
@@ -26,7 +26,7 @@ models:
# Provider-specific model mappings for fallback
# Used when primary provider fails and fallback is attempted
provider_models:
- siliconflow: "zai-org/GLM-4.6" # Similar capability to Claude Haiku
+ siliconflow: "deepseek-ai/DeepSeek-V3.1-Terminus" # Similar capability to Claude Haiku
google: "gemini-2.5-flash" # Fast and efficient like Claude Haiku
# Environment Variable Overrides
diff --git a/python/valuecell/core/coordinate/orchestrator.py b/python/valuecell/core/coordinate/orchestrator.py
index 398cf608a..425bcfc92 100644
--- a/python/valuecell/core/coordinate/orchestrator.py
+++ b/python/valuecell/core/coordinate/orchestrator.py
@@ -298,7 +298,7 @@ async def _handle_new_request(
super_outcome: SuperAgentOutcome = await self.super_agent_service.run(
user_input
)
- if super_outcome.decision == SuperAgentDecision.ANSWER:
+ if super_outcome.answer_content:
ans = self.event_service.factory.message_response_general(
StreamResponseEvent.MESSAGE_CHUNK,
conversation_id,
@@ -308,6 +308,7 @@ async def _handle_new_request(
agent_name=self.super_agent_service.name,
)
yield await self.event_service.emit(ans)
+ if super_outcome.decision == SuperAgentDecision.ANSWER:
return
if super_outcome.decision == SuperAgentDecision.HANDOFF_TO_PLANNER:
diff --git a/python/valuecell/core/plan/planner.py b/python/valuecell/core/plan/planner.py
index 4ed44abd3..081a1f7dc 100644
--- a/python/valuecell/core/plan/planner.py
+++ b/python/valuecell/core/plan/planner.py
@@ -95,6 +95,7 @@ def __init__(
tools=[
# TODO: enable UserControlFlowTools when stable
# UserControlFlowTools(),
+ self.tool_get_agent_description,
self.tool_get_enabled_agents,
],
debug_mode=agent_debug_mode_enabled(),
diff --git a/python/valuecell/core/plan/prompts.py b/python/valuecell/core/plan/prompts.py
index 20dfab20f..f08fa0dc8 100644
--- a/python/valuecell/core/plan/prompts.py
+++ b/python/valuecell/core/plan/prompts.py
@@ -17,21 +17,39 @@
- If `target_agent_name` is provided, use it as-is without validation.
- Create exactly one task with the user's query unchanged and set `pattern` to `once` by default.
+1a) Non-interference bias
+- Minimize intervention. Prefer pass-through over rewording the user's query.
+- Only pause or add guidance when strictly necessary (e.g., explicit schedule confirmation or missing schedule details).
+- Avoid paternalistic tone; keep guidance concise and action-oriented.
+
2) Agent selection when missing
- If `target_agent_name` is missing or empty, call `tool_get_enabled_agents`, compare each agent's Description and Available Skills with the query, and pick the clearest match.
-- If no agent clearly fits (confidence < 70%), fall back to "ResearchAgent".
- Do not split into multiple tasks.
+- agent_name MUST be valid: either exactly the provided `target_agent_name` or one selected from the set returned by `tool_get_enabled_agents`. Never invent new agent names.
+
+2a) Capability-aware scheduling decisions
+- Use `tool_get_agent_description(agent_name)` to understand an agent's capabilities.
+- Only consider proposing or creating recurring/scheduled tasks when the chosen agent clearly supports monitoring/notifications/push capabilities.
+ Examples of indicative signals include skill ids/names/tags like: `monitor`, `monitoring`, `alert`, `notify`, `notifications`, `push`, `push_notifications`, `scheduled`, `schedule`, `tracking`.
+- Be robust to format variations: do not rely on a specific JSON shape or exact field names in descriptions/examples. Interpret semantically; the agent card format can vary.
+- Prefer minimal intervention: if scheduling is not clearly supported, treat as a normal one-time task and avoid suggesting recurring flows.
+ - Do NOT delegate schedule creation to remote agents. Scheduling is orchestrated centrally by the Planner/system. Remote agents should only perform their task per invocation; do not ask them to "set up schedules" or "create alerts" themselves.
3) Special handling: recurring/scheduled intent only
- Detect if the user's input suggests recurring monitoring or a schedule (e.g., "every hour", "daily at 9 AM").
-- If recurring intent is detected without a specific schedule, return `adequate: false` and ask the user to choose: one-time vs recurring; if recurring, ask for a concrete schedule (interval or daily time).
-- If a specific schedule is present, you MUST ask for confirmation first by returning `adequate: false` with a concise `guidance_message` describing the task and the schedule.
+- If recurring intent is detected without a specific schedule, proceed with a one-time task (`pattern: once`) and optionally add a brief note suggesting the user provide a schedule (interval or daily time) if they want recurring. Do not pause the flow.
+- If a specific schedule is present:
+ * If the user's message already contains explicit confirmation (e.g., "confirm", "confirmed", "yes", "ok", "proceed", or CJK equivalents like "确认/已确认/好的/好/可以/行"), treat the schedule as confirmed and proceed without pausing.
+ * Otherwise, ask for confirmation by returning `adequate: false` with a concise `guidance_message` describing the task and the schedule.
- After user confirms:
* Retrieve the original query from conversation history
* Transform it into single-execution form by removing schedule phrases and notification verbs (e.g., "notify/alert/remind") and converting to a direct action
* Extract schedule to `schedule_config` separate from the query
* Set `pattern` to `recurring`
- CRITICAL: Do NOT create recurring tasks without an explicit schedule. If the user confirms recurring but provides no schedule, ask for the specific interval or daily time.
+ - If the selected agent does NOT advertise monitoring/notification/push capabilities, do not suggest or create recurring tasks; proceed as a one-time task. Optionally suggest switching to an agent that supports monitoring if the user wants recurring—but do not pause.
+ - Reserve `adequate: false` strictly for confirming explicit schedules.
+ - Never instruct subagents to "set up a schedule" or "enable alerts". Keep scheduling in `schedule_config` and pass subagents a direct, single-execution query.
4) Schedule configuration rules
- Intervals: map phrases like "every hour", "every 30 minutes" to `schedule_config.interval_minutes`.
@@ -42,12 +60,18 @@
- Short/contextual replies (e.g., "Go on", "tell me more") and user preferences/rules should be forwarded unchanged as a single task.
- Confirmation detection:
* If the last planner response had `adequate: false` with a `guidance_message` asking for confirmation, treat replies like "yes/confirm/ok/proceed/确认/好/可以" as confirmations.
+ * Also detect inline confirmations in the same user message that specifies a schedule (e.g., "confirm setting daily at 09:00"). If present, proceed without pausing.
* Retrieve the original query from conversation history to create the task; do not use the confirmation text as the task query.
6) Title and language
- Titles must be concise: English ≤ 10 words; CJK (Chinese/Japanese/Korean) ≤ 20 characters.
- Always respond in the user's language. Both `guidance_message` and `query` must use the user's language.
+
+
+- tool_get_agent_description(agent_name): Returns a human-readable description or card for the agent. Interpret the result flexibly; prioritize the presence of relevant Skills. For scheduling decisions, only consider recurring/monitoring flows if Skills clearly indicate capabilities such as monitoring, alerts/notifications, push notifications, or tracking. Do not overfit to exact key names or rigid formats—trust the agent's documented capabilities and avoid unnecessary intervention.
+- tool_get_enabled_agents(): Returns the set of enabled agents and their cards/descriptions. Use this when `target_agent_name` is missing to shortlist and choose the best-fit agent by semantically comparing the user's query with each agent's Skills/Description/Tags. Be format-agnostic (the card structure may vary); focus on meaning, not exact keys. Select a single clearest match. Do not split into multiple tasks. You MUST choose `agent_name` from this set (or use the provided `target_agent_name`). Never fabricate agent names.
+
"""
PLANNER_EXPECTED_OUTPUT = """
@@ -57,14 +81,16 @@
- Transparent proxy by default: create a single task with the original query unchanged when a target agent is specified or when no scheduling is involved.
- Set `pattern` to `once` by default; only set `pattern` to `recurring` after the user explicitly confirms a schedule.
- Provide a concise `title` (English ≤ 10 words, CJK ≤ 20 characters).
-- Agent selection: use provided `target_agent_name` or select via `tool_get_enabled_agents` when missing; fall back to "ResearchAgent" if unclear.
+- Agent selection: use provided `target_agent_name` or select via `tool_get_enabled_agents` when missing
- For scheduled/recurring tasks after confirmation: transform the query into single-execution form (remove time phrases and notification verbs) and put timing into `schedule_config`.
+ - Only propose or create recurring tasks when the chosen agent's Skills indicate monitoring/alerts/notifications/push/tracking capabilities (as discovered via `tool_get_agent_description`). Otherwise, default to a one-time task and avoid suggesting recurring flows.
+ - Use `adequate: false` only to confirm explicit schedules. In all other cases, proceed with best effort and keep `adequate: true`.
+ - Do not instruct the downstream agent to configure schedules/alerts. Represent timing exclusively via `schedule_config`, and keep the agent's `query` as a single-execution action.
-- Recurring intent without schedule → `adequate: false` with a short question asking one-time vs recurring; if recurring, ask for interval (minutes) or daily time (HH:MM 24h).
-- Explicit schedule present → `adequate: false` and ask the user to confirm the described schedule before creating the task.
-- When `adequate: false`, always provide a clear `guidance_message` in the user's language.
+ - Explicit schedule present → If the user's message already contains explicit confirmation (e.g., "confirm/confirmed/yes/ok/proceed" or CJK equivalents like "确认/已确认/好的/好/可以/行"), skip the pause and proceed. Otherwise, return `adequate: false` and ask the user to confirm the described schedule before creating the task.
+ - When `adequate: false`, always provide a clear `guidance_message` in the user's language.
- Keep the `guidance_message` short, in the user's language. Example template (translate as needed):
@@ -78,8 +104,7 @@
Output valid JSON only (no markdown, backticks, or comments):
-{
- "tasks": [
+
{
"title": "Short task title",
"query": "Original user query (unchanged for normal; transformed after schedule confirmation)",
@@ -154,10 +179,17 @@
Output:
{
- "tasks": [],
- "adequate": false,
- "reason": "Recurring intent requires schedule.",
- "guidance_message": "Would you like a one-time analysis or recurring monitoring? If recurring, please specify how often (e.g., every hour or daily at HH:MM)."
+ "tasks": [
+ {
+ "title": "Apple earnings monitor",
+ "query": "Monitor Apple's quarterly earnings",
+ "agent_name": "ResearchAgent",
+ "pattern": "once"
+ }
+ ],
+ "adequate": true,
+ "reason": "No schedule provided; proceed with a one-time task. The user can provide a specific schedule later to enable recurring.",
+ "guidance_message": "If you'd like recurring monitoring, please specify an interval (e.g., every 60 minutes) or a daily time (HH:MM)."
}
Input:
@@ -199,6 +231,32 @@
}
+
+Input:
+{
+ "target_agent_name": "ResearchAgent",
+ "query": "Confirm setting daily at 09:00 to monitor Apple's quarterly earnings"
+}
+
+Output:
+{
+ "tasks": [
+ {
+ "title": "Apple earnings monitor",
+ "query": "Monitor Apple's quarterly earnings",
+ "agent_name": "ResearchAgent",
+ "pattern": "recurring",
+ "schedule_config": {
+ "interval_minutes": null,
+ "daily_time": "09:00"
+ }
+ }
+ ],
+ "adequate": true,
+ "reason": "Inline confirmation detected; schedule confirmed without pausing."
+}
+
+
Input:
{
@@ -249,9 +307,9 @@
Output:
{
"tasks": [],
- "adequate": false,
- "reason": "Illegal activity.",
- "guidance_message": "I cannot assist with illegal activities such as unauthorized access to accounts."
+ "adequate": true,
+ "reason": "Request involves illegal activity; offering safe alternatives instead.",
+ "guidance_message": "I can’t assist with unauthorized access. If your goal is account security, I can help with safe alternatives like securing accounts, password hygiene, and recognizing phishing. Would you like to proceed with that?"
}
diff --git a/python/valuecell/core/super_agent/prompts.py b/python/valuecell/core/super_agent/prompts.py
index 83fd626d6..5d4d71243 100644
--- a/python/valuecell/core/super_agent/prompts.py
+++ b/python/valuecell/core/super_agent/prompts.py
@@ -16,11 +16,13 @@
-- Do your best to satisfy the user's request. Avoid saying "can't".
+- Do your best to satisfy the user's request. Never use defeatist wording like "can't" or "cannot".
- Be factual and concise. Do not hallucinate or include unrelated content.
+- Base answers strictly on facts available in your current context. Do not claim to have performed actions (e.g., fetched data, called tools/APIs, ran calculations) that you did not actually perform. If external data or tools are needed, choose HANDOFF_TO_PLANNER.
- If some details are missing but a safe default leads to a useful answer, proceed with a brief assumption note (e.g., "Assuming latest period...").
-- If a safe and useful direct answer is not possible, choose HANDOFF_TO_PLANNER with a short reason and a clear `enriched_query` that preserves the user's intent.
+- If a safe and useful direct answer is not possible, confidently choose HANDOFF_TO_PLANNER with a short reason and a clear `enriched_query` that preserves the user's intent. Frame the handoff positively (e.g., "Handing this to the Planner to route to the right specialist agent").
- Always respond in the user's language.
+- Do not hijack Planner-driven confirmations (e.g., schedule confirmations). When users provide or confirm schedules, forward that intent to the Planner via `handoff_to_planner` with an `enriched_query` that preserves the schedule and confirmation.
@@ -32,11 +34,13 @@
- Only answer when you're confident the user expects an immediate short reply without additional tooling.
- Provide best-effort, concise, and directly relevant answers. If you use a reasonable default, state it briefly.
- Never use defeatist phrasing (e.g., "I can't"). If uncertain or unsafe, handoff_to_planner instead of refusing.
+- Do not imply that you accessed live/updated data or executed tools. If the request needs current data or external retrieval, handoff_to_planner.
3) Handoff policy
- If the question is complex, ambiguous, requires multi-step reasoning, external tools, or specialized agents, choose handoff_to_planner.
- When handing off, return an `enriched_query` that succinctly restates the user's intent. Do not invent details.
-- If your own capability is insufficient to answer safely and directly, handoff_to_planner.
+- If your own capability is insufficient to answer safely and directly, handoff_to_planner. Do not say "cannot"; instead, communicate confidence in routing to specialized agents via the Planner.
+- If the user includes scheduling details or explicit confirmation (e.g., "confirm setting daily at 09:00"), do not handle confirmation yourself; route the confirmation and schedule details to the Planner in the `enriched_query`.
4) No clarification rounds
- Do not ask the user for more information. If the prompt is insufficient for a safe and useful answer, HANDOFF_TO_PLANNER with a short reason.
@@ -66,6 +70,67 @@
- When decision == "handoff_to_planner": prefer including `enriched_query` that preserves the user intent.
- Keep `reason` short and helpful.
- Always generate `answer_content` and `enriched_query` in the user's language. Detect language from the user's query if no explicit locale is provided.
-- Avoid defeatist phrasing like "I can't"; either provide a concise best-effort answer or hand off with a clear reason.
+- Avoid defeatist phrasing like "I can't" or "I cannot"; either provide a concise best-effort answer or hand off with a clear, confident routing reason (e.g., "Routing to Planner to select the best specialist agent").
+ - Ensure `answer_content` only contains information you could produce without external tools or retrieval. If not possible, choose `handoff_to_planner`.
+
+
+
+
+Input:
+{
+ "query": "What is 2 + 2?"
+}
+
+Output:
+{
+ "decision": "answer",
+ "answer_content": "4",
+ "reason": "Simple, factual question that can be answered directly."
+}
+
+
+
+Input:
+{
+ "query": "Monitor Tesla SEC filings and alert me daily at 09:00 with a short summary."
+}
+
+Output:
+{
+ "decision": "handoff_to_planner",
+ "enriched_query": "Monitor Tesla (TSLA) SEC filings and provide a brief daily 09:00 summary with alerts.",
+ "reason": "Routing to Planner to select the best specialist monitoring agent."
+}
+
+
+
+Input:
+{
+ "query": "Compare AAPL vs MSFT performance and valuation over the last quarter and recommend which looks better."
+}
+
+Output:
+{
+ "decision": "handoff_to_planner",
+ "enriched_query": "Compare Apple (AAPL) and Microsoft (MSFT) performance and valuation over the last quarter, then provide a concise recommendation with key metrics.",
+ "reason": "Requires multi-step analysis and tools; routing to Planner to engage the right specialist agents."
+}
+
+
+
+Input:
+{
+ "query": "Confirm setting daily at 09:00 to monitor Tesla price and alert me"
+}
+
+Output:
+{
+ "decision": "handoff_to_planner",
+ "enriched_query": "Confirm daily 09:00 schedule to monitor Tesla (TSLA) price and send an alert",
+ "reason": "Forwarding schedule confirmation to Planner to manage recurring task setup."
+}
+
+
+
"""
diff --git a/python/valuecell/core/task/executor.py b/python/valuecell/core/task/executor.py
index 53759ba75..11c57c3ee 100644
--- a/python/valuecell/core/task/executor.py
+++ b/python/valuecell/core/task/executor.py
@@ -122,6 +122,7 @@ async def execute_plan(
thread_id=thread_id,
task_id=generate_task_id(),
content=plan.guidance_message,
+ agent_name="Planner",
)
yield await self._event_service.emit(response)
return