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
2 changes: 1 addition & 1 deletion python/configs/agents/super_agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion python/valuecell/core/coordinate/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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:
Expand Down
1 change: 1 addition & 0 deletions python/valuecell/core/plan/planner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
90 changes: 74 additions & 16 deletions python/valuecell/core/plan/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand All @@ -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.
</core_rules>

<tools>
- 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.
</tools>
"""

PLANNER_EXPECTED_OUTPUT = """
Expand All @@ -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.
</default_behavior>

<when_to_pause>
- 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.

<scheduled_confirmation_format>
- Keep the `guidance_message` short, in the user's language. Example template (translate as needed):
Expand All @@ -78,8 +104,7 @@
Output valid JSON only (no markdown, backticks, or comments):

<response_json_format>
{
"tasks": [

{
"title": "Short task title",
"query": "Original user query (unchanged for normal; transformed after schedule confirmation)",
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -199,6 +231,32 @@
}
</example_3_recurring_confirmation>

<example_3_recurring_confirmation_with_inline_confirmation>
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."
}
</example_3_recurring_confirmation_with_inline_confirmation>

<example_4_scheduled_task>
Input:
{
Expand Down Expand Up @@ -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?"
}
</example_5_unusable_request>

Expand Down
73 changes: 69 additions & 4 deletions python/valuecell/core/super_agent/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
</purpose>

<answering_principles>
- 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.
</answering_principles>

<core_rules>
Expand All @@ -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.
Expand Down Expand Up @@ -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`.
</response_requirements>

<examples>

<example_1_direct_answer>
Input:
{
"query": "What is 2 + 2?"
}

Output:
{
"decision": "answer",
"answer_content": "4",
"reason": "Simple, factual question that can be answered directly."
}
</example_1_direct_answer>

<example_2_handoff_to_planner_specialist>
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."
}
</example_2_handoff_to_planner_specialist>

<example_3_handoff_for_multi_step_analysis>
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."
}
</example_3_handoff_for_multi_step_analysis>

<example_4_handoff_schedule_confirmation>
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."
}
</example_4_handoff_schedule_confirmation>

</examples>
"""
1 change: 1 addition & 0 deletions python/valuecell/core/task/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down