ai-browser 0.2.1 → 0.2.2

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 (76) hide show
  1. package/README.md +76 -7
  2. package/dist/agent/agent-loop.d.ts.map +1 -1
  3. package/dist/agent/agent-loop.js +2 -1
  4. package/dist/agent/agent-loop.js.map +1 -1
  5. package/dist/api/mcp-sse.d.ts.map +1 -1
  6. package/dist/api/mcp-sse.js +26 -8
  7. package/dist/api/mcp-sse.js.map +1 -1
  8. package/dist/api/routes.js +1 -1
  9. package/dist/api/routes.js.map +1 -1
  10. package/dist/browser/index.d.ts +1 -1
  11. package/dist/browser/index.d.ts.map +1 -1
  12. package/dist/cli/mcp-stdio.js +1 -1
  13. package/dist/cli/mcp-stdio.js.map +1 -1
  14. package/dist/mcp/browser-mcp-server.d.ts +6 -9
  15. package/dist/mcp/browser-mcp-server.d.ts.map +1 -1
  16. package/dist/mcp/browser-mcp-server.js +125 -218
  17. package/dist/mcp/browser-mcp-server.js.map +1 -1
  18. package/dist/mcp/task-tools.d.ts +6 -0
  19. package/dist/mcp/task-tools.d.ts.map +1 -0
  20. package/dist/mcp/task-tools.js +303 -0
  21. package/dist/mcp/task-tools.js.map +1 -0
  22. package/dist/task/artifact-store.d.ts +36 -0
  23. package/dist/task/artifact-store.d.ts.map +1 -0
  24. package/dist/task/artifact-store.js +115 -0
  25. package/dist/task/artifact-store.js.map +1 -0
  26. package/dist/task/cancel-token.d.ts +13 -0
  27. package/dist/task/cancel-token.d.ts.map +1 -0
  28. package/dist/task/cancel-token.js +42 -0
  29. package/dist/task/cancel-token.js.map +1 -0
  30. package/dist/task/error-codes.d.ts +19 -0
  31. package/dist/task/error-codes.d.ts.map +1 -0
  32. package/dist/task/error-codes.js +22 -0
  33. package/dist/task/error-codes.js.map +1 -0
  34. package/dist/task/index.d.ts +17 -0
  35. package/dist/task/index.d.ts.map +1 -0
  36. package/dist/task/index.js +10 -0
  37. package/dist/task/index.js.map +1 -0
  38. package/dist/task/run-manager.d.ts +77 -0
  39. package/dist/task/run-manager.d.ts.map +1 -0
  40. package/dist/task/run-manager.js +286 -0
  41. package/dist/task/run-manager.js.map +1 -0
  42. package/dist/task/run-store.d.ts +39 -0
  43. package/dist/task/run-store.d.ts.map +1 -0
  44. package/dist/task/run-store.js +88 -0
  45. package/dist/task/run-store.js.map +1 -0
  46. package/dist/task/templates/batch-extract.d.ts +33 -0
  47. package/dist/task/templates/batch-extract.d.ts.map +1 -0
  48. package/dist/task/templates/batch-extract.js +153 -0
  49. package/dist/task/templates/batch-extract.js.map +1 -0
  50. package/dist/task/templates/login-keep-session.d.ts +34 -0
  51. package/dist/task/templates/login-keep-session.d.ts.map +1 -0
  52. package/dist/task/templates/login-keep-session.js +190 -0
  53. package/dist/task/templates/login-keep-session.js.map +1 -0
  54. package/dist/task/templates/multi-tab-compare.d.ts +43 -0
  55. package/dist/task/templates/multi-tab-compare.d.ts.map +1 -0
  56. package/dist/task/templates/multi-tab-compare.js +204 -0
  57. package/dist/task/templates/multi-tab-compare.js.map +1 -0
  58. package/dist/task/templates/registry.d.ts +13 -0
  59. package/dist/task/templates/registry.d.ts.map +1 -0
  60. package/dist/task/templates/registry.js +40 -0
  61. package/dist/task/templates/registry.js.map +1 -0
  62. package/dist/task/tool-actions.d.ts +114 -0
  63. package/dist/task/tool-actions.d.ts.map +1 -0
  64. package/dist/task/tool-actions.js +371 -0
  65. package/dist/task/tool-actions.js.map +1 -0
  66. package/dist/task/tool-context.d.ts +26 -0
  67. package/dist/task/tool-context.d.ts.map +1 -0
  68. package/dist/task/tool-context.js +2 -0
  69. package/dist/task/tool-context.js.map +1 -0
  70. package/dist/utils/url-validator.d.ts +13 -0
  71. package/dist/utils/url-validator.d.ts.map +1 -1
  72. package/dist/utils/url-validator.js +64 -0
  73. package/dist/utils/url-validator.js.map +1 -1
  74. package/package.json +3 -2
  75. package/public/agent.html +3 -927
  76. package/public/index.html +1910 -664
