From 17150a53bd816751979a2b36406abb8d523d6824 Mon Sep 17 00:00:00 2001 From: Richard Tang Date: Mon, 20 Apr 2026 13:09:02 -0700 Subject: [PATCH] chore: lint --- .../agent_loop/internals/compaction.py | 2 +- core/framework/agents/discovery.py | 6 +- .../agents/queen/incubating_evaluator.py | 13 +-- core/framework/agents/queen/nodes/__init__.py | 14 +-- core/framework/server/compaction_status.py | 3 +- core/framework/server/routes_execution.py | 16 ++-- core/framework/tools/queen_lifecycle_tools.py | 36 +++----- core/tests/test_create_colony_tool.py | 8 +- tools/src/gcu/browser/bridge.py | 87 +++++++++++-------- tools/src/gcu/browser/tools/inspection.py | 80 ++++++++--------- tools/src/gcu/browser/tools/interactions.py | 6 +- 11 files changed, 120 insertions(+), 151 deletions(-) diff --git a/core/framework/agent_loop/internals/compaction.py b/core/framework/agent_loop/internals/compaction.py index 561c9249..a1abec13 100644 --- a/core/framework/agent_loop/internals/compaction.py +++ b/core/framework/agent_loop/internals/compaction.py @@ -567,7 +567,7 @@ def build_llm_compaction_prompt( user_messages_section = ( "6. **User Messages** — Reproduce EVERY user message verbatim and " "in full, in chronological order, each on its own line prefixed " - "with the message index (e.g. \"[U1] ...\"). Do NOT paraphrase, " + 'with the message index (e.g. "[U1] ..."). Do NOT paraphrase, ' "summarise, merge, or omit any user message. Preserve markdown, " "code fences, whitespace, and punctuation exactly as the user " "wrote them.\n" diff --git a/core/framework/agents/discovery.py b/core/framework/agents/discovery.py index 9183a94b..24c9d863 100644 --- a/core/framework/agents/discovery.py +++ b/core/framework/agents/discovery.py @@ -4,6 +4,7 @@ from __future__ import annotations import json from dataclasses import dataclass, field +from datetime import UTC from pathlib import Path @@ -227,9 +228,10 @@ def discover_agents() -> dict[str, list[AgentEntry]]: # Fallback: use directory creation time if metadata lacks created_at if not colony_created_at: try: - from datetime import datetime, timezone + from datetime import datetime + stat = path.stat() - colony_created_at = datetime.fromtimestamp(stat.st_birthtime, tz=timezone.utc).isoformat() + colony_created_at = datetime.fromtimestamp(stat.st_birthtime, tz=UTC).isoformat() except Exception: pass diff --git a/core/framework/agents/queen/incubating_evaluator.py b/core/framework/agents/queen/incubating_evaluator.py index 071ee079..42c12654 100644 --- a/core/framework/agents/queen/incubating_evaluator.py +++ b/core/framework/agents/queen/incubating_evaluator.py @@ -112,10 +112,7 @@ def format_conversation_excerpt(messages: list[Message]) -> str: # Surface tool-call intent for empty assistant turns so the # evaluator sees what the queen has been doing. if not content and msg.tool_calls: - names = [ - tc.get("function", {}).get("name", "?") - for tc in msg.tool_calls - ] + names = [tc.get("function", {}).get("name", "?") for tc in msg.tool_calls] content = f"(called: {', '.join(names)})" if len(content) > _MAX_ASSISTANT_CONTENT_CHARS: content = content[:_MAX_ASSISTANT_CONTENT_CHARS] + "..." @@ -224,9 +221,7 @@ async def evaluate( return { "ready": False, "reasons": ["evaluation_failed"], - "missing_prerequisites": [ - "evaluator LLM call failed; retry once the queen can reach the model again" - ], + "missing_prerequisites": ["evaluator LLM call failed; retry once the queen can reach the model again"], } raw = (getattr(response, "content", "") or "").strip() @@ -239,9 +234,7 @@ async def evaluate( return { "ready": False, "reasons": ["evaluation_failed"], - "missing_prerequisites": [ - "evaluator returned malformed JSON; retry" - ], + "missing_prerequisites": ["evaluator returned malformed JSON; retry"], } return _normalize_verdict(parsed) diff --git a/core/framework/agents/queen/nodes/__init__.py b/core/framework/agents/queen/nodes/__init__.py index 1a254e3c..e72a0848 100644 --- a/core/framework/agents/queen/nodes/__init__.py +++ b/core/framework/agents/queen/nodes/__init__.py @@ -474,12 +474,7 @@ queen_node = NodeSpec( nullable_output_keys=[], # Queen should never have this skip_judge=True, # Queen is a conversational agent; suppress tool-use pressure feedback tools=sorted( - set( - _QUEEN_INDEPENDENT_TOOLS - + _QUEEN_INCUBATING_TOOLS - + _QUEEN_WORKING_TOOLS - + _QUEEN_REVIEWING_TOOLS - ) + set(_QUEEN_INDEPENDENT_TOOLS + _QUEEN_INCUBATING_TOOLS + _QUEEN_WORKING_TOOLS + _QUEEN_REVIEWING_TOOLS) ), system_prompt=( _queen_character_core @@ -492,12 +487,7 @@ queen_node = NodeSpec( ) ALL_QUEEN_TOOLS = sorted( - set( - _QUEEN_INDEPENDENT_TOOLS - + _QUEEN_INCUBATING_TOOLS - + _QUEEN_WORKING_TOOLS - + _QUEEN_REVIEWING_TOOLS - ) + set(_QUEEN_INDEPENDENT_TOOLS + _QUEEN_INCUBATING_TOOLS + _QUEEN_WORKING_TOOLS + _QUEEN_REVIEWING_TOOLS) ) __all__ = [ diff --git a/core/framework/server/compaction_status.py b/core/framework/server/compaction_status.py index dab8f8ff..b0220ab1 100644 --- a/core/framework/server/compaction_status.py +++ b/core/framework/server/compaction_status.py @@ -141,8 +141,7 @@ async def await_completion( return last if loop.time() >= deadline: logger.warning( - "compaction_status: timed out after %.0fs waiting for %s " - "(proceeding with raw transcript)", + "compaction_status: timed out after %.0fs waiting for %s (proceeding with raw transcript)", timeout, queen_dir, ) diff --git a/core/framework/server/routes_execution.py b/core/framework/server/routes_execution.py index 267a7a2c..8330aa65 100644 --- a/core/framework/server/routes_execution.py +++ b/core/framework/server/routes_execution.py @@ -1081,8 +1081,7 @@ async def _compact_inherited_conversation( of the summary. """ import json as _json - from datetime import UTC as _UTC - from datetime import datetime as _datetime + from datetime import UTC as _UTC, datetime as _datetime try: result = await _compact_queen_conversation_in_place( @@ -1140,8 +1139,7 @@ async def _compact_inherited_conversation( logger.warning("compact_inherited: failed to append fork marker", exc_info=True) logger.info( - "compact_inherited: compacted %d parent message(s) -> 1 summary " - "(%d chars) for colony forked from %s", + "compact_inherited: compacted %d parent message(s) -> 1 summary (%d chars) for colony forked from %s", messages_compacted, summary_chars, source_session_id, @@ -1501,8 +1499,7 @@ async def fork_session_into_colony( ) except TimeoutError: compaction_error = ( - f"compaction timed out after {_COMPACTION_TIMEOUT_SECONDS:.0f}s " - "(falling back to raw transcript)" + f"compaction timed out after {_COMPACTION_TIMEOUT_SECONDS:.0f}s (falling back to raw transcript)" ) logger.warning( "fork_session_into_colony: %s for %s", @@ -1512,8 +1509,7 @@ async def fork_session_into_colony( except Exception as exc: compaction_error = f"compaction failed: {exc}" logger.warning( - "fork_session_into_colony: %s for %s " - "(falling back to raw transcript)", + "fork_session_into_colony: %s for %s (falling back to raw transcript)", compaction_error, _dest_queen_dir, exc_info=True, @@ -1619,9 +1615,7 @@ async def fork_session_into_colony( # compact). Frontend uses this to decide whether to display a # "preparing colony…" state while session-load blocks on the # compaction marker. - "compaction_status": ( - "in_progress" if source_queen_dir.exists() else "skipped" - ), + "compaction_status": ("in_progress" if source_queen_dir.exists() else "skipped"), } diff --git a/core/framework/tools/queen_lifecycle_tools.py b/core/framework/tools/queen_lifecycle_tools.py index 272728d3..c8efeee4 100644 --- a/core/framework/tools/queen_lifecycle_tools.py +++ b/core/framework/tools/queen_lifecycle_tools.py @@ -86,8 +86,6 @@ _INCUBATING_APPROVAL_GUIDANCE = ( ) - - def _render_credentials_block(provider: Any) -> str: """Call a credentials_prompt_provider safely and return its output. @@ -570,9 +568,7 @@ async def _start_trigger_timer(session: Any, trigger_id: str, tdef: Any) -> None if cron_expr: try: _peek = croniter(cron_expr, datetime.now(tz=UTC)).get_next(datetime) - _next_delay = max( - 0.0, (_peek - datetime.now(tz=UTC)).total_seconds() - ) + _next_delay = max(0.0, (_peek - datetime.now(tz=UTC)).total_seconds()) except Exception: _next_delay = 60.0 else: @@ -1557,8 +1553,7 @@ def register_queen_lifecycle_tools( return None, f"triggers[{idx}] ('{tid}') interval_minutes must be > 0, got {interval}" else: return None, ( - f"triggers[{idx}] ('{tid}') timer trigger needs 'cron' or " - "'interval_minutes' in trigger_config." + f"triggers[{idx}] ('{tid}') timer trigger needs 'cron' or 'interval_minutes' in trigger_config." ) else: # webhook path = (t_config.get("path") or "").strip() if isinstance(t_config.get("path"), str) else "" @@ -1573,7 +1568,9 @@ def register_queen_lifecycle_tools( "trigger_type": t_type, "trigger_config": t_config, "task": task_str.strip(), - "name": entry.get("name") if isinstance(entry.get("name"), str) and entry.get("name").strip() else tid, + "name": ( + entry.get("name") if isinstance(entry.get("name"), str) and entry.get("name").strip() else tid + ), } ) return normalized, None @@ -1698,7 +1695,9 @@ def register_queen_lifecycle_tools( colony_name=cn, task=(task or "").strip(), tasks=tasks if isinstance(tasks, list) else None, - concurrency_hint=concurrency_hint if isinstance(concurrency_hint, int) and concurrency_hint > 0 else None, + concurrency_hint=( + concurrency_hint if isinstance(concurrency_hint, int) and concurrency_hint > 0 else None + ), ) except Exception as e: logger.exception("create_colony: fork failed after installing skill") @@ -1739,9 +1738,7 @@ def register_queen_lifecycle_tools( # the background; opening the colony will # block on that until it finishes. "skipped" # means no compaction was needed. - "compaction_status": fork_result.get( - "compaction_status", "skipped" - ), + "compaction_status": fork_result.get("compaction_status", "skipped"), }, ) ) @@ -1820,9 +1817,7 @@ def register_queen_lifecycle_tools( "tasks_seeded": len(fork_result.get("task_ids") or []), # Transcript compaction runs in the background; opening # the colony blocks on this marker until it finishes. - "compaction_status": fork_result.get( - "compaction_status", "skipped" - ), + "compaction_status": fork_result.get("compaction_status", "skipped"), } ) @@ -2105,12 +2100,7 @@ def register_queen_lifecycle_tools( cn = (colony_name or "").strip() if not _COLONY_NAME_RE.match(cn): return json.dumps( - { - "error": ( - "colony_name must be lowercase alphanumeric with " - "underscores (e.g. 'morning_hn_digest')." - ) - } + {"error": ("colony_name must be lowercase alphanumeric with underscores (e.g. 'morning_hn_digest').")} ) purpose = (intended_purpose or "").strip() @@ -2197,9 +2187,7 @@ def register_queen_lifecycle_tools( "status": "not_ready", "colony_name": cn, "reasons": verdict.get("reasons", []), - "missing_prerequisites": verdict.get( - "missing_prerequisites", [] - ), + "missing_prerequisites": verdict.get("missing_prerequisites", []), } ) diff --git a/core/tests/test_create_colony_tool.py b/core/tests/test_create_colony_tool.py index e0768adf..844c6f17 100644 --- a/core/tests/test_create_colony_tool.py +++ b/core/tests/test_create_colony_tool.py @@ -565,9 +565,7 @@ async def test_triggers_written_to_triggers_json(patched_home: Path, patched_for @pytest.mark.asyncio -async def test_triggers_omitted_does_not_write_triggers_json( - patched_home: Path, patched_fork: list[dict] -) -> None: +async def test_triggers_omitted_does_not_write_triggers_json(patched_home: Path, patched_fork: list[dict]) -> None: """No triggers arg → no triggers.json (colony runs on-demand).""" executor, _ = _make_executor() @@ -585,9 +583,7 @@ async def test_triggers_omitted_does_not_write_triggers_json( @pytest.mark.asyncio -async def test_triggers_invalid_cron_fails_before_fork( - patched_home: Path, patched_fork: list[dict] -) -> None: +async def test_triggers_invalid_cron_fails_before_fork(patched_home: Path, patched_fork: list[dict]) -> None: """A bad cron fails fast: no skill written, no fork call.""" executor, _ = _make_executor() diff --git a/tools/src/gcu/browser/bridge.py b/tools/src/gcu/browser/bridge.py index 355ed70d..8e77c97f 100644 --- a/tools/src/gcu/browser/bridge.py +++ b/tools/src/gcu/browser/bridge.py @@ -469,11 +469,13 @@ class BeelineBridge: parsed = json.loads(payload) except Exception: parsed = {"_raw": payload} - write_log({ - "type": "viewport_event", - "tab_id": tab_id, - **parsed, - }) + write_log( + { + "type": "viewport_event", + "tab_id": tab_id, + **parsed, + } + ) return # Attach-time canary → attach_canary (proves extension @@ -483,11 +485,13 @@ class BeelineBridge: parsed = json.loads(payload) except Exception: parsed = {"_raw": payload} - write_log({ - "type": "attach_canary", - "tab_id": tab_id, - **parsed, - }) + write_log( + { + "type": "attach_canary", + "tab_id": tab_id, + **parsed, + } + ) return # Everything else — keep a compact row so we can tell @@ -503,24 +507,28 @@ class BeelineBridge: compact.append(v[:120]) elif v is not None: compact.append(str(v)[:120]) - write_log({ - "type": "cdp_event", - "tab_id": tab_id, - "method": method, - "level": params.get("type"), - "args": compact, - }) + write_log( + { + "type": "cdp_event", + "tab_id": tab_id, + "method": method, + "level": params.get("type"), + "args": compact, + } + ) return # Other forwarded events (Page.lifecycleEvent, frameResized, # frameNavigated, Target.targetInfoChanged) are rare and high # signal — keep the full param dict but truncate strings. - write_log({ - "type": "cdp_event", - "tab_id": tab_id, - "method": method, - "params": params, - }) + write_log( + { + "type": "cdp_event", + "tab_id": tab_id, + "method": method, + "params": params, + } + ) # Main-frame navigation wipes the previous document's scripts. # Our [hive_vp] probe's event listeners die with it. Reinstall @@ -541,6 +549,7 @@ class BeelineBridge: if method == "Page.frameResized" and tab_id is not None: try: from .tools.inspection import _viewport_sizes + _viewport_sizes.pop(tab_id, None) except Exception: pass @@ -550,6 +559,7 @@ class BeelineBridge: current document of ``tab_id``. Called from sync context inside ``_handle_cdp_event``, so we create a task on the running loop. Failures are silent.""" + async def _do() -> None: try: # The new document's global scope doesn't have @@ -566,6 +576,7 @@ class BeelineBridge: ) except Exception: pass + try: asyncio.get_event_loop().create_task(_do()) except RuntimeError: @@ -868,8 +879,7 @@ class BeelineBridge: { "expression": ( "console.info('[hive_attach_canary]', " - "JSON.stringify({tabId: " - + str(tab_id) + ", ts: Date.now()}))" + "JSON.stringify({tabId: " + str(tab_id) + ", ts: Date.now()}))" ), "returnByValue": True, "awaitPromise": False, @@ -1379,9 +1389,7 @@ class BeelineBridge: # `(function(){ return (...)(x,y) })()` and the value # actually comes back — without it the wrapper drops # the result on the floor (returns undefined). - probe_result = await self.evaluate( - tab_id, f"return ({_HIT_ELEMENT_JS})({x}, {y})" - ) + probe_result = await self.evaluate(tab_id, f"return ({_HIT_ELEMENT_JS})({x}, {y})") hit_probe = (probe_result or {}).get("result") except Exception: hit_probe = None @@ -1410,16 +1418,19 @@ class BeelineBridge: if hit_probe is not None: try: from .telemetry import write_log - write_log({ - "type": "click_hit_probe", - "tab_id": tab_id, - "intended": {"x": x, "y": y}, - "viewport": hit_probe.get("viewport"), - "hit": hit_probe.get("hit"), - "stack": hit_probe.get("stack"), - "sweep": hit_probe.get("sweep"), - "offsetInRect": hit_probe.get("offsetInRect"), - }) + + write_log( + { + "type": "click_hit_probe", + "tab_id": tab_id, + "intended": {"x": x, "y": y}, + "viewport": hit_probe.get("viewport"), + "hit": hit_probe.get("hit"), + "stack": hit_probe.get("stack"), + "sweep": hit_probe.get("sweep"), + "offsetInRect": hit_probe.get("offsetInRect"), + } + ) except Exception: pass return resp diff --git a/tools/src/gcu/browser/tools/inspection.py b/tools/src/gcu/browser/tools/inspection.py index d5f5209e..80f2d88f 100644 --- a/tools/src/gcu/browser/tools/inspection.py +++ b/tools/src/gcu/browser/tools/inspection.py @@ -240,23 +240,22 @@ async def _ensure_viewport_size(tab_id: int, _caller: str = "unknown") -> tuple[ try: from ..telemetry import write_log - write_log({ - "type": "viewport_sample", - "tab_id": tab_id, - "caller": _caller, - "live_w": cw, - "live_h": ch, - "cached_w": cached_before[0] if cached_before else None, - "cached_h": cached_before[1] if cached_before else None, - "deltaH_vs_cache": ( - (ch - cached_before[1]) - if (cached_before and ch > 0) - else None - ), - "returned_w": result_cw, - "returned_h": result_ch, - "evaluate_error": evaluate_error, - }) + + write_log( + { + "type": "viewport_sample", + "tab_id": tab_id, + "caller": _caller, + "live_w": cw, + "live_h": ch, + "cached_w": cached_before[0] if cached_before else None, + "cached_h": cached_before[1] if cached_before else None, + "deltaH_vs_cache": ((ch - cached_before[1]) if (cached_before and ch > 0) else None), + "returned_w": result_cw, + "returned_h": result_ch, + "evaluate_error": evaluate_error, + } + ) except Exception: pass @@ -362,31 +361,32 @@ def register_inspection_tools(mcp: FastMCP) -> None: # physical_scale is derived from pngWidth. try: from ..telemetry import write_log + expected_w = css_width * dpr expected_h = css_height_raw * dpr - write_log({ - "type": "screenshot_geometry", - "tab_id": target_tab, - "url": screenshot_result.get("url", ""), - "pngWidth": png_w, - "pngHeight": png_h, - "cssWidth": css_width, - "cssHeight": css_height_raw, - "dpr": dpr, - "expectedPngWidth": expected_w, - "expectedPngHeight": expected_h, - "deltaPngWidthPx": png_w - expected_w, - "deltaPngHeightPx": png_h - expected_h, - # If the PNG is taller than cssHeight×dpr (e.g. a - # devtools-attached banner adds rows above the page - # in the capture), clicks land BELOW intended at - # the top of the page and converge to 0 error at - # the bottom. Reverse signs if PNG is shorter. - # Worst-case error in CSS px at fy=0: - "yErrorAtTopCssPx": ( - (png_h - expected_h) / dpr if dpr else 0 - ), - }) + write_log( + { + "type": "screenshot_geometry", + "tab_id": target_tab, + "url": screenshot_result.get("url", ""), + "pngWidth": png_w, + "pngHeight": png_h, + "cssWidth": css_width, + "cssHeight": css_height_raw, + "dpr": dpr, + "expectedPngWidth": expected_w, + "expectedPngHeight": expected_h, + "deltaPngWidthPx": png_w - expected_w, + "deltaPngHeightPx": png_h - expected_h, + # If the PNG is taller than cssHeight×dpr (e.g. a + # devtools-attached banner adds rows above the page + # in the capture), clicks land BELOW intended at + # the top of the page and converge to 0 error at + # the bottom. Reverse signs if PNG is shorter. + # Worst-case error in CSS px at fy=0: + "yErrorAtTopCssPx": ((png_h - expected_h) / dpr if dpr else 0), + } + ) except Exception: pass diff --git a/tools/src/gcu/browser/tools/interactions.py b/tools/src/gcu/browser/tools/interactions.py index 53b20178..0ae83cd9 100644 --- a/tools/src/gcu/browser/tools/interactions.py +++ b/tools/src/gcu/browser/tools/interactions.py @@ -64,11 +64,7 @@ async def _build_visual_response(result: dict, bridge, target_tab: int | None) - shot = await bridge.screenshot(target_tab, full_page=False) if not shot.get("ok"): return [text_block] - highlights = ( - [_interaction_highlights[target_tab]] - if target_tab in _interaction_highlights - else None - ) + highlights = [_interaction_highlights[target_tab]] if target_tab in _interaction_highlights else None data, _ = await asyncio.to_thread( _resize_and_annotate, shot["data"],