explorbot 0.1.32-beta.1 → 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 (222) hide show
  1. package/README.md +35 -19
  2. package/bin/explorbot-cli.ts +33 -10
  3. package/boat/api-tester/src/config.ts +45 -3
  4. package/boat/doc-collector/src/ai/documentarian.ts +26 -28
  5. package/boat/doc-collector/src/ai/tools.ts +74 -16
  6. package/boat/doc-collector/src/cli.ts +1 -6
  7. package/boat/doc-collector/src/docbot.ts +30 -9
  8. package/boat/doc-collector/src/docs-renderer.ts +19 -24
  9. package/boat/doc-collector/src/screenshots.ts +34 -2
  10. package/boat/doc-collector/src/state-diagram.ts +281 -0
  11. package/dist/bin/explorbot-cli.js +29 -9
  12. package/dist/boat/api-tester/src/config.js +43 -4
  13. package/dist/boat/doc-collector/src/ai/documentarian.js +19 -7
  14. package/dist/boat/doc-collector/src/ai/tools.js +53 -16
  15. package/dist/boat/doc-collector/src/cli.js +1 -5
  16. package/dist/boat/doc-collector/src/docbot.js +27 -8
  17. package/dist/boat/doc-collector/src/docs-renderer.js +18 -3
  18. package/dist/boat/doc-collector/src/screenshots.js +30 -1
  19. package/dist/boat/doc-collector/src/state-diagram.js +200 -0
  20. package/dist/models.json +30 -0
  21. package/dist/package.json +23 -3
  22. package/dist/src/action-result.d.ts +8 -10
  23. package/dist/src/action-result.js +72 -164
  24. package/dist/src/action.d.ts +13 -12
  25. package/dist/src/action.js +37 -113
  26. package/dist/src/ai/agent.d.ts +17 -0
  27. package/dist/src/ai/captain/idle-mode.js +1 -1
  28. package/dist/src/ai/captain/test-mode.js +1 -1
  29. package/dist/src/ai/captain/web-mode.js +18 -29
  30. package/dist/src/ai/captain.d.ts +1 -3
  31. package/dist/src/ai/captain.js +17 -45
  32. package/dist/src/ai/conversation.d.ts +2 -5
  33. package/dist/src/ai/conversation.js +9 -28
  34. package/dist/src/ai/driller.d.ts +2 -17
  35. package/dist/src/ai/driller.js +26 -50
  36. package/dist/src/ai/experience-compactor.d.ts +2 -2
  37. package/dist/src/ai/experience-compactor.js +16 -33
  38. package/dist/src/ai/fisherman-tools.js +1 -1
  39. package/dist/src/ai/fisherman.d.ts +0 -1
  40. package/dist/src/ai/fisherman.js +0 -3
  41. package/dist/src/ai/historian/codeceptjs.d.ts +2 -0
  42. package/dist/src/ai/historian/codeceptjs.js +4 -3
  43. package/dist/src/ai/historian/playwright.d.ts +4 -1
  44. package/dist/src/ai/historian/playwright.js +4 -3
  45. package/dist/src/ai/historian/screencast.d.ts +2 -1
  46. package/dist/src/ai/historian/screencast.js +2 -2
  47. package/dist/src/ai/historian/utils.d.ts +0 -1
  48. package/dist/src/ai/historian/utils.js +0 -1
  49. package/dist/src/ai/historian.d.ts +10 -8
  50. package/dist/src/ai/historian.js +1 -5
  51. package/dist/src/ai/navigator.d.ts +8 -6
  52. package/dist/src/ai/navigator.js +34 -65
  53. package/dist/src/ai/pilot.d.ts +13 -8
  54. package/dist/src/ai/pilot.js +53 -59
  55. package/dist/src/ai/planner.d.ts +5 -4
  56. package/dist/src/ai/planner.js +66 -52
  57. package/dist/src/ai/provider.d.ts +4 -1
  58. package/dist/src/ai/provider.js +77 -137
  59. package/dist/src/ai/quartermaster.d.ts +22 -22
  60. package/dist/src/ai/quartermaster.js +8 -14
  61. package/dist/src/ai/rerunner.d.ts +3 -13
  62. package/dist/src/ai/rerunner.js +23 -44
  63. package/dist/src/ai/researcher/cache.js +11 -18
  64. package/dist/src/ai/researcher/coordinates.js +4 -3
  65. package/dist/src/ai/researcher/deep-analysis.d.ts +2 -0
  66. package/dist/src/ai/researcher/deep-analysis.js +8 -11
  67. package/dist/src/ai/researcher/locators.d.ts +9 -2
  68. package/dist/src/ai/researcher/locators.js +65 -8
  69. package/dist/src/ai/researcher/parser.js +1 -1
  70. package/dist/src/ai/researcher/research-result.d.ts +0 -1
  71. package/dist/src/ai/researcher/research-result.js +0 -19
  72. package/dist/src/ai/researcher/sections.d.ts +2 -0
  73. package/dist/src/ai/researcher/sections.js +7 -3
  74. package/dist/src/ai/researcher.js +40 -106
  75. package/dist/src/ai/rules.d.ts +1 -0
  76. package/dist/src/ai/rules.js +22 -15
  77. package/dist/src/ai/session-analyst.js +8 -5
  78. package/dist/src/ai/task-agent.d.ts +19 -6
  79. package/dist/src/ai/task-agent.js +37 -33
  80. package/dist/src/ai/tester.d.ts +6 -14
  81. package/dist/src/ai/tester.js +46 -111
  82. package/dist/src/ai/tools.d.ts +26 -14
  83. package/dist/src/ai/tools.js +138 -132
  84. package/dist/src/command-handler.js +1 -1
  85. package/dist/src/commands/compact-command.d.ts +1 -1
  86. package/dist/src/commands/compact-command.js +6 -6
  87. package/dist/src/commands/context-aria-command.js +1 -1
  88. package/dist/src/commands/context-command.js +8 -6
  89. package/dist/src/commands/context-data-command.js +2 -2
  90. package/dist/src/commands/context-experience-command.js +2 -2
  91. package/dist/src/commands/context-html-command.js +2 -2
  92. package/dist/src/commands/context-knowledge-command.js +2 -2
  93. package/dist/src/commands/drill-command.js +1 -1
  94. package/dist/src/commands/experience-command.js +1 -1
  95. package/dist/src/commands/explore-command.js +4 -3
  96. package/dist/src/commands/freesail-command.js +2 -2
  97. package/dist/src/commands/knows-command.js +1 -1
  98. package/dist/src/commands/learn-command.js +5 -3
  99. package/dist/src/commands/path-command.js +1 -1
  100. package/dist/src/commands/research-command.js +1 -1
  101. package/dist/src/commands/test-command.js +1 -1
  102. package/dist/src/components/AddKnowledge.d.ts +2 -0
  103. package/dist/src/components/AddKnowledge.js +3 -7
  104. package/dist/src/components/App.js +3 -3
  105. package/dist/src/config.d.ts +19 -0
  106. package/dist/src/config.js +156 -10
  107. package/dist/src/experience-tracker.d.ts +11 -6
  108. package/dist/src/experience-tracker.js +82 -155
  109. package/dist/src/explorbot.d.ts +21 -13
  110. package/dist/src/explorbot.js +84 -80
  111. package/dist/src/explorer.d.ts +66 -102
  112. package/dist/src/explorer.js +332 -623
  113. package/dist/src/knowledge-tracker.d.ts +2 -2
  114. package/dist/src/knowledge-tracker.js +38 -45
  115. package/dist/src/state-manager.d.ts +10 -30
  116. package/dist/src/state-manager.js +11 -129
  117. package/dist/src/utils/aria.d.ts +6 -1
  118. package/dist/src/utils/aria.js +4 -1
  119. package/dist/src/utils/cache.d.ts +15 -0
  120. package/dist/src/utils/cache.js +34 -0
  121. package/dist/src/utils/context-formatter.d.ts +6 -0
  122. package/dist/src/utils/context-formatter.js +15 -27
  123. package/dist/src/utils/hooks-runner.js +2 -4
  124. package/dist/src/utils/html.d.ts +5 -0
  125. package/dist/src/utils/html.js +71 -0
  126. package/dist/src/utils/markdown-files.d.ts +10 -0
  127. package/dist/src/utils/markdown-files.js +21 -0
  128. package/dist/src/utils/markdown-query.d.ts +6 -0
  129. package/dist/src/utils/markdown-query.js +14 -1
  130. package/dist/src/utils/page-readiness.d.ts +1 -0
  131. package/dist/src/utils/page-readiness.js +1 -1
  132. package/dist/src/utils/secrets.js +2 -2
  133. package/dist/src/utils/strings.d.ts +2 -0
  134. package/dist/src/utils/strings.js +10 -0
  135. package/dist/src/utils/test-files.js +1 -1
  136. package/dist/src/utils/web-annotate.d.ts +5 -0
  137. package/dist/src/utils/web-annotate.js +58 -0
  138. package/dist/src/utils/web-eidx.d.ts +2 -0
  139. package/dist/src/utils/web-eidx.js +20 -0
  140. package/dist/src/utils/web-element.d.ts +3 -1
  141. package/dist/src/utils/web-element.js +32 -0
  142. package/dist/src/utils/web-sandbox.d.ts +4 -0
  143. package/dist/src/utils/web-sandbox.js +37 -0
  144. package/models.json +30 -0
  145. package/package.json +23 -3
  146. package/src/action-result.ts +70 -173
  147. package/src/action.ts +38 -132
  148. package/src/ai/agent.ts +20 -0
  149. package/src/ai/captain/idle-mode.ts +1 -1
  150. package/src/ai/captain/test-mode.ts +1 -1
  151. package/src/ai/captain/web-mode.ts +18 -30
  152. package/src/ai/captain.ts +17 -42
  153. package/src/ai/conversation.ts +9 -32
  154. package/src/ai/driller.ts +53 -83
  155. package/src/ai/experience-compactor.ts +16 -35
  156. package/src/ai/fisherman-tools.ts +1 -1
  157. package/src/ai/fisherman.ts +0 -4
  158. package/src/ai/historian/codeceptjs.ts +5 -3
  159. package/src/ai/historian/playwright.ts +7 -4
  160. package/src/ai/historian/screencast.ts +4 -3
  161. package/src/ai/historian/utils.ts +0 -1
  162. package/src/ai/historian.ts +6 -8
  163. package/src/ai/navigator.ts +39 -70
  164. package/src/ai/pilot.ts +59 -61
  165. package/src/ai/planner.ts +76 -62
  166. package/src/ai/provider.ts +85 -146
  167. package/src/ai/quartermaster.ts +39 -45
  168. package/src/ai/rerunner.ts +27 -50
  169. package/src/ai/researcher/cache.ts +10 -16
  170. package/src/ai/researcher/coordinates.ts +4 -3
  171. package/src/ai/researcher/deep-analysis.ts +10 -11
  172. package/src/ai/researcher/locators.ts +66 -9
  173. package/src/ai/researcher/parser.ts +1 -1
  174. package/src/ai/researcher/research-result.ts +0 -18
  175. package/src/ai/researcher/sections.ts +9 -3
  176. package/src/ai/researcher.ts +42 -119
  177. package/src/ai/rules.ts +24 -13
  178. package/src/ai/session-analyst.ts +8 -5
  179. package/src/ai/task-agent.ts +45 -38
  180. package/src/ai/tester.ts +51 -129
  181. package/src/ai/tools.ts +145 -153
  182. package/src/command-handler.ts +1 -1
  183. package/src/commands/compact-command.ts +7 -8
  184. package/src/commands/context-aria-command.ts +1 -1
  185. package/src/commands/context-command.ts +8 -6
  186. package/src/commands/context-data-command.ts +2 -2
  187. package/src/commands/context-experience-command.ts +2 -2
  188. package/src/commands/context-html-command.ts +2 -2
  189. package/src/commands/context-knowledge-command.ts +2 -2
  190. package/src/commands/drill-command.ts +1 -1
  191. package/src/commands/experience-command.ts +1 -1
  192. package/src/commands/explore-command.ts +4 -3
  193. package/src/commands/freesail-command.ts +2 -2
  194. package/src/commands/knows-command.ts +1 -1
  195. package/src/commands/learn-command.ts +5 -3
  196. package/src/commands/path-command.ts +1 -1
  197. package/src/commands/research-command.ts +1 -1
  198. package/src/commands/test-command.ts +1 -1
  199. package/src/components/AddKnowledge.tsx +5 -7
  200. package/src/components/App.tsx +3 -3
  201. package/src/config.ts +185 -11
  202. package/src/experience-tracker.ts +89 -152
  203. package/src/explorbot.ts +88 -83
  204. package/src/explorer.ts +402 -693
  205. package/src/knowledge-tracker.ts +42 -49
  206. package/src/state-manager.ts +20 -155
  207. package/src/utils/aria.ts +11 -2
  208. package/src/utils/cache.ts +40 -0
  209. package/src/utils/context-formatter.ts +12 -15
  210. package/src/utils/hooks-runner.ts +2 -4
  211. package/src/utils/html.ts +79 -0
  212. package/src/utils/markdown-files.ts +30 -0
  213. package/src/utils/markdown-query.ts +15 -1
  214. package/src/utils/page-readiness.ts +1 -1
  215. package/src/utils/secrets.ts +2 -3
  216. package/src/utils/strings.ts +12 -0
  217. package/src/utils/test-files.ts +1 -1
  218. package/src/utils/web-annotate.ts +64 -0
  219. package/src/utils/web-eidx.ts +21 -0
  220. package/src/utils/web-element.ts +34 -0
  221. package/src/utils/web-sandbox.ts +43 -0
  222. package/dist/boat/api-tester/example/apibot.config.js +0 -30
