web-task-api 0.2.1
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 +25 -0
- package/README.md +284 -0
- package/dist/scripts/demo.d.ts +1 -0
- package/dist/scripts/demo.js +32 -0
- package/dist/scripts/demo.js.map +1 -0
- package/dist/scripts/profile-login.d.ts +1 -0
- package/dist/scripts/profile-login.js +38 -0
- package/dist/scripts/profile-login.js.map +1 -0
- package/dist/src/agents/auto-agent.d.ts +22 -0
- package/dist/src/agents/auto-agent.js +54 -0
- package/dist/src/agents/auto-agent.js.map +1 -0
- package/dist/src/agents/cliproxy-agent.d.ts +18 -0
- package/dist/src/agents/cliproxy-agent.js +137 -0
- package/dist/src/agents/cliproxy-agent.js.map +1 -0
- package/dist/src/agents/index.d.ts +2 -0
- package/dist/src/agents/index.js +17 -0
- package/dist/src/agents/index.js.map +1 -0
- package/dist/src/agents/mock-agent.d.ts +15 -0
- package/dist/src/agents/mock-agent.js +132 -0
- package/dist/src/agents/mock-agent.js.map +1 -0
- package/dist/src/agents/opencode-agent.d.ts +20 -0
- package/dist/src/agents/opencode-agent.js +122 -0
- package/dist/src/agents/opencode-agent.js.map +1 -0
- package/dist/src/agents/planner-prompt.d.ts +6 -0
- package/dist/src/agents/planner-prompt.js +116 -0
- package/dist/src/agents/planner-prompt.js.map +1 -0
- package/dist/src/browser/session.d.ts +41 -0
- package/dist/src/browser/session.js +267 -0
- package/dist/src/browser/session.js.map +1 -0
- package/dist/src/client.d.ts +44 -0
- package/dist/src/client.js +59 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/config.d.ts +16 -0
- package/dist/src/config.js +18 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib.d.ts +6 -0
- package/dist/src/lib.js +5 -0
- package/dist/src/lib.js.map +1 -0
- package/dist/src/mcp-server.d.ts +3 -0
- package/dist/src/mcp-server.js +191 -0
- package/dist/src/mcp-server.js.map +1 -0
- package/dist/src/mcp.d.ts +2 -0
- package/dist/src/mcp.js +14 -0
- package/dist/src/mcp.js.map +1 -0
- package/dist/src/recipes/registry.d.ts +21 -0
- package/dist/src/recipes/registry.js +38 -0
- package/dist/src/recipes/registry.js.map +1 -0
- package/dist/src/server/app.d.ts +5 -0
- package/dist/src/server/app.js +89 -0
- package/dist/src/server/app.js.map +1 -0
- package/dist/src/sessions/store.d.ts +48 -0
- package/dist/src/sessions/store.js +84 -0
- package/dist/src/sessions/store.js.map +1 -0
- package/dist/src/storage/run-store.d.ts +12 -0
- package/dist/src/storage/run-store.js +30 -0
- package/dist/src/storage/run-store.js.map +1 -0
- package/dist/src/tasks/errors.d.ts +5 -0
- package/dist/src/tasks/errors.js +11 -0
- package/dist/src/tasks/errors.js.map +1 -0
- package/dist/src/tasks/output-validator.d.ts +1 -0
- package/dist/src/tasks/output-validator.js +21 -0
- package/dist/src/tasks/output-validator.js.map +1 -0
- package/dist/src/tasks/runner.d.ts +38 -0
- package/dist/src/tasks/runner.js +236 -0
- package/dist/src/tasks/runner.js.map +1 -0
- package/dist/src/tasks/schemas.d.ts +266 -0
- package/dist/src/tasks/schemas.js +67 -0
- package/dist/src/tasks/schemas.js.map +1 -0
- package/dist/tests/agent-adapters.test.d.ts +1 -0
- package/dist/tests/agent-adapters.test.js +87 -0
- package/dist/tests/agent-adapters.test.js.map +1 -0
- package/dist/tests/agent-selection.test.d.ts +1 -0
- package/dist/tests/agent-selection.test.js +26 -0
- package/dist/tests/agent-selection.test.js.map +1 -0
- package/dist/tests/auto-agent.test.d.ts +1 -0
- package/dist/tests/auto-agent.test.js +86 -0
- package/dist/tests/auto-agent.test.js.map +1 -0
- package/dist/tests/browser-session.test.d.ts +1 -0
- package/dist/tests/browser-session.test.js +41 -0
- package/dist/tests/browser-session.test.js.map +1 -0
- package/dist/tests/client.test.d.ts +1 -0
- package/dist/tests/client.test.js +35 -0
- package/dist/tests/client.test.js.map +1 -0
- package/dist/tests/fixture-site.d.ts +6 -0
- package/dist/tests/fixture-site.js +93 -0
- package/dist/tests/fixture-site.js.map +1 -0
- package/dist/tests/mcp.test.d.ts +1 -0
- package/dist/tests/mcp.test.js +186 -0
- package/dist/tests/mcp.test.js.map +1 -0
- package/dist/tests/output-validator.test.d.ts +1 -0
- package/dist/tests/output-validator.test.js +27 -0
- package/dist/tests/output-validator.test.js.map +1 -0
- package/dist/tests/request-validation.test.d.ts +1 -0
- package/dist/tests/request-validation.test.js +25 -0
- package/dist/tests/request-validation.test.js.map +1 -0
- package/dist/tests/runner-options.test.d.ts +1 -0
- package/dist/tests/runner-options.test.js +44 -0
- package/dist/tests/runner-options.test.js.map +1 -0
- package/dist/tests/session-api.test.d.ts +1 -0
- package/dist/tests/session-api.test.js +244 -0
- package/dist/tests/session-api.test.js.map +1 -0
- package/dist/tests/session-client.test.d.ts +1 -0
- package/dist/tests/session-client.test.js +28 -0
- package/dist/tests/session-client.test.js.map +1 -0
- package/dist/tests/task-api-failure.test.d.ts +1 -0
- package/dist/tests/task-api-failure.test.js +39 -0
- package/dist/tests/task-api-failure.test.js.map +1 -0
- package/dist/tests/task-api.test.d.ts +1 -0
- package/dist/tests/task-api.test.js +50 -0
- package/dist/tests/task-api.test.js.map +1 -0
- package/docs/design.md +513 -0
- package/docs/releasing.md +62 -0
- package/package.json +78 -0
- package/recipes/dexscreener-token-read.json +19 -0
- package/recipes/fixture-catalog.json +14 -0
- package/recipes/generic-search.json +14 -0
- package/recipes/gmgn-token-read.json +19 -0
- package/server.json +79 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1] - 2026-03-27
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- release packaging now tracks `src/sessions/store.ts` correctly by anchoring repo-root artifact ignores to `/runs/` and `/sessions/`, which fixes the broken 0.2.0 CI/release attempt on GitHub
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-03-27
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- first-class MCP server entrypoint with tools for task runs, task lookup, recipe listing, and session lifecycle management
|
|
14
|
+
- MCP packaging metadata (`server.json`), metadata validation, Claude/OpenCode config examples, and tag-driven GitHub workflows for CI, npm release, and MCP Registry publication
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- the same repo now intentionally ships both surfaces: `web-task-api-http` for the HTTP API runtime and `web-task-api` for the stdio MCP server, so one codebase exposes the same browser-task engine to both API and MCP clients
|
|
19
|
+
- MCP tools now reuse the same shared request/session validation rules as the HTTP API, and release automation pins the MCP publisher version for reproducibility
|
|
20
|
+
- package metadata now pins dependency versions explicitly, and release checks include a built-entrypoint MCP smoke test instead of trusting only the source `tsx` path
|
|
21
|
+
- tagged release automation is now a single coordinated pipeline so MCP publication only runs after npm publication is guaranteed instead of racing a separate workflow
|
|
22
|
+
|
|
23
|
+
## References
|
|
24
|
+
|
|
25
|
+
[^1]: `docs/releasing.md` documents the tag-driven release flow and versioned metadata files for this repository.
|
package/README.md
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Web Task API
|
|
2
|
+
|
|
3
|
+
`web-task-api` is a generalized browser-task runtime for projects that want to treat websites like programmable APIs.
|
|
4
|
+
|
|
5
|
+
It exposes one API for:
|
|
6
|
+
|
|
7
|
+
- starting from a URL + goal
|
|
8
|
+
- letting an agent drive a real browser
|
|
9
|
+
- validating structured output against a schema
|
|
10
|
+
- reusing persistent browser profiles and promoted recipes
|
|
11
|
+
- storing traces and artifacts for replay/debugging
|
|
12
|
+
|
|
13
|
+
The same runtime now ships in **two surfaces**:
|
|
14
|
+
|
|
15
|
+
- **HTTP API** for application-to-application integration
|
|
16
|
+
- **MCP server** for Claude Code, OpenCode, and other MCP clients[^1]
|
|
17
|
+
|
|
18
|
+
## Why this exists
|
|
19
|
+
|
|
20
|
+
Instead of building one brittle adapter per website, this project uses an agent-first browser runtime:
|
|
21
|
+
|
|
22
|
+
- default path: goal-driven browser control
|
|
23
|
+
- optimization path: reusable recipes for common flows
|
|
24
|
+
- escape hatch: login profiles and artifacts for debugging failures
|
|
25
|
+
|
|
26
|
+
That gives a more future-proof foundation for “API for any site” style automation.
|
|
27
|
+
|
|
28
|
+
## Implemented MVP
|
|
29
|
+
|
|
30
|
+
- Fastify HTTP API
|
|
31
|
+
- stdio MCP server
|
|
32
|
+
- Playwright browser runtime
|
|
33
|
+
- CLIProxyAPI-backed planner for freeform browser control
|
|
34
|
+
- Optional OpenCode SDK planner adapter for environments that already use OpenCode well
|
|
35
|
+
- Auto planner mode that falls back to your existing local OpenCode auth/runtime when direct CLIProxy credentials are not wired yet
|
|
36
|
+
- Mock agent for local deterministic demos/tests
|
|
37
|
+
- Recipe registry and matching
|
|
38
|
+
- Persistent browser profile reuse
|
|
39
|
+
- Run artifacts and step traces
|
|
40
|
+
- Local demo and end-to-end tests
|
|
41
|
+
|
|
42
|
+
## Initial workflow targets
|
|
43
|
+
|
|
44
|
+
- generic search/form workflows
|
|
45
|
+
- Dexscreener token/pair reading starter recipe
|
|
46
|
+
- GMGN token/wallet reading starter recipe
|
|
47
|
+
|
|
48
|
+
For Dexscreener/GMGN, treat the shipped recipes as **starter recipes**, not guaranteed turnkey integrations yet. A warmed persistent browser source is often required because fresh headless sessions can hit Cloudflare or similar anti-bot checks. The runtime now fails fast for these protected-site recipes unless you provide one of:
|
|
49
|
+
|
|
50
|
+
- `request.profile`
|
|
51
|
+
- `BROWSER_USER_DATA_DIR`
|
|
52
|
+
- `sessionId` for a **warmed** session that already preserves browser storage across tasks
|
|
53
|
+
|
|
54
|
+
## Quick start
|
|
55
|
+
|
|
56
|
+
1. Install dependencies:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install
|
|
60
|
+
npm run playwright:install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. Start the HTTP API:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run dev
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. Or start the MCP server:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run dev:mcp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
4. Run the demo flow:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npm run demo
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## MCP
|
|
82
|
+
|
|
83
|
+
The package now exposes the MCP server binary directly:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx -y web-task-api
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
That launches the stdio MCP server.
|
|
90
|
+
|
|
91
|
+
The HTTP runtime remains available separately:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx -y -p web-task-api web-task-api-http
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### MCP tools
|
|
98
|
+
|
|
99
|
+
- `webtask_run`
|
|
100
|
+
- `webtask_get_task`
|
|
101
|
+
- `webtask_list_recipes`
|
|
102
|
+
- `webtask_create_session`
|
|
103
|
+
- `webtask_list_sessions`
|
|
104
|
+
- `webtask_get_session`
|
|
105
|
+
- `webtask_update_session`
|
|
106
|
+
- `webtask_health`
|
|
107
|
+
|
|
108
|
+
### MCP config examples
|
|
109
|
+
|
|
110
|
+
- Claude Code: `examples/claude.mcp.json`
|
|
111
|
+
- OpenCode: `examples/opencode.json`
|
|
112
|
+
|
|
113
|
+
## API
|
|
114
|
+
|
|
115
|
+
### `POST /v1/tasks/run`
|
|
116
|
+
|
|
117
|
+
Runs a browser task synchronously and returns structured results.
|
|
118
|
+
|
|
119
|
+
Example request is in `examples/demo-task.json`.
|
|
120
|
+
|
|
121
|
+
### `GET /v1/tasks/:taskId`
|
|
122
|
+
|
|
123
|
+
Returns the persisted run record with step trace and artifact paths.
|
|
124
|
+
|
|
125
|
+
### `GET /v1/recipes`
|
|
126
|
+
|
|
127
|
+
Lists registered recipes.
|
|
128
|
+
|
|
129
|
+
### `POST /v1/sessions`
|
|
130
|
+
|
|
131
|
+
Creates a reusable session for connected tasks. Sessions can carry:
|
|
132
|
+
|
|
133
|
+
- guest vs profile mode
|
|
134
|
+
- default start URL
|
|
135
|
+
- default planner config
|
|
136
|
+
- notes
|
|
137
|
+
- compact task history
|
|
138
|
+
|
|
139
|
+
### `GET /v1/sessions`
|
|
140
|
+
|
|
141
|
+
Lists saved sessions.
|
|
142
|
+
|
|
143
|
+
### `GET /v1/sessions/:sessionId`
|
|
144
|
+
|
|
145
|
+
Returns session metadata and recent task history.
|
|
146
|
+
|
|
147
|
+
### `PATCH /v1/sessions/:sessionId`
|
|
148
|
+
|
|
149
|
+
Updates session metadata like notes, default start URL, or the bound profile for an existing profile-mode session. Guest sessions cannot be rebound into named profiles by patch.
|
|
150
|
+
|
|
151
|
+
### `GET /health`
|
|
152
|
+
|
|
153
|
+
Basic health endpoint.
|
|
154
|
+
|
|
155
|
+
## TypeScript client
|
|
156
|
+
|
|
157
|
+
Software can use the bundled client:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { WebTaskApiClient } from "web-task-api"
|
|
161
|
+
|
|
162
|
+
const client = new WebTaskApiClient({ baseUrl: "http://127.0.0.1:4317" })
|
|
163
|
+
const session = await client.createSession({
|
|
164
|
+
name: "axiom trader",
|
|
165
|
+
mode: "profile",
|
|
166
|
+
profile: "axiom",
|
|
167
|
+
notes: "Authenticated Axiom trading session"
|
|
168
|
+
})
|
|
169
|
+
const result = await client.runTask({
|
|
170
|
+
goal: "Extract token name and price",
|
|
171
|
+
startUrl: "https://example.com",
|
|
172
|
+
sessionId: session.id,
|
|
173
|
+
agent: { kind: "auto" },
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Connected tasks with sessions
|
|
178
|
+
|
|
179
|
+
Sessions let related web tasks share:
|
|
180
|
+
|
|
181
|
+
- browser/profile identity
|
|
182
|
+
- guest-session cookies and local storage across tasks
|
|
183
|
+
- default start URL
|
|
184
|
+
- planner defaults
|
|
185
|
+
- recent task context
|
|
186
|
+
|
|
187
|
+
Example pattern:
|
|
188
|
+
|
|
189
|
+
1. Create session for `axiom` profile
|
|
190
|
+
2. Run login/manual warmup task once
|
|
191
|
+
3. Run later research/action tasks with the same `sessionId`
|
|
192
|
+
4. Inspect session history to see what the agent already found
|
|
193
|
+
|
|
194
|
+
Guest sessions also work: create a `mode: "guest"` session and repeated tasks will preserve browser storage between runs under that session ID.
|
|
195
|
+
|
|
196
|
+
For protected recipes, that guest session still needs to be **warmed first** before you rely on it as a continuity source.
|
|
197
|
+
|
|
198
|
+
## Browser profiles
|
|
199
|
+
|
|
200
|
+
To create a reusable login profile:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
npm run profile:login -- --id my-profile --url https://example.com/login
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This opens a real persistent browser profile. Log in manually or solve bot challenges, then press Enter in the terminal. The runtime saves a reusable Chromium user-data directory at `profiles/<id>/user-data-dir` and later tasks can use `"profile": "my-profile"`.
|
|
207
|
+
|
|
208
|
+
This matters for sites like Dexscreener or GMGN that may block fresh headless sessions behind Cloudflare or similar anti-bot checks.
|
|
209
|
+
|
|
210
|
+
If you want the runtime to behave as closely as possible to your normal local Chrome, you can also point it at an existing browser profile:
|
|
211
|
+
|
|
212
|
+
- `BROWSER_USER_DATA_DIR=/path/to/your/chrome/profile`
|
|
213
|
+
|
|
214
|
+
That is the closest match to “it works in my Chrome already”.
|
|
215
|
+
|
|
216
|
+
## Planner backends
|
|
217
|
+
|
|
218
|
+
### Recommended: CLIProxyAPI
|
|
219
|
+
|
|
220
|
+
This is the default non-mock path to avoid tying the system too tightly to OpenCode.
|
|
221
|
+
|
|
222
|
+
CLIProxyAPI is treated as a **multi-provider router**, not a single-provider API key wrapper. You can point this product at any model alias/provider path exposed by your CLIProxy setup.
|
|
223
|
+
|
|
224
|
+
Useful environment variables:
|
|
225
|
+
|
|
226
|
+
- `CLIPROXY_BASE_URL` — default `http://127.0.0.1:8317/v1`
|
|
227
|
+
- `CLIPROXY_AUTH_TOKEN` — optional client token if your CLIProxy instance requires one
|
|
228
|
+
- `CLIPROXY_MODEL` — planner model alias/name exposed by your proxy, for example whatever provider/model mapping you configured there
|
|
229
|
+
|
|
230
|
+
Example:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"agent": {
|
|
235
|
+
"kind": "cliproxy"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Easiest local path right now: `auto`
|
|
241
|
+
|
|
242
|
+
If your GPT/OAuth is already working through local OpenCode, use:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"agent": {
|
|
247
|
+
"kind": "auto"
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`auto` probes CLIProxy first and uses it when reachable/authenticated **and** a planner model is configured; otherwise it falls back to OpenCode so the product can still use your existing local auth/runtime. This path is verified locally against the fixture flow; for real sites, treat it as the recommended runtime path, not a guarantee that every protected site will work without profile warmup.
|
|
253
|
+
|
|
254
|
+
### Optional: OpenCode
|
|
255
|
+
|
|
256
|
+
If you already run OpenCode headless and want to reuse that stack, the project also supports an OpenCode planner adapter.
|
|
257
|
+
|
|
258
|
+
Useful variables:
|
|
259
|
+
|
|
260
|
+
- `OPENCODE_BASE_URL`
|
|
261
|
+
- `OPENCODE_MODEL`
|
|
262
|
+
|
|
263
|
+
Then use:
|
|
264
|
+
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"agent": {
|
|
268
|
+
"kind": "opencode"
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Main files
|
|
274
|
+
|
|
275
|
+
- `docs/design.md` — architecture, decisions, and implementation plan
|
|
276
|
+
- `docs/releasing.md` — tag-driven release flow and MCP registry packaging notes
|
|
277
|
+
- `src/` — server, runtime, agent, browser, and storage code
|
|
278
|
+
- `tests/` — end-to-end verification with a local fixture site
|
|
279
|
+
- `scripts/` — demo runner and profile bootstrap
|
|
280
|
+
|
|
281
|
+
## References
|
|
282
|
+
|
|
283
|
+
[^1]: `docs/design.md` for the detailed system design, tradeoffs, and roadmap.
|
|
284
|
+
[^2]: `server.json` is the MCP registry metadata source of truth; `package.json` carries the npm package and executable metadata.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createApp } from "../src/server/app.js";
|
|
2
|
+
import { startFixtureSite } from "../tests/fixture-site.js";
|
|
3
|
+
const fixture = await startFixtureSite();
|
|
4
|
+
const app = createApp();
|
|
5
|
+
try {
|
|
6
|
+
const response = await app.inject({
|
|
7
|
+
method: "POST",
|
|
8
|
+
url: "/v1/tasks/run",
|
|
9
|
+
payload: {
|
|
10
|
+
goal: "Search for banana and return product, price, and stock.",
|
|
11
|
+
startUrl: fixture.url,
|
|
12
|
+
recipeId: "fixture-catalog",
|
|
13
|
+
input: { query: "banana" },
|
|
14
|
+
outputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
required: ["product", "price", "stock"],
|
|
17
|
+
properties: {
|
|
18
|
+
product: { type: "string" },
|
|
19
|
+
price: { type: "string" },
|
|
20
|
+
stock: { type: "string" },
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
agent: { kind: "mock" },
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
console.log(response.body);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await app.close();
|
|
30
|
+
await fixture.close();
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../../scripts/demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;AACzC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;AAExB,IAAI,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC;QAChC,MAAM,EAAE,MAAM;QACd,GAAG,EAAE,eAAe;QACpB,OAAO,EAAE;YACP,IAAI,EAAE,yDAAyD;YAC/D,QAAQ,EAAE,OAAO,CAAC,GAAG;YACrB,QAAQ,EAAE,iBAAiB;YAC3B,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;YAC1B,YAAY,EAAE;gBACZ,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;gBACvC,UAAU,EAAE;oBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBAC1B;aACF;YACD,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SACxB;KACF,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;QAAS,CAAC;IACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { chromium } from "playwright";
|
|
4
|
+
import { PROFILES_DIR } from "../src/config.js";
|
|
5
|
+
const args = new Map();
|
|
6
|
+
for (let index = 2; index < process.argv.length; index += 2) {
|
|
7
|
+
const key = process.argv[index];
|
|
8
|
+
const value = process.argv[index + 1];
|
|
9
|
+
if (key?.startsWith("--") && value) {
|
|
10
|
+
args.set(key.slice(2), value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const id = args.get("id");
|
|
14
|
+
const url = args.get("url");
|
|
15
|
+
if (!id || !url) {
|
|
16
|
+
console.error("Usage: npm run profile:login -- --id my-profile --url https://example.com/login");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const profileDir = path.join(PROFILES_DIR, id);
|
|
20
|
+
await fs.mkdir(profileDir, { recursive: true });
|
|
21
|
+
const userDataDir = path.join(profileDir, "user-data-dir");
|
|
22
|
+
await fs.mkdir(userDataDir, { recursive: true });
|
|
23
|
+
const context = await chromium.launchPersistentContext(userDataDir, { headless: false });
|
|
24
|
+
const page = context.pages()[0] ?? (await context.newPage());
|
|
25
|
+
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
26
|
+
console.log(`Log in or solve challenges in the opened browser for profile '${id}'.`);
|
|
27
|
+
await waitForEnter();
|
|
28
|
+
await context.close();
|
|
29
|
+
console.log(`Saved persistent browser profile to ${userDataDir}`);
|
|
30
|
+
function waitForEnter() {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
console.log("Press Enter here when login is complete.");
|
|
33
|
+
process.stdin.resume();
|
|
34
|
+
process.stdin.setEncoding("utf8");
|
|
35
|
+
process.stdin.once("data", () => resolve());
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=profile-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile-login.js","sourceRoot":"","sources":["../../scripts/profile-login.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;AACvC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACtC,IAAI,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAE5B,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;IAChB,OAAO,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;IACjG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC/C,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;AAC3D,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAEjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;AACzF,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;AAExD,OAAO,CAAC,GAAG,CAAC,iEAAiE,EAAE,IAAI,CAAC,CAAC;AAErF,MAAM,YAAY,EAAE,CAAC;AACrB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;AACtB,OAAO,CAAC,GAAG,CAAC,uCAAuC,WAAW,EAAE,CAAC,CAAC;AAElE,SAAS,YAAY;IACnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { probeCliProxy } from "./cliproxy-agent.js";
|
|
2
|
+
import type { AgentAdapter, AgentTurnInput, PlannedAction, TaskRequest } from "../tasks/schemas.js";
|
|
3
|
+
type AutoAgentDeps = {
|
|
4
|
+
probe?: typeof probeCliProxy;
|
|
5
|
+
createCliProxy?: (request: TaskRequest) => AgentAdapter;
|
|
6
|
+
createOpencode?: (request: TaskRequest) => AgentAdapter;
|
|
7
|
+
};
|
|
8
|
+
export declare class AutoAgent implements AgentAdapter {
|
|
9
|
+
private readonly request;
|
|
10
|
+
private readonly deps;
|
|
11
|
+
private delegate?;
|
|
12
|
+
private selectedReason;
|
|
13
|
+
constructor(request: TaskRequest, deps?: AutoAgentDeps);
|
|
14
|
+
init(): Promise<void>;
|
|
15
|
+
nextAction(input: AgentTurnInput): Promise<PlannedAction>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
debugInfo(): {
|
|
18
|
+
planner: string;
|
|
19
|
+
reason: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { probeCliProxy } from "./cliproxy-agent.js";
|
|
2
|
+
import { CliProxyAgent } from "./cliproxy-agent.js";
|
|
3
|
+
import { OpencodeAgent } from "./opencode-agent.js";
|
|
4
|
+
import { DEFAULT_CLIPROXY_MODEL } from "../config.js";
|
|
5
|
+
export class AutoAgent {
|
|
6
|
+
request;
|
|
7
|
+
deps;
|
|
8
|
+
delegate;
|
|
9
|
+
selectedReason = "auto not initialized";
|
|
10
|
+
constructor(request, deps = {}) {
|
|
11
|
+
this.request = request;
|
|
12
|
+
this.deps = deps;
|
|
13
|
+
}
|
|
14
|
+
async init() {
|
|
15
|
+
const probe = this.deps.probe ?? probeCliProxy;
|
|
16
|
+
const createCliProxy = this.deps.createCliProxy ??
|
|
17
|
+
((request) => new CliProxyAgent({
|
|
18
|
+
...request,
|
|
19
|
+
agent: { ...request.agent, kind: "cliproxy" },
|
|
20
|
+
}));
|
|
21
|
+
const createOpencode = this.deps.createOpencode ??
|
|
22
|
+
((request) => new OpencodeAgent({
|
|
23
|
+
...request,
|
|
24
|
+
agent: { ...request.agent, kind: "opencode" },
|
|
25
|
+
}));
|
|
26
|
+
const cliproxy = await probe();
|
|
27
|
+
const hasCliProxyModel = Boolean(this.request.agent.model ?? DEFAULT_CLIPROXY_MODEL);
|
|
28
|
+
this.delegate = cliproxy.ok && hasCliProxyModel
|
|
29
|
+
? createCliProxy(this.request)
|
|
30
|
+
: createOpencode(this.request);
|
|
31
|
+
this.selectedReason = cliproxy.ok
|
|
32
|
+
? hasCliProxyModel
|
|
33
|
+
? "CLIProxy reachable and model configured"
|
|
34
|
+
: "CLIProxy reachable but no model configured; fell back to OpenCode"
|
|
35
|
+
: `CLIProxy unavailable (${cliproxy.reason ?? "unknown"}); fell back to OpenCode`;
|
|
36
|
+
await this.delegate.init();
|
|
37
|
+
}
|
|
38
|
+
async nextAction(input) {
|
|
39
|
+
if (!this.delegate) {
|
|
40
|
+
throw new Error("AutoAgent not initialized.");
|
|
41
|
+
}
|
|
42
|
+
return this.delegate.nextAction(input);
|
|
43
|
+
}
|
|
44
|
+
async close() {
|
|
45
|
+
await this.delegate?.close();
|
|
46
|
+
}
|
|
47
|
+
debugInfo() {
|
|
48
|
+
return {
|
|
49
|
+
planner: this.delegate?.debugInfo().planner ?? "auto",
|
|
50
|
+
reason: this.selectedReason,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=auto-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-agent.js","sourceRoot":"","sources":["../../../src/agents/auto-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAStD,MAAM,OAAO,SAAS;IAKD;IACA;IALX,QAAQ,CAAgB;IACxB,cAAc,GAAG,sBAAsB,CAAC;IAEhD,YACmB,OAAoB,EACpB,OAAsB,EAAE;QADxB,YAAO,GAAP,OAAO,CAAa;QACpB,SAAI,GAAJ,IAAI,CAAoB;IACxC,CAAC;IAEJ,KAAK,CAAC,IAAI;QACR,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC;QAC/C,MAAM,cAAc,GAClB,IAAI,CAAC,IAAI,CAAC,cAAc;YACxB,CAAC,CAAC,OAAoB,EAAE,EAAE,CACxB,IAAI,aAAa,CAAC;gBAChB,GAAG,OAAO;gBACV,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE;aAC9C,CAAC,CAAC,CAAC;QACR,MAAM,cAAc,GAClB,IAAI,CAAC,IAAI,CAAC,cAAc;YACxB,CAAC,CAAC,OAAoB,EAAE,EAAE,CACxB,IAAI,aAAa,CAAC;gBAChB,GAAG,OAAO;gBACV,KAAK,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE;aAC9C,CAAC,CAAC,CAAC;QAER,MAAM,QAAQ,GAAG,MAAM,KAAK,EAAE,CAAC;QAC/B,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,sBAAsB,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,EAAE,IAAI,gBAAgB;YAC7C,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC;YAC9B,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC,EAAE;YAC/B,CAAC,CAAC,gBAAgB;gBAChB,CAAC,CAAC,yCAAyC;gBAC3C,CAAC,CAAC,mEAAmE;YACvE,CAAC,CAAC,yBAAyB,QAAQ,CAAC,MAAM,IAAI,SAAS,0BAA0B,CAAC;QACpF,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAqB;QACpC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC/B,CAAC;IAED,SAAS;QACP,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,OAAO,IAAI,MAAM;YACrD,MAAM,EAAE,IAAI,CAAC,cAAc;SAC5B,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentAdapter, AgentTurnInput, PlannedAction, TaskRequest } from "../tasks/schemas.js";
|
|
2
|
+
export declare class CliProxyAgent implements AgentAdapter {
|
|
3
|
+
private readonly request;
|
|
4
|
+
constructor(request: TaskRequest);
|
|
5
|
+
init(): Promise<void>;
|
|
6
|
+
nextAction(input: AgentTurnInput): Promise<PlannedAction>;
|
|
7
|
+
close(): Promise<void>;
|
|
8
|
+
debugInfo(): {
|
|
9
|
+
planner: string;
|
|
10
|
+
reason: string;
|
|
11
|
+
};
|
|
12
|
+
private callCliProxy;
|
|
13
|
+
}
|
|
14
|
+
export declare function probeCliProxy(): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
reason?: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function parseCliProxyAction(content: string): PlannedAction | undefined;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { DEFAULT_CLIPROXY_AUTH_TOKEN, DEFAULT_CLIPROXY_BASE_URL, DEFAULT_CLIPROXY_MODEL, } from "../config.js";
|
|
2
|
+
import { ACTION_SCHEMA, buildPlannerPrompt, systemInstructions, validatePlannedAction, } from "./planner-prompt.js";
|
|
3
|
+
export class CliProxyAgent {
|
|
4
|
+
request;
|
|
5
|
+
constructor(request) {
|
|
6
|
+
this.request = request;
|
|
7
|
+
}
|
|
8
|
+
async init() {
|
|
9
|
+
const probe = await probeCliProxy();
|
|
10
|
+
if (!probe.ok) {
|
|
11
|
+
throw new Error(`CliProxy unavailable: ${probe.reason}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async nextAction(input) {
|
|
15
|
+
const messages = [
|
|
16
|
+
{ role: "system", content: systemInstructions() },
|
|
17
|
+
{
|
|
18
|
+
role: "user",
|
|
19
|
+
content: `${buildPlannerPrompt(input)}\n\nReturn only one JSON object for the next action.`,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
const model = this.request.agent.model ?? DEFAULT_CLIPROXY_MODEL;
|
|
23
|
+
if (!model) {
|
|
24
|
+
throw new Error("CliProxy planner needs a model alias/name. Set agent.model or CLIPROXY_MODEL.");
|
|
25
|
+
}
|
|
26
|
+
const firstAttempt = await this.callCliProxy({ messages, model, withSchema: true });
|
|
27
|
+
const parsed = parseCliProxyAction(firstAttempt);
|
|
28
|
+
if (parsed) {
|
|
29
|
+
validatePlannedAction(parsed);
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
const secondAttempt = await this.callCliProxy({
|
|
33
|
+
messages: [
|
|
34
|
+
...messages,
|
|
35
|
+
{
|
|
36
|
+
role: "user",
|
|
37
|
+
content: "Your last answer was not valid JSON. Return exactly one JSON object matching the action schema and nothing else.",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
model,
|
|
41
|
+
withSchema: false,
|
|
42
|
+
});
|
|
43
|
+
const repaired = parseCliProxyAction(secondAttempt);
|
|
44
|
+
if (!repaired) {
|
|
45
|
+
throw new Error("CliProxy planner did not return parseable JSON.");
|
|
46
|
+
}
|
|
47
|
+
validatePlannedAction(repaired);
|
|
48
|
+
return repaired;
|
|
49
|
+
}
|
|
50
|
+
async close() { }
|
|
51
|
+
debugInfo() {
|
|
52
|
+
return {
|
|
53
|
+
planner: "cliproxy",
|
|
54
|
+
reason: "CLIProxy reachable with configured model alias",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async callCliProxy(options) {
|
|
58
|
+
const body = {
|
|
59
|
+
model: options.model,
|
|
60
|
+
messages: options.messages,
|
|
61
|
+
temperature: 0.1,
|
|
62
|
+
};
|
|
63
|
+
if (options.withSchema) {
|
|
64
|
+
body.response_format = {
|
|
65
|
+
type: "json_schema",
|
|
66
|
+
json_schema: {
|
|
67
|
+
name: "browser_action",
|
|
68
|
+
strict: true,
|
|
69
|
+
schema: ACTION_SCHEMA,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const response = await fetch(`${DEFAULT_CLIPROXY_BASE_URL}/chat/completions`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: withOptionalAuth({
|
|
76
|
+
"content-type": "application/json",
|
|
77
|
+
}),
|
|
78
|
+
body: JSON.stringify(body),
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
throw new Error(`CliProxy request failed: ${response.status} ${await response.text()}`);
|
|
82
|
+
}
|
|
83
|
+
const payload = (await response.json());
|
|
84
|
+
const content = payload.choices?.[0]?.message?.content;
|
|
85
|
+
if (typeof content === "string") {
|
|
86
|
+
return content;
|
|
87
|
+
}
|
|
88
|
+
if (Array.isArray(content)) {
|
|
89
|
+
return content.map((part) => part.text ?? "").join("");
|
|
90
|
+
}
|
|
91
|
+
throw new Error("CliProxy response did not include planner content.");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export async function probeCliProxy() {
|
|
95
|
+
try {
|
|
96
|
+
const response = await fetch(`${DEFAULT_CLIPROXY_BASE_URL}/models`, {
|
|
97
|
+
headers: withOptionalAuth({ accept: "application/json" }),
|
|
98
|
+
});
|
|
99
|
+
if (response.ok) {
|
|
100
|
+
return { ok: true };
|
|
101
|
+
}
|
|
102
|
+
if (response.status === 401) {
|
|
103
|
+
return { ok: false, reason: "authentication required or token invalid" };
|
|
104
|
+
}
|
|
105
|
+
return { ok: false, reason: `unexpected status ${response.status}` };
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return { ok: false, reason: String(error) };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function withOptionalAuth(headers) {
|
|
112
|
+
return DEFAULT_CLIPROXY_AUTH_TOKEN
|
|
113
|
+
? { ...headers, authorization: `Bearer ${DEFAULT_CLIPROXY_AUTH_TOKEN}` }
|
|
114
|
+
: headers;
|
|
115
|
+
}
|
|
116
|
+
export function parseCliProxyAction(content) {
|
|
117
|
+
const trimmed = content.trim();
|
|
118
|
+
const candidates = [trimmed];
|
|
119
|
+
const blockMatch = trimmed.match(/```json\s*([\s\S]+?)```/i) ?? trimmed.match(/```([\s\S]+?)```/i);
|
|
120
|
+
if (blockMatch?.[1]) {
|
|
121
|
+
candidates.push(blockMatch[1].trim());
|
|
122
|
+
}
|
|
123
|
+
const objectMatch = trimmed.match(/\{[\s\S]*\}/);
|
|
124
|
+
if (objectMatch?.[0]) {
|
|
125
|
+
candidates.push(objectMatch[0]);
|
|
126
|
+
}
|
|
127
|
+
for (const candidate of candidates) {
|
|
128
|
+
try {
|
|
129
|
+
return JSON.parse(candidate);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=cliproxy-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliproxy-agent.js","sourceRoot":"","sources":["../../../src/agents/cliproxy-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AutoAgent } from "./auto-agent.js";
|
|
2
|
+
import { CliProxyAgent } from "./cliproxy-agent.js";
|
|
3
|
+
import { MockAgent } from "./mock-agent.js";
|
|
4
|
+
import { OpencodeAgent } from "./opencode-agent.js";
|
|
5
|
+
export function createAgent(request) {
|
|
6
|
+
if (request.agent.kind === "auto") {
|
|
7
|
+
return new AutoAgent(request);
|
|
8
|
+
}
|
|
9
|
+
if (request.agent.kind === "cliproxy") {
|
|
10
|
+
return new CliProxyAgent(request);
|
|
11
|
+
}
|
|
12
|
+
if (request.agent.kind === "opencode") {
|
|
13
|
+
return new OpencodeAgent(request);
|
|
14
|
+
}
|
|
15
|
+
return new MockAgent(request);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/agents/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,UAAU,WAAW,CAAC,OAAoB;IAC9C,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAClC,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACtC,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC"}
|