chore: ruff lint
This commit is contained in:
@@ -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."
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 ──────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user