[eric] app-use: strip pierre's transient [app-agent] trace scaffolding + write-only controls cache (no speculative scaffolding)

This commit is contained in:
ciregenz
2026-06-29 23:03:45 -07:00
parent 717763771f
commit 8eb48dfc42
5 changed files with 2 additions and 107 deletions
+1 -58
View File
@@ -151,22 +151,6 @@ def p_app_output_id(browser_id: str) -> str | None:
return browser_id[4:] if browser_id.startswith("app:") else None
def p_app_workspace_dir(browser_id: str) -> str | None:
"""Resolve the on-disk workspace folder for an `app:<output_id>` target."""
oid = p_app_output_id(browser_id)
if not oid:
return None
try:
from backend.apps.outputs.workspace_io import load_output
from backend.config.paths import OUTPUTS_WORKSPACE_DIR
out = load_output(oid)
if not out or not getattr(out, "workspace_id", None):
return None
return os.path.join(OUTPUTS_WORKSPACE_DIR, out.workspace_id)
except Exception:
return None
def render_app_controls(describe_value: object) -> tuple[str, str] | None:
"""From a decoded describe() value build (rules_md, controls_md). Returns
None when the value is not a ready, usable describe."""
@@ -194,29 +178,6 @@ def render_app_controls(describe_value: object) -> tuple[str, str] | None:
return rules_md, controls_md
def p_persist_app_controls(browser_id: str, describe_value: object) -> None:
"""Cache rules.md + controls.md into the app workspace so the agent reads them
up front and only re-describes when controls change. Best-effort; written
under .openswarm/ so they stay out of the app's own file tree."""
rendered = render_app_controls(describe_value)
if not rendered:
return
folder = p_app_workspace_dir(browser_id)
if not folder or not os.path.isdir(folder):
return
rules_md, controls_md = rendered
try:
cache_dir = os.path.join(folder, ".openswarm")
os.makedirs(cache_dir, exist_ok=True)
with open(os.path.join(cache_dir, "controls.md"), "w", encoding="utf-8") as f:
f.write(controls_md)
if rules_md:
with open(os.path.join(cache_dir, "rules.md"), "w", encoding="utf-8") as f:
f.write(rules_md)
except Exception:
logger.debug("[app-agent] failed to persist controls cache", exc_info=True)
# Single-tool names -> the sub-action type they map to, so one summarizer covers
# both BrowserPressKey({key}) and a batch's {"type":"press_key","params":{key}}.
P_SINGLE_ACTION_TYPE = {
@@ -286,10 +247,6 @@ async def execute_browser_tool(
tool_name: str, tool_input: dict, browser_id: str, tab_id: str = "",
) -> dict:
"""Execute a browser tool via ws_manager directly (no MCP/HTTP round-trip)."""
# [app-agent] step trace: only for app targets / bridge tools so normal
# browser-agent runs stay quiet. Greppable prefix; remove when done.
p_trace = browser_id.startswith("app:") or tool_name in APP_BRIDGE_TOOLS
# One greppable line naming the actual buttons/keys/selectors this call drives,
# so a run reads as "key:ArrowRight x5" rather than an opaque tool name. Fires
# for action tools only (reads stay quiet) and ungated so web runs get it too.
@@ -306,12 +263,7 @@ async def execute_browser_tool(
async def p_eval_once() -> dict:
rid = uuid4().hex
if p_trace:
logger.info(f"[app-agent] DISPATCH {tool_name} -> {browser_id} (req {rid[:8]}) js={expr[:120]}")
r = await ws_manager.send_browser_command(rid, action, browser_id, params, tab_id=tab_id)
if p_trace:
logger.info(f"[app-agent] RESULT {tool_name} <- {browser_id}: {json.dumps(r)[:300]}")
return r
return await ws_manager.send_browser_command(rid, action, browser_id, params, tab_id=tab_id)
result = await p_eval_once()
# Reads poll for the bridge to come up (app still mounting on turn 1).
@@ -334,8 +286,6 @@ async def execute_browser_tool(
p_bridge_known_absent.discard(browser_id)
else:
p_bridge_known_absent.add(browser_id)
if tool_name == "AppDescribe":
p_persist_app_controls(browser_id, parse_bridge_result(result))
return result
action = ACTION_MAP.get(tool_name)
@@ -344,13 +294,9 @@ async def execute_browser_tool(
params = {k: v for k, v in tool_input.items()}
request_id = uuid4().hex
if p_trace:
logger.info(f"[app-agent] DISPATCH {tool_name}/{action} -> {browser_id} (req {request_id[:8]})")
result = await ws_manager.send_browser_command(
request_id, action, browser_id, params, tab_id=tab_id,
)
if p_trace:
logger.info(f"[app-agent] RESULT {tool_name} <- {browser_id}: {json.dumps(result)[:300]}")
return result
@@ -604,9 +550,6 @@ async def run_browser_agent(
p_browser_perms = load_builtin_permissions()
if app_mode:
logger.info(f"[app-agent] START loop: browser_id={browser_id} task={task[:140]!r}")
session_id = uuid4().hex
cancel_event = asyncio.Event()
session = AgentSession(
-8
View File
@@ -485,14 +485,6 @@ async def browser_agent_run(request: Request):
if not tasks:
return JSONResponse({"error": "tasks array is required"}, status_code=400)
# [app-agent] step trace: log app-mode dispatches arriving at the route.
for p_t in tasks:
if p_t.get("app_mode") or str(p_t.get("browser_id", "")).startswith("app:"):
logger.info(
f"[app-agent] ROUTE /run: browser_id={p_t.get('browser_id')!r} "
f"app_mode={p_t.get('app_mode')} task={str(p_t.get('task',''))[:120]!r}"
)
results = await run_browser_agents(
tasks=tasks,
model=model,
-17
View File
@@ -203,7 +203,6 @@ def test_app_describe_polls_until_bridge_ready(monkeypatch):
monkeypatch.setattr(BA.ws_manager, "send_browser_command", p_send, raising=False)
monkeypatch.setattr(BA.asyncio, "sleep", p_no_sleep, raising=True)
monkeypatch.setattr(BA, "p_persist_app_controls", lambda *a, **k: None, raising=True)
out = asyncio.run(BA.execute_browser_tool("AppDescribe", {}, "app:abc"))
assert calls["n"] == 3 # polled twice, succeeded on the third
@@ -225,19 +224,3 @@ def test_app_invoke_does_not_poll(monkeypatch):
asyncio.run(BA.execute_browser_tool("AppInvoke", {"name": "flap"}, "app:abc"))
assert calls["n"] == 1 # single shot, no readiness wait
def test_app_describe_persists_controls_cache(monkeypatch, tmp_path):
ready = {"rules": "Keep the bird airborne.", "controls": [{"name": "flap", "keys": "Space"}], "__rev": 1}
async def p_send(request_id, action, browser_id, params, tab_id=""):
return {"text": json.dumps(ready)}
monkeypatch.setattr(BA.ws_manager, "send_browser_command", p_send, raising=False)
monkeypatch.setattr(BA, "p_app_workspace_dir", lambda bid: str(tmp_path), raising=True)
asyncio.run(BA.execute_browser_tool("AppDescribe", {}, "app:abc"))
controls = (tmp_path / ".openswarm" / "controls.md").read_text()
rules = (tmp_path / ".openswarm" / "rules.md").read_text()
assert "- `flap`" in controls and "[Space]" in controls
assert "Keep the bird airborne." in rules
+1 -19
View File
@@ -1,4 +1,4 @@
import { getWebview, registeredKeys, type BrowserWebview } from './browserRegistry';
import { getWebview, type BrowserWebview } from './browserRegistry';
import { store } from './state/store';
import { resumeBrowserCard } from './state/dashboardLayoutSlice';
import { dashboardWs } from './ws/WebSocketManager';
@@ -1339,13 +1339,8 @@ async function handleReplayRoute(wv: BrowserWebview, params: Record<string, any>
async function handleEvaluate(wv: BrowserWebview, params: Record<string, any>): Promise<Record<string, any>> {
const expression = params.expression as string;
if (!expression) return { error: 'expression parameter is required' };
// [app-agent] step trace: surface what the app's bridge actually returned.
const _bridgeCall = expression.includes('OPENSWARM_APP');
try {
const result = await wv.executeJavaScript(expression);
if (_bridgeCall) {
console.log(`[app-agent] BRIDGE eval -> ${typeof result === 'string' ? result : JSON.stringify(result)}`);
}
const text = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
// evaluate is the agent's main read path; sample routes here too (XHRs have fired by now) so the backend can surface the fast network tier once.
const routes_available = await countSafeRoutes(wv);
@@ -1405,27 +1400,14 @@ async function runBrowserCommand(
request_id: string, action: string, browser_id: string, tab_id: string | undefined,
params: Record<string, any>,
) {
// [app-agent] step trace: only for app targets so browser-agent runs stay quiet.
const _appTrace = String(browser_id || '').startsWith('app:');
if (_appTrace) {
console.log(`[app-agent] CMD recv: action=${action} browser_id=${browser_id} tab_id=${tab_id ?? ''} registered=[${registeredKeys().join(', ')}]`);
}
const wv = await awaitWebview(browser_id, tab_id || undefined);
if (!wv) {
if (_appTrace) {
console.warn(`[app-agent] LOOKUP MISS: no webview for '${browser_id}' (registered keys: [${registeredKeys().join(', ')}]) -> the app card isn't mounted on the active dashboard`);
}
dashboardWs.send('browser:result', {
request_id,
error: `Browser card '${browser_id}'${tab_id ? ` tab '${tab_id}'` : ''} not found or not an Electron webview`,
});
return;
}
if (_appTrace) {
let _url = '';
try { _url = wv.getURL(); } catch (_e) {}
console.log(`[app-agent] LOOKUP HIT: webview for '${browser_id}' found, url=${_url} loading=${(() => { try { return wv.isLoading(); } catch { return '?'; } })()}`);
}
const detail = params.url || params.selector || params.expression || undefined;
setActivity(browser_id, { action: action as BrowserAction, detail });
-5
View File
@@ -54,11 +54,6 @@ export function setActiveTab(browserId: string, tabId: string): void {
activeTabMap.set(browserId, tabId);
}
// [app-agent] diagnostic: list currently-registered keys ("browserId:tabId").
export function registeredKeys(): string[] {
return Array.from(registry.keys());
}
export function getWebview(browserId: string, tabId?: string): BrowserWebview | undefined {
const resolvedTabId = tabId || activeTabMap.get(browserId);
if (!resolvedTabId) return undefined;