@isoldex/sentinel 0.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +368 -62
  2. package/dist/__tests__/action-engine.test.d.ts +2 -0
  3. package/dist/__tests__/action-engine.test.d.ts.map +1 -0
  4. package/dist/__tests__/action-engine.test.js +144 -0
  5. package/dist/__tests__/action-engine.test.js.map +1 -0
  6. package/dist/__tests__/state-parser.test.d.ts +2 -0
  7. package/dist/__tests__/state-parser.test.d.ts.map +1 -0
  8. package/dist/__tests__/state-parser.test.js +176 -0
  9. package/dist/__tests__/state-parser.test.js.map +1 -0
  10. package/dist/__tests__/verifier.test.d.ts +2 -0
  11. package/dist/__tests__/verifier.test.d.ts.map +1 -0
  12. package/dist/__tests__/verifier.test.js +68 -0
  13. package/dist/__tests__/verifier.test.js.map +1 -0
  14. package/dist/__tests__/workflow-recorder.test.d.ts +2 -0
  15. package/dist/__tests__/workflow-recorder.test.d.ts.map +1 -0
  16. package/dist/__tests__/workflow-recorder.test.js +71 -0
  17. package/dist/__tests__/workflow-recorder.test.js.map +1 -0
  18. package/dist/agent/agent-loop.d.ts +36 -0
  19. package/dist/agent/agent-loop.d.ts.map +1 -0
  20. package/dist/agent/agent-loop.js +127 -0
  21. package/dist/agent/agent-loop.js.map +1 -0
  22. package/dist/agent/memory.d.ts +24 -0
  23. package/dist/agent/memory.d.ts.map +1 -0
  24. package/dist/agent/memory.js +34 -0
  25. package/dist/agent/memory.js.map +1 -0
  26. package/dist/agent/planner.d.ts +18 -0
  27. package/dist/agent/planner.d.ts.map +1 -0
  28. package/dist/agent/planner.js +68 -0
  29. package/dist/agent/planner.js.map +1 -0
  30. package/dist/api/act.d.ts +4 -2
  31. package/dist/api/act.d.ts.map +1 -1
  32. package/dist/api/act.js +174 -30
  33. package/dist/api/act.js.map +1 -1
  34. package/dist/api/extract.d.ts +2 -3
  35. package/dist/api/extract.d.ts.map +1 -1
  36. package/dist/api/extract.js +0 -1
  37. package/dist/api/extract.js.map +1 -1
  38. package/dist/api/observe.d.ts +2 -2
  39. package/dist/api/observe.d.ts.map +1 -1
  40. package/dist/api/observe.js +0 -1
  41. package/dist/api/observe.js.map +1 -1
  42. package/dist/core/driver.d.ts +21 -1
  43. package/dist/core/driver.d.ts.map +1 -1
  44. package/dist/core/driver.js +109 -19
  45. package/dist/core/driver.js.map +1 -1
  46. package/dist/core/state-parser.d.ts +1 -0
  47. package/dist/core/state-parser.d.ts.map +1 -1
  48. package/dist/core/state-parser.js +60 -0
  49. package/dist/core/state-parser.js.map +1 -1
  50. package/dist/core/vision-grounding.d.ts +36 -0
  51. package/dist/core/vision-grounding.d.ts.map +1 -0
  52. package/dist/core/vision-grounding.js +118 -0
  53. package/dist/core/vision-grounding.js.map +1 -0
  54. package/dist/index.d.ts +111 -2
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +168 -4
  57. package/dist/index.js.map +1 -1
  58. package/dist/recorder/workflow-recorder.d.ts +30 -0
  59. package/dist/recorder/workflow-recorder.d.ts.map +1 -0
  60. package/dist/recorder/workflow-recorder.js +83 -0
  61. package/dist/recorder/workflow-recorder.js.map +1 -0
  62. package/dist/reliability/verifier.d.ts +2 -2
  63. package/dist/reliability/verifier.d.ts.map +1 -1
  64. package/dist/reliability/verifier.js +0 -1
  65. package/dist/reliability/verifier.js.map +1 -1
  66. package/dist/types/errors.d.ts +45 -0
  67. package/dist/types/errors.d.ts.map +1 -0
  68. package/dist/types/errors.js +69 -0
  69. package/dist/types/errors.js.map +1 -0
  70. package/dist/utils/gemini.d.ts +3 -6
  71. package/dist/utils/gemini.d.ts.map +1 -1
  72. package/dist/utils/gemini.js +9 -94
  73. package/dist/utils/gemini.js.map +1 -1
  74. package/dist/utils/llm-provider.d.ts +28 -0
  75. package/dist/utils/llm-provider.d.ts.map +1 -0
  76. package/dist/utils/llm-provider.js +2 -0
  77. package/dist/utils/llm-provider.js.map +1 -0
  78. package/dist/utils/providers/claude-provider.d.ts +17 -0
  79. package/dist/utils/providers/claude-provider.d.ts.map +1 -0
  80. package/dist/utils/providers/claude-provider.js +49 -0
  81. package/dist/utils/providers/claude-provider.js.map +1 -0
  82. package/dist/utils/providers/gemini-provider.d.ts +14 -0
  83. package/dist/utils/providers/gemini-provider.d.ts.map +1 -0
  84. package/dist/utils/providers/gemini-provider.js +95 -0
  85. package/dist/utils/providers/gemini-provider.js.map +1 -0
  86. package/dist/utils/providers/ollama-provider.d.ts +18 -0
  87. package/dist/utils/providers/ollama-provider.d.ts.map +1 -0
  88. package/dist/utils/providers/ollama-provider.js +62 -0
  89. package/dist/utils/providers/ollama-provider.js.map +1 -0
  90. package/dist/utils/providers/openai-provider.d.ts +18 -0
  91. package/dist/utils/providers/openai-provider.d.ts.map +1 -0
  92. package/dist/utils/providers/openai-provider.js +51 -0
  93. package/dist/utils/providers/openai-provider.js.map +1 -0
  94. package/dist/utils/token-tracker.d.ts +25 -0
  95. package/dist/utils/token-tracker.d.ts.map +1 -0
  96. package/dist/utils/token-tracker.js +45 -0
  97. package/dist/utils/token-tracker.js.map +1 -0
  98. package/dist/whatsapp-test.js +58 -17
  99. package/dist/whatsapp-test.js.map +1 -1
  100. package/package.json +10 -4
