| 1 | // Package browser implements the agent-facing browser tools over one |
| 2 | // host-neutral Executor. The local Electron shell and the remote SSH broker |
| 3 | // each provide an Executor; the tools never learn which one answers. |
| 4 | // |
| 5 | // The tools are registry-only. Boot registers them so use_capability can list |
| 6 | // and call tool:browser_* targets, but they never join the provider-visible |
| 7 | // schema array. That array is part of the cache-stable system-prompt prefix |
| 8 | // and must stay byte-identical whether or not a browser is attached: a desktop |
| 9 | // session with a browser and a CLI session without one share the same prefix, |
| 10 | // which is what keeps DeepSeek's automatic prefix cache warm across both. |
| 11 | // Every tool also implements tool.ContextualTool, so a build without an |
| 12 | // Executor, or an Executor whose grant lapsed, fails closed with a blocked |
| 13 | // card instead of dispatching. |
| 14 | // |
| 15 | // Writes are reserved by the model, not minted here: each write takes an |
| 16 | // operationId that must be unique per attempt and is rejected forever once |
| 17 | // used. Reference-bound writes (click, type, press, scroll, select, upload) |
| 18 | // also carry the documentToken of the snapshot they were planned against. A |
| 19 | // navigation or user take-over invalidates it; the executor then answers |
| 20 | // ErrStaleReference or ErrTakenOver, which the tools translate into |
| 21 | // tool.Blocked results so the model re-reads the page instead of guessing. A |
| 22 | // lost receipt is ErrUnknownOutcome: the action may or may not have run, and |
| 23 | // the error text tells the model it must not be retried. |
| 24 | package browser |
| 25 |