@praveen-palanisamy/agent-browser-runtime 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/LICENSE +23 -0
- package/README.md +261 -0
- package/action.yml +185 -0
- package/dist/attribution.d.ts +22 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +57 -0
- package/dist/attribution.js.map +1 -0
- package/dist/cli.d.ts +21 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/index.d.ts +9 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +26 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/runner-client.d.ts +41 -0
- package/dist/client/runner-client.d.ts.map +1 -0
- package/dist/client/runner-client.js +98 -0
- package/dist/client/runner-client.js.map +1 -0
- package/dist/core/capture.d.ts +50 -0
- package/dist/core/capture.d.ts.map +1 -0
- package/dist/core/capture.js +129 -0
- package/dist/core/capture.js.map +1 -0
- package/dist/core/poster.d.ts +45 -0
- package/dist/core/poster.d.ts.map +1 -0
- package/dist/core/poster.js +132 -0
- package/dist/core/poster.js.map +1 -0
- package/dist/core/stores.d.ts +35 -0
- package/dist/core/stores.d.ts.map +1 -0
- package/dist/core/stores.js +32 -0
- package/dist/core/stores.js.map +1 -0
- package/dist/core/types.d.ts +138 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +13 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +6 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +3 -0
- package/dist/platform.js.map +1 -0
- package/dist/protocol.d.ts +84 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +24 -0
- package/dist/protocol.js.map +1 -0
- package/dist/providers/kernel.d.ts +53 -0
- package/dist/providers/kernel.d.ts.map +1 -0
- package/dist/providers/kernel.js +82 -0
- package/dist/providers/kernel.js.map +1 -0
- package/dist/providers/playwright.d.ts +88 -0
- package/dist/providers/playwright.d.ts.map +1 -0
- package/dist/providers/playwright.js +114 -0
- package/dist/providers/playwright.js.map +1 -0
- package/dist/providers/steel.d.ts +48 -0
- package/dist/providers/steel.d.ts.map +1 -0
- package/dist/providers/steel.js +79 -0
- package/dist/providers/steel.js.map +1 -0
- package/dist/service/config.d.ts +33 -0
- package/dist/service/config.d.ts.map +1 -0
- package/dist/service/config.js +59 -0
- package/dist/service/config.js.map +1 -0
- package/dist/service/index.d.ts +30 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +53 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/live-proxy.d.ts +27 -0
- package/dist/service/live-proxy.d.ts.map +1 -0
- package/dist/service/live-proxy.js +146 -0
- package/dist/service/live-proxy.js.map +1 -0
- package/dist/service/runner.d.ts +35 -0
- package/dist/service/runner.d.ts.map +1 -0
- package/dist/service/runner.js +139 -0
- package/dist/service/runner.js.map +1 -0
- package/dist/service/serialized-provider.d.ts +20 -0
- package/dist/service/serialized-provider.d.ts.map +1 -0
- package/dist/service/serialized-provider.js +68 -0
- package/dist/service/serialized-provider.js.map +1 -0
- package/dist/service/server.d.ts +17 -0
- package/dist/service/server.d.ts.map +1 -0
- package/dist/service/server.js +159 -0
- package/dist/service/server.js.map +1 -0
- package/docs/AGENTS.md +46 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/DEPLOY.md +61 -0
- package/docs/GITHUB_ACTION.md +92 -0
- package/examples/demo-strategy/index.js +53 -0
- package/examples/demo-strategy/session.json +5 -0
- package/package.json +96 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal HTTP layer for the agent runner (no framework: `node:http` only).
|
|
4
|
+
*
|
|
5
|
+
* - Bearer-token auth on every /v1 route
|
|
6
|
+
* - JSON bodies, size-capped
|
|
7
|
+
* - /live/{captureId}/... proxies the provider live view (no token: the
|
|
8
|
+
* capture id is the credential, scoped to an active capture)
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.HttpError = void 0;
|
|
12
|
+
exports.isAuthorized = isAuthorized;
|
|
13
|
+
exports.createRunnerServer = createRunnerServer;
|
|
14
|
+
const node_crypto_1 = require("node:crypto");
|
|
15
|
+
const node_http_1 = require("node:http");
|
|
16
|
+
const attribution_1 = require("../attribution");
|
|
17
|
+
const protocol_1 = require("../protocol");
|
|
18
|
+
const live_proxy_1 = require("./live-proxy");
|
|
19
|
+
const MAX_BODY_BYTES = 8 * 1024 * 1024; // sessions with localStorage can be large
|
|
20
|
+
class HttpError extends Error {
|
|
21
|
+
status;
|
|
22
|
+
constructor(status, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.status = status;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.HttpError = HttpError;
|
|
28
|
+
function json(res, status, body) {
|
|
29
|
+
res.writeHead(status, {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
Server: (0, attribution_1.userAgentString)(),
|
|
32
|
+
});
|
|
33
|
+
res.end(JSON.stringify(body));
|
|
34
|
+
}
|
|
35
|
+
async function readJson(req) {
|
|
36
|
+
const chunks = [];
|
|
37
|
+
let size = 0;
|
|
38
|
+
for await (const chunk of req) {
|
|
39
|
+
size += chunk.length;
|
|
40
|
+
if (size > MAX_BODY_BYTES) {
|
|
41
|
+
throw new HttpError(413, 'Request body too large');
|
|
42
|
+
}
|
|
43
|
+
chunks.push(chunk);
|
|
44
|
+
}
|
|
45
|
+
if (chunks.length === 0) {
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new HttpError(400, 'Invalid JSON body');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function isAuthorized(header, token) {
|
|
56
|
+
const presented = header?.startsWith('Bearer ') ? header.slice(7) : '';
|
|
57
|
+
const a = Buffer.from(presented);
|
|
58
|
+
const b = Buffer.from(token);
|
|
59
|
+
return a.length === b.length && (0, node_crypto_1.timingSafeEqual)(a, b);
|
|
60
|
+
}
|
|
61
|
+
function requireFields(body, fields) {
|
|
62
|
+
for (const f of fields) {
|
|
63
|
+
if (body[f] === undefined || body[f] === null || body[f] === '') {
|
|
64
|
+
throw new HttpError(400, `Missing required field: ${f}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function createRunnerServer(runner) {
|
|
69
|
+
const { config } = runner;
|
|
70
|
+
const liveDeps = {
|
|
71
|
+
resolve: (captureId) => runner.capture.liveViewUrlFor(captureId),
|
|
72
|
+
publicUrl: config.publicUrl,
|
|
73
|
+
livePrefix: protocol_1.RUNNER_ROUTES.live,
|
|
74
|
+
};
|
|
75
|
+
const server = (0, node_http_1.createServer)(async (req, res) => {
|
|
76
|
+
const url = new URL(req.url || '/', 'http://runner');
|
|
77
|
+
try {
|
|
78
|
+
if (req.method === 'GET' && url.pathname === protocol_1.RUNNER_ROUTES.health) {
|
|
79
|
+
json(res, 200, {
|
|
80
|
+
ok: true,
|
|
81
|
+
name: attribution_1.PROJECT.name,
|
|
82
|
+
version: (0, attribution_1.packageVersion)(),
|
|
83
|
+
repository: attribution_1.PROJECT.repository,
|
|
84
|
+
jobProvider: config.jobProvider,
|
|
85
|
+
captureProvider: config.captureProvider,
|
|
86
|
+
activeCaptures: runner.capture.size,
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if ((0, live_proxy_1.handleLiveHttp)(req, res, liveDeps)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!url.pathname.startsWith('/v1/')) {
|
|
94
|
+
throw new HttpError(404, 'Not found');
|
|
95
|
+
}
|
|
96
|
+
if (!isAuthorized(req.headers.authorization, config.token)) {
|
|
97
|
+
throw new HttpError(401, 'Unauthorized');
|
|
98
|
+
}
|
|
99
|
+
if (req.method !== 'POST') {
|
|
100
|
+
throw new HttpError(405, 'Method not allowed');
|
|
101
|
+
}
|
|
102
|
+
const body = await readJson(req);
|
|
103
|
+
switch (url.pathname) {
|
|
104
|
+
case protocol_1.RUNNER_ROUTES.post:
|
|
105
|
+
requireFields(body, [
|
|
106
|
+
'jobId',
|
|
107
|
+
'workspaceId',
|
|
108
|
+
'accountId',
|
|
109
|
+
'platform',
|
|
110
|
+
'content',
|
|
111
|
+
'session',
|
|
112
|
+
]);
|
|
113
|
+
json(res, 200, await runner.post(body));
|
|
114
|
+
return;
|
|
115
|
+
case protocol_1.RUNNER_ROUTES.probe:
|
|
116
|
+
requireFields(body, [
|
|
117
|
+
'workspaceId',
|
|
118
|
+
'accountId',
|
|
119
|
+
'platform',
|
|
120
|
+
'session',
|
|
121
|
+
]);
|
|
122
|
+
json(res, 200, await runner.probe(body));
|
|
123
|
+
return;
|
|
124
|
+
case protocol_1.RUNNER_ROUTES.captureStart:
|
|
125
|
+
requireFields(body, ['platform']);
|
|
126
|
+
json(res, 200, await runner.captureStart(body));
|
|
127
|
+
return;
|
|
128
|
+
case protocol_1.RUNNER_ROUTES.captureFinish:
|
|
129
|
+
requireFields(body, ['captureId']);
|
|
130
|
+
json(res, 200, await runner.captureFinish(body));
|
|
131
|
+
return;
|
|
132
|
+
case protocol_1.RUNNER_ROUTES.captureCancel:
|
|
133
|
+
requireFields(body, ['captureId']);
|
|
134
|
+
json(res, 200, await runner.captureCancel(body));
|
|
135
|
+
return;
|
|
136
|
+
default:
|
|
137
|
+
throw new HttpError(404, 'Not found');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
if (e instanceof HttpError) {
|
|
142
|
+
json(res, e.status, { error: e.message });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
console.error('[agent-runner] request failed', url.pathname, e);
|
|
146
|
+
json(res, 500, {
|
|
147
|
+
error: e instanceof Error ? e.message : 'Internal error',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
server.on('upgrade', (req, socket, head) => {
|
|
152
|
+
if (!(0, live_proxy_1.handleLiveUpgrade)(req, socket, head, liveDeps)) {
|
|
153
|
+
socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
154
|
+
socket.destroy();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
return server;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/service/server.ts"],"names":[],"mappings":"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"}
|
package/docs/AGENTS.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Notes for coding agents and LLM tool builders
|
|
2
|
+
|
|
3
|
+
This file is written for AI agents (Cursor, Claude Code, Codex, custom MCP tools) that integrate or extend `agent-browser-runtime`.
|
|
4
|
+
|
|
5
|
+
## What this package is, in one sentence
|
|
6
|
+
|
|
7
|
+
A runtime that lets software act inside a user's authenticated browser session, unattended, on infrastructure the operator controls, with explicit verification and re-auth signalling.
|
|
8
|
+
|
|
9
|
+
## When to reach for it
|
|
10
|
+
|
|
11
|
+
- You need to perform actions on a website **as a specific user** and there is no API, the API is metered, or the API lacks the capability.
|
|
12
|
+
- The action must run **later** (cron, queue) without the user present.
|
|
13
|
+
- You need a **safe outcome model**: confirmed / uncertain / needs re-auth, so you never double-act.
|
|
14
|
+
|
|
15
|
+
## When not to
|
|
16
|
+
|
|
17
|
+
- Scraping public pages (use a plain headless browser).
|
|
18
|
+
- Anything that violates the target site's terms or acts without the user's explicit instruction.
|
|
19
|
+
|
|
20
|
+
## Integration recipe
|
|
21
|
+
|
|
22
|
+
1. **Implement a `WebPostStrategy`** for the target site: `validate(content)`, `isAuthenticated(ctx)`, `post(ctx, content)`. Verify inside `post` (read back the UI or find the permalink); return `uncertain: true` if you submitted but could not confirm.
|
|
23
|
+
2. **Run the service**: `startRunner({ strategies })` or `agent-browser-runtime serve --strategies ./strategies.js` with `AGENT_RUNNER_TOKEN`.
|
|
24
|
+
3. **Capture once**: `captureStart` → embed `liveViewUrl` → user signs in → `captureFinish` → encrypt and store `state`.
|
|
25
|
+
4. **Act unattended**: `post` / `probe` with the decrypted session; persist `refreshedSession`; honour `needsReauth` and `uncertain`.
|
|
26
|
+
|
|
27
|
+
## Public API surface (stable)
|
|
28
|
+
|
|
29
|
+
- `@praveen-palanisamy/agent-browser-runtime` — contracts (`SessionStore`, `SessionProvider`, `WebPostStrategy`, `AgentSessionState`, `AgentPostResult`), `AgentPoster`, `SessionCaptureManager`, providers, `AgentRunnerClient`, protocol types.
|
|
30
|
+
- `…/client` — `AgentRunnerClient` + protocol only (no Playwright).
|
|
31
|
+
- `…/service` — `startRunner`, `AgentRunner`, `loadConfig`, `createRunnerServer`.
|
|
32
|
+
- CLI `agent-browser-runtime` — `serve`, `health`, `probe`, `post`; `--local` runs probe/post in-process (no service). Exit codes: `0` ok · `2` not authenticated / failed · `3` uncertain.
|
|
33
|
+
- GitHub Action `praveen-palanisamy/agent-browser-runtime@v0` — `command: probe|post`, outputs `ok`, `authenticated`, `needs-reauth`, `uncertain`, `result-file`, `session-file` (see `docs/GITHUB_ACTION.md`).
|
|
34
|
+
- `GET /healthz` returns `{ name, version, repository, jobProvider, captureProvider, activeCaptures }`; every JSON response carries a `Server: agent-browser-runtime/<version> (+repo)` header.
|
|
35
|
+
|
|
36
|
+
Wire protocol routes and request/response shapes live in `src/protocol.ts`; treat them as the contract when generating client code in other languages.
|
|
37
|
+
|
|
38
|
+
## Extending
|
|
39
|
+
|
|
40
|
+
- **New provider**: implement `SessionProvider.acquire({ platform, state, interactive })` returning an `AgentSessionHandle` (`context`, `exportState`, `dispose`, optional `liveViewUrl`). Use `attachOverCdp` for any CDP-speaking backend. Add a unit test with a fake `fetch` (see `__tests__/kernel-provider.test.ts`).
|
|
41
|
+
- **New strategy**: keep it in your application; the runtime never hard-codes platforms.
|
|
42
|
+
|
|
43
|
+
## Testing conventions
|
|
44
|
+
|
|
45
|
+
- `npm test` must stay browser-free and fast; anything that launches Chromium goes under `__tests__/browser/*.browser.test.ts`.
|
|
46
|
+
- Fake providers/handles are sufficient for orchestration tests (`__tests__/runner.test.ts`).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
## Layers
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart TB
|
|
7
|
+
Client[client/ AgentRunnerClient<br/>no Playwright] -->|HTTP + bearer| Server[service/server.ts]
|
|
8
|
+
Server --> Runner[service/runner.ts AgentRunner]
|
|
9
|
+
Runner --> Poster[core/poster.ts AgentPoster]
|
|
10
|
+
Runner --> Capture[core/capture.ts SessionCaptureManager]
|
|
11
|
+
Poster --> Store[core/stores.ts InMemorySessionStore]
|
|
12
|
+
Poster --> Prov[SessionProvider]
|
|
13
|
+
Capture --> Prov
|
|
14
|
+
Prov --> Local[providers/playwright.ts<br/>LocalBrowserSessionProvider]
|
|
15
|
+
Prov --> Cdp[providers/playwright.ts<br/>CdpSessionProvider]
|
|
16
|
+
Prov --> Steel[providers/steel.ts]
|
|
17
|
+
Prov --> Kernel[providers/kernel.ts]
|
|
18
|
+
Server --> Live[service/live-proxy.ts]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- **core** — pure orchestration over the three contracts. No HTTP, no env.
|
|
22
|
+
- **providers** — turn a stored session into a live `BrowserContext`. Remote providers create a browser via REST, connect over CDP, inject `storageState`, and dispose/release on close.
|
|
23
|
+
- **service** — env-driven runner: chooses providers per job type, registers the caller's strategies, exposes typed handlers and the HTTP server; proxies Steel's live view.
|
|
24
|
+
- **client / protocol** — the wire contract. Everything an orchestrator needs without pulling Playwright into its bundle.
|
|
25
|
+
|
|
26
|
+
## Session lifecycle
|
|
27
|
+
|
|
28
|
+
```mermaid
|
|
29
|
+
sequenceDiagram
|
|
30
|
+
participant U as User
|
|
31
|
+
participant A as Your app
|
|
32
|
+
participant R as Runner
|
|
33
|
+
participant B as Browser (Steel/Kernel/local)
|
|
34
|
+
A->>R: POST /v1/capture/start {platform}
|
|
35
|
+
R->>B: acquire(interactive)
|
|
36
|
+
R-->>A: captureId, liveViewUrl
|
|
37
|
+
A->>U: iframe liveViewUrl
|
|
38
|
+
U->>B: signs in
|
|
39
|
+
A->>R: POST /v1/capture/finish {captureId}
|
|
40
|
+
R->>B: isAuthenticated? exportState
|
|
41
|
+
R-->>A: AgentSessionState
|
|
42
|
+
A->>A: encrypt + persist
|
|
43
|
+
Note over A,R: later, unattended
|
|
44
|
+
A->>R: POST /v1/post {session, content}
|
|
45
|
+
R->>B: acquire(state) → strategy.isAuthenticated → strategy.post
|
|
46
|
+
R-->>A: AgentPostResult + refreshedSession
|
|
47
|
+
A->>A: persist refreshed session
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Verification model
|
|
51
|
+
|
|
52
|
+
A strategy is responsible for proving the action happened. `AgentPostResult` encodes three distinct outcomes so orchestrators can act safely:
|
|
53
|
+
|
|
54
|
+
| Result | Meaning | Recommended orchestrator behaviour |
|
|
55
|
+
|--------|---------|-------------------------------------|
|
|
56
|
+
| `ok: true` + `verification` | Action confirmed (toast/permalink or read-back) | Mark done, persist `refreshedSession` |
|
|
57
|
+
| `ok: false`, `uncertain: true` | Submit happened but nothing confirmed it | Flag for manual review; **do not** retry or fall back automatically |
|
|
58
|
+
| `ok: false`, `needsReauth: true` | Session invalid | Mark account needs re-auth, notify user, optional fallback |
|
|
59
|
+
| `ok: false`, `failureStage` ∈ precheck/compose/media | Aborted **before** submitting | Safe to retry or fall back |
|
|
60
|
+
| `ok: false`, `failureStage: submit/verify` (not uncertain) | Failed with evidence nothing was posted | Safe to retry/fallback; inspect screenshot |
|
|
61
|
+
|
|
62
|
+
## Pacing
|
|
63
|
+
|
|
64
|
+
`AgentPoster` applies a small randomized delay before acting (`pacing: true`) to look human-scale. Per-account rate limits (minimum spacing, hourly caps) belong in the orchestrator where account state lives; the runner is stateless.
|
|
65
|
+
|
|
66
|
+
## Provider selection
|
|
67
|
+
|
|
68
|
+
`RunnerConfig.jobProvider` and `captureProvider` are independent. Typical production layout:
|
|
69
|
+
|
|
70
|
+
- jobs → `local` (parallel, fresh Chromium per job inside the runner container)
|
|
71
|
+
- capture → `steel` (live view) or `kernel` (headful browser with live view URL)
|
|
72
|
+
|
|
73
|
+
`SerializedProvider` wraps single-session backends (Steel OSS) with a mutex so concurrent requests queue instead of failing.
|
package/docs/DEPLOY.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Deploying and integrating ABR
|
|
2
|
+
|
|
3
|
+
## Environment
|
|
4
|
+
|
|
5
|
+
| Variable | Required | Notes |
|
|
6
|
+
|----------|----------|-------|
|
|
7
|
+
| `AGENT_RUNNER_TOKEN` | yes | ≥ 16 chars; shared with orchestrators |
|
|
8
|
+
| `AGENT_RUNNER_PUBLIC_URL` | for capture | Absolute URL users reach the runner at (live view links) |
|
|
9
|
+
| `PORT` | no | default 8080 |
|
|
10
|
+
| `AGENT_RUNNER_JOB_PROVIDER` | no | `local` (default) · `steel` · `kernel` |
|
|
11
|
+
| `AGENT_RUNNER_CAPTURE_PROVIDER` | no | `steel` when `STEEL_API_URL` is set, else `local` |
|
|
12
|
+
| `STEEL_API_URL` / `STEEL_API_KEY` | for steel | e.g. `http://steel:3000`; key only for Steel Cloud |
|
|
13
|
+
| `KERNEL_API_KEY` / `KERNEL_API_URL` | for kernel | default `https://api.onkernel.com` |
|
|
14
|
+
| `AGENT_RUNNER_CAPTURE_TTL_MS` | no | default 20 min |
|
|
15
|
+
| `AGENT_RUNNER_PACING` | no | `false` disables human-pace jitter (tests) |
|
|
16
|
+
|
|
17
|
+
## Local (Docker Compose)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
AGENT_RUNNER_TOKEN=$(openssl rand -base64 32) STRATEGIES_DIR=$PWD/examples/demo-strategy docker compose up --build
|
|
21
|
+
curl -H "authorization: Bearer $AGENT_RUNNER_TOKEN" localhost:8080/healthz
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Steel is exposed on `:3000` (API + live view) and `:9223` (CDP). Only the runtime should reach them in production.
|
|
25
|
+
|
|
26
|
+
## Container image
|
|
27
|
+
|
|
28
|
+
`ghcr.io/praveen-palanisamy/agent-browser-runtime:<version>` bundles Node, Playwright's Chromium and the runtime CLI. Extend it with your strategies:
|
|
29
|
+
|
|
30
|
+
```dockerfile
|
|
31
|
+
FROM ghcr.io/praveen-palanisamy/agent-browser-runtime:latest
|
|
32
|
+
COPY dist/strategies.js /app/strategies.js
|
|
33
|
+
CMD ["serve", "--strategies", "/app/strategies.js"]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The image pins `playwright-core` to the base image's Playwright version (`ARG PLAYWRIGHT_VERSION`), verified in CI by `scripts/check-playwright-pin.mjs`, so no browser download happens at runtime.
|
|
37
|
+
|
|
38
|
+
## Cloud Run (runtime + Steel sidecar)
|
|
39
|
+
|
|
40
|
+
- One service, two containers: the runtime (ingress) and `ghcr.io/steel-dev/steel-browser-api` on `localhost:3000`.
|
|
41
|
+
- Set `STEEL_API_URL=http://127.0.0.1:3000`, `AGENT_RUNNER_CAPTURE_PROVIDER=steel`, `AGENT_RUNNER_JOB_PROVIDER=local`.
|
|
42
|
+
- Interactive captures are stateful (a browser stays open while the user signs in), so pin `minScale = maxScale = 1` or add sticky routing. Headless jobs are parallel inside the instance.
|
|
43
|
+
- Ingress must be public for the live view; every API route is still token-protected. Store `AGENT_RUNNER_TOKEN` in Secret Manager.
|
|
44
|
+
- Give the Steel container ≥ 2 GiB memory and mount an in-memory volume at `/app/.cache`; nothing durable lives there.
|
|
45
|
+
|
|
46
|
+
The same shape works on ECS/Fargate task definitions or a Nomad group.
|
|
47
|
+
|
|
48
|
+
## Scaling beyond one instance
|
|
49
|
+
|
|
50
|
+
- Move captures to **Kernel** (`AGENT_RUNNER_CAPTURE_PROVIDER=kernel`): each capture gets its own microVM with a live view URL, so instances become interchangeable.
|
|
51
|
+
- Or run several runner instances and route `/v1/capture/finish|cancel` and `/live/{captureId}` by capture id (hash or header) at the load balancer.
|
|
52
|
+
|
|
53
|
+
## Ways to consume ABR
|
|
54
|
+
|
|
55
|
+
| Channel | Best for | Pin |
|
|
56
|
+
|---------|----------|-----|
|
|
57
|
+
| [npm `@praveen-palanisamy/agent-browser-runtime`](https://www.npmjs.com/package/@praveen-palanisamy/agent-browser-runtime) | embedding the library or client in your app | `^0.1` |
|
|
58
|
+
| [GHCR `ghcr.io/praveen-palanisamy/agent-browser-runtime`](https://github.com/praveen-palanisamy/agent-browser-runtime/pkgs/container/agent-browser-runtime) | running the runner service (Chromium included) | `:0.1`, `:latest` |
|
|
59
|
+
| [GitHub Action](GITHUB_ACTION.md) | probes and jobs from CI without a service | `@v0` |
|
|
60
|
+
|
|
61
|
+
Releases are cut automatically from `main`; every semver tag publishes all three channels with provenance. Follow the [Releases page](https://github.com/praveen-palanisamy/agent-browser-runtime/releases) or watch the [changelog](../CHANGELOG.md).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# GitHub Action
|
|
2
|
+
|
|
3
|
+
ABR ships as a composite action so you can run authenticated browser jobs from any workflow — no runner service to deploy. It installs the runtime and Chromium on the job runner and executes the CLI in-process (`--local`).
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
- uses: praveen-palanisamy/agent-browser-runtime@v0
|
|
7
|
+
with:
|
|
8
|
+
command: probe # or: post
|
|
9
|
+
platform: expense-portal
|
|
10
|
+
strategies: ./automation/strategies.js
|
|
11
|
+
session: ${{ secrets.EXPENSE_PORTAL_SESSION }}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Typical workflows
|
|
15
|
+
|
|
16
|
+
### Nightly session health check
|
|
17
|
+
|
|
18
|
+
Tell users *before* a scheduled job fails that they need to sign in again.
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
name: session-health
|
|
22
|
+
on:
|
|
23
|
+
schedule: [{ cron: "0 6 * * *" }]
|
|
24
|
+
jobs:
|
|
25
|
+
probe:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v5
|
|
29
|
+
- id: abr
|
|
30
|
+
uses: praveen-palanisamy/agent-browser-runtime@v0
|
|
31
|
+
with:
|
|
32
|
+
command: probe
|
|
33
|
+
platform: expense-portal
|
|
34
|
+
strategies: ./automation/strategies.js
|
|
35
|
+
session: ${{ secrets.EXPENSE_PORTAL_SESSION }}
|
|
36
|
+
fail-on-reauth: "false"
|
|
37
|
+
- if: steps.abr.outputs.needs-reauth == 'true'
|
|
38
|
+
run: ./notify.sh "Expense portal session expired — please sign in again"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Run a job with the stored session
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
- id: abr
|
|
45
|
+
uses: praveen-palanisamy/agent-browser-runtime@v0
|
|
46
|
+
with:
|
|
47
|
+
command: post
|
|
48
|
+
platform: expense-portal
|
|
49
|
+
strategies: ./automation/strategies.js
|
|
50
|
+
session: ${{ secrets.EXPENSE_PORTAL_SESSION }}
|
|
51
|
+
text: "March travel — client onsite"
|
|
52
|
+
media: https://files.example/receipt-1.jpg,https://files.example/receipt-2.jpg
|
|
53
|
+
- name: Persist rotated cookies
|
|
54
|
+
if: always()
|
|
55
|
+
run: ./vault put expense-portal-session "${{ steps.abr.outputs.session-file }}"
|
|
56
|
+
- name: Never retry blindly
|
|
57
|
+
if: steps.abr.outputs.uncertain == 'true'
|
|
58
|
+
run: ./open-review-ticket.sh "${{ steps.abr.outputs.result-file }}"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Inputs
|
|
62
|
+
|
|
63
|
+
| Input | Default | Notes |
|
|
64
|
+
|-------|---------|-------|
|
|
65
|
+
| `command` | `probe` | `probe` or `post` |
|
|
66
|
+
| `platform` | — | must match a strategy's `platform` |
|
|
67
|
+
| `session` / `session-file` | — | `AgentSessionState` JSON; pass a secret or a file path |
|
|
68
|
+
| `strategies` | bundled demo | module exporting `WebPostStrategy[]` |
|
|
69
|
+
| `text`, `media`, `link`, `content-file` | — | job content (`post`) |
|
|
70
|
+
| `workspace`, `account` | `github-actions` / `default` | job identity |
|
|
71
|
+
| `session-out` | `.abr/session.refreshed.json` | refreshed session written here |
|
|
72
|
+
| `result-out` | `.abr/result.json` | JSON result written here |
|
|
73
|
+
| `fail-on-reauth` | `true` | fail the step when re-auth is needed |
|
|
74
|
+
| `pacing` | `true` | human-pace jitter before acting |
|
|
75
|
+
| `node-version` | `24` | |
|
|
76
|
+
|
|
77
|
+
## Outputs
|
|
78
|
+
|
|
79
|
+
`ok`, `authenticated`, `needs-reauth`, `uncertain`, `result-file`, `session-file`.
|
|
80
|
+
|
|
81
|
+
Exit codes of the underlying CLI: `0` success · `2` not authenticated / failed · `3` uncertain (ran, unverified).
|
|
82
|
+
|
|
83
|
+
## Security notes
|
|
84
|
+
|
|
85
|
+
- Store sessions as **encrypted secrets**; the action writes the secret to a temp file and deletes it after the run.
|
|
86
|
+
- Refreshed sessions are written to `session-out` in the workspace — persist them back to your vault and do not upload them as public artifacts.
|
|
87
|
+
- The action runs on GitHub's runner IPs. Sites that fingerprint location may still ask for re-auth; for stable egress, run the [HTTP runner service](DEPLOY.md) instead.
|
|
88
|
+
- Use ABR only with the user's explicit authorization and within each site's terms of service.
|
|
89
|
+
|
|
90
|
+
## Versioning
|
|
91
|
+
|
|
92
|
+
`@v0` tracks the latest green commit on `main` (moved automatically); pin `@v0.1.0` for immutable builds.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Minimal WebPostStrategy module for `agent-browser-runtime serve --strategies`.
|
|
2
|
+
// It drives example.com so it works anywhere without credentials; real
|
|
3
|
+
// strategies implement the same three methods against a platform's UI.
|
|
4
|
+
//
|
|
5
|
+
// AGENT_RUNNER_TOKEN=... npx agent-browser-runtime serve --strategies ./examples/demo-strategy/index.js
|
|
6
|
+
|
|
7
|
+
/** @type {import('@praveen-palanisamy/agent-browser-runtime').WebPostStrategy} */
|
|
8
|
+
const demoStrategy = {
|
|
9
|
+
platform: 'demo',
|
|
10
|
+
loginUrl: 'https://example.com/',
|
|
11
|
+
|
|
12
|
+
validate(content) {
|
|
13
|
+
if (!content.text?.trim()) return 'Text is required';
|
|
14
|
+
if (content.text.length > 280) return 'Text exceeds 280 characters';
|
|
15
|
+
return null;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
async isAuthenticated(context) {
|
|
19
|
+
// A real strategy checks for a logged-in marker (avatar, compose button…).
|
|
20
|
+
const page = await context.newPage();
|
|
21
|
+
try {
|
|
22
|
+
await page.goto('https://example.com/', {
|
|
23
|
+
waitUntil: 'domcontentloaded',
|
|
24
|
+
});
|
|
25
|
+
return (await page.title()).length > 0;
|
|
26
|
+
} finally {
|
|
27
|
+
await page.close();
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
async post(context, _content) {
|
|
32
|
+
const page = await context.newPage();
|
|
33
|
+
try {
|
|
34
|
+
await page.goto('https://example.com/', {
|
|
35
|
+
waitUntil: 'domcontentloaded',
|
|
36
|
+
});
|
|
37
|
+
// Verification is the strategy's job: read back what the UI shows and
|
|
38
|
+
// only report ok when it matches `content`.
|
|
39
|
+
const heading = await page.textContent('h1');
|
|
40
|
+
return heading
|
|
41
|
+
? {
|
|
42
|
+
ok: true,
|
|
43
|
+
platformPostId: `demo-${Date.now()}`,
|
|
44
|
+
verification: 'toast',
|
|
45
|
+
}
|
|
46
|
+
: { ok: false, failureStage: 'verify', error: 'no heading rendered' };
|
|
47
|
+
} finally {
|
|
48
|
+
await page.close();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = [demoStrategy];
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@praveen-palanisamy/agent-browser-runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Stateful, secure browser-session execution for agents: pluggable browser providers (local Chromium, CDP, Steel, Kernel), post/probe/capture orchestration, an HTTP runner service and a Playwright-free client",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agents",
|
|
7
|
+
"ai-agents",
|
|
8
|
+
"authenticated-sessions",
|
|
9
|
+
"browser-agent",
|
|
10
|
+
"browser-automation",
|
|
11
|
+
"cdp",
|
|
12
|
+
"github-action",
|
|
13
|
+
"headless-chrome",
|
|
14
|
+
"kernel",
|
|
15
|
+
"kernel-browsers",
|
|
16
|
+
"playwright",
|
|
17
|
+
"rpa",
|
|
18
|
+
"self-hosted",
|
|
19
|
+
"session",
|
|
20
|
+
"steel",
|
|
21
|
+
"steel-browser",
|
|
22
|
+
"storage-state",
|
|
23
|
+
"web-automation"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "Praveen Palanisamy",
|
|
27
|
+
"homepage": "https://praveen-palanisamy.github.io/agent-browser-runtime/",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/praveen-palanisamy/agent-browser-runtime.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/praveen-palanisamy/agent-browser-runtime/issues"
|
|
34
|
+
},
|
|
35
|
+
"main": "dist/index.js",
|
|
36
|
+
"types": "dist/index.d.ts",
|
|
37
|
+
"bin": {
|
|
38
|
+
"agent-browser-runtime": "./dist/cli.js"
|
|
39
|
+
},
|
|
40
|
+
"exports": {
|
|
41
|
+
".": {
|
|
42
|
+
"types": "./dist/index.d.ts",
|
|
43
|
+
"default": "./dist/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./client": {
|
|
46
|
+
"types": "./dist/client/index.d.ts",
|
|
47
|
+
"default": "./dist/client/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./service": {
|
|
50
|
+
"types": "./dist/service/index.d.ts",
|
|
51
|
+
"default": "./dist/service/index.js"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"files": [
|
|
55
|
+
"dist",
|
|
56
|
+
"docs",
|
|
57
|
+
"examples",
|
|
58
|
+
"README.md",
|
|
59
|
+
"CHANGELOG.md",
|
|
60
|
+
"LICENSE",
|
|
61
|
+
"action.yml"
|
|
62
|
+
],
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=22"
|
|
65
|
+
},
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"scripts": {
|
|
70
|
+
"build": "tsc -p tsconfig.json",
|
|
71
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
72
|
+
"lint": "biome check .",
|
|
73
|
+
"format": "biome check --write .",
|
|
74
|
+
"test": "vitest run",
|
|
75
|
+
"test:browser": "ABR_TEST_SUITE=browser vitest run",
|
|
76
|
+
"browsers:install": "npx playwright-core install chromium",
|
|
77
|
+
"ci:check": "npm run lint && npm run typecheck && npm test && node scripts/check-playwright-pin.mjs && node scripts/check-action-manifest.mjs",
|
|
78
|
+
"pack:check": "npm pack --dry-run",
|
|
79
|
+
"release:prepare": "node scripts/release.mjs",
|
|
80
|
+
"prepublishOnly": "npm run build",
|
|
81
|
+
"site:build": "node scripts/site-build.mjs",
|
|
82
|
+
"site:serve": "node scripts/site-build.mjs && npx -y serve site/dist",
|
|
83
|
+
"site:demos": "node scripts/site-demos.mjs"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"playwright-core": "^1.57.0"
|
|
87
|
+
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@biomejs/biome": "^2.5.12",
|
|
90
|
+
"@types/node": "^26.4.1",
|
|
91
|
+
"marked": "^18.0.11",
|
|
92
|
+
"typescript": "^7.0.2",
|
|
93
|
+
"vitest": "^5.0.0"
|
|
94
|
+
},
|
|
95
|
+
"funding": "https://github.com/sponsors/praveen-palanisamy"
|
|
96
|
+
}
|