@@ -0,0 +1,115 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ const MAX_CHUNK_SIZE = 256 * 1024; // 256KB per read
3
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
4
+ const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
5
+ export class ArtifactStore {
6
+ artifacts = new Map();
7
+ runIndex = new Map();
8
+ expirations = new Map();
9
+ cleanupTimer = null;
10
+ ttlMs;
11
+ constructor(ttlMs = DEFAULT_TTL_MS) {
12
+ this.ttlMs = ttlMs;
13
+ this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
14
+ if (this.cleanupTimer.unref)
15
+ this.cleanupTimer.unref();
16
+ }
17
+ save(runId, data, mimeType) {
18
+ const artifactId = randomUUID();
19
+ const buf = typeof data === 'string' ? Buffer.from(data, 'utf-8') : data;
20
+ const meta = {
21
+ artifactId,
22
+ runId,
23
+ mimeType,
24
+ size: buf.length,
25
+ createdAt: Date.now(),
26
+ };
27
+ this.artifacts.set(artifactId, { meta, data: buf });
28
+ // Update run index
29
+ let ids = this.runIndex.get(runId);
30
+ if (!ids) {
31
+ ids = new Set();
32
+ this.runIndex.set(runId, ids);
33
+ }
34
+ ids.add(artifactId);
35
+ return artifactId;
36
+ }
37
+ get(artifactId, offset, limit) {
38
+ const entry = this.artifacts.get(artifactId);
39
+ if (!entry)
40
+ return undefined;
41
+ const { meta, data } = entry;
42
+ const start = Math.min(offset ?? 0, data.length);
43
+ const maxLen = Math.min(limit ?? MAX_CHUNK_SIZE, MAX_CHUNK_SIZE);
44
+ const end = Math.min(start + maxLen, data.length);
45
+ const slice = data.subarray(start, end);
46
+ const isText = meta.mimeType.startsWith('text/') ||
47
+ meta.mimeType === 'application/json';
48
+ return {
49
+ artifactId,
50
+ mimeType: meta.mimeType,
51
+ totalSize: meta.size,
52
+ offset: start,
53
+ length: slice.length,
54
+ data: isText ? slice.toString('utf-8') : slice.toString('base64'),
55
+ complete: end >= data.length,
56
+ };
57
+ }
58
+ getMeta(artifactId) {
59
+ return this.artifacts.get(artifactId)?.meta;
60
+ }
61
+ listByRun(runId) {
62
+ const ids = this.runIndex.get(runId);
63
+ if (!ids)
64
+ return [];
65
+ const result = [];
66
+ for (const id of ids) {
67
+ const entry = this.artifacts.get(id);
68
+ if (entry)
69
+ result.push(entry.meta);
70
+ }
71
+ return result;
72
+ }
73
+ /**
74
+ * Mark artifacts for a run as expiring.
75
+ * Called when the associated run reaches a terminal state.
76
+ */
77
+ markExpiring(runId) {
78
+ const ids = this.runIndex.get(runId);
79
+ if (!ids)
80
+ return;
81
+ const expireAt = Date.now() + this.ttlMs;
82
+ for (const id of ids) {
83
+ this.expirations.set(id, expireAt);
84
+ }
85
+ }
86
+ dispose() {
87
+ if (this.cleanupTimer) {
88
+ clearInterval(this.cleanupTimer);
89
+ this.cleanupTimer = null;
90
+ }
91
+ this.artifacts.clear();
92
+ this.runIndex.clear();
93
+ this.expirations.clear();
94
+ }
95
+ cleanup() {
96
+ const now = Date.now();
97
+ for (const [id, expireAt] of this.expirations) {
98
+ if (now >= expireAt) {
99
+ const entry = this.artifacts.get(id);
100
+ if (entry) {
101
+ const runIds = this.runIndex.get(entry.meta.runId);
102
+ if (runIds) {
103
+ runIds.delete(id);
104
+ if (runIds.size === 0) {
105
+ this.runIndex.delete(entry.meta.runId);
106
+ }
107
+ }
108
+ }
109
+ this.artifacts.delete(id);
110
+ this.expirations.delete(id);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=artifact-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-store.js","sourceRoot":"","sources":["../../src/task/artifact-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Cooperative cancellation primitive.
3
+ * Passed to template executors; checked between steps.
4
+ */
5
+ export declare class CancelToken {
6
+ private _canceled;
7
+ private _listeners;
8
+ get canceled(): boolean;
9
+ cancel(): void;
10
+ onCancel(fn: () => void): void;
11
+ throwIfCanceled(): void;
12
+ }
13
+ //# sourceMappingURL=cancel-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-token.d.ts","sourceRoot":"","sources":["../../src/task/cancel-token.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAyB;IAE3C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,MAAM,IAAI,IAAI;IASd,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI;IAQ9B,eAAe,IAAI,IAAI;CAOxB"}
@@ -0,0 +1,42 @@
1
+ import { ErrorCode } from './error-codes.js';
2
+ /**
3
+ * Cooperative cancellation primitive.
4
+ * Passed to template executors; checked between steps.
5
+ */
6
+ export class CancelToken {
7
+ _canceled = false;
8
+ _listeners = [];
9
+ get canceled() {
10
+ return this._canceled;
11
+ }
12
+ cancel() {
13
+ if (this._canceled)
14
+ return;
15
+ this._canceled = true;
16
+ for (const fn of this._listeners) {
17
+ try {
18
+ fn();
19
+ }
20
+ catch { }
21
+ }
22
+ this._listeners.length = 0;
23
+ }
24
+ onCancel(fn) {
25
+ if (this._canceled) {
26
+ try {
27
+ fn();
28
+ }
29
+ catch { }
30
+ return;
31
+ }
32
+ this._listeners.push(fn);
33
+ }
34
+ throwIfCanceled() {
35
+ if (this._canceled) {
36
+ const err = new Error('Run canceled');
37
+ err.errorCode = ErrorCode.RUN_CANCELED;
38
+ throw err;
39
+ }
40
+ }
41
+ }
42
+ //# sourceMappingURL=cancel-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-token.js","sourceRoot":"","sources":["../../src/task/cancel-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C;;;GAGG;AACH,MAAM,OAAO,WAAW;IACd,SAAS,GAAG,KAAK,CAAC;IAClB,UAAU,GAAsB,EAAE,CAAC;IAE3C,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACjC,IAAI,CAAC;gBAAC,EAAE,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,QAAQ,CAAC,EAAc;QACrB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC;gBAAC,EAAE,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACtB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;YACrC,GAAW,CAAC,SAAS,GAAG,SAAS,CAAC,YAAY,CAAC;YAChD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ export declare enum ErrorCode {
2
+ ELEMENT_NOT_FOUND = "ELEMENT_NOT_FOUND",
3
+ NAVIGATION_TIMEOUT = "NAVIGATION_TIMEOUT",
4
+ SESSION_NOT_FOUND = "SESSION_NOT_FOUND",
5
+ PAGE_CRASHED = "PAGE_CRASHED",
6
+ INVALID_PARAMETER = "INVALID_PARAMETER",
7
+ EXECUTION_ERROR = "EXECUTION_ERROR",
8
+ TEMPLATE_NOT_FOUND = "TEMPLATE_NOT_FOUND",
9
+ RUN_NOT_FOUND = "RUN_NOT_FOUND",
10
+ RUN_TIMEOUT = "RUN_TIMEOUT",
11
+ RUN_CANCELED = "RUN_CANCELED",
12
+ STEP_EXECUTION_FAILED = "STEP_EXECUTION_FAILED",
13
+ TRUST_LEVEL_NOT_ALLOWED = "TRUST_LEVEL_NOT_ALLOWED",
14
+ TEMPLATE_VERSION_UNSUPPORTED = "TEMPLATE_VERSION_UNSUPPORTED",
15
+ ARTIFACT_NOT_FOUND = "ARTIFACT_NOT_FOUND",
16
+ ARTIFACT_EXPIRED = "ARTIFACT_EXPIRED",
17
+ TPL_LOGIN_FIELD_NOT_FOUND = "TPL_LOGIN_FIELD_NOT_FOUND"
18
+ }
19
+ //# sourceMappingURL=error-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../../src/task/error-codes.ts"],"names":[],"mappings":"AACA,oBAAY,SAAS;IACnB,iBAAiB,sBAAsB;IACvC,kBAAkB,uBAAuB;IACzC,iBAAiB,sBAAsB;IACvC,YAAY,iBAAiB;IAC7B,iBAAiB,sBAAsB;IACvC,eAAe,oBAAoB;IACnC,kBAAkB,uBAAuB;IACzC,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAE3B,YAAY,iBAAiB;IAC7B,qBAAqB,0BAA0B;IAC/C,uBAAuB,4BAA4B;IACnD,4BAA4B,iCAAiC;IAC7D,kBAAkB,uBAAuB;IACzC,gBAAgB,qBAAqB;IACrC,yBAAyB,8BAA8B;CACxD"}
@@ -0,0 +1,22 @@
1
+ // Structured error codes for Agent consumption
2
+ export var ErrorCode;
3
+ (function (ErrorCode) {
4
+ ErrorCode["ELEMENT_NOT_FOUND"] = "ELEMENT_NOT_FOUND";
5
+ ErrorCode["NAVIGATION_TIMEOUT"] = "NAVIGATION_TIMEOUT";
6
+ ErrorCode["SESSION_NOT_FOUND"] = "SESSION_NOT_FOUND";
7
+ ErrorCode["PAGE_CRASHED"] = "PAGE_CRASHED";
8
+ ErrorCode["INVALID_PARAMETER"] = "INVALID_PARAMETER";
9
+ ErrorCode["EXECUTION_ERROR"] = "EXECUTION_ERROR";
10
+ ErrorCode["TEMPLATE_NOT_FOUND"] = "TEMPLATE_NOT_FOUND";
11
+ ErrorCode["RUN_NOT_FOUND"] = "RUN_NOT_FOUND";
12
+ ErrorCode["RUN_TIMEOUT"] = "RUN_TIMEOUT";
13
+ // v0.2 additions
14
+ ErrorCode["RUN_CANCELED"] = "RUN_CANCELED";
15
+ ErrorCode["STEP_EXECUTION_FAILED"] = "STEP_EXECUTION_FAILED";
16
+ ErrorCode["TRUST_LEVEL_NOT_ALLOWED"] = "TRUST_LEVEL_NOT_ALLOWED";
17
+ ErrorCode["TEMPLATE_VERSION_UNSUPPORTED"] = "TEMPLATE_VERSION_UNSUPPORTED";
18
+ ErrorCode["ARTIFACT_NOT_FOUND"] = "ARTIFACT_NOT_FOUND";
19
+ ErrorCode["ARTIFACT_EXPIRED"] = "ARTIFACT_EXPIRED";
20
+ ErrorCode["TPL_LOGIN_FIELD_NOT_FOUND"] = "TPL_LOGIN_FIELD_NOT_FOUND";
21
+ })(ErrorCode || (ErrorCode = {}));
22
+ //# sourceMappingURL=error-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../../src/task/error-codes.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,CAAN,IAAY,SAkBX;AAlBD,WAAY,SAAS;IACnB,oDAAuC,CAAA;IACvC,sDAAyC,CAAA;IACzC,oDAAuC,CAAA;IACvC,0CAA6B,CAAA;IAC7B,oDAAuC,CAAA;IACvC,gDAAmC,CAAA;IACnC,sDAAyC,CAAA;IACzC,4CAA+B,CAAA;IAC/B,wCAA2B,CAAA;IAC3B,iBAAiB;IACjB,0CAA6B,CAAA;IAC7B,4DAA+C,CAAA;IAC/C,gEAAmD,CAAA;IACnD,0EAA6D,CAAA;IAC7D,sDAAyC,CAAA;IACzC,kDAAqC,CAAA;IACrC,oEAAuD,CAAA;AACzD,CAAC,EAlBW,SAAS,KAAT,SAAS,QAkBpB"}
@@ -0,0 +1,17 @@
1
+ export type { ToolContext, TrustLevel } from './tool-context.js';
2
+ export * as toolActions from './tool-actions.js';
3
+ export { ErrorCode } from './error-codes.js';
4
+ export { CancelToken } from './cancel-token.js';
5
+ export { RunManager } from './run-manager.js';
6
+ export type { RunState, RunStatus, RunManagerOptions } from './run-manager.js';
7
+ export { ArtifactStore } from './artifact-store.js';
8
+ export type { ArtifactMeta, ArtifactChunk } from './artifact-store.js';
9
+ export { getTemplate, listTemplates } from './templates/registry.js';
10
+ export type { TemplateMeta } from './templates/registry.js';
11
+ export { executeBatchExtract } from './templates/batch-extract.js';
12
+ export type { BatchExtractInputs, BatchExtractResult } from './templates/batch-extract.js';
13
+ export { executeLoginKeepSession, LOGIN_TOTAL_STEPS } from './templates/login-keep-session.js';
14
+ export type { LoginKeepSessionInputs, LoginKeepSessionResult } from './templates/login-keep-session.js';
15
+ export { executeMultiTabCompare } from './templates/multi-tab-compare.js';
16
+ export type { MultiTabCompareInputs, MultiTabCompareResult } from './templates/multi-tab-compare.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/F,YAAY,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * as toolActions from './tool-actions.js';
2
+ export { ErrorCode } from './error-codes.js';
3
+ export { CancelToken } from './cancel-token.js';
4
+ export { RunManager } from './run-manager.js';
5
+ export { ArtifactStore } from './artifact-store.js';
6
+ export { getTemplate, listTemplates } from './templates/registry.js';
7
+ export { executeBatchExtract } from './templates/batch-extract.js';
8
+ export { executeLoginKeepSession, LOGIN_TOTAL_STEPS } from './templates/login-keep-session.js';
9
+ export { executeMultiTabCompare } from './templates/multi-tab-compare.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/task/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAErE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { CancelToken } from './cancel-token.js';
2
+ export type RunStatus = 'queued' | 'running' | 'succeeded' | 'failed' | 'partial_success' | 'canceled';
3
+ export interface RunState {
4
+ runId: string;
5
+ templateId: string;
6
+ status: RunStatus;
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ sessionId: string;
10
+ ownsSession: boolean;
11
+ progress: {
12
+ totalSteps: number;
13
+ doneSteps: number;
14
+ };
15
+ metrics: {
16
+ elapsedMs: number;
17
+ };
18
+ result?: any;
19
+ error?: {
20
+ errorCode: string;
21
+ message: string;
22
+ details?: any;
23
+ };
24
+ artifactIds: string[];
25
+ }
26
+ export interface RunManagerOptions {
27
+ ttlMs?: number;
28
+ maxConcurrentRuns?: number;
29
+ }
30
+ type TerminalHook = (run: RunState) => void | Promise<void>;
31
+ export declare class RunManager {
32
+ private runs;
33
+ private tokens;
34
+ private timers;
35
+ private terminalHooks;
36
+ private cleanupTimer;
37
+ private ttlMs;
38
+ private semaphore;
39
+ constructor(opts?: RunManagerOptions);
40
+ /**
41
+ * Submit a run for execution.
42
+ * In sync mode, awaits the executor and returns the result inline.
43
+ * In async mode, fires the executor and returns immediately with runId.
44
+ */
45
+ submit(templateId: string, sessionId: string, ownsSession: boolean, totalSteps: number, executor: (runId: string, token: CancelToken, onProgress: (done: number) => void) => Promise<any>, opts: {
46
+ timeoutMs?: number;
47
+ mode: 'sync' | 'async';
48
+ onTerminal?: TerminalHook;
49
+ }): Promise<{
50
+ runId: string;
51
+ syncResult?: any;
52
+ }>;
53
+ get(runId: string): RunState | undefined;
54
+ cancel(runId: string): boolean;
55
+ list(filter?: {
56
+ status?: RunStatus;
57
+ templateId?: string;
58
+ limit?: number;
59
+ offset?: number;
60
+ }): RunState[];
61
+ count(filter?: {
62
+ status?: RunStatus;
63
+ templateId?: string;
64
+ }): number;
65
+ attachArtifact(runId: string, artifactId: string): void;
66
+ dispose(): void;
67
+ private createRun;
68
+ private transition;
69
+ private updateProgress;
70
+ private executeRun;
71
+ private fireTerminalHook;
72
+ private determineStatus;
73
+ private filterRuns;
74
+ private cleanup;
75
+ }
76
+ export {};
77
+ //# sourceMappingURL=run-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-manager.d.ts","sourceRoot":"","sources":["../../src/task/run-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,UAAU,CAAC;AAMvG,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAsCD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,KAAK,YAAY,GAAG,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5D,qBAAa,UAAU;IACrB,OAAO,CAAC,IAAI,CAA+B;IAC3C,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,MAAM,CAAoD;IAClE,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAY;gBAEjB,IAAI,CAAC,EAAE,iBAAiB;IAOpC;;;;OAIG;IACG,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,OAAO,EACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CACR,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,KAC/B,OAAO,CAAC,GAAG,CAAC,EACjB,IAAI,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,YAAY,CAAA;KAAE,GAC9E,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAkB/C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIxC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAa9B,IAAI,CAAC,MAAM,CAAC,EAAE;QACZ,MAAM,CAAC,EAAE,SAAS,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,QAAQ,EAAE;IAOd,KAAK,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,SAAS,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAInE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAOvD,OAAO,IAAI,IAAI;IAmBf,OAAO,CAAC,SAAS;IAuBjB,OAAO,CAAC,UAAU;IAkBlB,OAAO,CAAC,cAAc;YAOR,UAAU;YAiFV,gBAAgB;IAiB9B,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,OAAO;CAehB"}
@@ -0,0 +1,286 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { CancelToken } from './cancel-token.js';
3
+ import { ErrorCode } from './error-codes.js';
4
+ const TERMINAL_STATUSES = new Set([
5
+ 'succeeded', 'failed', 'partial_success', 'canceled',
6
+ ]);
7
+ // ===== Semaphore for concurrency control =====
8
+ class Semaphore {
9
+ _count;
10
+ _waiters = [];
11
+ constructor(max) {
12
+ this._count = max;
13
+ }
14
+ async acquire() {
15
+ if (this._count > 0) {
16
+ this._count--;
17
+ return;
18
+ }
19
+ return new Promise((resolve) => {
20
+ this._waiters.push(resolve);
21
+ });
22
+ }
23
+ release() {
24
+ const next = this._waiters.shift();
25
+ if (next) {
26
+ next();
27
+ }
28
+ else {
29
+ this._count++;
30
+ }
31
+ }
32
+ }
33
+ // ===== RunManager =====
34
+ const DEFAULT_TTL_MS = 30 * 60 * 1000; // 30 minutes
35
+ const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
36
+ const DEFAULT_MAX_CONCURRENT = 5;
37
+ export class RunManager {
38
+ runs = new Map();
39
+ tokens = new Map();
40
+ timers = new Map();
41
+ terminalHooks = new Map();
42
+ cleanupTimer = null;
43
+ ttlMs;
44
+ semaphore;
45
+ constructor(opts) {
46
+ this.ttlMs = opts?.ttlMs ?? DEFAULT_TTL_MS;
47
+ this.semaphore = new Semaphore(opts?.maxConcurrentRuns ?? DEFAULT_MAX_CONCURRENT);
48
+ this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
49
+ if (this.cleanupTimer.unref)
50
+ this.cleanupTimer.unref();
51
+ }
52
+ /**
53
+ * Submit a run for execution.
54
+ * In sync mode, awaits the executor and returns the result inline.
55
+ * In async mode, fires the executor and returns immediately with runId.
56
+ */
57
+ async submit(templateId, sessionId, ownsSession, totalSteps, executor, opts) {
58
+ const run = this.createRun(templateId, sessionId, ownsSession, totalSteps);
59
+ const token = new CancelToken();
60
+ this.tokens.set(run.runId, token);
61
+ if (opts.onTerminal) {
62
+ this.terminalHooks.set(run.runId, opts.onTerminal);
63
+ }
64
+ if (opts.mode === 'sync') {
65
+ const result = await this.executeRun(run.runId, executor, token, opts.timeoutMs);
66
+ return { runId: run.runId, syncResult: result };
67
+ }
68
+ // Async: fire-and-forget
69
+ this.executeRun(run.runId, executor, token, opts.timeoutMs).catch(() => { });
70
+ return { runId: run.runId };
71
+ }
72
+ get(runId) {
73
+ return this.runs.get(runId);
74
+ }
75
+ cancel(runId) {
76
+ const run = this.runs.get(runId);
77
+ if (!run)
78
+ return false;
79
+ if (TERMINAL_STATUSES.has(run.status))
80
+ return false;
81
+ const token = this.tokens.get(runId);
82
+ if (token)
83
+ token.cancel();
84
+ this.transition(runId, 'canceled');
85
+ run.error = { errorCode: ErrorCode.RUN_CANCELED, message: 'Run canceled by user' };
86
+ return true;
87
+ }
88
+ list(filter) {
89
+ const results = this.filterRuns(filter);
90
+ const offset = filter?.offset ?? 0;
91
+ const limit = filter?.limit ?? 50;
92
+ return results.slice(offset, offset + limit);
93
+ }
94
+ count(filter) {
95
+ return this.filterRuns(filter).length;
96
+ }
97
+ attachArtifact(runId, artifactId) {
98
+ const run = this.runs.get(runId);
99
+ if (!run)
100
+ return;
101
+ run.artifactIds.push(artifactId);
102
+ run.updatedAt = Date.now();
103
+ }
104
+ dispose() {
105
+ if (this.cleanupTimer) {
106
+ clearInterval(this.cleanupTimer);
107
+ this.cleanupTimer = null;
108
+ }
109
+ for (const timer of this.timers.values()) {
110
+ clearTimeout(timer);
111
+ }
112
+ this.timers.clear();
113
+ for (const token of this.tokens.values()) {
114
+ token.cancel();
115
+ }
116
+ this.tokens.clear();
117
+ this.terminalHooks.clear();
118
+ this.runs.clear();
119
+ }
120
+ // --- Internal helpers ---
121
+ createRun(templateId, sessionId, ownsSession, totalSteps) {
122
+ const now = Date.now();
123
+ const run = {
124
+ runId: randomUUID(),
125
+ templateId,
126
+ status: 'queued',
127
+ createdAt: now,
128
+ updatedAt: now,
129
+ sessionId,
130
+ ownsSession,
131
+ progress: { totalSteps, doneSteps: 0 },
132
+ metrics: { elapsedMs: 0 },
133
+ artifactIds: [],
134
+ };
135
+ this.runs.set(run.runId, run);
136
+ return run;
137
+ }
138
+ transition(runId, status) {
139
+ const run = this.runs.get(runId);
140
+ if (!run)
141
+ return;
142
+ if (TERMINAL_STATUSES.has(run.status))
143
+ return;
144
+ run.status = status;
145
+ run.updatedAt = Date.now();
146
+ if (TERMINAL_STATUSES.has(status)) {
147
+ run.metrics.elapsedMs = run.updatedAt - run.createdAt;
148
+ // Cleanup token and timer
149
+ this.tokens.delete(runId);
150
+ const timer = this.timers.get(runId);
151
+ if (timer) {
152
+ clearTimeout(timer);
153
+ this.timers.delete(runId);
154
+ }
155
+ }
156
+ }
157
+ updateProgress(runId, doneSteps) {
158
+ const run = this.runs.get(runId);
159
+ if (!run || TERMINAL_STATUSES.has(run.status))
160
+ return;
161
+ run.progress.doneSteps = doneSteps;
162
+ run.updatedAt = Date.now();
163
+ }
164
+ async executeRun(runId, executor, token, timeoutMs) {
165
+ // Acquire semaphore slot
166
+ await this.semaphore.acquire();
167
+ try {
168
+ // Check if canceled while waiting for semaphore
169
+ if (token.canceled) {
170
+ this.transition(runId, 'canceled');
171
+ return undefined;
172
+ }
173
+ this.transition(runId, 'running');
174
+ // Setup timeout
175
+ const timeout = Math.min(timeoutMs ?? 300_000, 600_000);
176
+ const timeoutTimer = setTimeout(() => {
177
+ const run = this.runs.get(runId);
178
+ if (run && run.status === 'running') {
179
+ token.cancel();
180
+ run.error = {
181
+ errorCode: ErrorCode.RUN_TIMEOUT,
182
+ message: 'Execution timed out',
183
+ };
184
+ this.transition(runId, 'failed');
185
+ }
186
+ }, timeout);
187
+ this.timers.set(runId, timeoutTimer);
188
+ // Execute
189
+ const result = await executor(runId, token, (done) => this.updateProgress(runId, done));
190
+ // Check if already transitioned (timeout/cancel)
191
+ const run = this.runs.get(runId);
192
+ if (!run) {
193
+ return undefined;
194
+ }
195
+ if (TERMINAL_STATUSES.has(run.status)) {
196
+ // Preserve partial results even if status has already been finalized.
197
+ if (run.result === undefined && result !== undefined) {
198
+ run.result = result;
199
+ }
200
+ return run.result;
201
+ }
202
+ // Determine final status from result
203
+ run.result = result;
204
+ const status = this.determineStatus(result);
205
+ this.transition(runId, status);
206
+ return result;
207
+ }
208
+ catch (err) {
209
+ const run = this.runs.get(runId);
210
+ if (run && TERMINAL_STATUSES.has(run.status)) {
211
+ return run.result;
212
+ }
213
+ if (run && !TERMINAL_STATUSES.has(run.status)) {
214
+ run.error = {
215
+ errorCode: err.errorCode ?? ErrorCode.EXECUTION_ERROR,
216
+ message: err.message || 'Execution failed',
217
+ };
218
+ this.transition(runId, 'failed');
219
+ }
220
+ throw err;
221
+ }
222
+ finally {
223
+ this.semaphore.release();
224
+ await this.fireTerminalHook(runId);
225
+ }
226
+ }
227
+ async fireTerminalHook(runId) {
228
+ const run = this.runs.get(runId);
229
+ if (!run || !TERMINAL_STATUSES.has(run.status)) {
230
+ return;
231
+ }
232
+ const hook = this.terminalHooks.get(runId);
233
+ if (!hook) {
234
+ return;
235
+ }
236
+ this.terminalHooks.delete(runId);
237
+ try {
238
+ await hook(run);
239
+ }
240
+ catch {
241
+ // Ignore terminal hook failures to avoid masking run status.
242
+ }
243
+ }
244
+ determineStatus(result) {
245
+ if (result?.summary && typeof result.summary.succeeded === 'number' && typeof result.summary.total === 'number') {
246
+ const { succeeded, total } = result.summary;
247
+ if (succeeded === total)
248
+ return 'succeeded';
249
+ if (total > 0 && succeeded / total >= 0.5)
250
+ return 'partial_success';
251
+ return 'failed';
252
+ }
253
+ if (typeof result?.success === 'boolean') {
254
+ return result.success ? 'succeeded' : 'failed';
255
+ }
256
+ return 'succeeded';
257
+ }
258
+ filterRuns(filter) {
259
+ let results = Array.from(this.runs.values());
260
+ if (filter?.status) {
261
+ results = results.filter((r) => r.status === filter.status);
262
+ }
263
+ if (filter?.templateId) {
264
+ results = results.filter((r) => r.templateId === filter.templateId);
265
+ }
266
+ // Sort by createdAt descending (newest first)
267
+ results.sort((a, b) => b.createdAt - a.createdAt);
268
+ return results;
269
+ }
270
+ cleanup() {
271
+ const now = Date.now();
272
+ for (const [id, run] of this.runs) {
273
+ if (TERMINAL_STATUSES.has(run.status) && now - run.updatedAt > this.ttlMs) {
274
+ this.runs.delete(id);
275
+ this.tokens.delete(id);
276
+ this.terminalHooks.delete(id);
277
+ const timer = this.timers.get(id);
278
+ if (timer) {
279
+ clearTimeout(timer);
280
+ this.timers.delete(id);
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ //# sourceMappingURL=run-manager.js.map