@@ -0,0 +1,176 @@
1
+ import { jest, describe, it, expect } from '@jest/globals';
2
+ import { StateParser } from '../core/state-parser.js';
3
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
4
+ function makeNode(role, name, backendDOMNodeId = 1, ignored = false) {
5
+ return {
6
+ role: { value: role },
7
+ name: { value: name },
8
+ description: { value: '' },
9
+ backendDOMNodeId,
10
+ ignored,
11
+ properties: [],
12
+ };
13
+ }
14
+ function makeBoxModel(x = 10, y = 20, width = 100, height = 30) {
15
+ return {
16
+ model: {
17
+ // CDP box model: [x0,y0, x1,y0, x1,y1, x0,y1] (8 values)
18
+ content: [x, y, x + width, y, x + width, y + height, x, y + height],
19
+ },
20
+ };
21
+ }
22
+ function makeMockCDP(nodes, boxModels) {
23
+ return {
24
+ send: jest.fn(async (method, params) => {
25
+ if (method === 'Accessibility.getFullAXTree')
26
+ return { nodes };
27
+ if (method === 'DOM.getBoxModel') {
28
+ const idx = nodes.findIndex((n) => n.backendDOMNodeId === params?.backendNodeId);
29
+ return boxModels[idx] ?? makeBoxModel();
30
+ }
31
+ return {};
32
+ }),
33
+ };
34
+ }
35
+ function makeMockPage(url = 'https://example.com', title = 'Example') {
36
+ return {
37
+ url: () => url,
38
+ title: jest.fn(async () => title),
39
+ evaluate: jest.fn(async () => []),
40
+ };
41
+ }
42
+ // ─── Tests ────────────────────────────────────────────────────────────────────
43
+ describe('StateParser', () => {
44
+ it('returns url and title from page', async () => {
45
+ const nodes = [makeNode('button', 'Submit', 1)];
46
+ const cdp = makeMockCDP(nodes, [makeBoxModel()]);
47
+ const page = makeMockPage('https://test.com', 'Test Page');
48
+ const parser = new StateParser(page, cdp);
49
+ const state = await parser.parse();
50
+ expect(state.url).toBe('https://test.com');
51
+ expect(state.title).toBe('Test Page');
52
+ });
53
+ it('parses interactive button element correctly', async () => {
54
+ const nodes = [makeNode('button', 'Login', 42)];
55
+ const cdp = makeMockCDP(nodes, [makeBoxModel(5, 10, 80, 25)]);
56
+ const page = makeMockPage();
57
+ const parser = new StateParser(page, cdp);
58
+ const state = await parser.parse();
59
+ expect(state.elements).toHaveLength(1);
60
+ const el = state.elements[0];
61
+ expect(el.role).toBe('button');
62
+ expect(el.name).toBe('Login');
63
+ expect(el.boundingClientRect.x).toBe(5);
64
+ expect(el.boundingClientRect.y).toBe(10);
65
+ expect(el.boundingClientRect.width).toBe(80);
66
+ expect(el.boundingClientRect.height).toBe(25);
67
+ });
68
+ it('filters out non-interactive roles', async () => {
69
+ const nodes = [
70
+ makeNode('generic', 'Some div', 1),
71
+ makeNode('heading', 'Title', 2),
72
+ makeNode('link', 'Click me', 3),
73
+ ];
74
+ const cdp = makeMockCDP(nodes, [makeBoxModel(), makeBoxModel(), makeBoxModel()]);
75
+ const page = makeMockPage();
76
+ const parser = new StateParser(page, cdp);
77
+ const state = await parser.parse();
78
+ // Only 'link' is interactive
79
+ expect(state.elements).toHaveLength(1);
80
+ expect(state.elements[0].role).toBe('link');
81
+ });
82
+ it('filters out ignored nodes', async () => {
83
+ const nodes = [
84
+ makeNode('button', 'Hidden', 1, true), // ignored = true
85
+ makeNode('button', 'Visible', 2, false),
86
+ ];
87
+ const cdp = makeMockCDP(nodes, [makeBoxModel(), makeBoxModel()]);
88
+ const page = makeMockPage();
89
+ const parser = new StateParser(page, cdp);
90
+ const state = await parser.parse();
91
+ expect(state.elements).toHaveLength(1);
92
+ expect(state.elements[0].name).toBe('Visible');
93
+ });
94
+ it('filters out nameless non-textbox elements', async () => {
95
+ const nodes = [
96
+ makeNode('button', '', 1), // no name → filtered
97
+ makeNode('textbox', '', 2), // textbox without name → kept
98
+ ];
99
+ const cdp = makeMockCDP(nodes, [makeBoxModel(), makeBoxModel()]);
100
+ const page = makeMockPage();
101
+ const parser = new StateParser(page, cdp);
102
+ const state = await parser.parse();
103
+ expect(state.elements).toHaveLength(1);
104
+ expect(state.elements[0].role).toBe('textbox');
105
+ });
106
+ it('uses description as fallback name', async () => {
107
+ const node = {
108
+ role: { value: 'button' },
109
+ name: { value: '' },
110
+ description: { value: 'Close dialog' },
111
+ backendDOMNodeId: 1,
112
+ ignored: false,
113
+ properties: [],
114
+ };
115
+ const cdp = makeMockCDP([node], [makeBoxModel()]);
116
+ const page = makeMockPage();
117
+ const parser = new StateParser(page, cdp);
118
+ const state = await parser.parse();
119
+ expect(state.elements[0].name).toBe('Close dialog');
120
+ });
121
+ it('caches state within TTL', async () => {
122
+ const nodes = [makeNode('button', 'OK', 1)];
123
+ const cdp = makeMockCDP(nodes, [makeBoxModel()]);
124
+ const page = makeMockPage();
125
+ const parser = new StateParser(page, cdp);
126
+ await parser.parse();
127
+ await parser.parse(); // second call – should use cache
128
+ // CDP.send for getFullAXTree should only be called once
129
+ const axCalls = cdp.send.mock.calls.filter((c) => c[0] === 'Accessibility.getFullAXTree');
130
+ expect(axCalls).toHaveLength(1);
131
+ });
132
+ it('invalidateCache forces fresh parse', async () => {
133
+ const nodes = [makeNode('button', 'OK', 1)];
134
+ const cdp = makeMockCDP(nodes, [makeBoxModel()]);
135
+ const page = makeMockPage();
136
+ const parser = new StateParser(page, cdp);
137
+ await parser.parse();
138
+ parser.invalidateCache();
139
+ await parser.parse();
140
+ const axCalls = cdp.send.mock.calls.filter((c) => c[0] === 'Accessibility.getFullAXTree');
141
+ expect(axCalls).toHaveLength(2);
142
+ });
143
+ it('assigns incrementing ids to elements', async () => {
144
+ const nodes = [
145
+ makeNode('button', 'A', 1),
146
+ makeNode('link', 'B', 2),
147
+ makeNode('textbox', 'C', 3),
148
+ ];
149
+ const cdp = makeMockCDP(nodes, [makeBoxModel(), makeBoxModel(), makeBoxModel()]);
150
+ const page = makeMockPage();
151
+ const parser = new StateParser(page, cdp);
152
+ const state = await parser.parse();
153
+ expect(state.elements.map((e) => e.id)).toEqual([0, 1, 2]);
154
+ });
155
+ it('skips elements where box model is rejected', async () => {
156
+ const nodes = [makeNode('button', 'Broken', 1), makeNode('link', 'Good', 2)];
157
+ const cdp = {
158
+ send: jest.fn(async (method, params) => {
159
+ if (method === 'Accessibility.getFullAXTree')
160
+ return { nodes };
161
+ if (method === 'DOM.getBoxModel') {
162
+ if (params?.backendNodeId === 1)
163
+ throw new Error('not found');
164
+ return makeBoxModel();
165
+ }
166
+ return {};
167
+ }),
168
+ };
169
+ const page = makeMockPage();
170
+ const parser = new StateParser(page, cdp);
171
+ const state = await parser.parse();
172
+ expect(state.elements).toHaveLength(1);
173
+ expect(state.elements[0].name).toBe('Good');
174
+ });
175
+ });
176
+ //# sourceMappingURL=state-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-parser.test.js","sourceRoot":"","sources":["../../src/__tests__/state-parser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,iFAAiF;AAEjF,SAAS,QAAQ,CAAC,IAAY,EAAE,IAAY,EAAE,gBAAgB,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK;IACjF,OAAO;QACL,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;QACrB,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;QACrB,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC1B,gBAAgB;QAChB,OAAO;QACP,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,EAAE;IAC5D,OAAO;QACL,KAAK,EAAE;YACL,yDAAyD;YACzD,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;SACpE;KACF,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAY,EAAE,SAAgB;IACjD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAc,EAAE,MAAY,EAAE,EAAE;YACnD,IAAI,MAAM,KAAK,6BAA6B;gBAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC/D,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,MAAM,EAAE,aAAa,CACpD,CAAC;gBACF,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,YAAY,EAAE,CAAC;YAC1C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,GAAG,GAAG,qBAAqB,EAAE,KAAK,GAAG,SAAS;IAClE,OAAO;QACL,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG;QACd,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC;QACjC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,YAAY,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAoB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEpD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC9B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,KAAK,GAAG;YACZ,QAAQ,CAAC,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;YAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;YAC/B,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;SAChC,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QACjF,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,6BAA6B;QAC7B,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,KAAK,GAAG;YACZ,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,iBAAiB;YACxD,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,KAAK,CAAC;SACxC,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,KAAK,GAAG;YACZ,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAI,qBAAqB;YAClD,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,EAAG,8BAA8B;SAC5D,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;YACzB,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACnB,WAAW,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE;YACtC,gBAAgB,EAAE,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,UAAU,EAAE,EAAE;SACf,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,iCAAiC;QAEvD,wDAAwD;QACxD,MAAM,OAAO,GAAI,GAAG,CAAC,IAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CACvD,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,6BAA6B,CACrD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,MAAM,CAAC,eAAe,EAAE,CAAC;QACzB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAErB,MAAM,OAAO,GAAI,GAAG,CAAC,IAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CACvD,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,6BAA6B,CACrD,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,KAAK,GAAG;YACZ,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YAC1B,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YACxB,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;SAC5B,CAAC;QACF,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,EAAE,YAAY,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;QACjF,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,GAAG,GAAG;YACV,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAc,EAAE,MAAY,EAAE,EAAE;gBACnD,IAAI,MAAM,KAAK,6BAA6B;oBAAE,OAAO,EAAE,KAAK,EAAE,CAAC;gBAC/D,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;oBACjC,IAAI,MAAM,EAAE,aAAa,KAAK,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;oBAC9D,OAAO,YAAY,EAAE,CAAC;gBACxB,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;SACH,CAAC;QACF,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;QAE5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAW,EAAE,GAAU,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAEnC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verifier.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/verifier.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { jest, describe, it, expect } from '@jest/globals';
2
+ import { Verifier } from '../reliability/verifier.js';
3
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
4
+ function makeState(overrides = {}) {
5
+ return {
6
+ url: 'https://example.com',
7
+ title: 'Example',
8
+ elements: [],
9
+ ...overrides,
10
+ };
11
+ }
12
+ function makeMockLLM(response) {
13
+ return {
14
+ generateStructuredData: jest.fn(async () => response),
15
+ generateText: jest.fn(async () => ''),
16
+ };
17
+ }
18
+ // ─── Tests ────────────────────────────────────────────────────────────────────
19
+ describe('Verifier', () => {
20
+ it('auto-succeeds when URL changes (fast path)', async () => {
21
+ const llm = makeMockLLM({ success: false, confidence: 0, explanation: 'should not be called' });
22
+ const verifier = new Verifier({}, {}, llm);
23
+ const before = makeState({ url: 'https://example.com/login' });
24
+ const after = makeState({ url: 'https://example.com/dashboard' });
25
+ const result = await verifier.verifyAction('Click login button', before, after);
26
+ expect(result.success).toBe(true);
27
+ expect(result.confidence).toBeGreaterThanOrEqual(0.9);
28
+ expect(llm.generateStructuredData).not.toHaveBeenCalled();
29
+ });
30
+ it('calls LLM when URL stays the same', async () => {
31
+ const llm = makeMockLLM({ success: true, confidence: 0.85, explanation: 'Form was submitted' });
32
+ const verifier = new Verifier({}, {}, llm);
33
+ const before = makeState({ elements: [] });
34
+ const after = makeState({ elements: [{ id: 0, role: 'alert', name: 'Success!', boundingClientRect: { x: 0, y: 0, width: 100, height: 30 } }] });
35
+ const result = await verifier.verifyAction('Submit form', before, after);
36
+ expect(llm.generateStructuredData).toHaveBeenCalledTimes(1);
37
+ expect(result.success).toBe(true);
38
+ expect(result.confidence).toBe(0.85);
39
+ expect(result.message).toBe('Form was submitted');
40
+ });
41
+ it('returns failure when LLM says action failed', async () => {
42
+ const llm = makeMockLLM({ success: false, confidence: 0.3, explanation: 'Nothing changed' });
43
+ const verifier = new Verifier({}, {}, llm);
44
+ const state = makeState();
45
+ const result = await verifier.verifyAction('Click invisible button', state, state);
46
+ expect(result.success).toBe(false);
47
+ expect(result.confidence).toBe(0.3);
48
+ });
49
+ it('always sets done: true', async () => {
50
+ const llm = makeMockLLM({ success: true, confidence: 0.9, explanation: 'OK' });
51
+ const verifier = new Verifier({}, {}, llm);
52
+ const state = makeState();
53
+ const result = await verifier.verifyAction('Any action', state, state);
54
+ expect(result.done).toBe(true);
55
+ });
56
+ it('passes action description and both states to LLM prompt', async () => {
57
+ const llm = makeMockLLM({ success: true, confidence: 0.8, explanation: 'Done' });
58
+ const verifier = new Verifier({}, {}, llm);
59
+ const before = makeState({ title: 'Before Page' });
60
+ const after = makeState({ title: 'After Page' });
61
+ await verifier.verifyAction('Fill in email', before, after);
62
+ const promptArg = llm.generateStructuredData.mock.calls[0][0];
63
+ expect(promptArg).toContain('Fill in email');
64
+ expect(promptArg).toContain('Before Page');
65
+ expect(promptArg).toContain('After Page');
66
+ });
67
+ });
68
+ //# sourceMappingURL=verifier.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier.test.js","sourceRoot":"","sources":["../../src/__tests__/verifier.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=workflow-recorder.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-recorder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/workflow-recorder.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ import { describe, it, expect } from '@jest/globals';
2
+ import { WorkflowRecorder } from '../recorder/workflow-recorder.js';
3
+ describe('WorkflowRecorder', () => {
4
+ it('starts and stops recording, returning a workflow', () => {
5
+ const recorder = new WorkflowRecorder();
6
+ recorder.startRecording('My Workflow');
7
+ recorder.record({ type: 'goto', url: 'https://example.com', pageUrl: 'https://example.com', pageTitle: 'Example' });
8
+ recorder.record({ type: 'act', instruction: 'Click login', pageUrl: 'https://example.com', pageTitle: 'Example' });
9
+ const workflow = recorder.stopRecording();
10
+ expect(workflow.name).toBe('My Workflow');
11
+ expect(workflow.steps).toHaveLength(2);
12
+ expect(workflow.steps[0].type).toBe('goto');
13
+ expect(workflow.steps[1].type).toBe('act');
14
+ });
15
+ it('does not record steps when not recording', () => {
16
+ const recorder = new WorkflowRecorder();
17
+ recorder.record({ type: 'act', instruction: 'Click something', pageUrl: '', pageTitle: '' });
18
+ recorder.startRecording();
19
+ const workflow = recorder.stopRecording();
20
+ expect(workflow.steps).toHaveLength(0);
21
+ });
22
+ it('exportAsJSON returns valid JSON with steps', () => {
23
+ const recorder = new WorkflowRecorder();
24
+ recorder.startRecording('Test');
25
+ recorder.record({ type: 'goto', url: 'https://test.com', pageUrl: 'https://test.com', pageTitle: 'Test' });
26
+ const workflow = recorder.stopRecording();
27
+ const json = recorder.exportAsJSON(workflow);
28
+ const parsed = JSON.parse(json);
29
+ expect(parsed.name).toBe('Test');
30
+ expect(Array.isArray(parsed.steps)).toBe(true);
31
+ expect(parsed.steps).toHaveLength(1);
32
+ });
33
+ it('exportAsCode returns TypeScript string containing goto url', () => {
34
+ const recorder = new WorkflowRecorder();
35
+ recorder.startRecording('Code Export');
36
+ recorder.record({ type: 'goto', url: 'https://example.com', pageUrl: 'https://example.com', pageTitle: '' });
37
+ recorder.record({ type: 'act', instruction: 'Click submit', pageUrl: 'https://example.com', pageTitle: '' });
38
+ const workflow = recorder.stopRecording();
39
+ const code = recorder.exportAsCode(workflow);
40
+ expect(code).toContain('https://example.com');
41
+ expect(code).toContain('Click submit');
42
+ expect(typeof code).toBe('string');
43
+ });
44
+ it('uses default name when none provided', () => {
45
+ const recorder = new WorkflowRecorder();
46
+ recorder.startRecording();
47
+ const workflow = recorder.stopRecording();
48
+ expect(typeof workflow.name).toBe('string');
49
+ expect(workflow.name.length).toBeGreaterThan(0);
50
+ });
51
+ it('records timestamp on each step', () => {
52
+ const recorder = new WorkflowRecorder();
53
+ recorder.startRecording();
54
+ recorder.record({ type: 'act', instruction: 'Click', pageUrl: '', pageTitle: '' });
55
+ const workflow = recorder.stopRecording();
56
+ expect(workflow.steps[0]).toHaveProperty('timestamp');
57
+ });
58
+ it('resets steps on new startRecording call', () => {
59
+ const recorder = new WorkflowRecorder();
60
+ recorder.startRecording('First');
61
+ recorder.record({ type: 'act', instruction: 'Step 1', pageUrl: '', pageTitle: '' });
62
+ recorder.stopRecording();
63
+ recorder.startRecording('Second');
64
+ recorder.record({ type: 'act', instruction: 'Step A', pageUrl: '', pageTitle: '' });
65
+ recorder.record({ type: 'act', instruction: 'Step B', pageUrl: '', pageTitle: '' });
66
+ const workflow = recorder.stopRecording();
67
+ expect(workflow.name).toBe('Second');
68
+ expect(workflow.steps).toHaveLength(2);
69
+ });
70
+ });
71
+ //# sourceMappingURL=workflow-recorder.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-recorder.test.js","sourceRoot":"","sources":["../../src/__tests__/workflow-recorder.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { ActionEngine } from '../api/act.js';
2
+ import type { StateParser } from '../core/state-parser.js';
3
+ import type { LLMProvider } from '../utils/llm-provider.js';
4
+ export interface AgentRunOptions {
5
+ maxSteps?: number;
6
+ onStep?: (step: AgentStepEvent) => void;
7
+ }
8
+ export interface AgentStepEvent {
9
+ stepNumber: number;
10
+ instruction: string;
11
+ reasoning: string;
12
+ success: boolean;
13
+ pageUrl: string;
14
+ pageTitle: string;
15
+ }
16
+ export interface AgentResult {
17
+ success: boolean;
18
+ goalAchieved: boolean;
19
+ totalSteps: number;
20
+ message: string;
21
+ history: AgentStepEvent[];
22
+ }
23
+ /**
24
+ * Autonomous multi-step agent loop.
25
+ * Implements a Plan → Execute → Verify → Reflect cycle.
26
+ */
27
+ export declare class AgentLoop {
28
+ private actionEngine;
29
+ private stateParser;
30
+ private gemini;
31
+ private planner;
32
+ private memory;
33
+ constructor(actionEngine: ActionEngine, stateParser: StateParser, gemini: LLMProvider);
34
+ run(goal: string, options?: AgentRunOptions): Promise<AgentResult>;
35
+ }
36
+ //# sourceMappingURL=agent-loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAI5D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAAa,SAAS;IAKlB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAc;gBAGlB,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,WAAW;IAMvB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;CAqH7E"}
@@ -0,0 +1,127 @@
1
+ import { AgentMemory } from './memory.js';
2
+ import { Planner } from './planner.js';
3
+ /**
4
+ * Autonomous multi-step agent loop.
5
+ * Implements a Plan → Execute → Verify → Reflect cycle.
6
+ */
7
+ export class AgentLoop {
8
+ actionEngine;
9
+ stateParser;
10
+ gemini;
11
+ planner;
12
+ memory;
13
+ constructor(actionEngine, stateParser, gemini) {
14
+ this.actionEngine = actionEngine;
15
+ this.stateParser = stateParser;
16
+ this.gemini = gemini;
17
+ this.planner = new Planner(gemini);
18
+ this.memory = new AgentMemory(20);
19
+ }
20
+ async run(goal, options = {}) {
21
+ const maxSteps = options.maxSteps ?? 15;
22
+ const stepEvents = [];
23
+ this.memory.clear();
24
+ console.log(`[Agent] 🎯 Goal: "${goal}" (max ${maxSteps} steps)`);
25
+ let stepNumber = 0;
26
+ let consecutiveFailures = 0;
27
+ while (stepNumber < maxSteps) {
28
+ stepNumber++;
29
+ console.log(`[Agent] 📍 Step ${stepNumber}/${maxSteps}`);
30
+ // 1. Parse current state
31
+ this.stateParser.invalidateCache();
32
+ const state = await this.stateParser.parse();
33
+ // 2. Plan next step
34
+ let planned;
35
+ try {
36
+ planned = await this.planner.planNextStep(goal, state, this.memory);
37
+ }
38
+ catch (err) {
39
+ console.error(`[Agent] Planner error: ${err.message}`);
40
+ break;
41
+ }
42
+ console.log(`[Agent] 💭 Plan: "${planned.instruction}" — ${planned.reasoning}`);
43
+ // 3. Check if goal is already complete
44
+ if (planned.isGoalComplete) {
45
+ console.log(`[Agent] ✅ Goal marked complete by planner.`);
46
+ const event = {
47
+ stepNumber,
48
+ instruction: planned.instruction,
49
+ reasoning: planned.reasoning,
50
+ success: true,
51
+ pageUrl: state.url,
52
+ pageTitle: state.title,
53
+ };
54
+ stepEvents.push(event);
55
+ options.onStep?.(event);
56
+ return {
57
+ success: true,
58
+ goalAchieved: true,
59
+ totalSteps: stepNumber,
60
+ message: `Goal achieved in ${stepNumber} step(s).`,
61
+ history: stepEvents,
62
+ };
63
+ }
64
+ // 4. Execute the planned step
65
+ let result;
66
+ try {
67
+ result = await this.actionEngine.act(planned.instruction);
68
+ }
69
+ catch (err) {
70
+ result = { success: false, message: err.message, action: planned.instruction };
71
+ }
72
+ const event = {
73
+ stepNumber,
74
+ instruction: planned.instruction,
75
+ reasoning: planned.reasoning,
76
+ success: result.success,
77
+ pageUrl: state.url,
78
+ pageTitle: state.title,
79
+ };
80
+ stepEvents.push(event);
81
+ options.onStep?.(event);
82
+ // 5. Record in memory
83
+ this.memory.add({
84
+ stepNumber,
85
+ instruction: planned.instruction,
86
+ action: result.action ?? planned.instruction,
87
+ success: result.success,
88
+ pageUrl: state.url,
89
+ pageTitle: state.title,
90
+ timestamp: Date.now(),
91
+ });
92
+ if (!result.success) {
93
+ consecutiveFailures++;
94
+ console.warn(`[Agent] ⚠️ Step failed (${consecutiveFailures} consecutive): ${result.message}`);
95
+ if (consecutiveFailures >= 3) {
96
+ console.error(`[Agent] ❌ Aborting: 3 consecutive failures.`);
97
+ break;
98
+ }
99
+ }
100
+ else {
101
+ consecutiveFailures = 0;
102
+ }
103
+ }
104
+ // 6. Final reflection – did we actually achieve the goal?
105
+ this.stateParser.invalidateCache();
106
+ const finalState = await this.stateParser.parse();
107
+ let goalAchieved = false;
108
+ try {
109
+ goalAchieved = await this.planner.reflect(goal, this.memory, finalState);
110
+ }
111
+ catch {
112
+ goalAchieved = false;
113
+ }
114
+ const message = goalAchieved
115
+ ? `Goal achieved in ${stepNumber} step(s).`
116
+ : `Agent stopped after ${stepNumber} step(s) without fully achieving the goal.`;
117
+ console.log(`[Agent] ${goalAchieved ? '✅' : '⚠️ '} ${message}`);
118
+ return {
119
+ success: goalAchieved,
120
+ goalAchieved,
121
+ totalSteps: stepNumber,
122
+ message,
123
+ history: stepEvents,
124
+ };
125
+ }
126
+ }
127
+ //# sourceMappingURL=agent-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-loop.js","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface StepRecord {
2
+ stepNumber: number;
3
+ instruction: string;
4
+ action: string;
5
+ success: boolean;
6
+ pageUrl: string;
7
+ pageTitle: string;
8
+ timestamp: number;
9
+ }
10
+ /**
11
+ * Sliding context window over agent step history.
12
+ * Keeps the last N steps to avoid exceeding LLM context limits.
13
+ */
14
+ export declare class AgentMemory {
15
+ private readonly maxSteps;
16
+ private history;
17
+ constructor(maxSteps?: number);
18
+ add(record: StepRecord): void;
19
+ getHistory(): StepRecord[];
20
+ getSummary(): string;
21
+ clear(): void;
22
+ get length(): number;
23
+ }
24
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,WAAW;IAGV,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,OAAO,CAAoB;gBAEN,QAAQ,GAAE,MAAW;IAElD,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAO7B,UAAU,IAAI,UAAU,EAAE;IAI1B,UAAU,IAAI,MAAM;IAUpB,KAAK,IAAI,IAAI;IAIb,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Sliding context window over agent step history.
3
+ * Keeps the last N steps to avoid exceeding LLM context limits.
4
+ */
5
+ export class AgentMemory {
6
+ maxSteps;
7
+ history = [];
8
+ constructor(maxSteps = 20) {
9
+ this.maxSteps = maxSteps;
10
+ }
11
+ add(record) {
12
+ this.history.push(record);
13
+ if (this.history.length > this.maxSteps) {
14
+ this.history.shift();
15
+ }
16
+ }
17
+ getHistory() {
18
+ return [...this.history];
19
+ }
20
+ getSummary() {
21
+ if (this.history.length === 0)
22
+ return 'No steps taken yet.';
23
+ return this.history
24
+ .map(s => `Step ${s.stepNumber}: [${s.success ? 'OK' : 'FAIL'}] ${s.instruction} → ${s.action} (${s.pageTitle})`)
25
+ .join('\n');
26
+ }
27
+ clear() {
28
+ this.history = [];
29
+ }
30
+ get length() {
31
+ return this.history.length;
32
+ }
33
+ }
34
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/agent/memory.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,MAAM,OAAO,WAAW;IAGO;IAFrB,OAAO,GAAiB,EAAE,CAAC;IAEnC,YAA6B,WAAmB,EAAE;QAArB,aAAQ,GAAR,QAAQ,CAAa;IAAG,CAAC;IAEtD,GAAG,CAAC,MAAkB;QACpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,UAAU;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IAED,UAAU;QACR,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,qBAAqB,CAAC;QAC5D,OAAO,IAAI,CAAC,OAAO;aAChB,GAAG,CACF,CAAC,CAAC,EAAE,CACF,QAAQ,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,WAAW,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,SAAS,GAAG,CACzG;aACA,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;IACpB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import type { LLMProvider } from '../utils/llm-provider.js';
2
+ import type { SimplifiedState } from '../core/state-parser.js';
3
+ import type { AgentMemory } from './memory.js';
4
+ export interface PlannedStep {
5
+ instruction: string;
6
+ reasoning: string;
7
+ isGoalComplete: boolean;
8
+ }
9
+ /**
10
+ * Uses Gemini to plan the next action step based on the current page state and history.
11
+ */
12
+ export declare class Planner {
13
+ private gemini;
14
+ constructor(gemini: LLMProvider);
15
+ planNextStep(goal: string, state: SimplifiedState, memory: AgentMemory): Promise<PlannedStep>;
16
+ reflect(goal: string, memory: AgentMemory, finalState: SimplifiedState): Promise<boolean>;
17
+ }
18
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/agent/planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAEjC,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,eAAe,EACtB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC;IAuCjB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC;CAgChG"}