# MMW Agent Browser Control

This plugin exposes two browser-control layers:

1. Page bridge: `window.postMessage(...)` inside the current page
2. Local session bridge: `http://127.0.0.1:18766/v1/agent-browser`

Current control split:

- `snapshot` / target resolution / highlight: page bridge
- `click` / `type` / `scroll` / `key` / `move`: browser-level input through `chrome.debugger`
- `navigate` / `back` / `forward` / `reload` / tab actions: Chrome tab APIs

The plugin switch is opt-in. The user must enable `AI 接管` in the popup first.
The blue glow frame and AI pointer only appear after a real page command reaches the page.

## Local session bridge

Start the local bridge:

```bat
desktop-tauri\python_bridge\start_agent_browser_bridge.bat
```

## Multi-agent rule

The local bridge supports multiple external agents, but each browser client is controlled through an exclusive lease.

- Many agents can connect to the same bridge
- Many browser clients can register to the same bridge
- One browser client can only have one active lease at a time
- Control commands must carry `agentId + leaseId`

## Lease flow

1. `GET /clients`
2. Pick a `clientId`
3. `POST /leases/acquire`
4. `POST /commands`
5. `GET /commands/<id>/wait?timeoutMs=30000`
6. Long-running control: `POST /leases/renew`
7. Done: `POST /leases/release`

Example:

```powershell
Invoke-WebRequest -UseBasicParsing http://127.0.0.1:18766/v1/agent-browser/clients
```

```json
POST /v1/agent-browser/leases/acquire
{
  "agentId": "codex-agent-1",
  "clientId": "mmw-...",
  "ttlMs": 45000
}
```

```json
POST /v1/agent-browser/commands
{
  "agentId": "codex-agent-1",
  "leaseId": "lease-...",
  "clientId": "mmw-...",
  "action": "list_tabs"
}
```

Renew:

```json
POST /v1/agent-browser/leases/renew
{
  "agentId": "codex-agent-1",
  "leaseId": "lease-...",
  "clientId": "mmw-...",
  "ttlMs": 45000
}
```

Release:

```json
POST /v1/agent-browser/leases/release
{
  "agentId": "codex-agent-1",
  "leaseId": "lease-...",
  "clientId": "mmw-..."
}
```

Force takeover:

```json
POST /v1/agent-browser/leases/acquire
{
  "agentId": "codex-agent-2",
  "clientId": "mmw-...",
  "ttlMs": 45000,
  "force": true
}
```

Lease inspection:

- `GET /leases`
- `GET /leases?clientId=...`
- `GET /leases?agentId=...`

Available browser-session actions:

- `state`
- `list_tabs`
- `activate_tab`
- `close_tab`
- `new_tab`
- `open_tab`
- `navigate`
- `back`
- `forward`
- `reload`
- `screenshot`
- `plugin_status`
- `plugin_logs`
- `plugin_logs_clear`
- all page actions below with optional `tabId`

Local debug actions are only exposed through the local session bridge. They are not available through page `window.postMessage(...)`.
For true browser-level control, prefer the local session bridge instead of directly calling page `window.postMessage(...)`.

## Page bridge

Send from page context:

```js
window.postMessage({
  type: "MMW_AGENT_BROWSER_CONTROL",
  requestId: "req-1",
  action: "snapshot",
  payload: { limit: 80 }
}, "*");
```

Listen for the result:

```js
window.addEventListener("message", (event) => {
  const data = event.data || {};
  if (data.type !== "MMW_AGENT_BROWSER_CONTROL_RESULT") return;
  console.log(data.requestId, data.ok, data.result || data.error);
});
```

Ping:

```js
window.postMessage({
  type: "MMW_AGENT_BROWSER_CONTROL_PING",
  requestId: "ping-1"
}, "*");
```

Page actions:

- `state`
- `snapshot`
- `click`
- `type`
- `scroll`
- `key`
- `move`
- `highlight`
- `wait`

When `click` / `type` / `scroll` / `key` / `move` are triggered through the local session bridge, the plugin resolves the page target first and then injects browser-level input through `chrome.debugger`. Direct page `window.postMessage(...)` still works, but it is no longer the preferred path for real browser takeover.

Browser actions exposed through the same page bridge:

- `navigate`
- `back`
- `forward`
- `reload`
- `screenshot`
- `new_tab`
- `open_tab`
- `list_tabs`
- `activate_tab`
- `close_tab`

For element actions, call `snapshot` first and reuse the returned `ref` while the page remains stable.
