explorbot 0.0.1 → 0.1.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.
- package/README.md +80 -26
- package/bin/explorbot-cli.ts +680 -0
- package/boat/api-tester/src/ai/chief/styles.ts +15 -0
- package/boat/api-tester/src/ai/chief.ts +335 -0
- package/boat/api-tester/src/ai/curler-tools.ts +278 -0
- package/boat/api-tester/src/ai/curler.ts +306 -0
- package/boat/api-tester/src/api-client.ts +28 -0
- package/boat/api-tester/src/apibot.ts +203 -0
- package/boat/api-tester/src/cli.ts +301 -0
- package/boat/api-tester/src/config.ts +190 -0
- package/dist/bin/explorbot-cli.js +23 -101
- package/dist/boat/api-tester/bin/apibot-cli.js +0 -1
- package/dist/boat/api-tester/src/ai/chief/styles.js +0 -1
- package/dist/boat/api-tester/src/ai/chief.js +0 -1
- package/dist/boat/api-tester/src/ai/curler-tools.js +0 -1
- package/dist/boat/api-tester/src/ai/curler.js +0 -1
- package/dist/boat/api-tester/src/api-client.js +0 -1
- package/dist/boat/api-tester/src/apibot.js +0 -1
- package/dist/boat/api-tester/src/cli.js +0 -1
- package/dist/boat/api-tester/src/config.js +0 -1
- package/dist/src/action-result.js +0 -1
- package/dist/src/action.js +14 -12
- package/dist/src/activity.js +0 -1
- package/dist/src/ai/agent.js +0 -1
- package/dist/src/ai/bosun.js +0 -1
- package/dist/src/ai/captain/idle-mode.js +0 -1
- package/dist/src/ai/captain/mixin.js +0 -1
- package/dist/src/ai/captain/test-mode.js +0 -1
- package/dist/src/ai/captain/web-mode.js +0 -1
- package/dist/src/ai/captain.js +0 -1
- package/dist/src/ai/conversation.js +0 -1
- package/dist/src/ai/experience-compactor.js +0 -1
- package/dist/src/ai/fisherman-tools.js +0 -1
- package/dist/src/ai/fisherman.js +0 -1
- package/dist/src/ai/historian.js +0 -1
- package/dist/src/ai/navigator.js +0 -1
- package/dist/src/ai/pilot.js +0 -1
- package/dist/src/ai/planner/session-dedup.js +0 -1
- package/dist/src/ai/planner/styles.js +0 -1
- package/dist/src/ai/planner/subpages.js +42 -7
- package/dist/src/ai/planner.js +15 -4
- package/dist/src/ai/provider.js +0 -1
- package/dist/src/ai/quartermaster.js +0 -1
- package/dist/src/ai/researcher/cache.js +13 -9
- package/dist/src/ai/researcher/coordinates.js +4 -3
- package/dist/src/ai/researcher/deep-analysis.js +16 -20
- package/dist/src/ai/researcher/fingerprint-worker.js +0 -1
- package/dist/src/ai/researcher/focus.js +0 -1
- package/dist/src/ai/researcher/locators.js +1 -2
- package/dist/src/ai/researcher/mixin.js +0 -1
- package/dist/src/ai/researcher/parser.js +4 -4
- package/dist/src/ai/researcher/research-result.js +2 -1
- package/dist/src/ai/researcher.js +6 -6
- package/dist/src/ai/rules.js +0 -1
- package/dist/src/ai/task-agent.js +0 -1
- package/dist/src/ai/tester.js +0 -1
- package/dist/src/ai/tools.js +4 -1
- package/dist/src/api/api-client.js +0 -1
- package/dist/src/api/request-result.js +0 -1
- package/dist/src/api/request-store.js +0 -1
- package/dist/src/api/spec-reader.js +0 -1
- package/dist/src/api/xhr-capture.js +0 -1
- package/dist/src/browser-server.js +0 -1
- package/dist/src/command-handler.js +0 -1
- package/dist/src/commands/add-rule-command.js +0 -1
- package/dist/src/commands/base-command.js +0 -1
- package/dist/src/commands/clean-command.js +0 -1
- package/dist/src/commands/context-aria-command.js +0 -1
- package/dist/src/commands/context-command.js +2 -3
- package/dist/src/commands/context-data-command.js +0 -1
- package/dist/src/commands/context-experience-command.js +0 -1
- package/dist/src/commands/context-html-command.js +0 -1
- package/dist/src/commands/context-knowledge-command.js +0 -1
- package/dist/src/commands/debug-command.js +0 -1
- package/dist/src/commands/drill-command.js +0 -1
- package/dist/src/commands/exit-command.js +0 -1
- package/dist/src/commands/explore-command.js +3 -3
- package/dist/src/commands/freesail-command.js +0 -1
- package/dist/src/commands/help-command.js +0 -1
- package/dist/src/commands/index.js +0 -1
- package/dist/src/commands/init-command.js +117 -0
- package/dist/src/commands/knows-command.js +0 -1
- package/dist/src/commands/learn-command.js +0 -1
- package/dist/src/commands/navigate-command.js +0 -1
- package/dist/src/commands/path-command.js +0 -1
- package/dist/src/commands/plan-clear-command.js +0 -1
- package/dist/src/commands/plan-command.js +6 -2
- package/dist/src/commands/plan-edit-command.js +0 -1
- package/dist/src/commands/plan-load-command.js +0 -1
- package/dist/src/commands/plan-reload-command.js +0 -1
- package/dist/src/commands/plan-save-command.js +0 -1
- package/dist/src/commands/research-command.js +0 -1
- package/dist/src/commands/start-command.js +0 -1
- package/dist/src/commands/status-command.js +0 -1
- package/dist/src/commands/test-command.js +0 -1
- package/dist/src/components/ActivityPane.js +0 -1
- package/dist/src/components/AddKnowledge.js +0 -1
- package/dist/src/components/AddRule.js +0 -1
- package/dist/src/components/App.js +0 -1
- package/dist/src/components/Autocomplete.js +0 -1
- package/dist/src/components/InputPane.js +0 -1
- package/dist/src/components/InputReadline.js +0 -1
- package/dist/src/components/LogPane.js +0 -1
- package/dist/src/components/PlanEditor.js +0 -1
- package/dist/src/components/PlanPane.js +0 -1
- package/dist/src/components/SessionTimer.js +0 -1
- package/dist/src/components/StateTransitionPane.js +0 -1
- package/dist/src/components/StatusPane.js +0 -1
- package/dist/src/components/TaskPane.js +0 -1
- package/dist/src/components/Welcome.js +0 -1
- package/dist/src/components/WelcomeChecklist.js +0 -1
- package/dist/src/components/WelcomeCommands.js +0 -1
- package/dist/src/components/autocomplete-store.js +0 -1
- package/dist/src/components/parse-keypress.js +0 -1
- package/dist/src/config.js +0 -1
- package/dist/src/execution-controller.js +0 -1
- package/dist/src/experience-tracker.js +0 -1
- package/dist/src/explorbot.js +1 -2
- package/dist/src/explorer.js +58 -17
- package/dist/src/index.js +0 -1
- package/dist/src/knowledge-tracker.js +2 -2
- package/dist/src/observability.js +0 -1
- package/dist/src/reporter.js +0 -1
- package/dist/src/state-manager.js +0 -1
- package/dist/src/stats.js +0 -1
- package/dist/src/test-plan.js +0 -1
- package/dist/src/utils/aria.js +0 -1
- package/dist/src/utils/cli-name.js +16 -0
- package/dist/src/utils/code-extractor.js +0 -1
- package/dist/src/utils/context-formatter.js +0 -1
- package/dist/src/utils/error-page.js +0 -1
- package/dist/src/utils/expandable.js +0 -1
- package/dist/src/utils/hooks-runner.js +0 -1
- package/dist/src/utils/html-diff.js +0 -1
- package/dist/src/utils/html.js +0 -1
- package/dist/src/utils/logger.js +0 -1
- package/dist/src/utils/loop.js +0 -1
- package/dist/src/utils/markdown-parser.js +0 -1
- package/dist/src/utils/markdown-query.js +0 -1
- package/dist/src/utils/markdown-terminal.js +0 -1
- package/dist/src/utils/research-parser.js +0 -1
- package/dist/src/utils/retry.js +0 -1
- package/dist/src/utils/rules-loader.js +0 -1
- package/dist/src/utils/strings.js +0 -1
- package/dist/src/utils/test-plan-markdown.js +0 -1
- package/dist/src/utils/throttle.js +0 -1
- package/dist/src/utils/unique-names.js +0 -1
- package/dist/src/utils/url-matcher.js +0 -1
- package/dist/src/utils/web-element.js +6 -5
- package/dist/src/utils/xpath.js +0 -1
- package/package.json +28 -4
- package/src/action-result.ts +694 -0
- package/src/action.ts +449 -0
- package/src/activity.ts +111 -0
- package/src/ai/agent.ts +3 -0
- package/src/ai/bosun.ts +557 -0
- package/src/ai/captain/idle-mode.ts +116 -0
- package/src/ai/captain/mixin.ts +22 -0
- package/src/ai/captain/test-mode.ts +262 -0
- package/src/ai/captain/web-mode.ts +136 -0
- package/src/ai/captain.ts +504 -0
- package/src/ai/conversation.ts +205 -0
- package/src/ai/experience-compactor.ts +284 -0
- package/src/ai/fisherman-tools.ts +181 -0
- package/src/ai/fisherman.ts +223 -0
- package/src/ai/historian.ts +457 -0
- package/src/ai/navigator.ts +572 -0
- package/src/ai/pilot.ts +776 -0
- package/src/ai/planner/session-dedup.ts +35 -0
- package/src/ai/planner/styles.ts +17 -0
- package/src/ai/planner/subpages.ts +171 -0
- package/src/ai/planner.ts +549 -0
- package/src/ai/provider.ts +613 -0
- package/src/ai/quartermaster.ts +286 -0
- package/src/ai/researcher/cache.ts +109 -0
- package/src/ai/researcher/coordinates.ts +239 -0
- package/src/ai/researcher/deep-analysis.ts +412 -0
- package/src/ai/researcher/fingerprint-worker.ts +59 -0
- package/src/ai/researcher/focus.ts +42 -0
- package/src/ai/researcher/locators.ts +282 -0
- package/src/ai/researcher/mixin.ts +4 -0
- package/src/ai/researcher/parser.ts +186 -0
- package/src/ai/researcher/research-result.ts +116 -0
- package/src/ai/researcher.ts +858 -0
- package/src/ai/rules.ts +376 -0
- package/src/ai/task-agent.ts +141 -0
- package/src/ai/tester.ts +939 -0
- package/src/ai/tools.ts +1122 -0
- package/src/api/api-client.ts +109 -0
- package/src/api/request-result.ts +212 -0
- package/src/api/request-store.ts +130 -0
- package/src/api/spec-reader.ts +174 -0
- package/src/api/xhr-capture.ts +100 -0
- package/src/browser-server.ts +74 -0
- package/src/command-handler.ts +454 -0
- package/src/commands/add-rule-command.ts +63 -0
- package/src/commands/base-command.ts +27 -0
- package/src/commands/clean-command.ts +73 -0
- package/src/commands/context-aria-command.ts +22 -0
- package/src/commands/context-command.ts +67 -0
- package/src/commands/context-data-command.ts +30 -0
- package/src/commands/context-experience-command.ts +48 -0
- package/src/commands/context-html-command.ts +33 -0
- package/src/commands/context-knowledge-command.ts +43 -0
- package/src/commands/debug-command.ts +13 -0
- package/src/commands/drill-command.ts +34 -0
- package/src/commands/exit-command.ts +32 -0
- package/src/commands/explore-command.ts +129 -0
- package/src/commands/freesail-command.ts +95 -0
- package/src/commands/help-command.ts +8 -0
- package/src/commands/index.ts +69 -0
- package/src/commands/init-command.ts +131 -0
- package/src/commands/knows-command.ts +68 -0
- package/src/commands/learn-command.ts +44 -0
- package/src/commands/navigate-command.ts +18 -0
- package/src/commands/path-command.ts +83 -0
- package/src/commands/plan-clear-command.ts +14 -0
- package/src/commands/plan-command.ts +46 -0
- package/src/commands/plan-edit-command.ts +9 -0
- package/src/commands/plan-load-command.ts +18 -0
- package/src/commands/plan-reload-command.ts +28 -0
- package/src/commands/plan-save-command.ts +25 -0
- package/src/commands/research-command.ts +45 -0
- package/src/commands/start-command.ts +13 -0
- package/src/commands/status-command.tsx +23 -0
- package/src/commands/test-command.ts +84 -0
- package/src/components/ActivityPane.tsx +80 -0
- package/src/components/AddKnowledge.tsx +169 -0
- package/src/components/AddRule.tsx +174 -0
- package/src/components/App.tsx +377 -0
- package/src/components/Autocomplete.tsx +63 -0
- package/src/components/InputPane.tsx +259 -0
- package/src/components/InputReadline.tsx +704 -0
- package/src/components/LogPane.tsx +187 -0
- package/src/components/PlanEditor.tsx +150 -0
- package/src/components/PlanPane.tsx +71 -0
- package/src/components/SessionTimer.tsx +35 -0
- package/src/components/StateTransitionPane.tsx +149 -0
- package/src/components/StatusPane.tsx +62 -0
- package/src/components/TaskPane.tsx +119 -0
- package/src/components/Welcome.tsx +83 -0
- package/src/components/WelcomeChecklist.tsx +118 -0
- package/src/components/WelcomeCommands.tsx +102 -0
- package/src/components/autocomplete-store.ts +35 -0
- package/src/components/parse-keypress.ts +170 -0
- package/src/config.ts +491 -0
- package/src/execution-controller.ts +109 -0
- package/src/experience-tracker.ts +350 -0
- package/src/explorbot.ts +405 -0
- package/src/explorer.ts +760 -0
- package/src/index.tsx +62 -0
- package/src/knowledge-tracker.ts +230 -0
- package/src/observability.ts +150 -0
- package/src/reporter.ts +224 -0
- package/src/state-manager.ts +556 -0
- package/src/stats.ts +53 -0
- package/src/test-plan.ts +432 -0
- package/src/utils/aria.ts +629 -0
- package/src/utils/cli-name.ts +13 -0
- package/src/utils/code-extractor.ts +22 -0
- package/src/utils/context-formatter.ts +239 -0
- package/src/utils/error-page.ts +23 -0
- package/src/utils/expandable.ts +38 -0
- package/src/utils/hooks-runner.ts +79 -0
- package/src/utils/html-diff.ts +918 -0
- package/src/utils/html.ts +1316 -0
- package/src/utils/logger.ts +534 -0
- package/src/utils/loop.ts +176 -0
- package/src/utils/markdown-parser.ts +127 -0
- package/src/utils/markdown-query.ts +466 -0
- package/src/utils/markdown-terminal.ts +43 -0
- package/src/utils/research-parser.ts +11 -0
- package/src/utils/retry.ts +73 -0
- package/src/utils/rules-loader.ts +118 -0
- package/src/utils/strings.ts +13 -0
- package/src/utils/test-plan-markdown.ts +332 -0
- package/src/utils/throttle.ts +18 -0
- package/src/utils/unique-names.ts +14 -0
- package/src/utils/url-matcher.ts +45 -0
- package/src/utils/web-element.ts +147 -0
- package/src/utils/xpath.ts +129 -0
- package/dist/bin/explorbot-cli.js.map +0 -1
- package/dist/boat/api-tester/bin/apibot-cli.js.map +0 -1
- package/dist/boat/api-tester/example/apibot.config.js +0 -31
- package/dist/boat/api-tester/example/apibot.config.js.map +0 -1
- package/dist/boat/api-tester/src/ai/chief/styles.js.map +0 -1
- package/dist/boat/api-tester/src/ai/chief.js.map +0 -1
- package/dist/boat/api-tester/src/ai/curler-tools.js.map +0 -1
- package/dist/boat/api-tester/src/ai/curler.js.map +0 -1
- package/dist/boat/api-tester/src/api-client.js.map +0 -1
- package/dist/boat/api-tester/src/apibot.js.map +0 -1
- package/dist/boat/api-tester/src/cli.js.map +0 -1
- package/dist/boat/api-tester/src/config.js.map +0 -1
- package/dist/prompts/audit-rules.md +0 -124
- package/dist/src/action-result.js.map +0 -1
- package/dist/src/action.js.map +0 -1
- package/dist/src/activity.js.map +0 -1
- package/dist/src/ai/agent.js.map +0 -1
- package/dist/src/ai/bosun.js.map +0 -1
- package/dist/src/ai/captain/idle-mode.js.map +0 -1
- package/dist/src/ai/captain/mixin.js.map +0 -1
- package/dist/src/ai/captain/test-mode.js.map +0 -1
- package/dist/src/ai/captain/web-mode.js.map +0 -1
- package/dist/src/ai/captain.js.map +0 -1
- package/dist/src/ai/conversation.js.map +0 -1
- package/dist/src/ai/experience-compactor.js.map +0 -1
- package/dist/src/ai/fisherman-tools.js.map +0 -1
- package/dist/src/ai/fisherman.js.map +0 -1
- package/dist/src/ai/historian.js.map +0 -1
- package/dist/src/ai/navigator.js.map +0 -1
- package/dist/src/ai/pilot.js.map +0 -1
- package/dist/src/ai/planner/session-dedup.js.map +0 -1
- package/dist/src/ai/planner/styles.js.map +0 -1
- package/dist/src/ai/planner/subpages.js.map +0 -1
- package/dist/src/ai/planner.js.map +0 -1
- package/dist/src/ai/provider.js.map +0 -1
- package/dist/src/ai/quartermaster.js.map +0 -1
- package/dist/src/ai/researcher/cache.js.map +0 -1
- package/dist/src/ai/researcher/coordinates.js.map +0 -1
- package/dist/src/ai/researcher/deep-analysis.js.map +0 -1
- package/dist/src/ai/researcher/fingerprint-worker.js.map +0 -1
- package/dist/src/ai/researcher/focus.js.map +0 -1
- package/dist/src/ai/researcher/locators.js.map +0 -1
- package/dist/src/ai/researcher/mixin.js.map +0 -1
- package/dist/src/ai/researcher/parser.js.map +0 -1
- package/dist/src/ai/researcher/research-result.js.map +0 -1
- package/dist/src/ai/researcher.js.map +0 -1
- package/dist/src/ai/rules.js.map +0 -1
- package/dist/src/ai/task-agent.js.map +0 -1
- package/dist/src/ai/tester.js.map +0 -1
- package/dist/src/ai/tools.js.map +0 -1
- package/dist/src/api/api-client.js.map +0 -1
- package/dist/src/api/request-result.js.map +0 -1
- package/dist/src/api/request-store.js.map +0 -1
- package/dist/src/api/spec-reader.js.map +0 -1
- package/dist/src/api/xhr-capture.js.map +0 -1
- package/dist/src/browser-server.js.map +0 -1
- package/dist/src/command-handler.js.map +0 -1
- package/dist/src/commands/add-rule-command.js.map +0 -1
- package/dist/src/commands/base-command.js.map +0 -1
- package/dist/src/commands/clean-command.js.map +0 -1
- package/dist/src/commands/context-aria-command.js.map +0 -1
- package/dist/src/commands/context-command.js.map +0 -1
- package/dist/src/commands/context-data-command.js.map +0 -1
- package/dist/src/commands/context-experience-command.js.map +0 -1
- package/dist/src/commands/context-html-command.js.map +0 -1
- package/dist/src/commands/context-knowledge-command.js.map +0 -1
- package/dist/src/commands/debug-command.js.map +0 -1
- package/dist/src/commands/drill-command.js.map +0 -1
- package/dist/src/commands/exit-command.js.map +0 -1
- package/dist/src/commands/explore-command.js.map +0 -1
- package/dist/src/commands/freesail-command.js.map +0 -1
- package/dist/src/commands/help-command.js.map +0 -1
- package/dist/src/commands/index.js.map +0 -1
- package/dist/src/commands/knows-command.js.map +0 -1
- package/dist/src/commands/learn-command.js.map +0 -1
- package/dist/src/commands/navigate-command.js.map +0 -1
- package/dist/src/commands/path-command.js.map +0 -1
- package/dist/src/commands/plan-clear-command.js.map +0 -1
- package/dist/src/commands/plan-command.js.map +0 -1
- package/dist/src/commands/plan-edit-command.js.map +0 -1
- package/dist/src/commands/plan-load-command.js.map +0 -1
- package/dist/src/commands/plan-reload-command.js.map +0 -1
- package/dist/src/commands/plan-save-command.js.map +0 -1
- package/dist/src/commands/research-command.js.map +0 -1
- package/dist/src/commands/start-command.js.map +0 -1
- package/dist/src/commands/status-command.js.map +0 -1
- package/dist/src/commands/test-command.js.map +0 -1
- package/dist/src/components/ActivityPane.js.map +0 -1
- package/dist/src/components/AddKnowledge.js.map +0 -1
- package/dist/src/components/AddRule.js.map +0 -1
- package/dist/src/components/App.js.map +0 -1
- package/dist/src/components/Autocomplete.js.map +0 -1
- package/dist/src/components/InputPane.js.map +0 -1
- package/dist/src/components/InputReadline.js.map +0 -1
- package/dist/src/components/LogPane.js.map +0 -1
- package/dist/src/components/PlanEditor.js.map +0 -1
- package/dist/src/components/PlanPane.js.map +0 -1
- package/dist/src/components/SessionTimer.js.map +0 -1
- package/dist/src/components/StateTransitionPane.js.map +0 -1
- package/dist/src/components/StatusPane.js.map +0 -1
- package/dist/src/components/TaskPane.js.map +0 -1
- package/dist/src/components/Welcome.js.map +0 -1
- package/dist/src/components/WelcomeChecklist.js.map +0 -1
- package/dist/src/components/WelcomeCommands.js.map +0 -1
- package/dist/src/components/autocomplete-store.js.map +0 -1
- package/dist/src/components/parse-keypress.js.map +0 -1
- package/dist/src/config.js.map +0 -1
- package/dist/src/execution-controller.js.map +0 -1
- package/dist/src/experience-tracker.js.map +0 -1
- package/dist/src/explorbot.js.map +0 -1
- package/dist/src/explorer.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/knowledge-tracker.js.map +0 -1
- package/dist/src/observability.js.map +0 -1
- package/dist/src/reporter.js.map +0 -1
- package/dist/src/state-manager.js.map +0 -1
- package/dist/src/stats.js.map +0 -1
- package/dist/src/test-plan.js.map +0 -1
- package/dist/src/utils/aria.js.map +0 -1
- package/dist/src/utils/code-extractor.js.map +0 -1
- package/dist/src/utils/context-formatter.js.map +0 -1
- package/dist/src/utils/error-page.js.map +0 -1
- package/dist/src/utils/expandable.js.map +0 -1
- package/dist/src/utils/hooks-runner.js.map +0 -1
- package/dist/src/utils/html-diff.js.map +0 -1
- package/dist/src/utils/html.js.map +0 -1
- package/dist/src/utils/logger.js.map +0 -1
- package/dist/src/utils/loop.js.map +0 -1
- package/dist/src/utils/markdown-parser.js.map +0 -1
- package/dist/src/utils/markdown-query.js.map +0 -1
- package/dist/src/utils/markdown-terminal.js.map +0 -1
- package/dist/src/utils/research-parser.js.map +0 -1
- package/dist/src/utils/retry.js.map +0 -1
- package/dist/src/utils/rules-loader.js.map +0 -1
- package/dist/src/utils/strings.js.map +0 -1
- package/dist/src/utils/test-plan-markdown.js.map +0 -1
- package/dist/src/utils/throttle.js.map +0 -1
- package/dist/src/utils/unique-names.js.map +0 -1
- package/dist/src/utils/url-matcher.js.map +0 -1
- package/dist/src/utils/web-element.js.map +0 -1
- package/dist/src/utils/xpath.js.map +0 -1
- package/prompts/audit-rules.md +0 -124
package/src/ai/rules.ts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import dedent from 'dedent';
|
|
2
|
+
|
|
3
|
+
export const recommendedCodeceptCommands = ['I.click', 'I.type', 'I.fillField', 'I.see', 'I.seeElement'] as const;
|
|
4
|
+
|
|
5
|
+
export const locatorRule = dedent`
|
|
6
|
+
<locator_priority>
|
|
7
|
+
Use the following priority when selecting locators:
|
|
8
|
+
|
|
9
|
+
1. ARIA locators (first choice) - target browser's accessibility tree, most reliable
|
|
10
|
+
Use JSON format: { "role": "button", "text": "Login" }
|
|
11
|
+
Best for: buttons, links, inputs, form controls, dropdowns, checkboxes, radio buttons
|
|
12
|
+
|
|
13
|
+
2. Text locators (second choice) - use only when text is unique on the page
|
|
14
|
+
Example: 'Login', 'Submit', 'Username'
|
|
15
|
+
Skip if the same text appears multiple times on the page
|
|
16
|
+
|
|
17
|
+
3. CSS selectors (third choice) - when ARIA/text don't work
|
|
18
|
+
Prefer semantic attributes: id, name, data-testid, aria-label, placeholder
|
|
19
|
+
Example: '#login-btn', '[data-testid="submit"]', 'form#login input[name="email"]'
|
|
20
|
+
|
|
21
|
+
4. XPath (last resort) - for complex hierarchy or when CSS can't express the path
|
|
22
|
+
Always start with //, never use positional indices like [1], [2]
|
|
23
|
+
Example: '//form[@id="login"]//input[@name="email"]'
|
|
24
|
+
</locator_priority>
|
|
25
|
+
|
|
26
|
+
<context_simplification>
|
|
27
|
+
When container is available from UI map sections:
|
|
28
|
+
- Text + container is simplest and PREFERRED: I.click('Save', '.modal')
|
|
29
|
+
- ARIA + container for disambiguation: I.click({"role":"button","text":"Save"}, '.modal')
|
|
30
|
+
- ALWAYS use context parameter unless locator is XPath or unique ID
|
|
31
|
+
- No need for complex ARIA when container narrows scope sufficiently
|
|
32
|
+
</context_simplification>
|
|
33
|
+
|
|
34
|
+
<disambiguation>
|
|
35
|
+
When multiple elements could match the request, select based on intent:
|
|
36
|
+
1. Match the context of recent actions - if filling a form, use elements in that same form
|
|
37
|
+
2. Follow form flow - forms are filled top-to-bottom, left-to-right
|
|
38
|
+
- If you just filled a field, the next target is likely below/after it in the DOM
|
|
39
|
+
3. Use ARIA snapshot to identify element state (focused, visible, selected, expanded, etc.)
|
|
40
|
+
4. Match semantic proximity - elements near fields you just interacted with
|
|
41
|
+
|
|
42
|
+
Once the correct element is identified pick the best unique locator following priority: ARIA → CSS → XPath
|
|
43
|
+
</disambiguation>
|
|
44
|
+
|
|
45
|
+
ARIA locators must specify role. Specify locator type as JSON string with role and text keys.
|
|
46
|
+
|
|
47
|
+
For icon-only buttons/links with no visible text:
|
|
48
|
+
- Use aria-label value if present: { "role": "button", "text": "Close" } (from aria-label="Close")
|
|
49
|
+
- Use title attribute if present: { "role": "button", "text": "Settings" } (from title="Settings")
|
|
50
|
+
- If no accessible name exists, mark ARIA as "-" and use CSS/XPath:
|
|
51
|
+
* CSS: use partial href a[href*="settings"] or SVG icon class a:has(svg.md-icon-cog)
|
|
52
|
+
* XPath: use contains(@href,"settings") or SVG class //a[.//svg[contains(@class,"md-icon-cog")]]
|
|
53
|
+
- NEVER use empty text: { "role": "button", "text": "" } is INVALID and useless
|
|
54
|
+
|
|
55
|
+
<good_aria_locator_example>
|
|
56
|
+
{ "role": "button", "text": "Login" },
|
|
57
|
+
{ "role": "input", "text": "Name" },
|
|
58
|
+
{ "role": "link", "text": "Forgot your password?" },
|
|
59
|
+
{ "role": "link", "text": "Sign Up" },
|
|
60
|
+
{ "role": "button", "text": "Sign In" },
|
|
61
|
+
{ "role": "button", "text": "Submit" },
|
|
62
|
+
{ "role": "button", "text": "Cancel" },
|
|
63
|
+
{ "role": "button", "text": "Close" } // from aria-label
|
|
64
|
+
</good_aria_locator_example>
|
|
65
|
+
|
|
66
|
+
<bad_aria_locator_example>
|
|
67
|
+
{ "role": "button", "text": "" } // INVALID - empty text is useless, use "-" instead
|
|
68
|
+
{ "role": "button", "name": "Save" } // WRONG key - use "text", not "name"
|
|
69
|
+
</bad_aria_locator_example>
|
|
70
|
+
|
|
71
|
+
NEVER include \`eidx\` attribute in any locator (ARIA, CSS, XPath). It is an internal annotation.
|
|
72
|
+
|
|
73
|
+
If <aria> section is not present or element is not found there, fall back to CSS/XPath locators from <html> section.
|
|
74
|
+
|
|
75
|
+
Stick to semantic attributes like role, aria-*, id, class, name, data-id, etc.
|
|
76
|
+
Avoid IDs that follow framework auto-generation patterns (these change on every page load):
|
|
77
|
+
- Ember: #ember123, #ember-basic-dropdown-content-ember456
|
|
78
|
+
- React: #react-select-*, #rc-*
|
|
79
|
+
- Angular: #ng-*, #cdk-*, #mat-*
|
|
80
|
+
- Vue: data-v-* attributes
|
|
81
|
+
Avoid locators that seem to have generated ids or class names (long random numbers, uuids, hashes, etc)
|
|
82
|
+
Prefer text or ARIA locators over href-based ones. But for icon-only links with no accessible name, use:
|
|
83
|
+
- Partial href match: a[href*="settings"], a[href*="requirements"] (use path segments, not full URLs)
|
|
84
|
+
- SVG icon class: a:has(svg.md-icon-cog), button:has(svg.md-icon-plus) (target the SVG class inside the link/button)
|
|
85
|
+
Avoid full absolute href like a[href="/projects/imr_manual12/settings"] — use generic path segments instead
|
|
86
|
+
Avoid CSS framework utility classes as containers (Tailwind: flex, grid, space-x-*, justify-*, items-*, w-*, h-*, p-*, m-*, etc; Bootstrap: col-*, row, d-flex, etc)
|
|
87
|
+
Prefer semantic class names, roles, data attributes, or element hierarchy for containers
|
|
88
|
+
|
|
89
|
+
<css_rules>
|
|
90
|
+
CSS selectors must use semantic attributes and :has-text("text") for disambiguation.
|
|
91
|
+
ALLOWED: :has-text("text") pseudo class for matching elements by visible text.
|
|
92
|
+
DO NOT use positional pseudo classes in CSS: :nth-of-type, :nth-child, :first, :last, :nth-last-child, :only-child, :only-of-type, :empty, :not, etc.
|
|
93
|
+
</css_rules>
|
|
94
|
+
|
|
95
|
+
<xpath_rules>
|
|
96
|
+
XPath locators must start with //.
|
|
97
|
+
XPath should use positional indices [1], [2], [3] and contains(., "text") for disambiguation.
|
|
98
|
+
XPath should rely less on class names — prefer element hierarchy, position, and text content.
|
|
99
|
+
XPath and CSS MUST provide different strategies for finding the same element.
|
|
100
|
+
</xpath_rules>
|
|
101
|
+
|
|
102
|
+
<good locator example>
|
|
103
|
+
'div[role=input][placeholder="Name"]'
|
|
104
|
+
'[aria-label="Name"]'
|
|
105
|
+
'form#user_form input[name="name"]'
|
|
106
|
+
'#content-top #user_name'
|
|
107
|
+
'#content-top form input[name="name"]'
|
|
108
|
+
'a.nav-item[href*="settings"]' // icon-only link matched by partial href
|
|
109
|
+
'a.nav-item:has(svg.md-icon-cog)' // icon-only link matched by SVG icon class
|
|
110
|
+
'//nav//a[contains(@href,"settings")]' // XPath for icon-only nav link
|
|
111
|
+
</good locator example>
|
|
112
|
+
|
|
113
|
+
<bad locator example>
|
|
114
|
+
'a.filter-tab:nth-of-type(1)' // WRONG: positional in CSS, use :has-text("Manual") instead
|
|
115
|
+
'//a[contains(@class,"filter-tab") and contains(@class,"active")]' // WRONG: XPath repeats CSS approach, use positional //a[contains(@class,"filter-tab")][1]
|
|
116
|
+
'//table//tbody/tr[1]//button[contains(@onclick,'fn()')]' // onclick is not semantic attribute
|
|
117
|
+
'//html/body/vue-button-123' // vue-framework specific locator
|
|
118
|
+
'link "New Template"' // WRONG: malformed string, use {"role":"link","text":"New Template"}
|
|
119
|
+
'a[href="/projects/imr_manual12/settings"]' // WRONG: full absolute href, use a[href*="settings"] instead
|
|
120
|
+
</bad locator example>
|
|
121
|
+
|
|
122
|
+
HTML locators must be valid JS strings
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
export const fileUploadRule = dedent`
|
|
126
|
+
<file_upload>
|
|
127
|
+
Explorbot CAN upload files using I.attachFile() via form() tool.
|
|
128
|
+
When a test scenario involves file uploading, use the available sample files listed in <available_files>.
|
|
129
|
+
Use I.attachFile(locator, filePath) where locator points to an input[type="file"] element.
|
|
130
|
+
Works with drag-and-drop upload zones.
|
|
131
|
+
</file_upload>
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
// in rage mode we do not protect from irreversible actions
|
|
135
|
+
export const protectionRule = dedent`
|
|
136
|
+
<important>
|
|
137
|
+
Do not sign out current user of the application.
|
|
138
|
+
Do not change current user account settings
|
|
139
|
+
</important>
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
export const focusedElementRule = dedent`
|
|
143
|
+
<focused_element_actions>
|
|
144
|
+
When a text input element is focused (textbox, combobox, contenteditable):
|
|
145
|
+
|
|
146
|
+
To CLEAR the field before typing:
|
|
147
|
+
- I.pressKey(['Meta', 'a']); // Select all (use 'Control' on Windows/Linux)
|
|
148
|
+
- I.pressKey('Backspace'); // Delete selection
|
|
149
|
+
|
|
150
|
+
To TYPE into the focused element:
|
|
151
|
+
- I.type('text to enter'); // Types into currently focused element
|
|
152
|
+
|
|
153
|
+
For comboboxes/dropdowns:
|
|
154
|
+
- I.type('search text'); // Filter options by typing
|
|
155
|
+
- I.pressKey('Enter'); // Select highlighted option
|
|
156
|
+
|
|
157
|
+
IMPORTANT: type() works WITHOUT a locator when element is already focused.
|
|
158
|
+
If focus is on wrong element, click the correct field first.
|
|
159
|
+
</focused_element_actions>
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
export const sectionContextRule = dedent`
|
|
163
|
+
<section_context_rule>
|
|
164
|
+
Context parameter is DEFAULT for all interactions. ALWAYS use container from UI map sections unless locator is XPath or unique ID.
|
|
165
|
+
|
|
166
|
+
1. Identify which section contains the target element
|
|
167
|
+
2. Get the Context Locator from that section in the UI map
|
|
168
|
+
3. Pass container as the last parameter
|
|
169
|
+
|
|
170
|
+
Context works with ALL interaction methods:
|
|
171
|
+
- I.click('Submit', '.modal-content')
|
|
172
|
+
- I.click({"role":"button","text":"Save"}, '.main')
|
|
173
|
+
- I.fillField('Username', 'admin', '.login-form')
|
|
174
|
+
- I.selectOption('Country', 'USA', '.address-section')
|
|
175
|
+
- I.attachFile('input[type="file"]', 'path/to/file', '.upload-section')
|
|
176
|
+
- I.seeInField('Email', 'john@example.com', '.profile-form')
|
|
177
|
+
- I.dontSeeInField('Password', '', '.login-form')
|
|
178
|
+
|
|
179
|
+
For CSS locators - prepend section context:
|
|
180
|
+
- I.click('.main button.submit') // instead of I.click('button.submit')
|
|
181
|
+
|
|
182
|
+
Only omit context when:
|
|
183
|
+
- Locator is XPath (already includes path context)
|
|
184
|
+
- Locator is a unique ID (#specific-element)
|
|
185
|
+
</section_context_rule>
|
|
186
|
+
|
|
187
|
+
<unexpected_popup_rule>
|
|
188
|
+
If a modal/popup appeared that you didn't expect, dismiss it first before continuing with original task.
|
|
189
|
+
If elements become hidden or unclickable (timeout errors on visible elements), a dialog or overlay may have appeared on top.
|
|
190
|
+
If buttons are disabled unexpectedly, check if a popup is blocking interaction or if required form fields are empty.
|
|
191
|
+
|
|
192
|
+
Dismiss strategy (try in order):
|
|
193
|
+
1. I.clickXY(0, 0) — click outside the popup to close it
|
|
194
|
+
2. I.pressKey('Escape') — press Escape to dismiss
|
|
195
|
+
3. I.click('Cancel') — click Cancel button if present
|
|
196
|
+
4. I.click({ role: 'button', text: 'Close' }) — click X/close button if present
|
|
197
|
+
</unexpected_popup_rule>
|
|
198
|
+
`;
|
|
199
|
+
|
|
200
|
+
export function multipleTabsRule(tabs: Array<{ url: string; title: string }>): string {
|
|
201
|
+
const tabsList = tabs.map((tab, i) => ` ${i + 1}. ${tab.title} - ${tab.url}`).join('\n');
|
|
202
|
+
|
|
203
|
+
return dedent`
|
|
204
|
+
<multiple_tabs_warning>
|
|
205
|
+
⚠️ MULTIPLE BROWSER TABS DETECTED!
|
|
206
|
+
|
|
207
|
+
Other open tabs:
|
|
208
|
+
${tabsList}
|
|
209
|
+
|
|
210
|
+
You MUST handle these tabs before continuing:
|
|
211
|
+
|
|
212
|
+
Option 1 - If the other tab(s) are NOT needed (external docs, popups, etc.):
|
|
213
|
+
\`\`\`js
|
|
214
|
+
I.closeOtherTabs();
|
|
215
|
+
\`\`\`
|
|
216
|
+
|
|
217
|
+
Option 2 - If you need content from another tab:
|
|
218
|
+
\`\`\`js
|
|
219
|
+
I.switchToNextTab(); // switch to the next tab
|
|
220
|
+
// ... interact with that tab ...
|
|
221
|
+
I.closeOtherTabs(); // then close other tabs
|
|
222
|
+
\`\`\`
|
|
223
|
+
|
|
224
|
+
IMPORTANT: Always close extra tabs to avoid confusion. Multiple tabs can cause test failures.
|
|
225
|
+
</multiple_tabs_warning>
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const actionRule = dedent`
|
|
230
|
+
<actions>
|
|
231
|
+
### I.click
|
|
232
|
+
|
|
233
|
+
clicks on the element by its locator
|
|
234
|
+
|
|
235
|
+
I.click(<locator>, <context_locator>)
|
|
236
|
+
|
|
237
|
+
locators can be ARIA, CSS, or XPath locators.
|
|
238
|
+
Prefer ARIA locators as the main argument, use CSS/XPath only when ARIA is not available.
|
|
239
|
+
|
|
240
|
+
Use context parameter (second argument) to narrow click area when:
|
|
241
|
+
- The same text/button appears multiple times on page
|
|
242
|
+
- You need to click inside a specific form, modal, or section
|
|
243
|
+
Context should be a CSS selector pointing to a unique container.
|
|
244
|
+
|
|
245
|
+
<example>
|
|
246
|
+
I.click('Submit', '#login-form');
|
|
247
|
+
I.click('Button', '.sidebar');
|
|
248
|
+
I.click({ role: 'button', text: 'Button' }, '.sidebar');
|
|
249
|
+
I.click({ role: 'combobox', text: 'Select age' }, '.settings-panel');
|
|
250
|
+
I.click('.sidebar .button');
|
|
251
|
+
I.click('//form[@id="login"]//button');
|
|
252
|
+
</example>
|
|
253
|
+
|
|
254
|
+
Prefer text/ARIA locators with context over complex CSS/XPath selectors.
|
|
255
|
+
If locator doesn't work, try CSS or XPath locators.
|
|
256
|
+
If nothing works, use I.clickXY(x, y) as last resort.
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
### I.fillField
|
|
260
|
+
|
|
261
|
+
fills the field with the given value
|
|
262
|
+
|
|
263
|
+
I.fillField(<locator>, <text>, <context>)
|
|
264
|
+
|
|
265
|
+
<example>
|
|
266
|
+
I.fillField('Username', 'John', '.login-form'); // fills Username inside .login-form
|
|
267
|
+
I.fillField('Username', 'John'); // fills the field located by name or placeholder or label "Username" with the text "John"
|
|
268
|
+
I.fillField('//user/input', 'John'); // fills the field located by XPath "//user/input" with the text "John"
|
|
269
|
+
</example>
|
|
270
|
+
|
|
271
|
+
### I.type
|
|
272
|
+
|
|
273
|
+
Types text into the currently focused element. Use when fillField doesn't work,
|
|
274
|
+
for instance, for highly customized input fields like Monaco editors or rich text editors.
|
|
275
|
+
|
|
276
|
+
I.type(<text>)
|
|
277
|
+
|
|
278
|
+
<example>
|
|
279
|
+
I.type('John'); // types the text "John" into the active element
|
|
280
|
+
</example>
|
|
281
|
+
|
|
282
|
+
IMPORTANT: Requires an active/focused input field. Click the field first if not focused.
|
|
283
|
+
DOES NOT receive any locator, just text to type.
|
|
284
|
+
NEVER write: I.type('text', locator) or I.type('text', {locator: '...'}) — this is INVALID.
|
|
285
|
+
To type into a specific field: use I.fillField(locator, text) or I.click(locator) then I.type(text).
|
|
286
|
+
|
|
287
|
+
### I.pressKey
|
|
288
|
+
|
|
289
|
+
Sends keyboard key presses to the browser. Use for special keys or key combinations.
|
|
290
|
+
|
|
291
|
+
I.pressKey(<key>)
|
|
292
|
+
I.pressKey([<modifier>, <key>])
|
|
293
|
+
|
|
294
|
+
<example>
|
|
295
|
+
I.pressKey('Enter'); // Press Enter key
|
|
296
|
+
I.pressKey('Escape'); // Press Escape key
|
|
297
|
+
I.pressKey('Tab'); // Press Tab key
|
|
298
|
+
I.pressKey('Backspace'); // Press Backspace key
|
|
299
|
+
I.pressKey(['Control', 'a']); // Select all (Ctrl+A)
|
|
300
|
+
I.pressKey(['Meta', 'a']); // Select all on Mac (Cmd+A)
|
|
301
|
+
I.pressKey(['Shift', 'Tab']); // Shift+Tab to go back
|
|
302
|
+
I.pressKey('ArrowDown'); // Navigate dropdown options
|
|
303
|
+
</example>
|
|
304
|
+
|
|
305
|
+
IMPORTANT: Requires an active/focused element for most keys.
|
|
306
|
+
Commonly used after I.type() to submit forms or navigate dropdowns.
|
|
307
|
+
|
|
308
|
+
### I.switchTo
|
|
309
|
+
|
|
310
|
+
Switches browser context to/from an iframe.
|
|
311
|
+
|
|
312
|
+
I.switchTo(<locator>) - switch INTO an iframe
|
|
313
|
+
I.switchTo() - switch back to MAIN page (exit iframe)
|
|
314
|
+
|
|
315
|
+
<example>
|
|
316
|
+
I.switchTo('#payment-iframe'); // Enter iframe
|
|
317
|
+
I.fillField('Card', '4242'); // Interact inside iframe
|
|
318
|
+
I.switchTo(); // Exit back to main page
|
|
319
|
+
</example>
|
|
320
|
+
|
|
321
|
+
IMPORTANT: When inside an iframe, you can only interact with elements inside that iframe.
|
|
322
|
+
Call I.switchTo() without arguments to exit the iframe before interacting with main page elements.
|
|
323
|
+
|
|
324
|
+
### I.selectOption
|
|
325
|
+
|
|
326
|
+
In case you deal with select elements, use selectOption instead of fillField.
|
|
327
|
+
|
|
328
|
+
I.selectOption(<locator>, <value>, <context>)
|
|
329
|
+
|
|
330
|
+
<example>
|
|
331
|
+
I.selectOption('Choose Plan', 'Monthly', '.billing-section'); // select inside section
|
|
332
|
+
I.selectOption('Choose Plan', 'Monthly'); // select by label
|
|
333
|
+
I.selectOption('subscription', 'Monthly'); // match option by text
|
|
334
|
+
I.selectOption('//form/select[@name=account]','Premium');
|
|
335
|
+
I.selectOption('form select[name=account]', 'Premium');
|
|
336
|
+
</example>
|
|
337
|
+
|
|
338
|
+
### I.attachFile
|
|
339
|
+
|
|
340
|
+
Attaches a file to a file input element.
|
|
341
|
+
|
|
342
|
+
I.attachFile(<locator>, <filePath>, <context>)
|
|
343
|
+
|
|
344
|
+
<example>
|
|
345
|
+
I.attachFile('input[type="file"]', 'path/to/sample.png', '.upload-section')
|
|
346
|
+
I.attachFile('input[type="file"]', 'path/to/sample.png')
|
|
347
|
+
I.attachFile('#file-upload', 'path/to/sample.pdf')
|
|
348
|
+
</example>
|
|
349
|
+
|
|
350
|
+
IMPORTANT: Only works with input[type="file"] elements.
|
|
351
|
+
The locator must point to a file input or a label associated with one.
|
|
352
|
+
Use file paths exactly as listed in <available_files>.
|
|
353
|
+
For drag-and-drop upload zones, look for a hidden input[type="file"] inside the dropzone container.
|
|
354
|
+
Use the file paths from <available_files> section.
|
|
355
|
+
|
|
356
|
+
### I.moveCursorTo
|
|
357
|
+
|
|
358
|
+
Moves the mouse cursor to an element, triggering hover effects. Does NOT click.
|
|
359
|
+
Use to discover hover-triggered UI: tooltips, popovers, dropdown menus, preview cards.
|
|
360
|
+
|
|
361
|
+
I.moveCursorTo(<locator>, <context>)
|
|
362
|
+
|
|
363
|
+
<example>
|
|
364
|
+
I.moveCursorTo('Settings');
|
|
365
|
+
I.moveCursorTo({ role: 'menuitem', text: 'Products' }, '.navigation');
|
|
366
|
+
I.moveCursorTo('.user-avatar');
|
|
367
|
+
</example>
|
|
368
|
+
|
|
369
|
+
After hovering, use see() or context() to check what appeared.
|
|
370
|
+
|
|
371
|
+
[DO NEVER USE OTHER CODECEPTJS COMMANDS THAN PROPOSED HERE]
|
|
372
|
+
[INTERACT ONLY WITH ELEMENTS THAT ARE ON THE PAGE HTML]
|
|
373
|
+
[DO NOT USE WAIT FUNCTIONS]
|
|
374
|
+
|
|
375
|
+
</actions>
|
|
376
|
+
`;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import dedent from 'dedent';
|
|
2
|
+
import type { ActionResult } from '../action-result.js';
|
|
3
|
+
import type { ExperienceTracker } from '../experience-tracker.js';
|
|
4
|
+
import type { KnowledgeTracker } from '../knowledge-tracker.js';
|
|
5
|
+
import { createDebug, pluralize, tag } from '../utils/logger.js';
|
|
6
|
+
|
|
7
|
+
const debugLog = createDebug('explorbot:task-agent');
|
|
8
|
+
import { Historian } from './historian.js';
|
|
9
|
+
import type { Navigator } from './navigator.js';
|
|
10
|
+
import type { Provider } from './provider.js';
|
|
11
|
+
import { Quartermaster } from './quartermaster.js';
|
|
12
|
+
|
|
13
|
+
export function isInteractive(): boolean {
|
|
14
|
+
return process.env.INK_RUNNING === 'true';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createNullProxy<T extends object>(): T {
|
|
18
|
+
return new Proxy({} as T, {
|
|
19
|
+
get: () => async () => {},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export abstract class TaskAgent {
|
|
24
|
+
protected consecutiveFailures = 0;
|
|
25
|
+
protected consecutiveEmptyResults = 0;
|
|
26
|
+
protected recentToolCalls: any[] = [];
|
|
27
|
+
protected abstract readonly ACTION_TOOLS: string[];
|
|
28
|
+
|
|
29
|
+
private _historian: Historian | null = null;
|
|
30
|
+
private _quartermaster: Quartermaster | null = null;
|
|
31
|
+
|
|
32
|
+
protected abstract getNavigator(): Navigator;
|
|
33
|
+
protected abstract getExperienceTracker(): ExperienceTracker;
|
|
34
|
+
protected abstract getKnowledgeTracker(): KnowledgeTracker;
|
|
35
|
+
protected abstract getProvider(): Provider;
|
|
36
|
+
|
|
37
|
+
protected getKnowledge(actionResult: ActionResult): string {
|
|
38
|
+
const knowledgeFiles = this.getKnowledgeTracker().getRelevantKnowledge(actionResult);
|
|
39
|
+
|
|
40
|
+
if (knowledgeFiles.length === 0) return '';
|
|
41
|
+
|
|
42
|
+
const knowledgeContent = knowledgeFiles
|
|
43
|
+
.map((k) => k.content)
|
|
44
|
+
.filter((k) => !!k)
|
|
45
|
+
.join('\n\n');
|
|
46
|
+
|
|
47
|
+
tag('substep').log(`Found ${knowledgeFiles.length} relevant knowledge ${pluralize(knowledgeFiles.length, 'file')}`);
|
|
48
|
+
return dedent`
|
|
49
|
+
<knowledge>
|
|
50
|
+
Here is relevant knowledge for this page:
|
|
51
|
+
|
|
52
|
+
${knowledgeContent}
|
|
53
|
+
</knowledge>
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected getExperience(actionResult: ActionResult): string {
|
|
58
|
+
const tracker = this.getExperienceTracker();
|
|
59
|
+
const relevantExperience = tracker.getRelevantExperience(actionResult);
|
|
60
|
+
|
|
61
|
+
if (relevantExperience.length === 0) return '';
|
|
62
|
+
|
|
63
|
+
const allContent = relevantExperience
|
|
64
|
+
.map((e) => e.content)
|
|
65
|
+
.filter((e) => !!e)
|
|
66
|
+
.join('\n\n---\n\n');
|
|
67
|
+
|
|
68
|
+
const totalChars = allContent.length;
|
|
69
|
+
let experienceContent: string;
|
|
70
|
+
|
|
71
|
+
if (totalChars <= 10_000) {
|
|
72
|
+
debugLog(`injecting all experience (${Math.round(totalChars / 1000)}k chars)`);
|
|
73
|
+
experienceContent = allContent;
|
|
74
|
+
} else {
|
|
75
|
+
experienceContent = tracker.getSuccessfulExperience(actionResult).join('\n\n---\n\n');
|
|
76
|
+
debugLog(`injecting success-only experience (${Math.round(experienceContent.length / 1000)}k chars, filtered from ${Math.round(totalChars / 1000)}k)`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!experienceContent) return '';
|
|
80
|
+
|
|
81
|
+
tag('substep').log(`Found ${relevantExperience.length} experience ${pluralize(relevantExperience.length, 'file')}`);
|
|
82
|
+
return dedent`
|
|
83
|
+
<experience>
|
|
84
|
+
Here is past experience of interacting with this page.
|
|
85
|
+
Use successful solutions first. Avoid repeating failed actions.
|
|
86
|
+
|
|
87
|
+
${experienceContent}
|
|
88
|
+
</experience>
|
|
89
|
+
`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
setHistorian(historian: Historian): void {
|
|
93
|
+
this._historian = historian;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected getHistorian(): Historian {
|
|
97
|
+
if (this._historian) return this._historian;
|
|
98
|
+
return createNullProxy<Historian>();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
setQuartermaster(quartermaster: Quartermaster): void {
|
|
102
|
+
this._quartermaster = quartermaster;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected getQuartermaster(): Quartermaster {
|
|
106
|
+
if (this._quartermaster) return this._quartermaster;
|
|
107
|
+
return createNullProxy<Quartermaster>();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected trackToolExecutions(toolExecutions: any[]): void {
|
|
111
|
+
if (toolExecutions.length === 0) {
|
|
112
|
+
this.consecutiveEmptyResults++;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.consecutiveEmptyResults = 0;
|
|
116
|
+
|
|
117
|
+
const failedActions = toolExecutions.filter((e) => !e.wasSuccessful && this.ACTION_TOOLS.includes(e.toolName));
|
|
118
|
+
const successActions = toolExecutions.filter((e) => e.wasSuccessful && this.ACTION_TOOLS.includes(e.toolName));
|
|
119
|
+
const hasAnyActionTool = toolExecutions.some((e) => this.ACTION_TOOLS.includes(e.toolName));
|
|
120
|
+
|
|
121
|
+
if (hasAnyActionTool) {
|
|
122
|
+
this.recentToolCalls.push(...toolExecutions);
|
|
123
|
+
if (this.recentToolCalls.length > 20) {
|
|
124
|
+
this.recentToolCalls = this.recentToolCalls.slice(-20);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (failedActions.length > 0) {
|
|
129
|
+
this.consecutiveFailures += failedActions.length;
|
|
130
|
+
}
|
|
131
|
+
if (successActions.length > 0) {
|
|
132
|
+
this.consecutiveFailures = 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
protected resetFailureCount(): void {
|
|
137
|
+
this.consecutiveFailures = 0;
|
|
138
|
+
this.consecutiveEmptyResults = 0;
|
|
139
|
+
this.recentToolCalls = [];
|
|
140
|
+
}
|
|
141
|
+
}
|