package/src/explorbot.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { existsSync, mkdirSync } from 'node:fs';
2
2
  import path from 'node:path';
3
- import { ActionResult } from './action-result.ts';
3
+ import type { AgentDeps } from './ai/agent.ts';
4
4
  import { Captain } from './ai/captain.ts';
5
5
  import { Driller } from './ai/driller.ts';
6
6
  import { ExperienceCompactor } from './ai/experience-compactor.ts';
@@ -24,10 +24,13 @@ import { ConfigParser } from './config.ts';
24
24
  import { ExperienceTracker } from './experience-tracker.ts';
25
25
  import Explorer from './explorer.ts';
26
26
  import { KnowledgeTracker } from './knowledge-tracker.ts';
27
- import { WebPageState } from './state-manager.ts';
27
+ import { PlaywrightRecorder } from './playwright-recorder.ts';
28
+ import { Reporter } from './reporter.ts';
29
+ import { StateManager, WebPageState } from './state-manager.ts';
28
30
  import { Stats } from './stats.ts';
29
31
  import type { Suite } from './suite.ts';
30
32
  import { Plan, type Test } from './test-plan.ts';
33
+ import { browserErrorMessage } from './utils/browser-errors.ts';
31
34
  import { setVerboseMode, tag } from './utils/logger.ts';
