chore: ruff lint

This commit is contained in:
Richard Tang
2026-03-06 19:11:53 -08:00
parent 196f3d645f
commit 19dd40ed3a
9 changed files with 138 additions and 73 deletions
@@ -176,8 +176,8 @@ to see ALL available tools (names + descriptions, grouped by category). \
ONLY use tools from this list in your node definitions. \
NEVER guess or fabricate tool names from memory.
list_agent_tools() # ALWAYS call this first (simple mode, truncated descriptions)
list_agent_tools(group="google", output_schema="full") # then drill into a provider for full descriptions + input_schema
list_agent_tools() # ALWAYS call this first (simple mode)
list_agent_tools(group="google", output_schema="full") # drill into a provider
NEVER skip the first call. Always start with the full list \
so you know what providers and tools exist before drilling in. \
@@ -541,7 +541,8 @@ on what it does from Worker Profile>."
5. Preferred loaded example:
local_business_extractor/*agent name*/ has been loaded. It finds local businesses on \
Google Maps, extracts contact details, and syncs them to Google Sheets.
ask_user("Do you want to run it?", ["Yes, run it", "Check credentials first", "Modify the worker"])
ask_user("Do you want to run it?", ["Yes, run it", "Check credentials first",
"Modify the worker"])
## When user ask identity and responsibility
@@ -886,8 +887,8 @@ queen_node = NodeSpec(
client_facing=True,
max_node_visits=0,
input_keys=["greeting"],
output_keys=[], # Queen should never have this
nullable_output_keys=[], # Queen should never have this
output_keys=[], # Queen should never have this
nullable_output_keys=[], # Queen should never have this
success_criteria=(
"User's intent is understood, coding tasks are completed correctly, "
"and the worker is managed effectively when delegated to."
+1 -2
View File
@@ -30,6 +30,7 @@ Usage:
from __future__ import annotations
import json as _json
import logging
import os
import time
@@ -37,8 +38,6 @@ from dataclasses import dataclass, field
from datetime import datetime
from typing import Any
import json as _json
import httpx
logger = logging.getLogger(__name__)
+4 -5
View File
@@ -230,9 +230,9 @@ class LoopConfig:
class HookContext:
"""Context passed to every lifecycle hook."""
event: str # event name, e.g. "session_start"
event: str # event name, e.g. "session_start"
trigger: str | None # message that triggered the hook, if any
system_prompt: str # current system prompt at hook invocation time
system_prompt: str # current system prompt at hook invocation time
@dataclass
@@ -240,7 +240,7 @@ class HookResult:
"""What a hook may return to modify node state."""
system_prompt: str | None = None # replace current system prompt
inject: str | None = None # inject an additional user message
inject: str | None = None # inject an additional user message
# ---------------------------------------------------------------------------
@@ -3699,8 +3699,7 @@ class EventLoopNode(NodeProtocol):
)
parts.append(
"DATA FILES (use load_data('<filename>'), read_file('<full_path>'), "
"or run_command('cat \"<full_path>\"') to read):\n"
+ file_list
"or run_command('cat \"<full_path>\"') to read):\n" + file_list
)
if not all_files:
parts.append(
+2 -2
View File
@@ -560,10 +560,10 @@ class SessionManager:
_QUEEN_BUILDING_TOOLS,
_QUEEN_RUNNING_TOOLS,
_QUEEN_STAGING_TOOLS,
_package_builder_knowledge,
_appendices,
_queen_behavior_always,
_gcu_building_section,
_package_builder_knowledge,
_queen_behavior_always,
_queen_behavior_building,
_queen_behavior_running,
_queen_behavior_staging,
+2 -1
View File
@@ -11,7 +11,7 @@ from framework.runner.tool_registry import ToolRegistry
from framework.runtime.agent_runtime import AgentRuntime, create_agent_runtime
from framework.runtime.execution_stream import EntryPointSpec
from .config import default_config, metadata
from .config import default_config
from .nodes import (
intake_node,
job_search_node,
@@ -291,5 +291,6 @@ class JobHunterAgent:
errors.append(f"Entry node '{self.entry_node}' not found")
return {"valid": len(errors) == 0, "errors": errors}
# Create default instance
default_agent = JobHunterAgent()
+3 -1
View File
@@ -130,5 +130,7 @@ if __name__ == "__main__":
print_running_prompt()
else:
print(f"Unknown phase: {phase}")
print("Usage: uv run scripts/debug_queen_prompt.py [building|staging|running|all]")
print(
"Usage: uv run scripts/debug_queen_prompt.py [building|staging|running|all]"
)
sys.exit(1)
+37 -8
View File
@@ -93,7 +93,11 @@ def _discover_records(logs_dir: Path, limit_files: int) -> list[dict[str, Any]]:
raise FileNotFoundError(f"log directory not found: {logs_dir}")
files = sorted(
[path for path in logs_dir.iterdir() if path.is_file() and path.suffix == ".jsonl"],
[
path
for path in logs_dir.iterdir()
if path.is_file() and path.suffix == ".jsonl"
],
key=lambda path: path.stat().st_mtime,
reverse=True,
)[:limit_files]
@@ -113,7 +117,9 @@ def _format_timestamp(raw: str) -> str:
return raw
def _group_sessions(records: list[dict[str, Any]]) -> tuple[list[SessionSummary], dict[str, list[dict[str, Any]]]]:
def _group_sessions(
records: list[dict[str, Any]],
) -> tuple[list[SessionSummary], dict[str, list[dict[str, Any]]]]:
by_session: dict[str, list[dict[str, Any]]] = defaultdict(list)
for record in records:
execution_id = str(record.get("execution_id") or "").strip()
@@ -122,7 +128,12 @@ def _group_sessions(records: list[dict[str, Any]]) -> tuple[list[SessionSummary]
summaries: list[SessionSummary] = []
for execution_id, session_records in by_session.items():
session_records.sort(key=lambda record: (str(record.get("timestamp", "")), record.get("iteration", 0)))
session_records.sort(
key=lambda record: (
str(record.get("timestamp", "")),
record.get("iteration", 0),
)
)
first = session_records[0]
last = session_records[-1]
summaries.append(
@@ -132,13 +143,26 @@ def _group_sessions(records: list[dict[str, Any]]) -> tuple[list[SessionSummary]
start_timestamp=str(first.get("timestamp", "")),
end_timestamp=str(last.get("timestamp", "")),
turn_count=len(session_records),
streams=sorted({str(r.get("stream_id", "")) for r in session_records if r.get("stream_id")}),
nodes=sorted({str(r.get("node_id", "")) for r in session_records if r.get("node_id")}),
streams=sorted(
{
str(r.get("stream_id", ""))
for r in session_records
if r.get("stream_id")
}
),
nodes=sorted(
{
str(r.get("node_id", ""))
for r in session_records
if r.get("node_id")
}
),
models=sorted(
{
str(r.get("token_counts", {}).get("model", ""))
for r in session_records
if isinstance(r.get("token_counts"), dict) and r.get("token_counts", {}).get("model")
if isinstance(r.get("token_counts"), dict)
and r.get("token_counts", {}).get("model")
}
),
)
@@ -172,7 +196,10 @@ def _render_html(
sessions_data = {
execution_id: sorted(
records,
key=lambda record: (str(record.get("timestamp", "")), record.get("iteration", 0)),
key=lambda record: (
str(record.get("timestamp", "")),
record.get("iteration", 0),
),
)
for execution_id, records in sessions.items()
}
@@ -809,7 +836,9 @@ def main() -> int:
records = _discover_records(args.logs_dir.expanduser(), args.limit_files)
summaries, sessions = _group_sessions(records)
initial_session_id = args.session or (summaries[0].execution_id if summaries else "")
initial_session_id = args.session or (
summaries[0].execution_id if summaries else ""
)
if initial_session_id and initial_session_id not in sessions:
print(f"session not found: {initial_session_id}")
return 1
+1
View File
@@ -10,6 +10,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "tools"))
# Set PROJECT_ROOT before importing
import tools.coder_tools_server as srv
srv.PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
# Access the underlying function (FastMCP wraps it as FunctionTool)
+82 -49
View File
@@ -1253,7 +1253,10 @@ def validate_agent_package(agent_name: str) -> str:
try:
proc = subprocess.run(
[
"uv", "run", "python", "-c",
"uv",
"run",
"python",
"-c",
f"from {agent_name} import default_agent; print(default_agent.validate())",
],
capture_output=True,
@@ -1279,10 +1282,13 @@ def validate_agent_package(agent_name: str) -> str:
try:
proc = subprocess.run(
[
"uv", "run", "python", "-c",
f'from framework.runner.runner import AgentRunner; '
"uv",
"run",
"python",
"-c",
f"from framework.runner.runner import AgentRunner; "
f'r = AgentRunner.load("exports/{agent_name}", '
f'skip_credential_validation=True); '
f"skip_credential_validation=True); "
f'print("AgentRunner.load (graph-only): OK")',
],
capture_output=True,
@@ -1336,7 +1342,6 @@ def validate_agent_package(agent_name: str) -> str:
# Build summary
failed_steps = [name for name, step in steps.items() if not step.get("passed")]
total = len(steps)
passed_count = total - len(failed_steps)
valid = len(failed_steps) == 0
if valid:
@@ -1394,13 +1399,15 @@ def initialize_agent_package(agent_name: str, nodes: str | None = None) -> str:
import re
if not re.match(r"^[a-z][a-z0-9_]*$", agent_name):
return json.dumps({
"success": False,
"error": (
f"Invalid agent_name '{agent_name}'. Must be snake_case: "
"lowercase letters, numbers, underscores, starting with a letter."
),
})
return json.dumps(
{
"success": False,
"error": (
f"Invalid agent_name '{agent_name}'. Must be snake_case: "
"lowercase letters, numbers, underscores, starting with a letter."
),
}
)
node_list = [n.strip() for n in nodes.split(",") if n.strip()] if nodes else ["start"]
@@ -1427,7 +1434,9 @@ def initialize_agent_package(agent_name: str, nodes: str | None = None) -> str:
}
# -- config.py --
_write("config.py", f'''\
_write(
"config.py",
f'''\
"""Runtime configuration."""
import json
@@ -1471,7 +1480,8 @@ class AgentMetadata:
metadata = AgentMetadata()
''')
''',
)
# -- nodes/__init__.py --
node_specs = []
@@ -1479,7 +1489,7 @@ metadata = AgentMetadata()
for node_id in node_list:
var = _node_var_name(node_id)
node_var_names.append(var)
is_first = (node_id == entry_node)
is_first = node_id == entry_node
node_specs.append(f'''\
{var} = NodeSpec(
id="{node_id}",
@@ -1516,17 +1526,19 @@ __all__ = {node_var_names!r}
edge_defs = []
for i in range(len(node_list) - 1):
src, tgt = node_list[i], node_list[i + 1]
edge_defs.append(f'''\
edge_defs.append(f"""\
EdgeSpec(
id="{src}-to-{tgt}",
source="{src}",
target="{tgt}",
condition=EdgeCondition.ON_SUCCESS,
priority=1,
),''')
),""")
edges_str = "\n".join(edge_defs) if edge_defs else " # TODO: Add edges"
_write("agent.py", f'''\
_write(
"agent.py",
f'''\
"""Agent graph construction for {human_name}."""
from pathlib import Path
@@ -1735,10 +1747,13 @@ class {class_name}:
default_agent = {class_name}()
''')
''',
)
# -- __init__.py --
_write("__init__.py", f'''\
_write(
"__init__.py",
f'''\
"""{human_name} — TODO: Add description."""
from .agent import (
@@ -1773,10 +1788,13 @@ __all__ = [
"default_config",
"metadata",
]
''')
''',
)
# -- __main__.py --
_write("__main__.py", f'''\
_write(
"__main__.py",
f'''\
"""CLI entry point for {human_name}."""
import asyncio
@@ -1827,7 +1845,9 @@ def info():
"""Show agent info."""
data = default_agent.info()
click.echo(
f"Agent: {{data[\'name\']}}\\nVersion: {{data[\'version\']}}\\nDescription: {{data[\'description\']}}"
f"Agent: {{data[\'name\']}}\n"
f"Version: {{data[\'version\']}}\n"
f"Description: {{data[\'description\']}}"
)
click.echo(f"Nodes: {{', '.join(data[\'nodes\'])}}")
click.echo(f"Client-facing: {{', '.join(data[\'client_facing_nodes\'])}}")
@@ -1848,21 +1868,30 @@ def validate():
if __name__ == "__main__":
cli()
''')
''',
)
# -- mcp_servers.json --
_write("mcp_servers.json", json.dumps({
"hive-tools": {
"transport": "stdio",
"command": "uv",
"args": ["run", "python", "mcp_server.py", "--stdio"],
"cwd": "../../tools",
"description": "Hive tools MCP server",
}
}, indent=2))
_write(
"mcp_servers.json",
json.dumps(
{
"hive-tools": {
"transport": "stdio",
"command": "uv",
"args": ["run", "python", "mcp_server.py", "--stdio"],
"cwd": "../../tools",
"description": "Hive tools MCP server",
}
},
indent=2,
),
)
# -- tests/conftest.py --
_write("tests/conftest.py", f'''\
_write(
"tests/conftest.py",
'''\
"""Test fixtures."""
import sys
@@ -1893,22 +1922,26 @@ def runner_loaded():
from framework.runner.runner import AgentRunner
return AgentRunner.load(AGENT_PATH)
''')
''',
)
return json.dumps({
"success": True,
"agent_name": agent_name,
"class_name": class_name,
"entry_node": entry_node,
"nodes": node_list,
"files_written": files_written,
"file_count": len(files_written),
"next_steps": [
f"Customize node definitions in exports/{agent_name}/nodes/__init__.py",
f"Define goal and edges in exports/{agent_name}/agent.py",
f"Run validate_agent_package(\"{agent_name}\") to check structure",
],
}, indent=2)
return json.dumps(
{
"success": True,
"agent_name": agent_name,
"class_name": class_name,
"entry_node": entry_node,
"nodes": node_list,
"files_written": files_written,
"file_count": len(files_written),
"next_steps": [
f"Customize node definitions in exports/{agent_name}/nodes/__init__.py",
f"Define goal and edges in exports/{agent_name}/agent.py",
f'Run validate_agent_package("{agent_name}") to check structure',
],
},
indent=2,
)
# ── Main ──────────────────────────────────────────────────────────────────