Skip to content

Commit 910561a

Browse files
committed
fix (tasks): general_instruction tool
1 parent 10fbada commit 910561a

4 files changed

Lines changed: 22 additions & 12 deletions

File tree

src/client/components/tasks/TaskDetailsPanel.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ const TaskDetailsPanel = ({
7272
// FIX: Filter out any null, undefined, or empty tool names from the plan
7373
// to prevent errors when rendering the missing tools buttons.
7474
const requiredTools = new Set(
75-
plan.map((step) => step.tool).filter(Boolean)
75+
plan
76+
.map((step) => step.tool)
77+
.filter((tool) => tool && tool !== "general_instruction")
7678
)
7779

7880
const connectedTools = new Set(

src/server/workers/executor/tasks.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
### `src\server\workers\executor\tasks.py`
2-
31
import os
42
import json
53
import datetime
@@ -282,7 +280,7 @@ async def async_execute_task_plan(task_id: str, user_id: str, run_id: str):
282280
if not plan_to_execute:
283281
plan_to_execute = task.get("plan", [])
284282

285-
required_tools_from_plan = {step['tool'] for step in plan_to_execute}
283+
required_tools_from_plan = {step['tool'] for step in plan_to_execute if step.get('tool') and step.get('tool') != 'general_instruction'}
286284
user_integrations = user_profile.get("userData", {}).get("integrations", {}) if user_profile else {}
287285
active_mcp_servers = {}
288286
for tool_name in required_tools_from_plan:
@@ -317,13 +315,14 @@ async def async_execute_task_plan(task_id: str, user_id: str, run_id: str):
317315
"1. **Think Step-by-Step:** Before each action, you MUST explain your reasoning and what you are about to do. This is your internal monologue and will be logged.\n"
318316
"2. **Execution Flow:** You MUST start by executing the first step of the plan. Do not summarize the plan or provide a final answer until you have executed all steps. Follow the plan sequentially. SEARCH FOR ANY RELEVANT CONTEXT THAT YOU NEED TO COMPLETE THE EXECUTION. If you are resuming a task after the user answered a clarifying question, the answered questions will be in the `clarifying_questions` field of the task context. Use this new information to proceed.\n"
319317
"3. **Map Plan to Tools:** The plan provides a high-level tool name (e.g., 'gmail', 'gdrive'). You must map this to the specific functions available to you (e.g., `gmail_server-sendEmail`, `gdrive_server-gdrive_search`).\n"
320-
"4. **Be Resourceful & Fill Gaps:** The plan is a guideline. If a step is missing information (e.g., an email address for a manager, a document name), your first action for that step MUST be to use the `memory-search_memory` tool to find the missing information. Do not proceed with incomplete information.\n"
321-
"5. **Remember New Information:** If you discover a new, permanent fact about the user during your execution (e.g., you find their manager's email is 'boss@example.com'), you MUST use `memory-cud_memory` to save it. This is critical for personalization.\n"
322-
"6. **Handle Failures:** If a tool fails, analyze the error, think about an alternative approach, and try again. Do not give up easily. Your thought process and the error will be logged automatically.\n"
323-
"7. **Provide a Final, Detailed Answer:** ONLY after all steps are successfully completed, you MUST provide a final, comprehensive answer to the user. This should be your final message, not a tool call. For example: 'I have successfully scheduled the meeting and sent an invitation to John Doe.'.\n"
324-
"8. **Fill Placeholders Dynamically:** If a step involves drafting content (e.g., emails), ALWAYS fill in placeholders like [name] or [description] using data from memory (first call `memory-search_memory` if needed) or context. NEVER leave brackets [] in final outputs.\n"
325-
"9. **Contact Information:** To find contact details like phone numbers or emails, use the `gpeople` tool before attempting to send an email or make a call.\n"
326-
"10. **Handle Missing Information**: If you have exhausted all tool options (including memory and search) and still lack critical information to proceed, you MUST fail. Your final answer should clearly state what information is missing. For example: `<answer>Task failed. I could not find the client's email address in memory or through any available tools.</answer>`\n"
318+
"4. **Special Tool 'general_instruction':** When a step's tool is `general_instruction`, you do not need to call an external tool. Instead, use your own reasoning and knowledge to fulfill the instruction in the step's `description`. This is for tasks like summarizing text from a previous step, analyzing data you already have, or drafting content.\n"
319+
"5. **Be Resourceful & Fill Gaps:** The plan is a guideline. If a step is missing information (e.g., an email address for a manager, a document name), your first action for that step MUST be to use the `memory-search_memory` tool to find the missing information. Do not proceed with incomplete information.\n"
320+
"6. **Remember New Information:** If you discover a new, permanent fact about the user during your execution (e.g., you find their manager's email is 'boss@example.com'), you MUST use `memory-cud_memory` to save it. This is critical for personalization.\n"
321+
"7. **Handle Failures:** If a tool fails, analyze the error, think about an alternative approach, and try again. Do not give up easily. Your thought process and the error will be logged automatically.\n"
322+
"8. **Provide a Final, Detailed Answer:** ONLY after all steps are successfully completed, you MUST provide a final, comprehensive answer to the user. This should be your final message, not a tool call. For example: 'I have successfully scheduled the meeting and sent an invitation to John Doe.'.\n"
323+
"9. **Fill Placeholders Dynamically:** If a step involves drafting content (e.g., emails), ALWAYS fill in placeholders like [name] or [description] using data from memory (first call `memory-search_memory` if needed) or context. NEVER leave brackets [] in final outputs.\n"
324+
"10. **Contact Information:** To find contact details like phone numbers or emails, use the `gpeople` tool before attempting to send an email or make a call.\n"
325+
"11. **Handle Missing Information**: If you have exhausted all tool options (including memory and search) and still lack critical information to proceed, you MUST fail. Your final answer should clearly state what information is missing.\n"
327326
"\nNow, begin your work. Think step-by-step and start executing the plan."
328327
)
329328

@@ -612,6 +611,9 @@ async def async_generate_task_result(task_id: str, run_id: str, user_id: str, ag
612611
}
613612
logger.info(f"Subtask {task_id} for step {parent_step_id} completed. Updating parent task {parent_task_id}.")
614613

614+
await push_task_list_update(user_id, task_id, run_id) # Push update for subtask completion
615+
await push_task_list_update(user_id, parent_task_id, "orchestrator_progress") # Push update for parent task
616+
615617
from workers.long_form_tasks import execute_orchestrator_cycle
616618
from mcp_hub.orchestrator.state_manager import mark_step_as_complete, add_execution_log, update_orchestrator_state
617619

@@ -645,10 +647,12 @@ async def async_generate_task_result(task_id: str, run_id: str, user_id: str, ag
645647
for run in runs:
646648
if run.get("run_id") == run_id:
647649
run["result"] = error_result
650+
run["status"] = "error" # Mark run as error
648651
break
649652
update_payload = {"runs": runs}
650653
encrypt_doc(update_payload, ["runs"])
651654
await db.tasks.update_one({"task_id": task_id, "user_id": user_id}, {"$set": update_payload})
655+
await push_task_list_update(user_id, task_id, run_id)
652656
except Exception as e:
653657
logger.error(f"Error in async_generate_task_result for task {task_id}: {e}", exc_info=True)
654658
error_result = {"summary": f"Failed to generate final report: {str(e)}"}
@@ -661,10 +665,12 @@ async def async_generate_task_result(task_id: str, run_id: str, user_id: str, ag
661665
for run in runs:
662666
if run.get("run_id") == run_id:
663667
run["result"] = error_result
668+
run["status"] = "error" # Mark run as error
664669
break
665670
update_payload = {"runs": runs}
666671
encrypt_doc(update_payload, ["runs"])
667672
await db.tasks.update_one({"task_id": task_id, "user_id": user_id}, {"$set": update_payload})
673+
await push_task_list_update(user_id, task_id, run_id)
668674

669675
@celery_app.task(name="run_single_item_worker", bind=True)
670676
def run_single_item_worker(self, sub_task_id: str, parent_task_id: str, user_id: str, item: Any, worker_prompt: str, worker_tools: List[str]):

src/server/workers/planner/prompts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
2121
Here is the complete list of services (tools) available to the executor agent, that you can use in your plan:
2222
{{
23+
"general_instruction": "Use for general tasks that do not require a specific tool, such as summarizing information, writing content, or providing analysis based on context from previous steps.",
2324
"accuweather": "Use this tool to get weather information for a specific location.",
2425
"discord": "Use this when the user wants to do something related to the messaging platform, Discord.",
2526
"gcalendar": "Use this tool to manage events in Google Calendar.",
@@ -64,6 +65,7 @@
6465
- Create a concise `name` for the task.
6566
- Create a concise `description` summarizing the overall goal.
6667
- ONLY USE tools from the provided list. Do not make up your own tools. Do not add tools like 'null' or 'none'.
68+
- Use the `general_instruction` tool for steps that rely on the LLM's native capabilities like summarization, analysis, or content creation without needing external data.
6769
- Break down the goal into logical steps, choosing the most appropriate tool for each.
6870
- If an action item is not actionable with the given tools (e.g., "Think about the marketing report"), do not create a plan for it.
6971
- Do not include any text outside of the JSON object. Your response must begin with `{{` and end with `}}`.

src/server/workers/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,7 @@ async def async_generate_plan(task_id: str, user_id: str):
684684

685685
missing_tools = []
686686
if is_auto_approvable:
687-
required_tools_from_plan = {step['tool'] for step in plan_data.get('plan', [])}
687+
required_tools_from_plan = {step['tool'] for step in plan_data.get('plan', []) if step.get('tool') and step.get('tool') != 'general_instruction'}
688688
user_integrations = user_profile.get("userData", {}).get("integrations", {})
689689

690690
for tool_name in required_tools_from_plan:

0 commit comments

Comments
 (0)