32
35
  import { relativeToCwd } from './utils/next-steps.ts';
33
36
  import { sanitizeFilename } from './utils/strings.ts';
@@ -42,7 +45,7 @@ export interface ExplorBotOptions {
42
45
  show?: boolean;
43
46
  headless?: boolean;
44
47
  incognito?: boolean;
45
- session?: string;
48
+ session?: string | boolean;
46
49
  }
47
50
 
48
51
  export type UserResolveFunction = (error?: Error, showWelcome?: boolean) => Promise<string | null>;
@@ -54,7 +57,6 @@ export class ExplorBot {
54
57
  private config!: ExplorbotConfig;
55
58
  private options: ExplorBotOptions;
56
59
  private userResolveFn: UserResolveFunction | null = null;
57
- public needsInput = false;
58
60
  private currentPlan?: Plan;
59
61
  private planFeature?: string;
60
62
  lastPlanError: Error | null = null;
@@ -62,6 +64,12 @@ export class ExplorBot {
62
64
  private agents: Record<string, any> = {};
63
65
  private sessionPlans: Plan[] = [];
64
66
  private lastReportedTestCount = 0;
67
+ private _experienceTracker?: ExperienceTracker;
68
+ private _knowledgeTracker?: KnowledgeTracker;
69
+ private _stateManager?: StateManager;
70
+ private _reporter?: Reporter;
71
+ private _requestStore?: RequestStore;
72
+ private _playwrightRecorder?: PlaywrightRecorder;
65
73
 
66
74
  constructor(options: ExplorBotOptions = {}) {
67
75
  this.options = options;
@@ -73,7 +81,7 @@ export class ExplorBot {
73
81
  }
74
82
 
75
83
  get isExploring(): boolean {
76
- return this.explorer?.isStarted;
84
+ return !!this.explorer;
77
85
  }
78
86
 
79
87
  setUserResolve(fn: UserResolveFunction): void {
@@ -81,20 +89,26 @@ export class ExplorBot {
81
89
  }
82
90
 
83
91
  async start(): Promise<void> {
84
- if (this.explorer?.isStarted) {
92
+ if (this.explorer) {
85
93
  return;
86
94
  }
87
95
 
88
96
  try {
89
97
  await this.startProviderOnly();
90
- this.explorer = new Explorer(this.config, this.provider, this.options);
98
+ const explorerOptions = { ...this.options, session: typeof this.options.session === 'string' ? this.options.session : undefined };
99
+ this.explorer = new Explorer(this.config, explorerOptions, {
100
+ stateManager: this.stateManager(),
101
+ knowledgeTracker: this.knowledgeTracker(),
102
+ reporter: this.reporter(),
103
+ requestStore: this.requestStore(),
104
+ playwrightRecorder: this.playwrightRecorder(),
105
+ });
91
106
  await this.explorer.start();
92
107
  if (!this.options.incognito) {
93
108
  await this.agentExperienceCompactor().autocompact();
94
109
  }
95
- if (this.userResolveFn) this.explorer.setUserResolve(this.userResolveFn);
96
110
  } catch (error) {
97
- const message = error instanceof Error ? error.message : String(error);
111
+ const message = browserErrorMessage(error);
98
112
  console.error('\nFailed to start:', message);
99
113
  process.exit(1);
100
114
  }
@@ -103,6 +117,7 @@ export class ExplorBot {
103
117
  async startProviderOnly(): Promise<void> {
104
118
  if (this.provider) return;
105
119
  this.config = await this.configParser.loadConfig(this.options);
120
+ if (this.options.session === true) this.options.session = path.join(this.configParser.getOutputDir(), 'session.json');
106
121
  this.provider = new AIProvider(this.config.ai);
107
122
  await this.provider.validateConnection();
108
123
  }
@@ -121,30 +136,40 @@ export class ExplorBot {
121
136
  return this.agentNavigator().visit(url);
122
137
  }
123
138
 
124
- async openFreshTab(): Promise<void> {
125
- await this.explorer.openFreshTab();
139
+ async openTab(): Promise<void> {
140
+ await this.explorer.openTab();
126
141
  }
127
142
 
128
143
  getCurrentState(): WebPageState | null {
129
- return this.explorer?.getStateManager().getCurrentState() ?? null;
144
+ return this._stateManager?.getCurrentState() ?? null;
130
145
  }
131
146
 
132
147
  getExplorer(): Explorer {
133
148
  return this.explorer;
134
149
  }
135
150
 
136
- getKnowledgeTracker(): KnowledgeTracker {
137
- if (this.explorer) {
138
- return this.explorer.getKnowledgeTracker();
139
- }
140
- return new KnowledgeTracker();
151
+ knowledgeTracker(): KnowledgeTracker {
152
+ return (this._knowledgeTracker ||= new KnowledgeTracker());
141
153
  }
142
154
 
143
- getExperienceTracker(): ExperienceTracker {
144
- if (this.explorer) {
145
- return this.explorer.getStateManager().getExperienceTracker();
146
- }
147
- return new ExperienceTracker();
155
+ experienceTracker(): ExperienceTracker {
156
+ return (this._experienceTracker ||= new ExperienceTracker(this.knowledgeTracker()));
157
+ }
158
+
159
+ stateManager(): StateManager {
160
+ return (this._stateManager ||= new StateManager(this.experienceTracker(), this.knowledgeTracker()));
161
+ }
162
+
163
+ reporter(): Reporter {
164
+ return (this._reporter ||= new Reporter(this.config.reporter, this.stateManager()));
165
+ }
166
+
167
+ requestStore(): RequestStore {
168
+ return (this._requestStore ||= new RequestStore(this.configParser.getOutputDir()));
169
+ }
170
+
171
+ playwrightRecorder(): PlaywrightRecorder {
172
+ return (this._playwrightRecorder ||= new PlaywrightRecorder());
148
173
  }
149
174
 
150
175
  getConfig(): ExplorbotConfig {
@@ -154,47 +179,39 @@ export class ExplorBot {
154
179
  getOptions(): ExplorBotOptions {
155
180
  return this.options;
156
181
  }
157
- isReady(): boolean {
158
- return this.explorer?.isStarted;
159
- }
160
-
161
- getConfigParser(): ConfigParser {
162
- return this.configParser;
163
- }
164
182
 
165
183
  getProvider(): AIProvider {
166
184
  return this.provider;
167
185
  }
168
186
 
169
- createAgent<T>(factory: (deps: { explorer: Explorer; ai: AIProvider; config: ExplorbotConfig }) => T): T {
187
+ createAgent<T>(factory: (deps: AgentDeps) => T): T {
170
188
  const agent = factory({
171
189
  explorer: this.explorer,
172
190
  ai: this.provider,
173
191
  config: this.config,
192
+ stateManager: this.stateManager(),
193
+ knowledgeTracker: this.knowledgeTracker(),
194
+ requestStore: this.requestStore(),
195
+ playwrightRecorder: this.playwrightRecorder(),
174
196
  });
175
197
 
176
- const agentEmoji = (agent as any).emoji || '';
177
198
  const agentName = (agent as any).constructor.name.toLowerCase();
178
199
  tag('debug').log(`Created ${agentName} agent`);
179
200
 
180
- // Agent is stored by the calling method using a string key
181
-
182
201
  return agent;
183
202
  }
184
203
 
185
204
  agentResearcher(): Researcher {
186
- return (this.agents.researcher ||= this.createAgent(({ ai, explorer }) => new Researcher(explorer, ai)));
205
+ return (this.agents.researcher ||= this.createAgent((deps) => new Researcher(deps)));
187
206
  }
188
207
 
189
208
  agentNavigator(): Navigator {
190
- return (this.agents.navigator ||= this.createAgent(({ ai, explorer }) => {
191
- return new Navigator(explorer, ai, this.agentExperienceCompactor(), explorer.getStateManager().getExperienceTracker());
192
- }));
209
+ return (this.agents.navigator ||= this.createAgent((deps) => new Navigator(deps)));
193
210
  }
194
211
 
195
212
  agentPlanner(): Planner {
196
213
  if (!this.agents.planner) {
197
- this.agents.planner = this.createAgent(({ ai, explorer }) => new Planner(explorer, ai));
214
+ this.agents.planner = this.createAgent((deps) => new Planner(deps, this.agentResearcher()));
198
215
  const fisherman = this.agentFisherman();
199
216
  if (fisherman) this.agents.planner.setFisherman(fisherman);
200
217
  }
@@ -202,38 +219,26 @@ export class ExplorBot {
202
219
  }
203
220
 
204
221
  agentPilot(): Pilot {
205
- return (this.agents.pilot ||= this.createAgent(({ ai, explorer }) => {
222
+ return (this.agents.pilot ||= this.createAgent((deps) => {
206
223
  const researcher = this.agentResearcher();
207
224
  const navigator = this.agentNavigator();
208
- const stateManager = explorer.getStateManager();
209
- const experienceTracker = stateManager.getExperienceTracker();
210
- const getState = () => {
211
- const state = stateManager.getCurrentState();
212
- return state ? ActionResult.fromState(state) : null;
213
- };
214
- const tools = createAgentTools({ explorer, researcher, navigator, experienceTracker, getState, supervisor: true });
215
- return new Pilot(ai, tools, researcher, explorer, experienceTracker);
225
+ const tools = createAgentTools({ ...deps, researcher, navigator, supervisor: true });
226
+ return new Pilot(deps, tools, researcher);
216
227
  }));
217
228
  }
218
229
 
219
230
  agentTester(): Tester {
220
231
  if (!this.agents.tester) {
221
- this.agents.tester = this.createAgent(({ ai, explorer }) => {
232
+ this.agents.tester = this.createAgent((deps) => {
222
233
  const researcher = this.agentResearcher();
223
234
  const navigator = this.agentNavigator();
224
- const stateManager = explorer.getStateManager();
225
- const experienceTracker = stateManager.getExperienceTracker();
226
- const getState = () => {
227
- const state = stateManager.getCurrentState();
228
- return state ? ActionResult.fromState(state) : null;
229
- };
230
- const tools = createAgentTools({ explorer, researcher, navigator, experienceTracker, getState });
231
- return new Tester(explorer, ai, researcher, navigator, tools);
235
+ const tools = createAgentTools({ ...deps, researcher, navigator });
236
+ return new Tester(deps, researcher, navigator, tools);
232
237
  });
233
238
 
234
239
  const qm = this.agentQuartermaster();
235
240
  if (qm) this.agents.tester.setQuartermaster(qm);
236
- this.agents.tester.setHistorian(this.agentHistorian());
241
+ if (this.isHistorianEnabled()) this.agents.tester.setHistorian(this.agentHistorian());
237
242
  this.agents.tester.setPilot(this.agentPilot());
238
243
  this.agents.tester.setCaptain(this.agentCaptain());
239
244
 
@@ -246,16 +251,12 @@ export class ExplorBot {
246
251
  agentCaptain(): Captain {
247
252
  if (!this.agents.captain) {
248
253
  this.agents.captain = new Captain(this);
249
-
250
- const qm = this.agentQuartermaster();
251
- if (qm) this.agents.captain.setQuartermaster(qm);
252
- this.agents.captain.setHistorian(this.agentHistorian());
253
254
  }
254
255
  return this.agents.captain;
255
256
  }
256
257
 
257
258
  agentExperienceCompactor(): ExperienceCompactor {
258
- return (this.agents.experienceCompactor ||= new ExperienceCompactor(this.provider, this.getExperienceTracker()));
259
+ return (this.agents.experienceCompactor ||= new ExperienceCompactor(this.provider, this.experienceTracker()));
259
260
  }
260
261
 
261
262
  agentQuartermaster(): Quartermaster | null {
@@ -266,41 +267,37 @@ export class ExplorBot {
266
267
  this.agents.quartermaster = new Quartermaster(this.provider, {
267
268
  model: config?.model,
268
269
  });
269
- this.agents.quartermaster.start(this.explorer.playwrightHelper, this.explorer.getStateManager());
270
+ this.agents.quartermaster.start(this.explorer, this.stateManager());
270
271
  }
271
272
  return this.agents.quartermaster;
272
273
  }
273
274
 
274
275
  agentHistorian(): Historian {
275
- return (this.agents.historian ||= this.createAgent(({ ai, explorer, config }) => {
276
- const experienceTracker = explorer.getStateManager().getExperienceTracker();
277
- const reporter = explorer.getReporter();
278
- return new Historian(ai, experienceTracker, reporter, explorer.getStateManager(), config, {
279
- recorder: explorer.getPlaywrightRecorder(),
280
- helper: explorer.playwrightHelper,
276
+ return (this.agents.historian ||= this.createAgent(({ ai, explorer, config, stateManager, playwrightRecorder }) => {
277
+ return new Historian(ai, this.experienceTracker(), this.reporter(), stateManager, config, {
278
+ recorder: playwrightRecorder,
279
+ explorer,
281
280
  });
282
281
  }));
283
282
  }
284
283
 
285
284
  agentRerunner(): Rerunner {
286
285
  if (!this.agents.rerunner) {
287
- this.agents.rerunner = this.createAgent(({ ai, explorer }) => {
286
+ this.agents.rerunner = this.createAgent((deps) => {
288
287
  const researcher = this.agentResearcher();
289
288
  const navigator = this.agentNavigator();
290
- const tools = createAgentTools({ explorer, researcher, navigator });
291
- return new Rerunner(explorer, ai, tools);
289
+ const tools = createAgentTools({ ...deps, researcher, navigator, withExperience: false });
290
+ return new Rerunner(deps, tools);
292
291
  });
293
- const qm = this.agentQuartermaster();
294
- if (qm) this.agents.rerunner.setQuartermaster(qm);
295
- this.agents.rerunner.setHistorian(this.agentHistorian());
292
+ if (this.isHistorianEnabled()) this.agents.rerunner.setHistorian(this.agentHistorian());
296
293
  }
297
294
  return this.agents.rerunner;
298
295
  }
299
296
 
300
297
  agentDriller(): Driller {
301
- return (this.agents.driller ||= this.createAgent(({ ai, explorer }) => {
298
+ return (this.agents.driller ||= this.createAgent((deps) => {
302
299
  const navigator = this.agentNavigator();
303
- return new Driller(explorer, ai, navigator);
300
+ return new Driller(deps, navigator);
304
301
  }));
305
302
  }
306
303
 
@@ -317,7 +314,7 @@ export class ExplorBot {
317
314
  if (!this.agents.fisherman) {
318
315
  const apiConfig = this.config.api;
319
316
  const outputDir = this.configParser.getOutputDir();
320
- const requestStore = this.explorer.getRequestStore() || new RequestStore(outputDir);
317
+ const requestStore = this.requestStore();
321
318
  const baseEndpoint = apiConfig?.baseEndpoint || this.config.playwright.url;
322
319
  const configHeaders = apiConfig?.headers || {};
323
320
  const apiClient = new ApiClient(baseEndpoint);
@@ -332,7 +329,11 @@ export class ExplorBot {
332
329
  }
333
330
  };
334
331
 
335
- const cookieProvider = () => this.explorer.extractCookies();
332
+ const cookieProvider = async (): Promise<Record<string, string>> => {
333
+ const cookies = await this.explorer.withPage((page) => page.context().cookies()).catch(() => []);
334
+ if (!cookies.length) return {};
335
+ return { Cookie: cookies.map((c: any) => `${c.name}=${c.value}`).join('; ') };
336
+ };
336
337
 
337
338
  this.agents.fisherman = this.createAgent(({ ai }) => {
338
339
  return new Fisherman(ai, apiClient, requestStore, specLoader, baseEndpoint, cookieProvider, configHeaders, hasApiConfig);
@@ -366,7 +367,7 @@ export class ExplorBot {
366
367
  }
367
368
 
368
369
  if (!opts.extend && this.currentPlan?.url) {
369
- const currentUrl = this.explorer?.getStateManager().getCurrentState()?.url;
370
+ const currentUrl = this._stateManager?.getCurrentState()?.url;
370
371
  if (currentUrl && currentUrl !== this.currentPlan.url) {
371
372
  tag('info').log('Different page detected, clearing previous plan');
372
373
  this.clearPlan();
@@ -419,7 +420,7 @@ export class ExplorBot {
419
420
  }
420
421
 
421
422
  generatePlanFilename(feature?: string): string {
422
- const state = this.explorer?.getStateManager().getCurrentState();
423
+ const state = this._stateManager?.getCurrentState();
423
424
  const urlPath = state?.url || '/';
424
425
  const urlPart = sanitizeFilename(urlPath) || 'root';
425
426
  const suffix = '.md';
@@ -499,7 +500,7 @@ export class ExplorBot {
499
500
  const filePath = this.agentSessionAnalyst().writeReport(markdown);
500
501
  tag('info').log(`Session report saved: ${relativeToCwd(filePath)}`);
501
502
 
502
- const reporter = this.explorer?.getReporter();
503
+ const reporter = this._reporter;
503
504
  if (reporter?.isEnabled()) {
504
505
  let description = markdown;
505
506
  const modelsTable = Stats.modelsTable(this.provider.getConfiguredModels());
@@ -509,8 +510,12 @@ export class ExplorBot {
509
510
 
510
511
  this.lastReportedTestCount = tests.length;
511
512
  } catch (error) {
512
- const message = error instanceof Error ? error.message : String(error);
513
+ const message = browserErrorMessage(error);
513
514
  tag('warning').log(`Session analysis failed: ${message}`);
514
515
  }
515
516
  }
517
+
518
+ private isHistorianEnabled(): boolean {
519
+ return this.config.ai?.agents?.historian?.enabled !== false;
520
+ }
516
521
  }