chore: ruff lint
This commit is contained in:
@@ -65,9 +65,7 @@ def _extract_error_message(response: httpx.Response) -> str:
|
||||
def _sanitize_openrouter_model_id(value: str) -> str:
|
||||
"""Sanitize pasted OpenRouter model IDs into a comparable slug."""
|
||||
normalized = unicodedata.normalize("NFKC", value or "")
|
||||
normalized = "".join(
|
||||
ch for ch in normalized if unicodedata.category(ch) not in {"Cc", "Cf"}
|
||||
)
|
||||
normalized = "".join(ch for ch in normalized if unicodedata.category(ch) not in {"Cc", "Cf"})
|
||||
normalized = normalized.translate(OPENROUTER_SEPARATOR_TRANSLATION)
|
||||
normalized = re.sub(r"\s+", "", normalized)
|
||||
if normalized.casefold().startswith("openrouter/"):
|
||||
@@ -203,9 +201,7 @@ def check_openrouter_model(
|
||||
)
|
||||
if r.status_code == 200:
|
||||
available_model_lookup = _extract_openrouter_model_lookup(r.json())
|
||||
matched_model = available_model_lookup.get(
|
||||
_normalize_openrouter_model_id(requested_model)
|
||||
)
|
||||
matched_model = available_model_lookup.get(_normalize_openrouter_model_id(requested_model))
|
||||
if matched_model:
|
||||
return {
|
||||
"valid": True,
|
||||
@@ -231,10 +227,7 @@ def check_openrouter_model(
|
||||
|
||||
detail = _extract_error_message(r)
|
||||
if r.status_code in (400, 404, 422):
|
||||
base = (
|
||||
"OpenRouter model is not available for this key/settings: "
|
||||
f"{requested_model}"
|
||||
)
|
||||
base = f"OpenRouter model is not available for this key/settings: {requested_model}"
|
||||
return {"valid": False, "message": f"{base}. {detail}" if detail else base}
|
||||
|
||||
suffix = f": {detail}" if detail else ""
|
||||
@@ -244,9 +237,7 @@ def check_openrouter_model(
|
||||
}
|
||||
|
||||
|
||||
def check_minimax(
|
||||
api_key: str, api_base: str = "https://api.minimax.io/v1", **_: str
|
||||
) -> dict:
|
||||
def check_minimax(api_key: str, api_base: str = "https://api.minimax.io/v1", **_: str) -> dict:
|
||||
"""Validate via chatcompletion_v2 endpoint with empty messages.
|
||||
|
||||
MiniMax doesn't support GET /models; their native endpoint is
|
||||
@@ -327,9 +318,7 @@ PROVIDERS = {
|
||||
"mistral": lambda key, **_: check_openai_compatible(
|
||||
key, "https://api.mistral.ai/v1/models", "Mistral"
|
||||
),
|
||||
"xai": lambda key, **_: check_openai_compatible(
|
||||
key, "https://api.x.ai/v1/models", "xAI"
|
||||
),
|
||||
"xai": lambda key, **_: check_openai_compatible(key, "https://api.x.ai/v1/models", "xAI"),
|
||||
"perplexity": lambda key, **_: check_openai_compatible(
|
||||
key, "https://api.perplexity.ai/v1/models", "Perplexity"
|
||||
),
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
|
||||
Examples:
|
||||
uv run scripts/debug_agent_node.py exports/reddit_star_growth_agent --list-nodes
|
||||
uv run scripts/debug_agent_node.py exports/reddit_star_growth_agent --node load_contacted_users --task '{"repo_url":"https://github.com/acme/repo"}'
|
||||
uv run scripts/debug_agent_node.py exports/reddit_star_growth_agent/nodes/__init__.py --node load_contacted_users --input-file /tmp/payload.json
|
||||
uv run scripts/debug_agent_node.py exports/reddit_star_growth_agent \
|
||||
--node load_contacted_users \
|
||||
--task '{"repo_url":"https://github.com/acme/repo"}'
|
||||
uv run scripts/debug_agent_node.py \
|
||||
exports/reddit_star_growth_agent/nodes/__init__.py \
|
||||
--node load_contacted_users --input-file /tmp/payload.json
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -23,11 +27,11 @@ REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from framework.graph.checkpoint_config import CheckpointConfig
|
||||
from framework.graph.edge import GraphSpec
|
||||
from framework.runtime.agent_runtime import create_agent_runtime
|
||||
from framework.runtime.execution_stream import EntryPointSpec
|
||||
from framework.runner.runner import AgentRunner
|
||||
from framework.graph.checkpoint_config import CheckpointConfig # noqa: E402
|
||||
from framework.graph.edge import GraphSpec # noqa: E402
|
||||
from framework.runtime.agent_runtime import create_agent_runtime # noqa: E402
|
||||
from framework.runtime.execution_stream import EntryPointSpec # noqa: E402
|
||||
from framework.runner.runner import AgentRunner # noqa: E402
|
||||
|
||||
|
||||
def _configure_event_debug_logging(storage_path: Path) -> None:
|
||||
@@ -122,7 +126,10 @@ def _parse_args() -> argparse.Namespace:
|
||||
)
|
||||
parser.add_argument(
|
||||
"agent_path",
|
||||
help="Export directory or file path (for example exports/my_agent or exports/my_agent/nodes/__init__.py).",
|
||||
help=(
|
||||
"Export directory or file path (for example"
|
||||
" exports/my_agent or exports/my_agent/nodes/__init__.py)."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--node",
|
||||
|
||||
@@ -162,8 +162,5 @@ if __name__ == "__main__":
|
||||
print_running_prompt()
|
||||
else:
|
||||
print(f"Unknown phase: {phase}")
|
||||
print(
|
||||
"Usage: uv run scripts/debug_queen_prompt.py "
|
||||
"[planning|building|staging|running|all]"
|
||||
)
|
||||
print("Usage: uv run scripts/debug_queen_prompt.py [planning|building|staging|running|all]")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -108,11 +108,7 @@ 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]
|
||||
@@ -164,9 +160,7 @@ def _group_sessions(
|
||||
|
||||
if not include_tests:
|
||||
by_session = {
|
||||
eid: recs
|
||||
for eid, recs in by_session.items()
|
||||
if not _is_test_session(eid, recs)
|
||||
eid: recs for eid, recs in by_session.items() if not _is_test_session(eid, recs)
|
||||
}
|
||||
|
||||
summaries: list[SessionSummary] = []
|
||||
@@ -187,18 +181,10 @@ def _group_sessions(
|
||||
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")
|
||||
}
|
||||
{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")
|
||||
}
|
||||
{str(r.get("node_id", "")) for r in session_records if r.get("node_id")}
|
||||
),
|
||||
models=sorted(
|
||||
{
|
||||
@@ -585,12 +571,14 @@ def _render_html(
|
||||
<aside class="sidebar">
|
||||
<div class="brand">
|
||||
<h1>Hive Debug</h1>
|
||||
<p>Pick a session in the browser and inspect prompts, inputs, outputs, and tool activity turn by turn.</p>
|
||||
<p>Pick a session in the browser and inspect prompts,
|
||||
inputs, outputs, and tool activity turn by turn.</p>
|
||||
</div>
|
||||
<input id="sessionSearch" type="search" placeholder="Filter sessions">
|
||||
<div class="setup-note">
|
||||
<h3>Logging status</h3>
|
||||
<p>LLM turn logging is always on. If this list is empty, run Hive once and refresh after the session produces turns.</p>
|
||||
<p>LLM turn logging is always on. If this list is empty,
|
||||
run Hive once and refresh after the session produces turns.</p>
|
||||
<pre>~/.hive/llm_logs</pre>
|
||||
</div>
|
||||
<div class="session-list" id="sessionList"></div>
|
||||
@@ -602,7 +590,8 @@ def _render_html(
|
||||
<div class="meta-grid" id="metaGrid"></div>
|
||||
</section>
|
||||
<div class="toolbar">
|
||||
<input id="turnFilter" type="search" placeholder="Filter selected session by text, tool name, role, model, or prompt content">
|
||||
<input id="turnFilter" type="search"
|
||||
placeholder="Filter by text, tool, role, model, or prompt">
|
||||
<button type="button" id="expandAll">Expand all</button>
|
||||
<button type="button" id="collapseAll">Collapse all</button>
|
||||
</div>
|
||||
@@ -610,7 +599,9 @@ def _render_html(
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script id="session-summaries" type="application/json">{json.dumps(summaries_data, ensure_ascii=False)}</script>
|
||||
<script id="session-summaries" type="application/json">{
|
||||
json.dumps(summaries_data, ensure_ascii=False)
|
||||
}</script>
|
||||
<script>
|
||||
const summaries = JSON.parse(document.getElementById("session-summaries").textContent);
|
||||
const recordCache = {{}};
|
||||
@@ -669,9 +660,15 @@ def _render_html(
|
||||
...(summary.models || []).slice(0, 2),
|
||||
];
|
||||
return `
|
||||
<button type="button" class="session-card${{active}}" data-session-id="${{escapeHtml(summary.execution_id)}}">
|
||||
<div class="sid">${{escapeHtml(summary.execution_id)}}</div>
|
||||
<div class="meta">${{chips.map((chip) => `<span>${{escapeHtml(chip)}}</span>`).join("")}}</div>
|
||||
<button type="button"
|
||||
class="session-card${{active}}"
|
||||
data-session-id="${{escapeHtml(summary.execution_id)}}">
|
||||
<div class="sid">${{escapeHtml(
|
||||
summary.execution_id
|
||||
)}}</div>
|
||||
<div class="meta">${{chips.map(
|
||||
(chip) => `<span>${{escapeHtml(chip)}}</span>`
|
||||
).join("")}}</div>
|
||||
</button>
|
||||
`;
|
||||
}})
|
||||
@@ -679,7 +676,9 @@ def _render_html(
|
||||
}}
|
||||
|
||||
function renderMetaCard(label, value) {{
|
||||
return `<div class="meta-card"><span class="label">${{escapeHtml(label)}}</span>${{escapeHtml(value || "-")}}</div>`;
|
||||
return `<div class="meta-card"><span class="label">${{
|
||||
escapeHtml(label)
|
||||
}}</span>${{escapeHtml(value || "-")}}</div>`;
|
||||
}}
|
||||
|
||||
function renderMessage(message, index) {{
|
||||
@@ -699,7 +698,8 @@ def _render_html(
|
||||
}}
|
||||
${{
|
||||
toolCalls
|
||||
? `<details class="block"><summary>tool_calls</summary><pre>${{prettyJson(toolCalls)}}</pre></details>`
|
||||
? `<details class="block"><summary>tool_calls</summary>` +
|
||||
`<pre>${{prettyJson(toolCalls)}}</pre></details>`
|
||||
: ""
|
||||
}}
|
||||
</div>
|
||||
@@ -746,12 +746,18 @@ def _render_html(
|
||||
</div>
|
||||
${{
|
||||
systemPrompt
|
||||
? `<details class="block" open><summary>System prompt</summary><pre>${{escapeHtml(systemPrompt)}}</pre></details>`
|
||||
? `<details class="block" open>` +
|
||||
`<summary>System prompt</summary>` +
|
||||
`<pre>${{escapeHtml(systemPrompt)}}</pre></details>`
|
||||
: ""
|
||||
}}
|
||||
${{
|
||||
messages.length
|
||||
? `<details class="block" open><summary>Input messages (${{messages.length}})</summary>${{messages.map((message, index) => renderMessage(message, index + 1)).join("")}}</details>`
|
||||
? `<details class="block" open>` +
|
||||
`<summary>Input messages (${{messages.length}})` +
|
||||
`</summary>${{messages.map((message, index) =>
|
||||
renderMessage(message, index + 1)
|
||||
).join("")}}</details>`
|
||||
: ""
|
||||
}}
|
||||
<details class="block" open>
|
||||
@@ -760,17 +766,26 @@ def _render_html(
|
||||
</details>
|
||||
${{
|
||||
toolCalls.length
|
||||
? `<details class="block" open><summary>Tool calls (${{toolCalls.length}})</summary>${{toolCalls.map((toolCall, index) => renderToolCall(toolCall, index + 1)).join("")}}</details>`
|
||||
? `<details class="block" open>` +
|
||||
`<summary>Tool calls (${{toolCalls.length}})` +
|
||||
`</summary>${{toolCalls.map((toolCall, index) =>
|
||||
renderToolCall(toolCall, index + 1)
|
||||
).join("")}}</details>`
|
||||
: ""
|
||||
}}
|
||||
${{
|
||||
toolResults.length
|
||||
? `<details class="block"><summary>Tool results (${{toolResults.length}})</summary><pre>${{prettyJson(toolResults)}}</pre></details>`
|
||||
? `<details class="block">` +
|
||||
`<summary>Tool results (${{toolResults.length}})` +
|
||||
`</summary><pre>${{prettyJson(toolResults)}}` +
|
||||
`</pre></details>`
|
||||
: ""
|
||||
}}
|
||||
${{
|
||||
parseError
|
||||
? `<details class="block"><summary>Parse error</summary><pre>${{prettyJson(record)}}</pre></details>`
|
||||
? `<details class="block">` +
|
||||
`<summary>Parse error</summary>` +
|
||||
`<pre>${{prettyJson(record)}}</pre></details>`
|
||||
: ""
|
||||
}}
|
||||
</section>
|
||||
@@ -881,9 +896,7 @@ def _run_server(
|
||||
if records is None:
|
||||
self._respond(404, "application/json", b"[]")
|
||||
else:
|
||||
body = json.dumps(
|
||||
_sort_records(records), ensure_ascii=False
|
||||
).encode("utf-8")
|
||||
body = json.dumps(_sort_records(records), ensure_ascii=False).encode("utf-8")
|
||||
self._respond(200, "application/json", body)
|
||||
else:
|
||||
self.send_error(404)
|
||||
@@ -919,9 +932,7 @@ def main() -> int:
|
||||
records = _discover_records(args.logs_dir.expanduser(), args.limit_files)
|
||||
summaries, sessions = _group_sessions(records, include_tests=args.include_tests)
|
||||
|
||||
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
|
||||
|
||||
@@ -48,9 +48,7 @@ def test_check_requirements():
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
assert data["json"] == "ok", "json should be ok"
|
||||
assert "error" in data["nonexistent_module"], (
|
||||
"nonexistent_module should have error"
|
||||
)
|
||||
assert "error" in data["nonexistent_module"], "nonexistent_module should have error"
|
||||
assert result.returncode == 1, "Exit code should be 1 when errors exist"
|
||||
print("✓ Test 2 passed")
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user