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.
Files changed (121) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +284 -0
  3. package/dist/scripts/demo.d.ts +1 -0
  4. package/dist/scripts/demo.js +32 -0
  5. package/dist/scripts/demo.js.map +1 -0
  6. package/dist/scripts/profile-login.d.ts +1 -0
  7. package/dist/scripts/profile-login.js +38 -0
  8. package/dist/scripts/profile-login.js.map +1 -0
  9. package/dist/src/agents/auto-agent.d.ts +22 -0
  10. package/dist/src/agents/auto-agent.js +54 -0
  11. package/dist/src/agents/auto-agent.js.map +1 -0
  12. package/dist/src/agents/cliproxy-agent.d.ts +18 -0
  13. package/dist/src/agents/cliproxy-agent.js +137 -0
  14. package/dist/src/agents/cliproxy-agent.js.map +1 -0
  15. package/dist/src/agents/index.d.ts +2 -0
  16. package/dist/src/agents/index.js +17 -0
  17. package/dist/src/agents/index.js.map +1 -0
  18. package/dist/src/agents/mock-agent.d.ts +15 -0
  19. package/dist/src/agents/mock-agent.js +132 -0
  20. package/dist/src/agents/mock-agent.js.map +1 -0
  21. package/dist/src/agents/opencode-agent.d.ts +20 -0
  22. package/dist/src/agents/opencode-agent.js +122 -0
  23. package/dist/src/agents/opencode-agent.js.map +1 -0
  24. package/dist/src/agents/planner-prompt.d.ts +6 -0
  25. package/dist/src/agents/planner-prompt.js +116 -0
  26. package/dist/src/agents/planner-prompt.js.map +1 -0
  27. package/dist/src/browser/session.d.ts +41 -0
  28. package/dist/src/browser/session.js +267 -0
  29. package/dist/src/browser/session.js.map +1 -0
  30. package/dist/src/client.d.ts +44 -0
  31. package/dist/src/client.js +59 -0
  32. package/dist/src/client.js.map +1 -0
  33. package/dist/src/config.d.ts +16 -0
  34. package/dist/src/config.js +18 -0
  35. package/dist/src/config.js.map +1 -0
  36. package/dist/src/index.d.ts +2 -0
  37. package/dist/src/index.js +15 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/lib.d.ts +6 -0
  40. package/dist/src/lib.js +5 -0
  41. package/dist/src/lib.js.map +1 -0
  42. package/dist/src/mcp-server.d.ts +3 -0
  43. package/dist/src/mcp-server.js +191 -0
  44. package/dist/src/mcp-server.js.map +1 -0
  45. package/dist/src/mcp.d.ts +2 -0
  46. package/dist/src/mcp.js +14 -0
  47. package/dist/src/mcp.js.map +1 -0
  48. package/dist/src/recipes/registry.d.ts +21 -0
  49. package/dist/src/recipes/registry.js +38 -0
  50. package/dist/src/recipes/registry.js.map +1 -0
  51. package/dist/src/server/app.d.ts +5 -0
  52. package/dist/src/server/app.js +89 -0
  53. package/dist/src/server/app.js.map +1 -0
  54. package/dist/src/sessions/store.d.ts +48 -0
  55. package/dist/src/sessions/store.js +84 -0
  56. package/dist/src/sessions/store.js.map +1 -0
  57. package/dist/src/storage/run-store.d.ts +12 -0
  58. package/dist/src/storage/run-store.js +30 -0
  59. package/dist/src/storage/run-store.js.map +1 -0
  60. package/dist/src/tasks/errors.d.ts +5 -0
  61. package/dist/src/tasks/errors.js +11 -0
  62. package/dist/src/tasks/errors.js.map +1 -0
  63. package/dist/src/tasks/output-validator.d.ts +1 -0
  64. package/dist/src/tasks/output-validator.js +21 -0
  65. package/dist/src/tasks/output-validator.js.map +1 -0
  66. package/dist/src/tasks/runner.d.ts +38 -0
  67. package/dist/src/tasks/runner.js +236 -0
  68. package/dist/src/tasks/runner.js.map +1 -0
  69. package/dist/src/tasks/schemas.d.ts +266 -0
  70. package/dist/src/tasks/schemas.js +67 -0
  71. package/dist/src/tasks/schemas.js.map +1 -0
  72. package/dist/tests/agent-adapters.test.d.ts +1 -0
  73. package/dist/tests/agent-adapters.test.js +87 -0
  74. package/dist/tests/agent-adapters.test.js.map +1 -0
  75. package/dist/tests/agent-selection.test.d.ts +1 -0
  76. package/dist/tests/agent-selection.test.js +26 -0
  77. package/dist/tests/agent-selection.test.js.map +1 -0
  78. package/dist/tests/auto-agent.test.d.ts +1 -0
  79. package/dist/tests/auto-agent.test.js +86 -0
  80. package/dist/tests/auto-agent.test.js.map +1 -0
  81. package/dist/tests/browser-session.test.d.ts +1 -0
  82. package/dist/tests/browser-session.test.js +41 -0
  83. package/dist/tests/browser-session.test.js.map +1 -0
  84. package/dist/tests/client.test.d.ts +1 -0
  85. package/dist/tests/client.test.js +35 -0
  86. package/dist/tests/client.test.js.map +1 -0
  87. package/dist/tests/fixture-site.d.ts +6 -0
  88. package/dist/tests/fixture-site.js +93 -0
  89. package/dist/tests/fixture-site.js.map +1 -0
  90. package/dist/tests/mcp.test.d.ts +1 -0
  91. package/dist/tests/mcp.test.js +186 -0
  92. package/dist/tests/mcp.test.js.map +1 -0
  93. package/dist/tests/output-validator.test.d.ts +1 -0
  94. package/dist/tests/output-validator.test.js +27 -0
  95. package/dist/tests/output-validator.test.js.map +1 -0
  96. package/dist/tests/request-validation.test.d.ts +1 -0
  97. package/dist/tests/request-validation.test.js +25 -0
  98. package/dist/tests/request-validation.test.js.map +1 -0
  99. package/dist/tests/runner-options.test.d.ts +1 -0
  100. package/dist/tests/runner-options.test.js +44 -0
  101. package/dist/tests/runner-options.test.js.map +1 -0
  102. package/dist/tests/session-api.test.d.ts +1 -0
  103. package/dist/tests/session-api.test.js +244 -0
  104. package/dist/tests/session-api.test.js.map +1 -0
  105. package/dist/tests/session-client.test.d.ts +1 -0
  106. package/dist/tests/session-client.test.js +28 -0
  107. package/dist/tests/session-client.test.js.map +1 -0
  108. package/dist/tests/task-api-failure.test.d.ts +1 -0
  109. package/dist/tests/task-api-failure.test.js +39 -0
  110. package/dist/tests/task-api-failure.test.js.map +1 -0
  111. package/dist/tests/task-api.test.d.ts +1 -0
  112. package/dist/tests/task-api.test.js +50 -0
  113. package/dist/tests/task-api.test.js.map +1 -0
  114. package/docs/design.md +513 -0
  115. package/docs/releasing.md +62 -0
  116. package/package.json +78 -0
  117. package/recipes/dexscreener-token-read.json +19 -0
  118. package/recipes/fixture-catalog.json +14 -0
  119. package/recipes/generic-search.json +14 -0
  120. package/recipes/gmgn-token-read.json +19 -0
  121. 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":"AAAA,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAU7B,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IAAG,CAAC;IAErD,KAAK,CAAC,IAAI;QACR,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAqB;QACpC,MAAM,QAAQ,GAAG;YACf,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE;YACjD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,GAAG,kBAAkB,CAAC,KAAK,CAAC,sDAAsD;aAC5F;SACF,CAAC;QAEF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,sBAAsB,CAAC;QACjE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,+EAA+E,CAChF,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,MAAM,MAAM,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;QACjD,IAAI,MAAM,EAAE,CAAC;YACX,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YAC5C,QAAQ,EAAE;gBACR,GAAG,QAAQ;gBACX;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EACL,kHAAkH;iBACrH;aACF;YACD,KAAK;YACL,UAAU,EAAE,KAAK;SAClB,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QACD,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAChC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,SAAS;QACP,OAAO;YACL,OAAO,EAAE,UAAU;YACnB,MAAM,EAAE,gDAAgD;SACzD,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,OAI1B;QACC,MAAM,IAAI,GAA4B;YACpC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,WAAW,EAAE,GAAG;SACjB,CAAC;QAEF,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,IAAI,CAAC,eAAe,GAAG;gBACrB,IAAI,EAAE,aAAa;gBACnB,WAAW,EAAE;oBACX,IAAI,EAAE,gBAAgB;oBACtB,MAAM,EAAE,IAAI;oBACZ,MAAM,EAAE,aAAa;iBACtB;aACF,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,yBAAyB,mBAAmB,EAAE;YAC5E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,gBAAgB,CAAC;gBACxB,cAAc,EAAE,kBAAkB;aACnC,CAAC;YACF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,MAAM,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA2B,CAAC;QAClE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC;QACvD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,yBAAyB,SAAS,EAAE;YAClE,OAAO,EAAE,gBAAgB,CAAC,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;SAC1D,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,0CAA0C,EAAE,CAAC;QAC3E,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qBAAqB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA+B;IACvD,OAAO,2BAA2B;QAChC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,UAAU,2BAA2B,EAAE,EAAE;QACxE,CAAC,CAAC,OAAO,CAAC;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACnG,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACjD,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAkB,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { AgentAdapter, TaskRequest } from "../tasks/schemas.js";
2
+ export declare function createAgent(request: TaskRequest): AgentAdapter;
@@ -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"}