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
@@ -0,0 +1,87 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { CliProxyAgent } from "../src/agents/cliproxy-agent.js";
4
+ import { parseCliProxyAction, probeCliProxy } from "../src/agents/cliproxy-agent.js";
5
+ import { extractOpencodeStructuredOutput, parseModel, } from "../src/agents/opencode-agent.js";
6
+ test("parses plain CliProxy JSON action", () => {
7
+ const action = parseCliProxyAction('{"type":"read_page","reason":"inspect"}');
8
+ assert.deepEqual(action, { type: "read_page", reason: "inspect" });
9
+ });
10
+ test("parses fenced CliProxy JSON action", () => {
11
+ const action = parseCliProxyAction('```json\n{"type":"click","elementId":"e2","reason":"submit"}\n```');
12
+ assert.deepEqual(action, { type: "click", elementId: "e2", reason: "submit" });
13
+ });
14
+ test("extracts OpenCode structured output payload", () => {
15
+ const action = extractOpencodeStructuredOutput({
16
+ data: {
17
+ info: {
18
+ structured: { type: "finish", reason: "done", result: { ok: true } },
19
+ },
20
+ },
21
+ });
22
+ assert.deepEqual(action, { type: "finish", reason: "done", result: { ok: true } });
23
+ });
24
+ test("parses provider/model format for OpenCode override", () => {
25
+ assert.deepEqual(parseModel("openai/gpt-4.1-mini"), {
26
+ providerID: "openai",
27
+ modelID: "gpt-4.1-mini",
28
+ });
29
+ });
30
+ test("CliProxyAgent nextAction parses structured response from transport", async () => {
31
+ const originalFetch = globalThis.fetch;
32
+ globalThis.fetch = (async () => new Response(JSON.stringify({
33
+ choices: [{ message: { content: '{"type":"read_page","reason":"inspect"}' } }],
34
+ }), { status: 200, headers: { "content-type": "application/json" } }));
35
+ const request = {
36
+ goal: "Inspect page",
37
+ mode: "read",
38
+ input: {},
39
+ agent: { kind: "cliproxy", model: "openai/gpt-5.4" },
40
+ limits: {},
41
+ };
42
+ const turn = {
43
+ request,
44
+ step: 1,
45
+ maxSteps: 5,
46
+ snapshot: {
47
+ url: "https://example.com",
48
+ title: "Example",
49
+ textPreview: "Hello",
50
+ interactive: [],
51
+ },
52
+ history: [],
53
+ };
54
+ try {
55
+ const agent = new CliProxyAgent(request);
56
+ await agent.init();
57
+ const action = await agent.nextAction(turn);
58
+ assert.deepEqual(action, { type: "read_page", reason: "inspect" });
59
+ }
60
+ finally {
61
+ globalThis.fetch = originalFetch;
62
+ }
63
+ });
64
+ test("probeCliProxy reports reachable endpoint", async () => {
65
+ const originalFetch = globalThis.fetch;
66
+ globalThis.fetch = (async () => new Response(JSON.stringify({ data: [] }), { status: 200 }));
67
+ try {
68
+ const result = await probeCliProxy();
69
+ assert.deepEqual(result, { ok: true });
70
+ }
71
+ finally {
72
+ globalThis.fetch = originalFetch;
73
+ }
74
+ });
75
+ test("probeCliProxy reports auth requirement on 401", async () => {
76
+ const originalFetch = globalThis.fetch;
77
+ globalThis.fetch = (async () => new Response("unauthorized", { status: 401 }));
78
+ try {
79
+ const result = await probeCliProxy();
80
+ assert.equal(result.ok, false);
81
+ assert.match(String(result.reason), /authentication required/i);
82
+ }
83
+ finally {
84
+ globalThis.fetch = originalFetch;
85
+ }
86
+ });
87
+ //# sourceMappingURL=agent-adapters.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-adapters.test.js","sourceRoot":"","sources":["../../tests/agent-adapters.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { createAgent } from "../src/agents/index.js";
4
+ test("createAgent returns AutoAgent for auto selection", () => {
5
+ const request = {
6
+ goal: "Inspect page",
7
+ mode: "read",
8
+ input: {},
9
+ agent: { kind: "auto" },
10
+ limits: {},
11
+ };
12
+ const agent = createAgent(request);
13
+ assert.equal(agent.constructor.name, "AutoAgent");
14
+ });
15
+ test("createAgent honors explicit CLIProxy selection", () => {
16
+ const request = {
17
+ goal: "Inspect page",
18
+ mode: "read",
19
+ input: {},
20
+ agent: { kind: "cliproxy" },
21
+ limits: {},
22
+ };
23
+ const agent = createAgent(request);
24
+ assert.equal(agent.constructor.name, "CliProxyAgent");
25
+ });
26
+ //# sourceMappingURL=agent-selection.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-selection.test.js","sourceRoot":"","sources":["../../tests/agent-selection.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGrD,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC5D,MAAM,OAAO,GAAgB;QAC3B,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACvB,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,MAAM,OAAO,GAAgB;QAC3B,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;QAC3B,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,86 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { AutoAgent } from "../src/agents/auto-agent.js";
4
+ test("AutoAgent falls back to OpenCode delegate when CLIProxy probe fails", async () => {
5
+ const calls = [];
6
+ const makeDelegate = (name) => ({
7
+ async init() {
8
+ calls.push(`init:${name}`);
9
+ },
10
+ async nextAction() {
11
+ calls.push(`next:${name}`);
12
+ return { type: "read_page", reason: name };
13
+ },
14
+ async close() {
15
+ calls.push(`close:${name}`);
16
+ },
17
+ debugInfo() {
18
+ return { planner: name, reason: name };
19
+ },
20
+ });
21
+ const request = {
22
+ goal: "Inspect page",
23
+ mode: "read",
24
+ input: {},
25
+ agent: { kind: "auto" },
26
+ limits: {},
27
+ };
28
+ const agent = new AutoAgent(request, {
29
+ probe: async () => ({ ok: false, reason: "unauthorized" }),
30
+ createCliProxy: () => makeDelegate("cliproxy"),
31
+ createOpencode: () => makeDelegate("opencode"),
32
+ });
33
+ await agent.init();
34
+ const action = await agent.nextAction({
35
+ request,
36
+ step: 1,
37
+ maxSteps: 3,
38
+ snapshot: { url: "https://example.com", title: "Example", textPreview: "Example", interactive: [] },
39
+ history: [],
40
+ });
41
+ await agent.close();
42
+ assert.deepEqual(action, { type: "read_page", reason: "opencode" });
43
+ assert.deepEqual(calls, ["init:opencode", "next:opencode", "close:opencode"]);
44
+ });
45
+ test("AutoAgent falls back to OpenCode when CLIProxy is reachable but no model is configured", async () => {
46
+ const calls = [];
47
+ const makeDelegate = (name) => ({
48
+ async init() {
49
+ calls.push(`init:${name}`);
50
+ },
51
+ async nextAction() {
52
+ calls.push(`next:${name}`);
53
+ return { type: "read_page", reason: name };
54
+ },
55
+ async close() {
56
+ calls.push(`close:${name}`);
57
+ },
58
+ debugInfo() {
59
+ return { planner: name, reason: name };
60
+ },
61
+ });
62
+ const request = {
63
+ goal: "Inspect page",
64
+ mode: "read",
65
+ input: {},
66
+ agent: { kind: "auto" },
67
+ limits: {},
68
+ };
69
+ const agent = new AutoAgent(request, {
70
+ probe: async () => ({ ok: true }),
71
+ createCliProxy: () => makeDelegate("cliproxy"),
72
+ createOpencode: () => makeDelegate("opencode"),
73
+ });
74
+ await agent.init();
75
+ const action = await agent.nextAction({
76
+ request,
77
+ step: 1,
78
+ maxSteps: 3,
79
+ snapshot: { url: "https://example.com", title: "Example", textPreview: "Example", interactive: [] },
80
+ history: [],
81
+ });
82
+ await agent.close();
83
+ assert.deepEqual(action, { type: "read_page", reason: "opencode" });
84
+ assert.deepEqual(calls, ["init:opencode", "next:opencode", "close:opencode"]);
85
+ });
86
+ //# sourceMappingURL=auto-agent.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-agent.test.js","sourceRoot":"","sources":["../../tests/auto-agent.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAGxD,IAAI,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;IACrF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,YAAY,GAAG,CAAC,IAAY,EAAgB,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI;YACR,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,KAAK,CAAC,UAAU;YACd,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YAC3B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC7C,CAAC;QACD,KAAK,CAAC,KAAK;YACT,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,SAAS;YACP,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAgB;QAC3B,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACvB,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE;QACnC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;QAC1D,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;QAC9C,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;KAC/C,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC;QACpC,OAAO;QACP,IAAI,EAAE,CAAC;QACP,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,EAAE,GAAG,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE;QACnG,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAEpB,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACpE,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAChF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;IACxG,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,YAAY,GAAG,CAAC,IAAY,EAAgB,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI;YACR,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,KAAK,CAAC,UAAU;YACd,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YAC3B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC7C,CAAC;QACD,KAAK,CAAC,KAAK;YACT,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;QACD,SAAS;YACP,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;KACF,CAAC,CAAC;IAEH,MAAM,OAAO,GAAgB;QAC3B,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACvB,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE;QACnC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACjC,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;QAC9C,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC;KAC/C,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC;QACpC,OAAO;QACP,IAAI,EAAE,CAAC;QACP,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,EAAE,GAAG,EAAE,qBAAqB,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,EAAE;QACnG,OAAO,EAAE,EAAE;KACZ,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAEpB,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IACpE,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAChF,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { BrowserSession, resolveUserDataDir } from "../src/browser/session.js";
6
+ import { startFixtureSite } from "./fixture-site.js";
7
+ test("resolveUserDataDir prefers explicit shared browser dir when provided", async () => {
8
+ const result = await resolveUserDataDir(undefined, "/tmp/existing-chrome-profile");
9
+ assert.deepEqual(result, {
10
+ userDataDir: "/tmp/existing-chrome-profile",
11
+ tempUserDataDir: undefined,
12
+ });
13
+ });
14
+ test("resolveUserDataDir uses named profile directory when profile is passed", async () => {
15
+ const result = await resolveUserDataDir("gmgn", undefined);
16
+ assert.match(result.userDataDir, /profiles\/gmgn\/user-data-dir$/);
17
+ assert.equal(result.tempUserDataDir, undefined);
18
+ });
19
+ test("BrowserSession preserves storage state across launches", async () => {
20
+ const fixture = await startFixtureSite();
21
+ const screenshotsDir = await fs.mkdtemp(path.join("/tmp", "web-task-api-shots-"));
22
+ const storageStatePath = path.join(screenshotsDir, "session.json");
23
+ const first = await BrowserSession.launch({
24
+ headless: true,
25
+ screenshotsDir,
26
+ storageStatePath,
27
+ });
28
+ await first.navigate(`${fixture.url}/seed-session`);
29
+ await first.close();
30
+ const second = await BrowserSession.launch({
31
+ headless: true,
32
+ screenshotsDir,
33
+ storageStatePath,
34
+ });
35
+ await second.navigate(`${fixture.url}/check-session`);
36
+ const snapshot = await second.snapshot();
37
+ await second.close();
38
+ await fixture.close();
39
+ assert.match(snapshot.textPreview, /Session Preserved/);
40
+ });
41
+ //# sourceMappingURL=browser-session.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-session.test.js","sourceRoot":"","sources":["../../tests/browser-session.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,IAAI,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;IACtF,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,SAAS,EAAE,8BAA8B,CAAC,CAAC;IACnF,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE;QACvB,WAAW,EAAE,8BAA8B;QAC3C,eAAe,EAAE,SAAS;KAC3B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;IACxF,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAY,EAAE,gCAAgC,CAAC,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;IACxE,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC;IAClF,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;IAEnE,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC;QACxC,QAAQ,EAAE,IAAI;QACd,cAAc;QACd,gBAAgB;KACjB,CAAC,CAAC;IACH,MAAM,KAAK,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,GAAG,eAAe,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC;QACzC,QAAQ,EAAE,IAAI;QACd,cAAc;QACd,gBAAgB;KACjB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,GAAG,gBAAgB,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IACzC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IAEtB,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;AAC1D,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { WebTaskApiClient } from "../src/client.js";
4
+ test("WebTaskApiClient sends runTask requests", async () => {
5
+ let seenUrl = "";
6
+ let seenBody = "";
7
+ const client = new WebTaskApiClient({
8
+ baseUrl: "http://127.0.0.1:9999",
9
+ fetch: (async (url, init) => {
10
+ seenUrl = String(url);
11
+ seenBody = String(init?.body ?? "");
12
+ return new Response(JSON.stringify({
13
+ taskId: "t1",
14
+ status: "completed",
15
+ goal: "Inspect page",
16
+ mode: "read",
17
+ startedAt: new Date().toISOString(),
18
+ finishedAt: new Date().toISOString(),
19
+ artifactsDir: "/tmp/run",
20
+ steps: [],
21
+ }), { status: 200, headers: { "content-type": "application/json" } });
22
+ }),
23
+ });
24
+ const result = await client.runTask({
25
+ goal: "Inspect page",
26
+ mode: "read",
27
+ input: {},
28
+ agent: { kind: "mock" },
29
+ limits: {},
30
+ });
31
+ assert.equal(seenUrl, "http://127.0.0.1:9999/v1/tasks/run");
32
+ assert.match(seenBody, /Inspect page/);
33
+ assert.equal(result.taskId, "t1");
34
+ });
35
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../tests/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;IACzD,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC;QAClC,OAAO,EAAE,uBAAuB;QAChC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAC1B,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YACtB,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;YACpC,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC;gBACb,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,WAAW;gBACnB,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,MAAM;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACpC,YAAY,EAAE,UAAU;gBACxB,KAAK,EAAE,EAAE;aACV,CAAC,EACF,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,CACjE,CAAC;QACJ,CAAC,CAAiB;KACnB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAClC,IAAI,EAAE,cAAc;QACpB,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACvB,MAAM,EAAE,EAAE;KACX,CAAC,CAAC;IAEH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,oCAAoC,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ type FixtureServer = {
2
+ url: string;
3
+ close: () => Promise<void>;
4
+ };
5
+ export declare function startFixtureSite(): Promise<FixtureServer>;
6
+ export {};
@@ -0,0 +1,93 @@
1
+ import http from "node:http";
2
+ const catalog = {
3
+ banana: { product: "Banana", price: "$1.29", stock: "In stock" },
4
+ apple: { product: "Apple", price: "$0.99", stock: "Low stock" },
5
+ };
6
+ export async function startFixtureSite() {
7
+ const server = http.createServer((req, res) => {
8
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
9
+ res.setHeader("content-type", "text/html; charset=utf-8");
10
+ const cookies = Object.fromEntries((req.headers.cookie ?? "")
11
+ .split(";")
12
+ .map((item) => item.trim())
13
+ .filter(Boolean)
14
+ .map((item) => {
15
+ const [key, ...rest] = item.split("=");
16
+ return [key, rest.join("=")];
17
+ }));
18
+ if (url.pathname === "/seed-session") {
19
+ res.setHeader("set-cookie", "fixture_guest=ready; Path=/; HttpOnly");
20
+ res.end(`<!doctype html>
21
+ <html>
22
+ <head><title>Session Seeded</title></head>
23
+ <body>
24
+ <main>
25
+ <h1>Session Seeded</h1>
26
+ <p>Product: Session Ready</p>
27
+ <p>Price: $0.00</p>
28
+ <p>Stock: Saved</p>
29
+ </main>
30
+ </body>
31
+ </html>`);
32
+ return;
33
+ }
34
+ if (url.pathname === "/check-session") {
35
+ const ready = cookies.fixture_guest === "ready";
36
+ res.end(`<!doctype html>
37
+ <html>
38
+ <head><title>Session Check</title></head>
39
+ <body>
40
+ <main>
41
+ <h1>Session Check</h1>
42
+ ${ready
43
+ ? `<p>Product: Session Preserved</p><p>Price: $9.99</p><p>Stock: Ready</p>`
44
+ : `<p>No preserved guest session found.</p>`}
45
+ </main>
46
+ </body>
47
+ </html>`);
48
+ return;
49
+ }
50
+ if (url.pathname === "/result") {
51
+ const q = (url.searchParams.get("query") ?? "banana").toLowerCase();
52
+ const item = catalog[q] ?? catalog.banana;
53
+ res.end(`<!doctype html>
54
+ <html>
55
+ <head><title>Catalog Result</title></head>
56
+ <body>
57
+ <main>
58
+ <h1>Catalog Result</h1>
59
+ <p>Product: ${item.product}</p>
60
+ <p>Price: ${item.price}</p>
61
+ <p>Stock: ${item.stock}</p>
62
+ <a href="/">Back</a>
63
+ </main>
64
+ </body>
65
+ </html>`);
66
+ return;
67
+ }
68
+ res.end(`<!doctype html>
69
+ <html>
70
+ <head><title>Catalog Search</title></head>
71
+ <body>
72
+ <main>
73
+ <h1>Product Catalog</h1>
74
+ <form action="/result" method="GET">
75
+ <label for="query">Query</label>
76
+ <input id="query" name="query" type="text" placeholder="Search product" />
77
+ <button type="submit">Search</button>
78
+ </form>
79
+ </main>
80
+ </body>
81
+ </html>`);
82
+ });
83
+ await new Promise((resolve) => server.listen(0, "127.0.0.1", () => resolve()));
84
+ const address = server.address();
85
+ if (!address || typeof address === "string") {
86
+ throw new Error("Failed to bind fixture server.");
87
+ }
88
+ return {
89
+ url: `http://127.0.0.1:${address.port}`,
90
+ close: () => new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))),
91
+ };
92
+ }
93
+ //# sourceMappingURL=fixture-site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture-site.js","sourceRoot":"","sources":["../../tests/fixture-site.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,186 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { dirname, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
7
+ import { startFixtureSite } from "./fixture-site.js";
8
+ const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9
+ function createTransport() {
10
+ return new StdioClientTransport({
11
+ command: process.execPath,
12
+ args: ["--import", "tsx", "src/mcp.ts"],
13
+ cwd: projectRoot,
14
+ stderr: "pipe",
15
+ });
16
+ }
17
+ test("MCP server exposes web-task tools", async (t) => {
18
+ const transport = createTransport();
19
+ const stderrChunks = [];
20
+ transport.stderr?.on("data", (chunk) => stderrChunks.push(String(chunk)));
21
+ const client = new Client({ name: "web-task-api-test", version: "0.1.0" });
22
+ await client.connect(transport);
23
+ t.after(async () => {
24
+ await transport.close();
25
+ });
26
+ const result = await client.listTools();
27
+ const toolNames = result.tools.map((tool) => tool.name).sort();
28
+ assert.deepEqual(toolNames, [
29
+ "webtask_create_session",
30
+ "webtask_get_session",
31
+ "webtask_get_task",
32
+ "webtask_health",
33
+ "webtask_list_recipes",
34
+ "webtask_list_sessions",
35
+ "webtask_run",
36
+ "webtask_update_session",
37
+ ]);
38
+ const runTool = result.tools.find((tool) => tool.name === "webtask_run");
39
+ assert.ok(runTool);
40
+ const runProperties = runTool.inputSchema.properties || {};
41
+ assert.ok("session_id" in runProperties);
42
+ assert.ok("recipe_id" in runProperties);
43
+ assert.ok("output_schema" in runProperties);
44
+ assert.equal(stderrChunks.join(""), "");
45
+ });
46
+ test("MCP session tools roundtrip and run a fixture task", async (t) => {
47
+ const fixture = await startFixtureSite();
48
+ const transport = createTransport();
49
+ const client = new Client({ name: "web-task-api-test", version: "0.1.0" });
50
+ await client.connect(transport);
51
+ t.after(async () => {
52
+ await transport.close();
53
+ await fixture.close();
54
+ });
55
+ const created = await client.callTool({
56
+ name: "webtask_create_session",
57
+ arguments: {
58
+ name: "fixture session",
59
+ mode: "guest",
60
+ start_url: fixture.url,
61
+ notes: "Use mock planner on local fixture.",
62
+ agent_kind: "mock",
63
+ },
64
+ });
65
+ const session = created.structuredContent;
66
+ assert.equal(session.name, "fixture session");
67
+ assert.equal(session.mode, "guest");
68
+ const listed = await client.callTool({ name: "webtask_list_sessions", arguments: {} });
69
+ const sessions = listed.structuredContent.sessions;
70
+ assert.ok(sessions.some((item) => item.id === session.id));
71
+ const updated = await client.callTool({
72
+ name: "webtask_update_session",
73
+ arguments: { session_id: session.id, notes: "Updated note" },
74
+ });
75
+ const updatedSession = updated.structuredContent;
76
+ assert.equal(updatedSession.notes, "Updated note");
77
+ const run = await client.callTool({
78
+ name: "webtask_run",
79
+ arguments: {
80
+ session_id: session.id,
81
+ goal: "Search for banana and return product, price, and stock.",
82
+ recipe_id: "fixture-catalog",
83
+ input: { query: "banana" },
84
+ output_schema: {
85
+ type: "object",
86
+ required: ["product", "price", "stock"],
87
+ properties: {
88
+ product: { type: "string" },
89
+ price: { type: "string" },
90
+ stock: { type: "string" },
91
+ },
92
+ },
93
+ agent_kind: "mock",
94
+ },
95
+ });
96
+ const task = run.structuredContent;
97
+ assert.equal(task.status, "completed");
98
+ assert.equal(task.result.product, "Banana");
99
+ assert.equal(task.sessionId, session.id);
100
+ const fetchedTask = await client.callTool({
101
+ name: "webtask_get_task",
102
+ arguments: { task_id: task.taskId },
103
+ });
104
+ const persistedTask = fetchedTask.structuredContent;
105
+ assert.equal(persistedTask.taskId, task.taskId);
106
+ assert.ok(Array.isArray(persistedTask.steps));
107
+ assert.ok(persistedTask.steps.length >= 3);
108
+ const fetchedSession = await client.callTool({
109
+ name: "webtask_get_session",
110
+ arguments: { session_id: session.id },
111
+ });
112
+ const persistedSession = fetchedSession.structuredContent;
113
+ assert.equal(persistedSession.taskCount, 1);
114
+ assert.equal(persistedSession.history[0].taskId, task.taskId);
115
+ });
116
+ test("MCP create session preserves agent_model even when kind is omitted", async (t) => {
117
+ const transport = createTransport();
118
+ const client = new Client({ name: "web-task-api-test", version: "0.1.0" });
119
+ await client.connect(transport);
120
+ t.after(async () => {
121
+ await transport.close();
122
+ });
123
+ const created = await client.callTool({
124
+ name: "webtask_create_session",
125
+ arguments: {
126
+ name: "model only session",
127
+ agent_model: "gpt-5.4",
128
+ },
129
+ });
130
+ const session = created.structuredContent;
131
+ assert.equal(session.agent.kind, "auto");
132
+ assert.equal(session.agent.model, "gpt-5.4");
133
+ });
134
+ test("MCP create session enforces the same guest/profile validation as HTTP", async (t) => {
135
+ const transport = createTransport();
136
+ const client = new Client({ name: "web-task-api-test", version: "0.1.0" });
137
+ await client.connect(transport);
138
+ t.after(async () => {
139
+ await transport.close();
140
+ });
141
+ const badGuest = await client.callTool({
142
+ name: "webtask_create_session",
143
+ arguments: {
144
+ name: "bad guest",
145
+ mode: "guest",
146
+ profile: "axiom",
147
+ },
148
+ });
149
+ assert.equal(badGuest.isError, true);
150
+ assert.match(JSON.stringify(badGuest.content), /guest mode cannot bind a named profile/);
151
+ const missingProfile = await client.callTool({
152
+ name: "webtask_create_session",
153
+ arguments: {
154
+ name: "missing profile",
155
+ mode: "profile",
156
+ },
157
+ });
158
+ assert.equal(missingProfile.isError, true);
159
+ assert.match(JSON.stringify(missingProfile.content), /profile mode requires a bound profile/);
160
+ });
161
+ test("MCP update session rejects rebinding a guest session to a profile", async (t) => {
162
+ const transport = createTransport();
163
+ const client = new Client({ name: "web-task-api-test", version: "0.1.0" });
164
+ await client.connect(transport);
165
+ t.after(async () => {
166
+ await transport.close();
167
+ });
168
+ const created = await client.callTool({
169
+ name: "webtask_create_session",
170
+ arguments: {
171
+ name: "guest session",
172
+ mode: "guest",
173
+ },
174
+ });
175
+ const session = created.structuredContent;
176
+ const updated = await client.callTool({
177
+ name: "webtask_update_session",
178
+ arguments: {
179
+ session_id: session.id,
180
+ profile: "axiom",
181
+ },
182
+ });
183
+ assert.equal(updated.isError, true);
184
+ assert.match(JSON.stringify(updated.content), /Guest sessions cannot be rebound to a named profile/);
185
+ });
186
+ //# sourceMappingURL=mcp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.test.js","sourceRoot":"","sources":["../../tests/mcp.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};