AWP-to-CDP Proxy
A reference implementation of the Agent Web Protocol (AWP) that works with any Chrome/Chromium browser via the Chrome DevTools Protocol (CDP).
Why This Exists
If only Plasmate speaks AWP, it is a proprietary protocol. This proxy proves AWP is a real open standard by providing a second, independent implementation that any AWP client can connect to.
AWP Client <--> awp-cdp-proxy <--> Chrome (CDP)
(agent) (this tool) (any browser)
Any agent that speaks AWP can use this proxy to control a real browser -- no Plasmate required.
Quick Start
# 1. Start Chrome with remote debugging
google-chrome --remote-debugging-port=9222
# or on macOS:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
# 2. Install and start the proxy
pip install -e .
awp-cdp-proxy --cdp-url ws://localhost:9222
# 3. Connect any AWP client to ws://localhost:9333
Supported AWP Methods (v0.1)
| Method | Description |
|---|---|
awp.hello |
Handshake and version negotiation |
session.create |
Create a browser session (opens a new Chrome tab) |
session.close |
Close a session (closes the tab) |
page.navigate |
Navigate to a URL, get SOM snapshot |
page.observe |
Return the current page's SOM |
page.act |
Execute actions: click, type, select, scroll |
page.extract |
Extract structured data from the SOM |
Architecture
AWP-CDP Proxy
+-----------------+
AWP Client -------->| server.py | AWP WebSocket (port 9333)
| | |
| v |
| translator.py | AWP method -> CDP command mapping
| | |
| v |
| cdp_client.py | CDP WebSocket -> Chrome
| | |
| v |
| som_generator.py| HTML -> SOM conversion
+-----------------+
|
v
Chrome / Chromium
(any CDP browser)
Components
- server.py -- AWP WebSocket server. Accepts client connections, dispatches to translator.
- translator.py -- Core translation logic. Maps AWP methods to sequences of CDP commands.
- cdp_client.py -- Minimal CDP WebSocket client. Sends commands, receives responses/events.
- som_generator.py -- Converts raw HTML into SOM using Python's html.parser and the
som-parserPydantic types.
This Proxy vs Plasmate Native AWP
| Feature | awp-cdp-proxy | Plasmate |
|---|---|---|
| Backend | Chrome via CDP | Custom Rust engine |
| JavaScript | Full (Chrome's V8) | Not in v0.1 |
| SOM quality | Good (HTML heuristics) | Best (html5ever + Rust) |
| Performance | Depends on Chrome | Optimized, no browser overhead |
| Dependencies | Chrome + Python | Single binary |
| Use case | Reference impl, testing | Production agent browsing |
The proxy is intentionally simpler. Its purpose is to prove AWP works as a standard, not to replace Plasmate.
Configuration
awp-cdp-proxy --help
| Flag | Default | Description |
|---|---|---|
--cdp-url |
ws://localhost:9222 |
Chrome DevTools Protocol URL |
--host |
127.0.0.1 |
Host to bind the AWP server |
--port |
9333 |
Port for the AWP server |
--verbose |
off | Enable debug logging |
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest -v
# Run with verbose logging
awp-cdp-proxy --verbose
Example: Python Client
import asyncio
import json
import websockets
async def main():
async with websockets.connect("ws://localhost:9333") as ws:
# Handshake
await ws.send(json.dumps({
"id": "1", "type": "request",
"method": "awp.hello",
"params": {"client_name": "demo", "awp_version": "0.1"}
}))
print(json.loads(await ws.recv()))
# Create session
await ws.send(json.dumps({
"id": "2", "type": "request",
"method": "session.create", "params": {}
}))
session = json.loads(await ws.recv())
sid = session["result"]["session_id"]
# Navigate
await ws.send(json.dumps({
"id": "3", "type": "request",
"method": "page.navigate",
"params": {"session_id": sid, "url": "https://example.com"}
}))
print(json.loads(await ws.recv()))
# Observe (get SOM)
await ws.send(json.dumps({
"id": "4", "type": "request",
"method": "page.observe",
"params": {"session_id": sid}
}))
som = json.loads(await ws.recv())
print(json.dumps(som["result"]["som"]["meta"], indent=2))
asyncio.run(main())
Links
License
Apache-2.0
Release files for awp-cdp-proxy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| awp_cdp_proxy-0.1.0.tar.gz | 19.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| awp_cdp_proxy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 37.0 kB
Release files / awp_cdp_proxy-0.1.0.tar.gz
| Download URL | awp_cdp_proxy-0.1.0.tar.gz |
|---|---|
| Size | 19.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8f54fcf67e4d253eac8fc8087550641bea5c6aa078dcde41c745f1423a700b76
|
|
BLAKE2b-256 checksum How to use checksums |
b183c1546ee789c8b09bf50b72c15e0727f6101023bfb302008eeb1a5f031d61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / awp_cdp_proxy-0.1.0-py3-none-any.whl
| Download URL | awp_cdp_proxy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
538e864209745920112136b2582b68321e0a2f130a9a1808eeb29aeabed5036e
|
|
BLAKE2b-256 checksum How to use checksums |
0093c24a8e4d023181b8dd0514bdbee5d923f85d3d399b490c97707f77b085ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|