Compare commits

...

1 Commits

Author SHA1 Message Date
Timothy 7b08ee17f2 refactor: clean dead codes 2026-04-14 09:34:55 -07:00
10 changed files with 76 additions and 2503 deletions
+7 -1
View File
@@ -39,7 +39,13 @@
"Bash(bun run:*)",
"Bash(npx eslint:*)",
"Bash(npm run:*)",
"Bash(npm test:*)"
"Bash(npm test:*)",
"Bash(grep -E \"\\\\.tsx$|^d\")",
"Bash(grep -E \"test_.*\\\\.py$\")",
"Bash(grep \"\\\\.py$\")",
"Bash(grep -l \"save_agent_draft\\\\|confirm_and_build\\\\|replan_agent\\\\|load_built_agent\\\\|planning\\\\|building\\\\|staging\" /home/timothy/aden/hive/core/framework/agents/queen/reference/*.md)",
"Bash(grep -E \"\\\\.tsx$|\\\\.ts$\")",
"Bash(find /home/timothy/aden/hive/core/framework/tools -name \"*.py\" -exec grep -l \"switch_to_\" {} \\\\;)"
],
"additionalDirectories": [
"/home/timothy/.hive/skills/writing-hive-skills",
+13 -783
View File
@@ -7,8 +7,6 @@ from framework.orchestrator import NodeSpec
# Load reference docs at import time so they're always in the system prompt.
# No voluntary read_file() calls needed — the LLM gets everything upfront.
_ref_dir = Path(__file__).parent.parent / "reference"
_framework_guide = (_ref_dir / "framework_guide.md").read_text(encoding="utf-8")
_anti_patterns = (_ref_dir / "anti_patterns.md").read_text(encoding="utf-8")
_gcu_guide_path = _ref_dir / "gcu_guide.md"
_gcu_guide = _gcu_guide_path.read_text(encoding="utf-8") if _gcu_guide_path.exists() else ""
@@ -22,63 +20,13 @@ def _is_gcu_enabled() -> bool:
return False
def _build_appendices() -> str:
parts = (
"\n\n# Appendix: Framework Reference\n\n"
+ _framework_guide
+ "\n\n# Appendix: Anti-Patterns\n\n"
+ _anti_patterns
)
return parts
# Shared appendices — appended to every coding node's system prompt.
_appendices = _build_appendices()
# GCU guide — shared between planning and building via _shared_building_knowledge.
# GCU guide — appended to phase prompts that need browser automation context.
_gcu_section = (
("\n\n# Browser Automation Nodes\n\n" + _gcu_guide) if _is_gcu_enabled() and _gcu_guide else ""
)
# Tools available to phases.
_SHARED_TOOLS = [
# File I/O
"read_file",
"write_file",
"edit_file",
"hashline_edit",
"list_directory",
"search_files",
"run_command",
"undo_changes",
# Meta-agent
"list_agent_tools",
]
# Queen phase-specific tool sets.
# Planning phase: read-only exploration + design, no write tools.
_QUEEN_PLANNING_TOOLS = [
# Read-only file tools
"read_file",
"list_directory",
"search_files",
"run_command",
# Parallel fan-out — use directly for one-off batch work the user
# wants RIGHT NOW (without first designing an agent for it).
"run_parallel_workers",
# Fork this session into a persistent colony so a headless /
# recurring / background job can run in parallel to this chat.
# Authors a skill first so the colony worker inherits context.
"create_colony",
]
# Building phase: full coding + agent construction tools.
_QUEEN_BUILDING_TOOLS = _SHARED_TOOLS + [
"load_built_agent",
"list_credentials",
]
# Staging phase: agent loaded but not yet running — inspect, configure, launch.
# No backward transitions — staging only goes forward to running.
_QUEEN_STAGING_TOOLS = [
@@ -125,8 +73,7 @@ _QUEEN_RUNNING_TOOLS = [
]
# Editing phase: worker done, still loaded — tweak config and re-run.
# Has inject_message for live adjustments. stop_worker_and_review/plan available
# here to escalate when a deeper change is needed.
# Has inject_message for live adjustments.
_QUEEN_EDITING_TOOLS = [
# Read-only (inspect)
"read_file",
@@ -171,386 +118,6 @@ _QUEEN_INDEPENDENT_TOOLS = [
]
# ---------------------------------------------------------------------------
# Shared agent-building knowledge: core mandates, tool docs, meta-agent
# capabilities, and workflow phases 1-6. Both the coder (worker) and
# queen compose their system prompts from this block + role-specific
# additions.
# ---------------------------------------------------------------------------
_shared_building_knowledge = (
"""\
# Shared Rules (Planning & Building)
## Paths (MANDATORY)
**Always use RELATIVE paths** \
(e.g. `exports/agent_name/agent.json`).
**Never use absolute paths** like `/mnt/data/...` or `/workspace/...` they fail.
The project root is implicit.
## Worker File Tools (hive_tools MCP)
Workers use a DIFFERENT MCP server (hive_tools) with DIFFERENT tool names. \
When designing worker nodes or writing worker system prompts, reference these \
tool names NOT the coder-tools names (read_file, write_file, etc.).
Worker data tools (for large results and spillover):
Worker data tools (from files-tools MCP server):
- read_file(path) read a file
- write_file(path, content) write/create a file
- list_files(path) list directory contents
- search_files(pattern, path) regex search in files
Worker data tools (from hive_tools MCP server):
- csv_read, csv_write, csv_append CSV operations
- pdf_read read PDF files
All tools are registered in the global MCP registry (~/.hive/mcp_registry/). \
Workers get tools from: hive_tools, gcu-tools, files-tools.
IMPORTANT: Do NOT tell workers to use read_file, write_file, edit_file, \
search_files, or list_directory those are YOUR tools, not theirs.
"""
+ _gcu_section
)
_planning_knowledge = """\
**Be responsible, understand the problem by asking practical qualify questions \
and be transparent about what the framework can and cannot do.**
# Core Mandates (Planning)
- **DO NOT propose a complete goal on your own.** Instead, \
collaborate with the user to define it.
- **NEVER call `confirm_and_build` without explicit user approval.** \
Present the full design first and wait for the user to confirm before building.
- **Discover tools dynamically.** NEVER reference tools from static \
docs. Always run list_agent_tools() to see what actually exists.
# Tool Discovery (MANDATORY before designing)
Before designing any agent, discover tools progressively start compact, drill into \
what you need. ONLY use tools from this list in your node definitions. \
NEVER guess or fabricate tool names from memory.
list_agent_tools() # Step 1: provider summary
list_agent_tools(group="google", output_schema="summary") # Step 2: service breakdown
list_agent_tools(group="google", service="gmail") # Step 3: tool names
list_agent_tools( # Step 4: full detail
group="google", service="gmail", output_schema="full"
)
Step 1 is MANDATORY. Returns provider names, tool counts, credential availability very compact. \
Step 2 breaks a provider into services (e.g. google gmail/calendar/sheets/drive). Only do this \
for providers that are relevant to the task. \
Step 3 gets tool names for a specific service no descriptions, minimal tokens. \
Step 4 only for services you plan to actually use. \
Use credentials="available" at any step to filter to tools whose credentials are already configured.
# Discovery & Design Workflow
## 1: Discovery (3-6 Turns)
**The core principle**: Discovery should feel like progress, not paperwork. \
The stakeholder should walk away feeling like you understood them faster \
than anyone else would have.
Ask questions to help the user find bridge the goal and the solution \
When the stakeholder describes what they want, mentally construct:
- **The pain**: What about today's situation is broken, slow, or missing?
- **The actors**: Who are the people/systems involved?
- **The trigger**: What kicks off the workflow?
- **The core loop**: What's the main thing that happens repeatedly?
- **The output**: What's the valuable thing produced at the end?
---
## 2: Capability Assessment & Gap Analysis
**After the user responds, assess fit and gaps together.** Be honest and specific. \
Reference tools from list_agent_tools() AND built-in capabilities:
- **Browser automation provides full Playwright-based \
browser control (navigation, clicking, typing, scrolling, JS-rendered pages, \
multi-tab). Do NOT list browser automation as missing use browser nodes with tools: {policy: "all"}.
Present a short **Framework Fit Assessment**:
- **Works well**: 2-4 strengths for this use case
- **Limitations**: 2-3 workable constraints (e.g., LLM latency, context limits)
- **Gaps/Deal-breakers**: Only list genuinely missing capabilities after checking \
both list_agent_tools() and built-in features like GCU
### Credential Check
Your **Connected integrations** block (in your system prompt above) is the \
authoritative list of credentials currently connected for this user. It is \
refreshed on every turn you do not need to call list_credentials to \
discover what is available. Treat the block as ground truth for connectivity.
**Important:** the block shows connectivity only, not liveness. OAuth tokens \
can expire between turns. The framework refreshes tokens automatically when \
a tool is called. If a refresh fails, the tool result you receive will be a \
structured payload of the form:
```
{"error": "credential_expired", "credential_id": "...", "provider": "...", \
"alias": "...", "reauth_url": "..."}
```
When you see this:
1. Stop the branch of work that needed that credential do **not** retry.
2. Tell the user which integration needs reauthorization (use the alias if \
present) and surface the `reauth_url` so they can fix it.
3. Wait for the user to confirm they have reauthorized before retrying.
**Before designing the layout**, cross-check which providers your design \
needs against the Connected integrations block. If a provider is missing \
entirely (not just expired), tell the user and ask whether they can connect \
it or whether you should design around it.
Example:
> "The design needs Google Sheets, but I don't see a `google` integration \
in your connected integrations. Can you connect one, or should I use CSV \
file output instead?"
`list_credentials` is still available as a diagnostic tool for inspecting \
specific credentials by id, but it is no longer part of the planning happy \
path the ambient block already gives you everything you need.
## 3: Design flowchart
Act like an experienced AI solution architect. Design the agent architecture \
in the flowchart
The flowchart is the shared canvas. Every structural change should be \
visible to the user immediately. The draft captures business logic \
(node purposes, data flow, tools) without requiring executable code. \
Include in each node: id, name, description, planned tools, \
input/output keys, and success criteria as high-level hints.
Each node is auto-classified into a flowchart symbol type with a unique \
color. You can override auto-detection by setting `flowchart_type` \
explicitly on a node. Available types:
- **start** (sage green, stadium): Entry point / trigger
- **terminal** (dusty red, stadium): End of flow
- **process** (blue-gray, rectangle): Standard processing step
- **decision** (warm amber, diamond): Conditional branching
- **io** (dusty purple, parallelogram): External data input/output
- **document** (steel blue, wavy rect): Report or document generation
- **database** (muted teal, cylinder): Database or data store
- **browser** (deep blue, hexagon): Browser automation node (uses gcu-tools).
Auto-detection works well for most cases: first node start, nodes with \
no outgoing edges terminal, nodes with multiple conditional outgoing \
edges decision, browser tool nodes browser, nodes mentioning "database" \
database, nodes mentioning "report/document" document, I/O tools like \
send_email io. Everything else defaults to process. Set flowchart_type \
explicitly only when auto-detection would be wrong.
## Decision Nodes — Planning-Only Conditional Branching
Decision nodes (amber diamonds) are **planning-only** visual elements. They \
let you show explicit conditional logic in the flowchart so the user can see \
and approve branching behavior. At `confirm_and_build()`, decision nodes are \
automatically **dissolved** into the runtime:
- The decision clause is merged into the predecessor node's `success_criteria`
- The yes/no edges are rewired as the predecessor's `on_success`/`on_failure` edges
- The original flowchart (with decision diamonds) is preserved for display
**When to use decision nodes:**
- When a workflow has a meaningful condition that determines the next step \
(e.g., "Did we find enough results?", "Is the data valid?", "Amount > $100?")
- When the branching logic is important for the user to understand and approve
- When different outcomes lead to genuinely different processing paths
**How to create a decision node:**
- Set `flowchart_type: "decision"` on the node
- Set `decision_clause` to the condition text (e.g., "Data passes validation?")
- Add two outgoing edges with `label: "Yes"` and `label: "No"` pointing \
to the respective target nodes
**Good flowcharts display conditions explicitly.** During planning, the user \
sees the full flowchart with decision diamonds. This is different from the \
building/running phase where conditions are embedded inside node criteria. \
The flowchart is the user-facing contract make branching logic visible.
Example with a decision node:
```
gather [Valid data?] Yes transform deliver
No notify_user
```
In the draft: the `[Valid data?]` node has `flowchart_type: "decision"`, \
`decision_clause: "Data passes validation checks?"`, with labeled yes/no edges.
## Browser Automation Nodes
Browser nodes are regular `event_loop` nodes with browser tools \
(from the gcu-tools MCP server) in their tool list. They are wired \
into the layout with edges like any other node:
```
research browser_scan analyze_results
```
Use `tools: {policy: "all"}` to give browser nodes access to all \
browser tools, or list specific ones with `policy: "explicit"`.
If the worker agent starts from some initial input it is okay. \
The queen(you) owns intake: you gather user requirements, then call \
`run_agent_with_input(task)` with a structured task description. \
When building the agent, design the entry node's `input_keys` to \
match what the queen will provide at run time. Worker nodes should \
use `escalate` for blockers.
## 4: Get User Confirmation (MANDATORY GATE)
**This is a hard boundary between planning and building.** \
You MUST get explicit user approval before ANY code is generated.
1. Call ask_user() with options like \
["Approve and build", "Adjust the design", "I have questions"]
2. **WAIT for user response.** Do NOT proceed without it.
3. Handle the response:
- If **Approve / Proceed**: Call confirm_and_build(), then \
confirm_and_build(agent_name)
- If **Adjust scope**: Discuss changes, update the draft with \
save_agent_draft() again, and re-ask
- If **More questions**: Answer them honestly, then ask again
- If **Reconsider**: Discuss alternatives. If they decide to proceed, \
that's their informed choice
**NEVER call confirm_and_build without first calling \
confirm_and_build().** The system will block the transition if you try.
"""
_building_knowledge = """\
# Core Mandates (Building)
- **Verify assumptions.** Never assume a class, import, or pattern \
exists. Read actual source to confirm. Search if unsure.
- **Self-verify.** After writing code, run validation and tests. Fix \
errors yourself. Don't declare success until validation passes.
# Tools
## File I/O (your tools — coder-tools MCP)
- read_file(path, offset?, limit?, hashline?) read with line numbers; \
hashline=True for N:hhhh|content anchors (use with hashline_edit)
- write_file(path, content) create/overwrite, auto-mkdir
- edit_file(path, old_text, new_text, replace_all?) fuzzy-match edit
- hashline_edit(path, edits, auto_cleanup?, encoding?) anchor-based \
editing using N:hhhh refs from read_file(hashline=True). Ops: set_line, \
replace_lines, insert_after, insert_before, replace, append
- list_directory(path, recursive?) list contents
- search_files(pattern, path?, include?, hashline?) regex search; \
hashline=True for anchors in results
- run_command(command, cwd?, timeout?) shell execution
- undo_changes(path?) restore from git snapshot
## Meta-Agent
- list_agent_tools(group?, service?, output_schema?, credentials?) discover tools \
progressively: no args=provider summary; group+output_schema="summary"=service breakdown; \
group+service=tool names; group+service+output_schema="full"=full details. \
credentials="available" filters to configured tools. Call FIRST before designing.
- validate_agent_package(agent_name) run ALL validation checks in one call \
(class validation, runner load, tool validation, tests). Call after building.
- list_agents() list all agent packages in exports/ with session counts
- list_agent_sessions(agent_name, status?, limit?) list sessions
- list_agent_checkpoints(agent_name, session_id) list checkpoints
- get_agent_checkpoint(agent_name, session_id, checkpoint_id?) load checkpoint
# Build & Validation Capabilities
## Post-Build Validation
After writing agent code, run a single comprehensive check:
validate_agent_package("{name}")
This runs class validation, runner load, tool validation, and tests \
in one call. Do NOT run these steps individually.
## Debugging Built Agents
When a user says "my agent is failing" or "debug this agent":
1. list_agent_sessions("{agent_name}") find the session
2. get_worker_status(focus="issues") check for problems
3. list_agent_checkpoints / get_agent_checkpoint trace execution
# Implementation Workflow
## 5. Implement
**You should only reach this step after the user has approved the draft design \
and you have called `confirm_and_build(agent_name="my_agent")`.**
`confirm_and_build` created the agent directory (returned in agent_path). \
Now write the complete agent config directly:
```
write_file("<colony_path>/agent.json", <complete JSON config>)
```
The agent.json must include ALL of these in one write:
- `name`, `version`, `description`
- `goal` with `description`, `success_criteria`, `constraints`
- `identity_prompt` (agent-level behavior)
- `nodes` each with `id`, `description`, `system_prompt`, `tools`, \
`input_keys`, `output_keys`, `success_criteria`
- `edges` connecting all nodes with proper conditions
- `entry_node`, `terminal_nodes`
- `mcp_servers` REQUIRED. Always include all three: \
`[{"name": "hive_tools"}, {"name": "gcu-tools"}, {"name": "files-tools"}]`
- `loop_config` `max_iterations`, `max_context_tokens`
**Write the COMPLETE config in one `write_file` call. No TODOs, no placeholders.** \
The queen writes final production-ready system prompts directly.
**There are NO Python files.** The framework loads agent.json directly.
MCP servers are loaded from the global registry by name. Available servers:
- `hive_tools` web search, email, CRM, calendar, 100+ integrations
- `gcu-tools` browser automation (click, type, navigate, screenshot)
- `files-tools` file I/O (read, write, edit, search, list)
**Template variables:** Add a `variables:` section at the top of agent.json \
and use `{{variable_name}}` in system prompts for config injection:
```yaml
variables:
spreadsheet_id: "1ZVx..."
nodes:
- id: start
system_prompt: |
Use spreadsheet: {{spreadsheet_id}}
```
### Tool access in nodes
Each node declares its tool access policy:
```yaml
# Explicit list (recommended)
tools:
policy: explicit
allowed: [web_search, write_file]
# All tools (for browser automation nodes)
tools:
policy: all
# No tools (for handoff/summary nodes)
tools:
policy: none
```
## 6. Verify and Load
Call `validate_agent_package("{name}")` after initialization. \
It runs structural checks (class validation, layout validation, tool \
validation, tests) and returns a consolidated result. If anything \
fails: read the error, fix with read_file+write_file, re-validate. Up to 3x.
When validation passes, immediately call \
`load_built_agent("<agent_path>")` to load the agent into the \
session. This switches to STAGING phase and shows the layout in the \
visualizer. Do NOT wait for user input between validation and loading.
"""
# Composed version — coder_node uses both halves (it has no phase split).
_package_builder_knowledge = _shared_building_knowledge + _planning_knowledge + _building_knowledge
# ---------------------------------------------------------------------------
@@ -575,30 +142,6 @@ phase. Your identity tells you WHO you are.\
# -- Phase-specific work roles (what you DO, not who you ARE) --
_queen_role_planning = """\
You are in PLANNING phase. Your work: understand what the user wants, \
research available tools, and design the agent architecture. \
You have read-only tools no write/edit. Focus on conversation, \
research, and design. \
Use ask_user / ask_user_multiple for structured design-decision questions \
(approvals, 24 concrete options, "Postgres or SQLite?"). Do NOT use \
ask_user for greetings, small talk, or free-form conversational questions \
write those as plain text and wait. \
If the user opens with a greeting or chat, reply in plain prose in \
character first. Check recall memory for name and past topics; weave \
them in. No tool calls on chat turns.\
"""
_queen_role_building = """\
You are in BUILDING phase. Your work: implement the approved design as \
production-ready code, validate it, and load the agent for staging. \
You have full coding tools. \
You design and build the agent to do the job but don't do the job yourself. \
If the user opens with a greeting or chat, reply in plain prose in \
character first check recall memory for name and past topics and weave \
them in. Task work only resumes when they ask for it. No tool calls on chat turns.\
"""
_queen_role_staging = """\
You are in STAGING phase. The agent is loaded and ready. \
Your work: verify configuration, confirm credentials, and launch \
@@ -620,8 +163,7 @@ them in. No tool calls on chat turns.\
_queen_identity_editing = """\
You are in EDITING mode. The worker has finished executing and is still loaded. \
You can tweak configuration, inject messages, and re-run with different input \
without rebuilding. If a deeper change is needed (code edits, new tools), \
escalate to BUILDING via stop_worker_and_review or to PLANNING via stop_worker_and_plan.
without rebuilding.
If the user opens with a greeting or chat, reply in plain prose in \
character first check recall memory for name and past topics and weave \
them in. No tool calls on chat turns.
@@ -639,134 +181,6 @@ them in. If you ask the user a question, you MUST use the \
ask_user or ask_user_multiple tools. \
"""
# -- Phase-specific tool docs --
_queen_tools_planning = """
# Tools (PLANNING phase)
You are in planning mode. You have read-only tools for exploration \
but no write/edit tools.
- read_file(path, offset?, limit?) Read files to study reference agents
- list_directory(path, recursive?) Explore project structure
- search_files(pattern, path?, include?) Search codebase
- run_command(command, cwd?, timeout?) Read-only commands only (grep, ls, git log). \
Never use this to write files, run scripts, or modify the filesystem transition \
to BUILDING phase for that.
- list_agent_tools(server_config_path?, output_schema?, group?, credentials?) \
Discover available tools for design (summary names full)
- list_agents() See existing agent packages for reference
- list_agent_sessions(agent_name, status?, limit?) Inspect past runs of an agent
- list_agent_checkpoints(agent_name, session_id) View execution history
- get_agent_checkpoint(agent_name, session_id, checkpoint_id?) Load a checkpoint
## Draft Workflow (new agents)
- save_agent_draft(agent_name, goal, nodes, edges?, terminal_nodes?, ...) \
Create an ISO 5807 color-coded flowchart draft. No code is generated. Each \
node is auto-classified into a standard flowchart symbol (process, decision, \
document, database, subprocess, etc.) with unique shapes and colors. Set \
flowchart_type on a node to override. Nodes need only an id. \
Use decision nodes (flowchart_type: "decision", with decision_clause and \
labeled yes/no edges) to make conditional branching explicit. \
hexagons connect them as leaf nodes to their parent.
- confirm_and_build() Record user confirmation of the draft. Dissolves \
planning-only nodes (decision predecessor criteria; browser/GCU \
approves via ask_user.
- confirm_and_build(agent_name) Scaffold the agent package \
and transition to BUILDING phase. For new agents, this REQUIRES \
save_agent_draft() + confirm_and_build() first. The draft metadata is used to \
pre-populate the generated files. Without agent_name: transition to BUILDING \
to fix the currently loaded agent (no draft required).
## Loading existing agents
- load_built_agent(agent_path) Load an existing agent and switch to STAGING \
phase. Only use this when the user explicitly asks to work with an existing agent \
(e.g. "load my_agent", "run the research agent"). Confirm with the user first.
## Parallel fan-out (one-off batch work — no agent build required)
- run_parallel_workers(tasks, timeout?) Spawn N workers concurrently and \
wait for all reports. Use this when the user asks for batch / parallel work \
RIGHT NOW that does NOT need a reusable agent (e.g. "fetch batches 15 from \
this API", "summarise these 10 PDFs", "compare these candidates"). Each task \
is a dict {"task": "...", "data"?: {...}}; the tool returns aggregated \
{worker_id, status, summary, data, error} reports. Read the summaries and \
write a single user-facing synthesis on your next turn. Prefer this over \
designing a draft when the work is one-shot and the user wants results, not \
a saved agent.
## Forking the session into a persistent colony
**When to use create_colony:** the user needs work to run \
**headless, recurring, or in parallel to this chat** something \
that keeps going after you stop talking. Typical triggers:
- "run this every morning / every hour / on a cron"
- "keep monitoring X and alert me when Y"
- "fire this off in the background, I'll check on it later"
- "spin up a dedicated agent for this so I can keep working here"
- any task that should survive the current conversation ending
**When NOT to use it:** if the user just wants results RIGHT NOW \
in this chat, use `run_parallel_workers` instead. If they want to \
iterate on an agent design, stay in the planning/building flow. \
Don't create a colony just because you "learned something \
reusable" — the trigger is operational (needs to keep running), \
not epistemic (knowledge worth saving).
**Two-step flow:**
1. AUTHOR A SKILL FIRST so the colony worker has the operational \
context it needs to run unattended. Use write_file to create a \
skill folder (recommended location: \
`~/.hive/skills/{skill-name}/SKILL.md`) capturing the \
procedure API endpoints, auth flow, response shapes, \
gotchas, conventions, query patterns, rate limits. The \
SKILL.md needs YAML frontmatter with `name` (matching the \
directory name) and `description` (1-1024 chars including \
trigger keywords), followed by a markdown body. Optional \
subdirs: scripts/, references/, assets/. Read your \
writing-hive-skills default skill for the full spec.
2. create_colony(colony_name, task, skill_path) Validates the \
skill folder, installs it under ~/.hive/skills/ if it isn't \
already there, and forks this session into a new colony. \
NOTHING RUNS after this call: the task is baked into \
worker.json and the user starts the worker (or wires up a \
trigger) later from the new colony page. The task string \
must be FULL and self-contained when the worker eventually \
runs it has zero memory of your chat. The skill you wrote is \
discovered on first scan so the worker starts informed.
## Workflow summary
1. Understand requirements discover tools design the layout
2. Call save_agent_draft() to create visual draft present to user
3. Call ask_user() to get explicit approval
4. Call confirm_and_build() to record approval
5. Call confirm_and_build() to scaffold and start building
For diagnosis of existing agents, call confirm_and_build() \
(no args) after agreeing on a fix plan with the user.
"""
_queen_tools_building = """
# Tools (BUILDING phase)
You have full coding tools for building and modifying agents:
- File I/O: read_file, write_file, edit_file, list_directory, search_files, \
run_command, undo_changes
- Meta-agent: list_agent_tools, validate_agent_package, \
list_agents, list_agent_sessions, \
list_agent_checkpoints, get_agent_checkpoint
- load_built_agent(agent_path) Load the agent and switch to STAGING phase
- list_credentials(credential_id?) List authorized credentials
- save_agent_draft(...) **Re-draft the flowchart during building.** When \
called during building, planning-only nodes (decision, browser/GCU) are \
dissolved automatically no re-confirmation needed. The user sees the \
updated flowchart immediately. Use this when you make structural changes \
(add/remove nodes, change edges) so the flowchart stays in sync.
- replan_agent() Switch back to PLANNING phase. The previous draft is \
restored (with decision/browser nodes intact) so you can edit it. Use \
when the user wants to change integrations, swap tools, rethink the \
flow, or discuss any design changes before you build them.
When you finish building an agent, call load_built_agent(path) to stage it.
"""
_queen_tools_staging = """
# Tools (STAGING phase)
@@ -926,12 +340,6 @@ lifecycle tools for spinning up work dynamically:
new colony page. Do NOT use this just because you "learned \
something reusable" — the trigger is operational (needs to keep \
running), not epistemic.
You do NOT have the agent-building lifecycle (no save_agent_draft, \
confirm_and_build, load_built_agent, run_agent_with_input). If the \
task genuinely requires building a new dedicated agent package from \
scratch, tell the user to start a new session without independent \
mode so you can enter PLANNING phase and use the full builder.
"""
# -- Behavior shared across all phases --
@@ -1006,57 +414,6 @@ Users can attach images to messages. Analyze them directly using your \
vision capability the image is embedded, no tool call needed.
"""
# -- PLANNING phase behavior --
_queen_behavior_planning = """
## Planning phase
You are in planning mode. Your job is to:
1. Thoroughly explore the code for the worker agent you're working on
2. Understand what the user wants (3-6 turns)
3. Discover available tools with list_agent_tools()
4. Assess framework fit and gaps
5. Consider multiple approaches and their trade-offs
6. Design the agent layout call save_agent_draft() **as soon as you have a \
rough shape**, even before finalizing all details
7. **Iterate on the draft interactively** every time the user gives feedback \
that changes the structure, call save_agent_draft() again so they see the \
update in real-time. The flowchart is a live collaboration tool.
8. When the design is stable, use ask_user to get explicit approval
9. Call confirm_and_build() after the user approves
10. Call confirm_and_build(agent_name) to scaffold and start building
**The flowchart is your shared whiteboard.** Don't describe changes in text \
and then ask "should I update the draft?" just update it. If the user says \
"add a validation step," immediately call save_agent_draft() with the new \
node added. If they say "remove that," update and re-draft. The user should \
see every structural change reflected in the visualizer as you discuss it.
**CRITICAL: Planning Building boundary.** You MUST get explicit user \
confirmation before moving to building. The sequence is:
save_agent_draft() iterate with user ask_user() confirm_and_build() \
confirm_and_build()
Skipping any of these steps will be blocked by the system.
Remember: DO NOT write or edit any files yet. This is a read-only exploration \
and planning phase. You have read-only tools but no write/edit tools in this \
phase. If the user asks you to write code, explain that you need to finalize \
the plan first.
## Diagnosis mode (returning from staging/running)
If you entered planning from a running/staged agent (via stop_worker_and_plan), \
your priority is diagnosis, not new design:
1. Inspect the agent's checkpoints, sessions, and logs to understand what went wrong
2. Summarize the root cause to the user
3. Propose a fix plan (what to change, what behavior to adjust)
4. Get user approval via ask_user
5. Call confirm_and_build() (no args) to transition to building and implement the fix
Do NOT start the full discovery workflow (tool discovery, gap analysis) in \
diagnosis mode you already have a built agent, you just need to fix it.
"""
_queen_memory_instructions = """
## Your Memory
@@ -1068,58 +425,6 @@ asserting them as fact.
_queen_behavior_always = _queen_behavior_always + _queen_memory_instructions
# -- BUILDING phase behavior --
_queen_behavior_building = """
## Direct coding
You can do any coding task directly reading files, writing code, running \
commands, building agents, debugging. For quick tasks, do them yourself.
**Decision rule if worker exists, read the Worker Profile first:**
- The user's request directly matches the worker's goal use \
run_agent_with_input(task) (if in staging) or load then run (if in building)
- Anything else do it yourself. Do NOT reframe user requests into \
subtasks to justify delegation.
- Building, modifying, or configuring agents is ALWAYS your job. Never \
delegate agent construction to the worker, even as a "research" subtask.
## Keeping the flowchart in sync during building
When you make structural changes to the agent (add/remove/rename nodes, \
change edges, modify node connections), call save_agent_draft() to \
update the flowchart. During building, this auto-dissolves planning-only \
nodes without needing user re-confirmation. The user sees the updated \
flowchart immediately.
- **Minor changes** (add a node, rename, adjust edges): call \
save_agent_draft() with the updated draft and keep building.
- **User wants to discuss, redesign, or change integrations/tools**: call \
replan_agent(). The previous draft is restored so you can edit it with \
the user. After they approve, confirm_and_build() continue building.
**When to call replan_agent():** Changing which tools or integrations a \
node uses, swapping data sources, rethinking the flow, or any time the \
user says "replan", "go back", "let's redesign", "change the approach", \
"use a different tool/API", etc. Do NOT stay in building to handle these \
switch to planning so the user can review and approve the new design.
## CRITICAL — Topology errors require replanning, not code edits
If you discover that the agent layout has structural problems browser nodes \
in the linear flow, missing edges, wrong node connections, incorrect \
node connections you MUST call replan_agent() and fix the draft. \
Do NOT attempt to fix topology by editing agent.json directly. The structure \
structure is defined by the draft dissolution code-gen pipeline. \
Editing the config to rewire nodes bypasses the flowchart and creates drift \
between what the user sees and what the config does.
**WRONG:** "Let me fix agent.json to remove browser nodes from edges..."
**RIGHT:** Call replan_agent(), fix the draft with save_agent_draft(), \
get user approval, then confirm_and_build() the corrected code is \
generated automatically.
"""
# -- STAGING phase behavior --
_queen_behavior_staging = """
@@ -1157,12 +462,11 @@ compose a structured task description from their input and call \
run_agent_with_input(task). The worker has no intake node it receives \
your task and starts processing.
- If the user wants to modify the agent, wait for EDITING phase \
(after worker finishes) where you will have stop_worker_and_review().
(after worker finishes) and use inject_message to tweak config.
## When idle (worker not running):
- Greet the user. Mention what the worker can do in one sentence.
- For tasks matching the worker's goal, use run_agent_with_input(task) \
(if in staging) or load the agent first (if in building).
- For tasks matching the worker's goal, use run_agent_with_input(task).
- For everything else, do it directly.
## When the user clicks Run (external event notification)
@@ -1185,15 +489,9 @@ building something new.
## Fixing or Modifying the loaded worker
During RUNNING phase, you cannot directly switch to building or planning. \
When the worker finishes, you move to EDITING where you can:
- Re-run with different input via run_agent_with_input(task)
- Tweak config via inject_message(content)
- Escalate to stop_worker_and_review() or stop_worker_and_plan() if deeper changes are needed
During STAGING or EDITING phase:
- Use stop_worker_and_plan() when the request is vague or needs discussion
- Use stop_worker_and_review() when the user gave a specific, concrete instruction
## Trigger Management
@@ -1305,11 +603,7 @@ decision via inject_message() so the worker can clean up.
**Errors / unexpected failures:**
- Explain what went wrong in plain terms.
- Ask the user: "Fix the agent and retry?" in EDITING phase, \
use stop_worker_and_review().
- Or offer: "Diagnose the issue" in EDITING phase, \
use stop_worker_and_plan().
- Or offer: "Retry as-is", "Skip this task", "Abort run"
- Offer: "Retry as-is", "Skip this task", "Abort run".
- (Skip asking if user explicitly told you to auto-retry or auto-skip errors.)
- If the escalation had wait_for_response: inject_message() with the decision.
@@ -1333,7 +627,7 @@ building something new.
When the user asks to fix or modify the worker while it is running, \
do NOT attempt to switch phases. Wait for the worker to finish \
you will move to EDITING phase automatically. From there you can \
use stop_worker_and_review() or stop_worker_and_plan().
re-run with new input or inject configuration tweaks.
## Trigger Handling
@@ -1353,51 +647,6 @@ when explicitly asked or when the trigger is clearly obsolete.
Never just say "it's removed" without actually calling the tool.
"""
# -- Backward-compatible composed versions (used by queen_node.system_prompt default) --
_queen_tools_docs = (
"\n\n## Queen Operating Phases\n\n"
"You operate in one of six phases. Your available tools change based on the "
"phase. The system notifies you when a phase change occurs.\n\n"
"### INDEPENDENT phase (standalone agent)\n"
+ _queen_tools_independent.strip()
+ "\n\n### PLANNING phase\n"
+ _queen_tools_planning.strip()
+ "\n\n### BUILDING phase\n"
+ _queen_tools_building.strip()
+ "\n\n### STAGING phase (agent loaded, not yet running)\n"
+ _queen_tools_staging.strip()
+ "\n\n### RUNNING phase (worker is executing)\n"
+ _queen_tools_running.strip()
+ "\n\n### Phase transitions\n"
"- save_agent_draft(...) → creates visual-only draft (stays in PLANNING)\n"
"- confirm_and_build() → records user approval of draft (stays in PLANNING)\n"
"- confirm_and_build(agent_name) → scaffolds package + switches to "
"BUILDING (requires draft + confirmation for new agents)\n"
"- replan_agent() → switches back to PLANNING phase (only when user explicitly requests)\n"
"- load_built_agent(path) → switches to STAGING phase\n"
"- run_agent_with_input(task) → starts worker, switches to RUNNING phase\n"
"- stop_worker() → stops worker, switches to STAGING phase (ask user: re-run or edit?)\n"
"- stop_worker_and_review() → stops worker (if running), switches to BUILDING phase\n"
"- stop_worker_and_plan() → stops worker (if running), switches to PLANNING phase\n"
)
_queen_behavior = (
_queen_behavior_always
+ _queen_behavior_planning
+ _queen_behavior_building
+ _queen_behavior_staging
+ _queen_behavior_running
)
_queen_phase_7 = """
## Running the Agent
After validation passes and load_built_agent succeeds (STAGING phase), \
offer to run the agent. Call run_agent_with_input(task) to start it. \
Do NOT tell the user to run `python -m {name} run` run it here.
"""
_queen_style = """
# Communication
@@ -1428,9 +677,7 @@ queen_node = NodeSpec(
skip_judge=True, # Queen is a conversational agent; suppress tool-use pressure feedback
tools=sorted(
set(
_QUEEN_PLANNING_TOOLS
+ _QUEEN_BUILDING_TOOLS
+ _QUEEN_STAGING_TOOLS
_QUEEN_STAGING_TOOLS
+ _QUEEN_RUNNING_TOOLS
+ _QUEEN_EDITING_TOOLS
+ _QUEEN_INDEPENDENT_TOOLS
@@ -1438,21 +685,17 @@ queen_node = NodeSpec(
),
system_prompt=(
_queen_character_core
+ _queen_role_building
+ _queen_role_independent
+ _queen_style
+ _package_builder_knowledge
+ _queen_tools_docs
+ _queen_behavior
+ _queen_phase_7
+ _appendices
+ _queen_tools_independent
+ _queen_behavior_always
+ _queen_behavior_independent
),
)
ALL_QUEEN_TOOLS = sorted(
set(
_QUEEN_PLANNING_TOOLS
+ _QUEEN_BUILDING_TOOLS
+ _QUEEN_STAGING_TOOLS
_QUEEN_STAGING_TOOLS
+ _QUEEN_RUNNING_TOOLS
+ _QUEEN_EDITING_TOOLS
+ _QUEEN_INDEPENDENT_TOOLS
@@ -1462,38 +705,25 @@ ALL_QUEEN_TOOLS = sorted(
__all__ = [
"queen_node",
"ALL_QUEEN_TOOLS",
"_QUEEN_PLANNING_TOOLS",
"_QUEEN_BUILDING_TOOLS",
"_QUEEN_STAGING_TOOLS",
"_QUEEN_RUNNING_TOOLS",
"_QUEEN_EDITING_TOOLS",
"_QUEEN_INDEPENDENT_TOOLS",
# Character + phase-specific prompt segments (used by session_manager for dynamic prompts)
"_queen_character_core",
"_queen_role_planning",
"_queen_role_building",
"_queen_role_staging",
"_queen_role_running",
"_queen_identity_editing",
"_queen_role_independent",
"_queen_tools_planning",
"_queen_tools_building",
"_queen_tools_staging",
"_queen_tools_running",
"_queen_tools_editing",
"_queen_tools_independent",
"_queen_behavior_always",
"_queen_behavior_building",
"_queen_behavior_staging",
"_queen_behavior_running",
"_queen_behavior_editing",
"_queen_behavior_independent",
"_queen_phase_7",
"_queen_style",
"_shared_building_knowledge",
"_planning_knowledge",
"_building_knowledge",
"_package_builder_knowledge",
"_appendices",
"_gcu_section",
]
+2 -78
View File
@@ -279,38 +279,25 @@ async def create_queen(
queen_loop_config as _base_loop_config,
)
from framework.agents.queen.nodes import (
_QUEEN_BUILDING_TOOLS,
_QUEEN_EDITING_TOOLS,
_QUEEN_INDEPENDENT_TOOLS,
_QUEEN_PLANNING_TOOLS,
_QUEEN_RUNNING_TOOLS,
_QUEEN_STAGING_TOOLS,
_appendices,
_building_knowledge,
_planning_knowledge,
_queen_behavior_always,
_queen_behavior_building,
_queen_behavior_editing,
_queen_behavior_independent,
_queen_behavior_planning,
_queen_behavior_running,
_queen_behavior_staging,
_queen_character_core,
_queen_identity_editing,
_queen_phase_7,
_queen_role_building,
_queen_role_independent,
_queen_role_planning,
_queen_role_running,
_queen_role_staging,
_queen_style,
_queen_tools_building,
_queen_tools_editing,
_queen_tools_independent,
_queen_tools_planning,
_queen_tools_running,
_queen_tools_staging,
_shared_building_knowledge,
)
from framework.host.event_bus import AgentEvent, EventType
from framework.loader.mcp_registry import MCPRegistry
@@ -359,7 +346,7 @@ async def create_queen(
logger.warning("Queen: MCP registry config failed to load", exc_info=True)
# ---- Phase state --------------------------------------------------
effective_phase = initial_phase or ("staging" if worker_identity else "planning")
effective_phase = initial_phase or ("staging" if worker_identity else "independent")
phase_state = QueenPhaseState(phase=effective_phase, event_bus=session.event_bus)
session.phase_state = phase_state
@@ -371,28 +358,6 @@ async def create_queen(
# when the user adds/removes an integration.
phase_state.credentials_prompt_provider = _build_credentials_provider()
# ---- Track ask rounds during planning ----------------------------
# Increment planning_ask_rounds each time the queen requests user
# input (ask_user or ask_user_multiple) while in the planning phase.
async def _track_planning_asks(event: AgentEvent) -> None:
if phase_state.phase != "planning":
return
# Only count explicit ask_user / ask_user_multiple calls, not
# auto-block (text-only turns emit CLIENT_INPUT_REQUESTED with
# an empty prompt and no options/questions).
data = event.data or {}
has_prompt = bool(data.get("prompt"))
has_questions = bool(data.get("questions"))
has_options = bool(data.get("options"))
if has_prompt or has_questions or has_options:
phase_state.planning_ask_rounds += 1
session.event_bus.subscribe(
[EventType.CLIENT_INPUT_REQUESTED],
_track_planning_asks,
filter_stream="queen",
)
# ---- Lifecycle tools (always registered) --------------------------
register_queen_lifecycle_tools(
queen_registry,
@@ -428,35 +393,21 @@ async def create_queen(
session._queen_tool_executor = queen_tool_executor # type: ignore[attr-defined]
# ---- Partition tools by phase ------------------------------------
planning_names = set(_QUEEN_PLANNING_TOOLS)
building_names = set(_QUEEN_BUILDING_TOOLS)
staging_names = set(_QUEEN_STAGING_TOOLS)
running_names = set(_QUEEN_RUNNING_TOOLS)
editing_names = set(_QUEEN_EDITING_TOOLS)
independent_names = set(_QUEEN_INDEPENDENT_TOOLS)
registered_names = {t.name for t in queen_tools}
missing_building = building_names - registered_names
if missing_building:
logger.warning(
"Queen: %d/%d building tools NOT registered: %s",
len(missing_building),
len(building_names),
sorted(missing_building),
)
logger.info("Queen: registered tools: %s", sorted(registered_names))
phase_state.planning_tools = [t for t in queen_tools if t.name in planning_names]
phase_state.building_tools = [t for t in queen_tools if t.name in building_names]
phase_state.staging_tools = [t for t in queen_tools if t.name in staging_names]
phase_state.running_tools = [t for t in queen_tools if t.name in running_names]
phase_state.editing_tools = [t for t in queen_tools if t.name in editing_names]
# Independent phase gets core tools + all MCP tools not claimed by any
# other phase (coder-tools file I/O, gcu-tools browser, etc.).
all_phase_names = (
planning_names | building_names | staging_names | running_names | editing_names
)
all_phase_names = staging_names | running_names | editing_names
mcp_tools = [t for t in queen_tools if t.name not in all_phase_names]
phase_state.independent_tools = [
t for t in queen_tools if t.name in independent_names
@@ -489,33 +440,6 @@ async def create_queen(
"according to your current phase."
)
_planning_body = (
_queen_character_core
+ _queen_role_planning
+ _queen_style
+ _shared_building_knowledge
+ _queen_tools_planning
+ _queen_behavior_always
+ _queen_behavior_planning
+ _planning_knowledge
+ worker_identity
)
phase_state.prompt_planning = _planning_body
_building_body = (
_queen_character_core
+ _queen_role_building
+ _queen_style
+ _shared_building_knowledge
+ _queen_tools_building
+ _queen_behavior_always
+ _queen_behavior_building
+ _building_knowledge
+ _queen_phase_7
+ _appendices
+ worker_identity
)
phase_state.prompt_building = _building_body
phase_state.prompt_staging = (
_queen_character_core
+ _queen_role_staging
-1
View File
@@ -120,7 +120,6 @@ async def handle_events(request: web.Request) -> web.StreamResponse:
"node_loop_iteration",
"node_loop_started",
"credentials_required",
"worker_graph_loaded",
"queen_phase_changed",
}
+2 -21
View File
@@ -50,18 +50,6 @@ _WORKER_INHERITED_TOOLS: frozenset[str] = frozenset(
)
# Queen-lifecycle tools that are registered into the queen's tool registry
# but NOT listed in any _QUEEN_*_TOOLS phase list (they're reachable only via
# explicit registration, not phase-based gating). These must still be stripped
# from forked worker configs.
_QUEEN_LIFECYCLE_EXTRAS: frozenset[str] = frozenset(
{
"stop_worker_and_plan",
"stop_worker_and_review",
}
)
def _resolve_queen_only_tools() -> frozenset[str]:
"""Compute the set of queen-lifecycle tool names to strip on fork.
@@ -69,34 +57,27 @@ def _resolve_queen_only_tools() -> frozenset[str]:
any tool listed in any ``_QUEEN_*_TOOLS`` set that is NOT in
:data:`_WORKER_INHERITED_TOOLS` is a queen-only tool. Browser and MCP
tools are not in the queen phase lists (they're added dynamically),
so they pass through untouched. Supplemented by
:data:`_QUEEN_LIFECYCLE_EXTRAS` for tools registered without phase
gating.
so they pass through untouched.
Computed lazily so this module can be imported before the queen
nodes package is loaded.
"""
from framework.agents.queen.nodes import (
_QUEEN_BUILDING_TOOLS,
_QUEEN_EDITING_TOOLS,
_QUEEN_INDEPENDENT_TOOLS,
_QUEEN_PLANNING_TOOLS,
_QUEEN_RUNNING_TOOLS,
_QUEEN_STAGING_TOOLS,
)
union: set[str] = set()
for tool_list in (
_QUEEN_PLANNING_TOOLS,
_QUEEN_BUILDING_TOOLS,
_QUEEN_STAGING_TOOLS,
_QUEEN_RUNNING_TOOLS,
_QUEEN_EDITING_TOOLS,
_QUEEN_INDEPENDENT_TOOLS,
):
union.update(tool_list)
derived = union - _WORKER_INHERITED_TOOLS
return frozenset(derived | _QUEEN_LIFECYCLE_EXTRAS)
return frozenset(union - _WORKER_INHERITED_TOOLS)
async def handle_trigger(request: web.Request) -> web.Response:
+1 -1
View File
@@ -61,7 +61,7 @@ def _session_to_live_dict(session) -> dict:
"intro_message": getattr(session.runner, "intro_message", "") or "",
"queen_phase": phase_state.phase
if phase_state
else ("staging" if session.colony_runtime else "planning"),
else ("staging" if session.colony_runtime else "independent"),
"queen_supports_images": supports_image_tool_results(queen_model) if queen_model else True,
"queen_id": getattr(phase_state, "queen_id", None) if phase_state else None,
"queen_name": (phase_state.queen_profile or {}).get("name") if phase_state else None,
+16 -27
View File
@@ -383,17 +383,10 @@ class SessionManager:
_resume_queen_id = _meta.get("queen_id")
except (json.JSONDecodeError, OSError):
pass
if _resume_phase in ("building", "planning"):
# Fall back to queen-only session — cold resume handler in
# _start_queen will set phase_state.agent_path and switch to
# the correct phase.
return await self.create_session(
session_id=session_id,
model=model,
initial_prompt=initial_prompt,
queen_resume_from=queen_resume_from,
queen_name=queen_name or _resume_queen_id,
)
# NOTE: legacy planning/building phases are not resumable; they
# were removed when the design-then-build flow was retired.
# Cold sessions resume into staging/running/editing/independent
# via the phase-resume block in _start_queen below.
# Use the colony's forked session ID as the live session ID.
# If it's already live (user navigated back), return it directly
@@ -1408,22 +1401,18 @@ class SessionManager:
_phase = _meta.get("phase")
if _agent_path and Path(_agent_path).exists():
if _phase in ("staging", "running", None):
# Agent fully built — load worker and resume
await self.load_colony(session.id, _agent_path)
if session.phase_state:
await session.phase_state.switch_to_staging(source="auto")
logger.info("Cold restore: auto-loaded worker from %s", _agent_path)
elif _phase == "building":
# Agent folder exists but incomplete — resume building
if session.phase_state:
session.phase_state.agent_path = _agent_path
await session.phase_state.switch_to_building(source="auto")
logger.info("Cold restore: resumed BUILDING phase for %s", _agent_path)
elif _phase == "planning":
if session.phase_state:
session.phase_state.agent_path = _agent_path
logger.info("Cold restore: PLANNING phase for %s", _agent_path)
# Any cold session that has an agent_path resumes
# into staging (worker loaded, ready to run).
# Legacy planning/building phases are no longer
# supported and are silently mapped to staging.
await self.load_colony(session.id, _agent_path)
if session.phase_state:
await session.phase_state.switch_to_staging(source="auto")
logger.info(
"Cold restore: auto-loaded worker from %s (was phase=%s)",
_agent_path,
_phase,
)
except Exception:
logger.warning("Cold restore: failed to auto-load worker", exc_info=True)
File diff suppressed because it is too large Load Diff
+5 -26
View File
@@ -89,19 +89,10 @@ interface AgentState {
error: string | null;
displayName: string | null;
awaitingInput: boolean;
workerInputMessageId: string | null;
queenPhase: "planning" | "building" | "staging" | "running" | "independent";
agentPath: string | null;
currentRunId: string | null;
nodeLogs: Record<string, string[]>;
nodeActionPlans: Record<string, string>;
subagentReports: {
subagent_id: string;
message: string;
data?: Record<string, unknown>;
timestamp: string;
}[];
isTyping: boolean;
isStreaming: boolean;
queenIsTyping: boolean;
workerIsTyping: boolean;
@@ -127,14 +118,10 @@ function defaultAgentState(): AgentState {
error: null,
displayName: null,
awaitingInput: false,
workerInputMessageId: null,
queenPhase: "planning",
agentPath: null,
currentRunId: null,
nodeLogs: {},
nodeActionPlans: {},
subagentReports: [],
isTyping: false,
isStreaming: false,
queenIsTyping: false,
workerIsTyping: false,
@@ -488,7 +475,6 @@ export default function ColonyChat() {
if (isQueen) {
turnCounterRef.current[turnKey] = currentTurn + 1;
updateState({
isTyping: true,
queenIsTyping: true,
...(shouldMarkQueenReady && { queenReady: true }),
});
@@ -510,13 +496,11 @@ export default function ColonyChat() {
}
turnCounterRef.current[turnKey] = currentTurn + 1;
updateState({
isTyping: true,
isStreaming: false,
workerIsTyping: true,
awaitingInput: false,
currentRunId: incomingRunId,
nodeLogs: {},
subagentReports: [],
llmSnapshots: {},
activeToolCalls: {},
pendingQuestion: null,
@@ -531,14 +515,12 @@ export default function ColonyChat() {
case "execution_completed":
if (isQueen) {
suppressIntroRef.current = false;
updateState({ isTyping: false, queenIsTyping: false });
updateState({ queenIsTyping: false });
} else {
updateState({
isTyping: false,
isStreaming: false,
workerIsTyping: false,
awaitingInput: false,
workerInputMessageId: null,
llmSnapshots: {},
pendingQuestion: null,
pendingOptions: null,
@@ -616,7 +598,6 @@ export default function ColonyChat() {
const prompt = (event.data?.prompt as string) || "";
updateState({
awaitingInput: true,
isTyping: false,
isStreaming: false,
queenIsTyping: false,
pendingQuestion: prompt || null,
@@ -629,7 +610,6 @@ export default function ColonyChat() {
if (event.type === "execution_paused") {
updateState({
isTyping: false,
isStreaming: false,
queenIsTyping: false,
workerIsTyping: false,
@@ -646,7 +626,6 @@ export default function ColonyChat() {
if (event.type === "execution_failed") {
updateState({
isTyping: false,
isStreaming: false,
queenIsTyping: false,
workerIsTyping: false,
@@ -670,7 +649,7 @@ export default function ColonyChat() {
case "node_loop_started":
turnCounterRef.current[turnKey] = currentTurn + 1;
updateState({ isTyping: true, activeToolCalls: {} });
updateState({ activeToolCalls: {} });
if (!isQueen && event.node_id) {
const existing = graphNodes.find((n) => n.id === event.node_id);
const isRevisit = existing?.status === "complete";
@@ -1022,7 +1001,7 @@ export default function ColonyChat() {
if (!agentState.sessionId) return;
try {
await executionApi.cancelQueen(agentState.sessionId);
updateState({ isTyping: false, isStreaming: false, queenIsTyping: false });
updateState({ isStreaming: false, queenIsTyping: false });
} catch {
// fire-and-forget
}
@@ -1052,7 +1031,7 @@ export default function ColonyChat() {
};
setMessages((prev) => [...prev, userMsg]);
suppressIntroRef.current = false;
updateState({ isTyping: true, queenIsTyping: true });
updateState({ queenIsTyping: true });
if (agentState.sessionId && agentState.ready) {
executionApi.chat(agentState.sessionId, text, images).catch((err: unknown) => {
@@ -1067,7 +1046,7 @@ export default function ColonyChat() {
thread: agentPath,
createdAt: Date.now(),
});
updateState({ isTyping: false, isStreaming: false, queenIsTyping: false });
updateState({ isStreaming: false, queenIsTyping: false });
});
}
},
+4 -4
View File
@@ -753,8 +753,8 @@ def test_build_system_prompt_injects_dynamic_memory():
def test_queen_phase_state_appends_global_memory_block():
phase = QueenPhaseState(
phase="building",
prompt_building="base prompt",
phase="independent",
prompt_independent="base prompt",
_cached_global_recall_block="--- Global Memories ---\nglobal stuff",
)
@@ -766,7 +766,7 @@ def test_queen_phase_state_appends_global_memory_block():
def test_queen_phase_state_appends_queen_memory_block():
phase = QueenPhaseState(
prompt_building="base prompt",
prompt_independent="base prompt",
_cached_global_recall_block="--- Global Memories ---\nglobal stuff",
_cached_queen_recall_block="--- Queen Memories: queen_technology ---\nqueen stuff",
)
@@ -779,7 +779,7 @@ def test_queen_phase_state_appends_queen_memory_block():
def test_queen_phase_state_prompt_without_memory():
phase = QueenPhaseState(phase="building", prompt_building="base prompt")
phase = QueenPhaseState(phase="independent", prompt_independent="base prompt")
prompt = phase.get_current_prompt()
assert "base prompt" in prompt