feat: add GCU knowledge to planning
This commit is contained in:
@@ -35,15 +35,21 @@ def _build_appendices() -> str:
|
|||||||
# Shared appendices — appended to every coding node's system prompt.
|
# Shared appendices — appended to every coding node's system prompt.
|
||||||
_appendices = _build_appendices()
|
_appendices = _build_appendices()
|
||||||
|
|
||||||
# GCU first-class section for building phase (when GCU is enabled).
|
# GCU first-class section (when GCU is enabled).
|
||||||
# This is placed prominently in the main prompt body, not as an appendix.
|
# Placed prominently in the main prompt body, not as an appendix.
|
||||||
_gcu_building_section = (
|
_gcu_building_section = (
|
||||||
("\n\n# GCU Nodes — Browser Automation\n\n" + _gcu_guide)
|
("\n\n# GCU Nodes — Browser Automation\n\n" + _gcu_guide)
|
||||||
if _is_gcu_enabled() and _gcu_guide
|
if _is_gcu_enabled() and _gcu_guide
|
||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Tools available to both coder (worker) and queen.
|
_gcu_planning_section = (
|
||||||
|
("\n\n# GCU Nodes — Browser Automation\n\n" + _gcu_guide)
|
||||||
|
if _is_gcu_enabled() and _gcu_guide
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tools available to phases.
|
||||||
_SHARED_TOOLS = [
|
_SHARED_TOOLS = [
|
||||||
# File I/O
|
# File I/O
|
||||||
"read_file",
|
"read_file",
|
||||||
@@ -335,7 +341,7 @@ use box-drawing characters and clear flow arrows:
|
|||||||
│ gather │
|
│ gather │
|
||||||
│ subagent: gcu_search │
|
│ subagent: gcu_search │
|
||||||
│ input: user_request │
|
│ input: user_request │
|
||||||
│ tools: web_search, │
|
│ tools: load_data, │
|
||||||
│ save_data │
|
│ save_data │
|
||||||
└────────────┬────────────┘
|
└────────────┬────────────┘
|
||||||
│ on_success
|
│ on_success
|
||||||
@@ -1057,4 +1063,5 @@ __all__ = [
|
|||||||
"_package_builder_knowledge",
|
"_package_builder_knowledge",
|
||||||
"_appendices",
|
"_appendices",
|
||||||
"_gcu_building_section",
|
"_gcu_building_section",
|
||||||
|
"_gcu_planning_section",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ async def create_queen(
|
|||||||
_appendices,
|
_appendices,
|
||||||
_building_knowledge,
|
_building_knowledge,
|
||||||
_gcu_building_section,
|
_gcu_building_section,
|
||||||
|
_gcu_planning_section,
|
||||||
_planning_knowledge,
|
_planning_knowledge,
|
||||||
_shared_building_knowledge,
|
_shared_building_knowledge,
|
||||||
_queen_behavior_always,
|
_queen_behavior_always,
|
||||||
@@ -155,6 +156,7 @@ async def create_queen(
|
|||||||
+ _queen_behavior_always
|
+ _queen_behavior_always
|
||||||
+ _queen_behavior_planning
|
+ _queen_behavior_planning
|
||||||
+ _planning_knowledge
|
+ _planning_knowledge
|
||||||
|
+ _gcu_planning_section
|
||||||
+ worker_identity
|
+ worker_identity
|
||||||
)
|
)
|
||||||
phase_state.prompt_planning = _queen_identity_planning + _planning_body
|
phase_state.prompt_planning = _queen_identity_planning + _planning_body
|
||||||
|
|||||||
@@ -514,6 +514,12 @@ def register_queen_lifecycle_tools(
|
|||||||
"Use your coding tools to modify the agent, then call "
|
"Use your coding tools to modify the agent, then call "
|
||||||
"load_built_agent(path) to stage it again."
|
"load_built_agent(path) to stage it again."
|
||||||
)
|
)
|
||||||
|
# Nudge the queen to start coding instead of blocking for user input.
|
||||||
|
if phase_state is not None and phase_state.inject_notification:
|
||||||
|
await phase_state.inject_notification(
|
||||||
|
"[PHASE CHANGE] Switched to BUILDING phase. "
|
||||||
|
"Start implementing the changes now."
|
||||||
|
)
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
_stop_edit_tool = Tool(
|
_stop_edit_tool = Tool(
|
||||||
@@ -609,19 +615,54 @@ def register_queen_lifecycle_tools(
|
|||||||
"""Wrapper: scaffold or just switch to building phase."""
|
"""Wrapper: scaffold or just switch to building phase."""
|
||||||
agent_name = (inputs.get("agent_name") or "").strip()
|
agent_name = (inputs.get("agent_name") or "").strip()
|
||||||
|
|
||||||
# No agent_name → just switch to building (for fixing existing agent)
|
# No agent_name → try to fall back to the session's current agent,
|
||||||
|
# or fail with actionable guidance.
|
||||||
if not agent_name:
|
if not agent_name:
|
||||||
runtime = _get_runtime()
|
# Try to resolve agent_name from the current session
|
||||||
if runtime is None:
|
fallback_path = getattr(session, "worker_path", None)
|
||||||
|
if fallback_path is not None:
|
||||||
|
agent_name = Path(fallback_path).name
|
||||||
|
else:
|
||||||
|
# Server path: check SessionManager
|
||||||
|
if session_manager is not None and manager_session_id:
|
||||||
|
srv_session = session_manager.get_session(manager_session_id)
|
||||||
|
if srv_session and getattr(srv_session, "worker_path", None):
|
||||||
|
fallback_path = srv_session.worker_path
|
||||||
|
agent_name = Path(fallback_path).name
|
||||||
|
|
||||||
|
if not agent_name:
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
{"error": "No worker loaded. Provide agent_name to scaffold a new agent."}
|
{
|
||||||
|
"error": (
|
||||||
|
"No agent_name provided and no agent loaded in this session. "
|
||||||
|
"To fix: call list_agents() to find the agent name, then call "
|
||||||
|
"initialize_and_build_agent(agent_name='<name>') to scaffold it."
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Fall back succeeded — switch to building without scaffolding
|
||||||
|
logger.info(
|
||||||
|
"initialize_and_build_agent: no agent_name provided, "
|
||||||
|
"falling back to session agent '%s'",
|
||||||
|
agent_name,
|
||||||
|
)
|
||||||
if phase_state is not None:
|
if phase_state is not None:
|
||||||
await phase_state.switch_to_building(source="tool")
|
await phase_state.switch_to_building(source="tool")
|
||||||
|
if phase_state.inject_notification:
|
||||||
|
await phase_state.inject_notification(
|
||||||
|
"[PHASE CHANGE] Switched to BUILDING phase. "
|
||||||
|
"Start implementing the fix now."
|
||||||
|
)
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
{
|
{
|
||||||
"status": "editing",
|
"status": "editing",
|
||||||
"phase": "building",
|
"phase": "building",
|
||||||
|
"agent_name": agent_name,
|
||||||
|
"warning": (
|
||||||
|
f"No agent_name provided — using session agent '{agent_name}'. "
|
||||||
|
f"Agent files are at exports/{agent_name}/."
|
||||||
|
),
|
||||||
"message": (
|
"message": (
|
||||||
"Switched to BUILDING phase. Full coding tools restored. "
|
"Switched to BUILDING phase. Full coding tools restored. "
|
||||||
"Implement the fix, then call load_built_agent(path) to reload."
|
"Implement the fix, then call load_built_agent(path) to reload."
|
||||||
@@ -643,6 +684,13 @@ def register_queen_lifecycle_tools(
|
|||||||
if parsed.get("success", True):
|
if parsed.get("success", True):
|
||||||
if phase_state is not None:
|
if phase_state is not None:
|
||||||
await phase_state.switch_to_building(source="tool")
|
await phase_state.switch_to_building(source="tool")
|
||||||
|
# Inject a continuation message so the queen starts
|
||||||
|
# building immediately instead of blocking for user input.
|
||||||
|
if phase_state.inject_notification:
|
||||||
|
await phase_state.inject_notification(
|
||||||
|
"[PHASE CHANGE] Agent scaffolded and switched to BUILDING phase. "
|
||||||
|
"Start implementing the agent nodes now."
|
||||||
|
)
|
||||||
except (json.JSONDecodeError, KeyError, TypeError):
|
except (json.JSONDecodeError, KeyError, TypeError):
|
||||||
pass
|
pass
|
||||||
return result_str
|
return result_str
|
||||||
|
|||||||
@@ -116,16 +116,39 @@ customize_node = NodeSpec(
|
|||||||
"for each selected job, saved as HTML, and Gmail drafts created in user's inbox."
|
"for each selected job, saved as HTML, and Gmail drafts created in user's inbox."
|
||||||
),
|
),
|
||||||
system_prompt="""\
|
system_prompt="""\
|
||||||
You are a career coach creating personalized application materials.
|
You are a career coach creating personalized application materials and Gmail drafts.
|
||||||
|
|
||||||
|
**CRITICAL: You MUST create Gmail drafts for each selected job using gmail_create_draft.**
|
||||||
|
|
||||||
**PROCESS:**
|
**PROCESS:**
|
||||||
1. Create application_materials.html using save_data and append_data.
|
1. Create application_materials.html using save_data and append_data.
|
||||||
2. Generate resume customization list and professional cold email for each selected job.
|
2. For each selected job:
|
||||||
3. Serve the file to the user.
|
a. Generate a specific resume customization list
|
||||||
4. Create Gmail drafts using gmail_create_draft.
|
b. Create a professional cold outreach email
|
||||||
|
c. **IMMEDIATELY call gmail_create_draft** with:
|
||||||
|
- to: hiring manager or recruiter email (if available) or company email
|
||||||
|
- subject: "Application for [Job Title] - [Your Name]"
|
||||||
|
- html: the professional cold email in HTML format
|
||||||
|
3. Serve the application_materials.html file to the user.
|
||||||
|
4. Confirm each Gmail draft was created successfully.
|
||||||
|
|
||||||
|
**EMAIL REQUIREMENTS:**
|
||||||
|
- Professional, personalized cold outreach email
|
||||||
|
- Reference specific company details and role
|
||||||
|
- Mention 2-3 relevant qualifications from their resume
|
||||||
|
- Include clear call-to-action
|
||||||
|
- Professional email signature
|
||||||
|
- Format as HTML with proper structure
|
||||||
|
|
||||||
|
**Gmail Draft Creation:**
|
||||||
|
For each job, you MUST call gmail_create_draft(to="[email]", subject="[subject]", html="[email_html]")
|
||||||
|
- Extract company email from job listing if available
|
||||||
|
- Use generic format like "careers@[company].com" if no specific email
|
||||||
|
- Subject format: "Application for [Job Title] - [Applicant Name]"
|
||||||
|
- HTML email body with proper formatting
|
||||||
|
|
||||||
**FINISH:**
|
**FINISH:**
|
||||||
Call set_output("application_materials", "Completed")
|
Only call set_output("application_materials", "Completed") AFTER creating ALL Gmail drafts.
|
||||||
""",
|
""",
|
||||||
tools=["save_data", "append_data", "serve_file_to_user", "gmail_create_draft"],
|
tools=["save_data", "append_data", "serve_file_to_user", "gmail_create_draft"],
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user