@poolzin/pool-bot 2026.3.13 → 2026.3.15

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 (186) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/dist/agents/checkpoint-manager.js +291 -0
  3. package/dist/agents/poolbot-tools.js +5 -0
  4. package/dist/agents/subagent-announce-reliability.js +160 -0
  5. package/dist/agents/tool-result-truncation.js +299 -0
  6. package/dist/agents/tools/nodes-file-tool.js +197 -0
  7. package/dist/build-info.json +3 -3
  8. package/dist/cli/config-cli.js +60 -0
  9. package/dist/cron/cron-improvements.js +195 -0
  10. package/dist/discord/discord-improvements.js +167 -0
  11. package/dist/gateway/auth-rate-limit.js +19 -0
  12. package/dist/gateway/auth.js +41 -0
  13. package/dist/gateway/gateway-improvements.js +294 -0
  14. package/dist/gateway/node-command-policy.js +7 -2
  15. package/dist/infra/net/ssrf.js +15 -2
  16. package/dist/infra/shell-security.js +201 -0
  17. package/dist/memory/memory-improvements.js +239 -0
  18. package/dist/node-host/runner.js +146 -79
  19. package/dist/security/prototype-pollution.js +141 -0
  20. package/dist/security/webhook-security.js +253 -0
  21. package/dist/shared/net/ip.js +52 -1
  22. package/dist/slack/slack-improvements.js +225 -0
  23. package/dist/telegram/telegram-improvements.js +220 -0
  24. package/dist/ui-plugins/ui-plugins-improvements.js +191 -0
  25. package/docs/ANALISE_OPENCLAW_PROFISSIONAL.md +520 -0
  26. package/docs/competitive-analysis.md +421 -0
  27. package/docs/implementation-analysis.md +393 -0
  28. package/docs/plans/2026-03-11-file-operations-security-hardening.md +307 -0
  29. package/docs/plans/2026-03-11-integracao-projetos-poolbot.md +666 -0
  30. package/extensions/agency-agents/README.md +301 -0
  31. package/extensions/agency-agents/agents/CONTRIBUTING.md +353 -0
  32. package/extensions/agency-agents/agents/README.md +602 -0
  33. package/extensions/agency-agents/agents/design/design-brand-guardian.md +320 -0
  34. package/extensions/agency-agents/agents/design/design-image-prompt-engineer.md +234 -0
  35. package/extensions/agency-agents/agents/design/design-ui-designer.md +381 -0
  36. package/extensions/agency-agents/agents/design/design-ux-architect.md +467 -0
  37. package/extensions/agency-agents/agents/design/design-ux-researcher.md +327 -0
  38. package/extensions/agency-agents/agents/design/design-visual-storyteller.md +147 -0
  39. package/extensions/agency-agents/agents/design/design-whimsy-injector.md +436 -0
  40. package/extensions/agency-agents/agents/engineering/engineering-ai-engineer.md +144 -0
  41. package/extensions/agency-agents/agents/engineering/engineering-backend-architect.md +233 -0
  42. package/extensions/agency-agents/agents/engineering/engineering-devops-automator.md +374 -0
  43. package/extensions/agency-agents/agents/engineering/engineering-frontend-developer.md +223 -0
  44. package/extensions/agency-agents/agents/engineering/engineering-mobile-app-builder.md +491 -0
  45. package/extensions/agency-agents/agents/engineering/engineering-rapid-prototyper.md +460 -0
  46. package/extensions/agency-agents/agents/engineering/engineering-security-engineer.md +275 -0
  47. package/extensions/agency-agents/agents/engineering/engineering-senior-developer.md +174 -0
  48. package/extensions/agency-agents/agents/examples/README.md +48 -0
  49. package/extensions/agency-agents/agents/examples/nexus-spatial-discovery.md +852 -0
  50. package/extensions/agency-agents/agents/examples/workflow-landing-page.md +119 -0
  51. package/extensions/agency-agents/agents/examples/workflow-startup-mvp.md +155 -0
  52. package/extensions/agency-agents/agents/integrations/README.md +117 -0
  53. package/extensions/agency-agents/agents/integrations/aider/README.md +38 -0
  54. package/extensions/agency-agents/agents/integrations/antigravity/README.md +49 -0
  55. package/extensions/agency-agents/agents/integrations/claude-code/README.md +31 -0
  56. package/extensions/agency-agents/agents/integrations/cursor/README.md +38 -0
  57. package/extensions/agency-agents/agents/integrations/gemini-cli/README.md +36 -0
  58. package/extensions/agency-agents/agents/integrations/opencode/README.md +58 -0
  59. package/extensions/agency-agents/agents/integrations/windsurf/README.md +26 -0
  60. package/extensions/agency-agents/agents/marketing/marketing-app-store-optimizer.md +319 -0
  61. package/extensions/agency-agents/agents/marketing/marketing-content-creator.md +52 -0
  62. package/extensions/agency-agents/agents/marketing/marketing-growth-hacker.md +52 -0
  63. package/extensions/agency-agents/agents/marketing/marketing-instagram-curator.md +111 -0
  64. package/extensions/agency-agents/agents/marketing/marketing-reddit-community-builder.md +121 -0
  65. package/extensions/agency-agents/agents/marketing/marketing-social-media-strategist.md +123 -0
  66. package/extensions/agency-agents/agents/marketing/marketing-tiktok-strategist.md +123 -0
  67. package/extensions/agency-agents/agents/marketing/marketing-twitter-engager.md +124 -0
  68. package/extensions/agency-agents/agents/marketing/marketing-wechat-official-account.md +143 -0
  69. package/extensions/agency-agents/agents/marketing/marketing-xiaohongshu-specialist.md +136 -0
  70. package/extensions/agency-agents/agents/marketing/marketing-zhihu-strategist.md +160 -0
  71. package/extensions/agency-agents/agents/product/product-feedback-synthesizer.md +117 -0
  72. package/extensions/agency-agents/agents/product/product-sprint-prioritizer.md +152 -0
  73. package/extensions/agency-agents/agents/product/product-trend-researcher.md +157 -0
  74. package/extensions/agency-agents/agents/project-management/project-management-experiment-tracker.md +196 -0
  75. package/extensions/agency-agents/agents/project-management/project-management-project-shepherd.md +192 -0
  76. package/extensions/agency-agents/agents/project-management/project-management-studio-operations.md +198 -0
  77. package/extensions/agency-agents/agents/project-management/project-management-studio-producer.md +201 -0
  78. package/extensions/agency-agents/agents/project-management/project-manager-senior.md +133 -0
  79. package/extensions/agency-agents/agents/scripts/convert.sh +362 -0
  80. package/extensions/agency-agents/agents/scripts/install.sh +465 -0
  81. package/extensions/agency-agents/agents/scripts/lint-agents.sh +115 -0
  82. package/extensions/agency-agents/agents/spatial-computing/macos-spatial-metal-engineer.md +335 -0
  83. package/extensions/agency-agents/agents/spatial-computing/terminal-integration-specialist.md +68 -0
  84. package/extensions/agency-agents/agents/spatial-computing/visionos-spatial-engineer.md +52 -0
  85. package/extensions/agency-agents/agents/spatial-computing/xr-cockpit-interaction-specialist.md +30 -0
  86. package/extensions/agency-agents/agents/spatial-computing/xr-immersive-developer.md +30 -0
  87. package/extensions/agency-agents/agents/spatial-computing/xr-interface-architect.md +30 -0
  88. package/extensions/agency-agents/agents/specialized/agentic-identity-trust.md +367 -0
  89. package/extensions/agency-agents/agents/specialized/agents-orchestrator.md +365 -0
  90. package/extensions/agency-agents/agents/specialized/data-analytics-reporter.md +52 -0
  91. package/extensions/agency-agents/agents/specialized/data-consolidation-agent.md +58 -0
  92. package/extensions/agency-agents/agents/specialized/lsp-index-engineer.md +312 -0
  93. package/extensions/agency-agents/agents/specialized/report-distribution-agent.md +63 -0
  94. package/extensions/agency-agents/agents/specialized/sales-data-extraction-agent.md +65 -0
  95. package/extensions/agency-agents/agents/strategy/EXECUTIVE-BRIEF.md +95 -0
  96. package/extensions/agency-agents/agents/strategy/QUICKSTART.md +194 -0
  97. package/extensions/agency-agents/agents/strategy/coordination/agent-activation-prompts.md +401 -0
  98. package/extensions/agency-agents/agents/strategy/coordination/handoff-templates.md +357 -0
  99. package/extensions/agency-agents/agents/strategy/nexus-strategy.md +1110 -0
  100. package/extensions/agency-agents/agents/strategy/playbooks/phase-0-discovery.md +178 -0
  101. package/extensions/agency-agents/agents/strategy/playbooks/phase-1-strategy.md +238 -0
  102. package/extensions/agency-agents/agents/strategy/playbooks/phase-2-foundation.md +278 -0
  103. package/extensions/agency-agents/agents/strategy/playbooks/phase-3-build.md +286 -0
  104. package/extensions/agency-agents/agents/strategy/playbooks/phase-4-hardening.md +332 -0
  105. package/extensions/agency-agents/agents/strategy/playbooks/phase-5-launch.md +277 -0
  106. package/extensions/agency-agents/agents/strategy/playbooks/phase-6-operate.md +318 -0
  107. package/extensions/agency-agents/agents/strategy/runbooks/scenario-enterprise-feature.md +157 -0
  108. package/extensions/agency-agents/agents/strategy/runbooks/scenario-incident-response.md +217 -0
  109. package/extensions/agency-agents/agents/strategy/runbooks/scenario-marketing-campaign.md +187 -0
  110. package/extensions/agency-agents/agents/strategy/runbooks/scenario-startup-mvp.md +154 -0
  111. package/extensions/agency-agents/agents/support/support-analytics-reporter.md +363 -0
  112. package/extensions/agency-agents/agents/support/support-executive-summary-generator.md +210 -0
  113. package/extensions/agency-agents/agents/support/support-finance-tracker.md +440 -0
  114. package/extensions/agency-agents/agents/support/support-infrastructure-maintainer.md +616 -0
  115. package/extensions/agency-agents/agents/support/support-legal-compliance-checker.md +586 -0
  116. package/extensions/agency-agents/agents/support/support-support-responder.md +583 -0
  117. package/extensions/agency-agents/agents/testing/testing-accessibility-auditor.md +313 -0
  118. package/extensions/agency-agents/agents/testing/testing-api-tester.md +304 -0
  119. package/extensions/agency-agents/agents/testing/testing-evidence-collector.md +208 -0
  120. package/extensions/agency-agents/agents/testing/testing-performance-benchmarker.md +266 -0
  121. package/extensions/agency-agents/agents/testing/testing-reality-checker.md +236 -0
  122. package/extensions/agency-agents/agents/testing/testing-test-results-analyzer.md +303 -0
  123. package/extensions/agency-agents/agents/testing/testing-tool-evaluator.md +392 -0
  124. package/extensions/agency-agents/agents/testing/testing-workflow-optimizer.md +448 -0
  125. package/extensions/agency-agents/index.ts +733 -0
  126. package/extensions/agency-agents/node_modules/.bin/jiti +21 -0
  127. package/extensions/agency-agents/node_modules/.bin/tsc +21 -0
  128. package/extensions/agency-agents/node_modules/.bin/tsserver +21 -0
  129. package/extensions/agency-agents/node_modules/.bin/tsx +21 -0
  130. package/extensions/agency-agents/node_modules/.bin/vite +21 -0
  131. package/extensions/agency-agents/node_modules/.bin/vitest +21 -0
  132. package/extensions/agency-agents/node_modules/.bin/yaml +21 -0
  133. package/extensions/agency-agents/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  134. package/extensions/agency-agents/package.json +25 -0
  135. package/extensions/agency-agents/poolbot.plugin.json +11 -0
  136. package/extensions/agency-agents/src/AgencyAgentsService.test.ts +443 -0
  137. package/extensions/agency-agents/src/AgencyAgentsService.ts +288 -0
  138. package/extensions/agency-agents/src/types.ts +147 -0
  139. package/extensions/agency-agents/vitest.config.ts +8 -0
  140. package/extensions/hexstrike-ai/README.md +98 -0
  141. package/extensions/hexstrike-ai/node_modules/.bin/tsc +21 -0
  142. package/extensions/hexstrike-ai/node_modules/.bin/tsserver +21 -0
  143. package/extensions/hexstrike-ai/package.json +29 -0
  144. package/extensions/hexstrike-ai/poolbot.plugin.json +31 -0
  145. package/extensions/hexstrike-ai/src/client.ts +91 -0
  146. package/extensions/hexstrike-ai/src/index.ts +170 -0
  147. package/extensions/hexstrike-ai/src/server/hexstrike_mcp.py +5470 -0
  148. package/extensions/hexstrike-ai/src/server/hexstrike_server.py +17289 -0
  149. package/extensions/hexstrike-ai/src/server/requirements.txt +84 -0
  150. package/extensions/hexstrike-ai/src/server-manager.ts +83 -0
  151. package/extensions/hexstrike-ai/tsconfig.json +20 -0
  152. package/extensions/page-agent/README.md +159 -0
  153. package/extensions/page-agent/index.ts +595 -0
  154. package/extensions/page-agent/node_modules/.bin/jiti +21 -0
  155. package/extensions/page-agent/node_modules/.bin/playwright +21 -0
  156. package/extensions/page-agent/node_modules/.bin/tsc +21 -0
  157. package/extensions/page-agent/node_modules/.bin/tsserver +21 -0
  158. package/extensions/page-agent/node_modules/.bin/tsx +21 -0
  159. package/extensions/page-agent/node_modules/.bin/vitest +21 -0
  160. package/extensions/page-agent/node_modules/.bin/yaml +21 -0
  161. package/extensions/page-agent/package.json +43 -0
  162. package/extensions/page-agent/poolbot.plugin.json +24 -0
  163. package/extensions/page-agent/src/PageAgentService.test.ts +517 -0
  164. package/extensions/page-agent/src/PageAgentService.ts +636 -0
  165. package/extensions/page-agent/src/PoolBotPageController.test.ts +358 -0
  166. package/extensions/page-agent/src/PoolBotPageController.ts +245 -0
  167. package/extensions/page-agent/src/index.ts +20 -0
  168. package/extensions/page-agent/src/tools.test.ts +231 -0
  169. package/extensions/page-agent/src/tools.ts +167 -0
  170. package/extensions/page-agent/src/types.ts +198 -0
  171. package/extensions/xyops/README.md +227 -0
  172. package/extensions/xyops/index.ts +342 -0
  173. package/extensions/xyops/node_modules/.bin/jiti +21 -0
  174. package/extensions/xyops/node_modules/.bin/tsc +21 -0
  175. package/extensions/xyops/node_modules/.bin/tsserver +21 -0
  176. package/extensions/xyops/node_modules/.bin/tsx +21 -0
  177. package/extensions/xyops/node_modules/.bin/vitest +21 -0
  178. package/extensions/xyops/node_modules/.bin/yaml +21 -0
  179. package/extensions/xyops/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  180. package/extensions/xyops/package.json +39 -0
  181. package/extensions/xyops/poolbot.plugin.json +21 -0
  182. package/extensions/xyops/src/client.test.ts +467 -0
  183. package/extensions/xyops/src/client.ts +157 -0
  184. package/extensions/xyops/src/types.ts +147 -0
  185. package/extensions/xyops/vitest.config.ts +8 -0
  186. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/tsx@4.21.0/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.15_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__6cb5e51e836830cd2cffacfc8438d429/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.15_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__6cb5e51e836830cd2cffacfc8438d429/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.15_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__6cb5e51e836830cd2cffacfc8438d429/node_modules/vitest/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/vitest@3.2.4_@types+node@22.19.15_@vitest+browser@4.0.18_vite@7.3.1_@types+node@25.2.3__6cb5e51e836830cd2cffacfc8438d429/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../vitest/vitest.mjs" "$@"
21
+ fi
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+ basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
+
4
+ case `uname` in
5
+ *CYGWIN*|*MINGW*|*MSYS*)
6
+ if command -v cygpath > /dev/null 2>&1; then
7
+ basedir=`cygpath -w "$basedir"`
8
+ fi
9
+ ;;
10
+ esac
11
+
12
+ if [ -z "$NODE_PATH" ]; then
13
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/yaml@2.8.2/node_modules/yaml/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/yaml@2.8.2/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules"
14
+ else
15
+ export NODE_PATH="/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/yaml@2.8.2/node_modules/yaml/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/yaml@2.8.2/node_modules:/Users/pool/Documents/GitHub/pool-bot/node_modules/.pnpm/node_modules:$NODE_PATH"
16
+ fi
17
+ if [ -x "$basedir/node" ]; then
18
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/yaml@2.8.2/node_modules/yaml/bin.mjs" "$@"
19
+ else
20
+ exec node "$basedir/../../../../node_modules/.pnpm/yaml@2.8.2/node_modules/yaml/bin.mjs" "$@"
21
+ fi
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@poolbot/page-agent",
3
+ "version": "2026.3.13",
4
+ "description": "Page Agent - GUI Browser Automation for PoolBot with AI-powered web interaction",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./core": "./dist/core/index.js",
11
+ "./controller": "./dist/controller/index.js",
12
+ "./tools": "./dist/tools/index.js"
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest"
19
+ },
20
+ "dependencies": {
21
+ "@sinclair/typebox": "^0.34.0",
22
+ "playwright": "^1.50.0",
23
+ "zod": "^3.22.0",
24
+ "chalk": "^5.3.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.0.0",
28
+ "typescript": "^5.0.0",
29
+ "vitest": "^3.0.0"
30
+ },
31
+ "peerDependencies": {
32
+ "poolbot": "workspace:*"
33
+ },
34
+ "poolbot": {
35
+ "plugin": true,
36
+ "config": {
37
+ "schema": "./dist/config/schema.js"
38
+ }
39
+ },
40
+ "keywords": ["browser", "automation", "gui", "playwright", "ai"],
41
+ "author": "PoolBot Team",
42
+ "license": "MIT"
43
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "page-agent",
3
+ "name": "Page Agent",
4
+ "description": "GUI Browser Automation for PoolBot with AI-powered web interaction",
5
+ "version": "2026.3.14",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "headless": {
11
+ "type": "boolean",
12
+ "default": true,
13
+ "description": "Run browser in headless mode"
14
+ },
15
+ "viewport": {
16
+ "type": "object",
17
+ "properties": {
18
+ "width": { "type": "number", "default": 1280 },
19
+ "height": { "type": "number", "default": 720 }
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,517 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2
+ import { PageAgentService } from './PageAgentService.js'
3
+ import { PoolBotPageController } from './PoolBotPageController.js'
4
+ import type { PageAgentConfig, PageAgentTool, PageAgentLLMConfig } from './types.js'
5
+
6
+ // Mock the browser client modules
7
+ vi.mock('../../../src/browser/client.js', () => ({
8
+ browserSnapshot: vi.fn(),
9
+ }))
10
+
11
+ vi.mock('../../../src/browser/client-actions.js', () => ({
12
+ browserAct: vi.fn(),
13
+ browserNavigate: vi.fn(),
14
+ browserScreenshotAction: vi.fn(),
15
+ }))
16
+
17
+ import { browserSnapshot } from '../../../src/browser/client.js'
18
+ import { browserNavigate } from '../../../src/browser/client-actions.js'
19
+
20
+ describe('PageAgentService', () => {
21
+ let controller: PoolBotPageController
22
+ let config: PageAgentConfig
23
+ let service: PageAgentService
24
+ let mockFetch: ReturnType<typeof vi.fn>
25
+
26
+ beforeEach(() => {
27
+ vi.clearAllMocks()
28
+
29
+ controller = new PoolBotPageController({
30
+ browserBaseUrl: 'http://localhost:9222',
31
+ profile: 'test-profile',
32
+ })
33
+
34
+ const llmConfig: PageAgentLLMConfig = {
35
+ provider: 'openai',
36
+ baseURL: 'http://localhost:11434/v1',
37
+ apiKey: 'test-key',
38
+ model: 'qwen2.5:14b',
39
+ temperature: 0.7,
40
+ }
41
+
42
+ config = {
43
+ llm: llmConfig,
44
+ maxSteps: 10,
45
+ }
46
+
47
+ service = new PageAgentService(config, controller)
48
+
49
+ // Create a proper mock for fetch
50
+ mockFetch = vi.fn()
51
+ global.fetch = mockFetch as unknown as typeof fetch
52
+ })
53
+
54
+ afterEach(() => {
55
+ service.dispose()
56
+ })
57
+
58
+ describe('constructor', () => {
59
+ it('should create service with valid config', () => {
60
+ expect(service).toBeDefined()
61
+ expect(service.id).toBeDefined()
62
+ expect(service.config).toBe(config)
63
+ expect(service.status).toBe('idle')
64
+ })
65
+
66
+ it('should generate unique IDs', () => {
67
+ const service2 = new PageAgentService(config, controller)
68
+ expect(service.id).not.toBe(service2.id)
69
+ service2.dispose()
70
+ })
71
+
72
+ it('should apply custom tools', () => {
73
+ const customTool: PageAgentTool = {
74
+ name: 'custom_tool',
75
+ description: 'A custom tool',
76
+ inputSchema: { type: 'object', properties: {} },
77
+ execute: vi.fn().mockResolvedValue('success'),
78
+ }
79
+
80
+ const configWithCustomTool: PageAgentConfig = {
81
+ ...config,
82
+ customTools: {
83
+ custom_tool: customTool,
84
+ },
85
+ }
86
+
87
+ const serviceWithCustom = new PageAgentService(configWithCustomTool, controller)
88
+ expect(serviceWithCustom).toBeDefined()
89
+ serviceWithCustom.dispose()
90
+ })
91
+
92
+ it('should remove tools when set to null', () => {
93
+ const configWithRemovedTool: PageAgentConfig = {
94
+ ...config,
95
+ customTools: {
96
+ navigate: null,
97
+ },
98
+ }
99
+
100
+ const serviceWithRemoved = new PageAgentService(configWithRemovedTool, controller)
101
+ expect(serviceWithRemoved).toBeDefined()
102
+ serviceWithRemoved.dispose()
103
+ })
104
+ })
105
+
106
+ describe('execute', () => {
107
+ it('should throw error if disposed', async () => {
108
+ service.dispose()
109
+ await expect(service.execute('test task')).rejects.toThrow('disposed')
110
+ })
111
+
112
+ it('should throw error if task is empty', async () => {
113
+ await expect(service.execute('')).rejects.toThrow('Task is required')
114
+ })
115
+
116
+ it('should set status to running when starting', async () => {
117
+ // Mock LLM response for immediate completion
118
+ const mockLLMResponse = {
119
+ choices: [{
120
+ message: {
121
+ tool_calls: [{
122
+ function: {
123
+ name: 'AgentOutput',
124
+ arguments: JSON.stringify({
125
+ evaluation_previous_goal: 'Starting task',
126
+ memory: '',
127
+ next_goal: 'Complete task',
128
+ action: { done: { success: true, answer: 'Done' } },
129
+ }),
130
+ },
131
+ }],
132
+ },
133
+ }],
134
+ }
135
+
136
+ mockFetch.mockResolvedValue({
137
+ ok: true,
138
+ json: () => Promise.resolve(mockLLMResponse),
139
+ })
140
+
141
+ vi.mocked(browserSnapshot).mockResolvedValue({
142
+ ok: true,
143
+ url: 'http://example.com',
144
+ snapshot: 'Test content',
145
+ format: 'ai',
146
+ targetId: 'test-target',
147
+ })
148
+
149
+ const statusChanges: string[] = []
150
+ service.addEventListener('statuschange', () => {
151
+ statusChanges.push(service.status)
152
+ })
153
+
154
+ await service.execute('test task')
155
+
156
+ expect(statusChanges).toContain('running')
157
+ expect(statusChanges).toContain('completed')
158
+ })
159
+
160
+ it('should complete task successfully', async () => {
161
+ const mockLLMResponse = {
162
+ choices: [{
163
+ message: {
164
+ tool_calls: [{
165
+ function: {
166
+ name: 'AgentOutput',
167
+ arguments: JSON.stringify({
168
+ evaluation_previous_goal: 'Task completed',
169
+ memory: 'Test memory',
170
+ next_goal: 'Finish',
171
+ action: { done: { success: true, answer: 'Task completed successfully' } },
172
+ }),
173
+ },
174
+ }],
175
+ },
176
+ }],
177
+ }
178
+
179
+ mockFetch.mockResolvedValue({
180
+ ok: true,
181
+ json: () => Promise.resolve(mockLLMResponse),
182
+ })
183
+
184
+ vi.mocked(browserSnapshot).mockResolvedValue({
185
+ ok: true,
186
+ url: 'http://example.com',
187
+ snapshot: 'Test content',
188
+ format: 'ai',
189
+ targetId: 'test-target',
190
+ })
191
+
192
+ const result = await service.execute('test task')
193
+
194
+ expect(result.success).toBe(true)
195
+ expect(result.data).toBe('Task completed successfully')
196
+ expect(result.totalSteps).toBe(1)
197
+ expect(result.duration).toBeGreaterThan(0)
198
+ })
199
+
200
+ it('should handle task failure', async () => {
201
+ const mockLLMResponse = {
202
+ choices: [{
203
+ message: {
204
+ tool_calls: [{
205
+ function: {
206
+ name: 'AgentOutput',
207
+ arguments: JSON.stringify({
208
+ evaluation_previous_goal: 'Task failed',
209
+ memory: '',
210
+ next_goal: 'Abort',
211
+ action: { done: { success: false, answer: 'Could not complete' } },
212
+ }),
213
+ },
214
+ }],
215
+ },
216
+ }],
217
+ }
218
+
219
+ mockFetch.mockResolvedValue({
220
+ ok: true,
221
+ json: () => Promise.resolve(mockLLMResponse),
222
+ })
223
+
224
+ vi.mocked(browserSnapshot).mockResolvedValue({
225
+ ok: true,
226
+ url: 'http://example.com',
227
+ snapshot: 'Test content',
228
+ format: 'ai',
229
+ targetId: 'test-target',
230
+ })
231
+
232
+ const result = await service.execute('test task')
233
+
234
+ expect(result.success).toBe(false)
235
+ expect(result.data).toBe('Could not complete')
236
+ })
237
+
238
+ it('should respect max steps limit', async () => {
239
+ const configWithLowMaxSteps: PageAgentConfig = {
240
+ ...config,
241
+ maxSteps: 2,
242
+ }
243
+
244
+ const serviceWithLowMax = new PageAgentService(configWithLowMaxSteps, controller)
245
+
246
+ const mockLLMResponse = {
247
+ choices: [{
248
+ message: {
249
+ tool_calls: [{
250
+ function: {
251
+ name: 'AgentOutput',
252
+ arguments: JSON.stringify({
253
+ evaluation_previous_goal: 'Step executed',
254
+ memory: '',
255
+ next_goal: 'Continue',
256
+ action: { navigate: { url: 'http://example.com' } },
257
+ }),
258
+ },
259
+ }],
260
+ },
261
+ }],
262
+ }
263
+
264
+ mockFetch.mockResolvedValue({
265
+ ok: true,
266
+ json: () => Promise.resolve(mockLLMResponse),
267
+ })
268
+
269
+ vi.mocked(browserSnapshot).mockResolvedValue({
270
+ ok: true,
271
+ url: 'http://example.com',
272
+ snapshot: 'Test content',
273
+ format: 'ai',
274
+ targetId: 'test-target',
275
+ })
276
+
277
+ vi.mocked(browserNavigate).mockResolvedValue({
278
+ ok: true,
279
+ targetId: 'test-target',
280
+ })
281
+
282
+ const result = await serviceWithLowMax.execute('test task')
283
+
284
+ expect(result.success).toBe(false)
285
+ expect(result.error).toContain('Step count exceeded')
286
+ expect(result.totalSteps).toBe(2)
287
+
288
+ serviceWithLowMax.dispose()
289
+ })
290
+
291
+ it('should handle LLM API errors', async () => {
292
+ mockFetch.mockResolvedValue({
293
+ ok: false,
294
+ status: 500,
295
+ statusText: 'Internal Server Error',
296
+ })
297
+
298
+ vi.mocked(browserSnapshot).mockResolvedValue({
299
+ ok: true,
300
+ url: 'http://example.com',
301
+ snapshot: 'Test content',
302
+ format: 'ai',
303
+ targetId: 'test-target',
304
+ })
305
+
306
+ const result = await service.execute('test task')
307
+
308
+ expect(result.success).toBe(false)
309
+ expect(result.error).toContain('LLM API error')
310
+ })
311
+
312
+ it('should handle missing tool calls in LLM response', async () => {
313
+ mockFetch.mockResolvedValue({
314
+ ok: true,
315
+ json: () => Promise.resolve({
316
+ choices: [{
317
+ message: {
318
+ content: 'No tool call',
319
+ },
320
+ }],
321
+ }),
322
+ })
323
+
324
+ vi.mocked(browserSnapshot).mockResolvedValue({
325
+ ok: true,
326
+ url: 'http://example.com',
327
+ snapshot: 'Test content',
328
+ format: 'ai',
329
+ targetId: 'test-target',
330
+ })
331
+
332
+ const result = await service.execute('test task')
333
+
334
+ expect(result.success).toBe(false)
335
+ expect(result.error).toContain('No tool call')
336
+ })
337
+
338
+ it('should call lifecycle hooks', async () => {
339
+ const onBeforeTask = vi.fn()
340
+ const onAfterTask = vi.fn()
341
+ const onBeforeStep = vi.fn()
342
+ const onAfterStep = vi.fn()
343
+
344
+ const configWithHooks: PageAgentConfig = {
345
+ ...config,
346
+ onBeforeTask,
347
+ onAfterTask,
348
+ onBeforeStep,
349
+ onAfterStep,
350
+ }
351
+
352
+ const serviceWithHooks = new PageAgentService(configWithHooks, controller)
353
+
354
+ const mockLLMResponse = {
355
+ choices: [{
356
+ message: {
357
+ tool_calls: [{
358
+ function: {
359
+ name: 'AgentOutput',
360
+ arguments: JSON.stringify({
361
+ evaluation_previous_goal: 'Done',
362
+ memory: '',
363
+ next_goal: 'Finish',
364
+ action: { done: { success: true, answer: 'Done' } },
365
+ }),
366
+ },
367
+ }],
368
+ },
369
+ }],
370
+ }
371
+
372
+ mockFetch.mockResolvedValue({
373
+ ok: true,
374
+ json: () => Promise.resolve(mockLLMResponse),
375
+ })
376
+
377
+ vi.mocked(browserSnapshot).mockResolvedValue({
378
+ ok: true,
379
+ url: 'http://example.com',
380
+ snapshot: 'Test content',
381
+ format: 'ai',
382
+ targetId: 'test-target',
383
+ })
384
+
385
+ await serviceWithHooks.execute('test task')
386
+
387
+ expect(onBeforeTask).toHaveBeenCalledWith(serviceWithHooks)
388
+ expect(onAfterTask).toHaveBeenCalled()
389
+ expect(onBeforeStep).toHaveBeenCalledWith(serviceWithHooks, 0)
390
+ expect(onAfterStep).toHaveBeenCalled()
391
+
392
+ serviceWithHooks.dispose()
393
+ })
394
+ })
395
+
396
+ describe('stop', () => {
397
+ it('should abort the current task', () => {
398
+ service.stop()
399
+ // Should not throw
400
+ })
401
+ })
402
+
403
+ describe('dispose', () => {
404
+ it('should dispose the service', () => {
405
+ const onDispose = vi.fn()
406
+ const configWithDispose: PageAgentConfig = {
407
+ ...config,
408
+ onDispose,
409
+ }
410
+
411
+ const serviceWithDispose = new PageAgentService(configWithDispose, controller)
412
+ serviceWithDispose.dispose()
413
+
414
+ expect(serviceWithDispose.disposed).toBe(true)
415
+ expect(onDispose).toHaveBeenCalledWith(serviceWithDispose)
416
+ })
417
+
418
+ it('should dispatch dispose event', () => {
419
+ const disposeHandler = vi.fn()
420
+ service.addEventListener('dispose', disposeHandler)
421
+
422
+ service.dispose()
423
+
424
+ expect(disposeHandler).toHaveBeenCalled()
425
+ })
426
+ })
427
+
428
+ describe('pushObservation', () => {
429
+ it('should add observations', () => {
430
+ service.pushObservation('Test observation')
431
+ // The observations are private, but we can verify through behavior
432
+ expect(service).toBeDefined()
433
+ })
434
+ })
435
+
436
+ describe('event handling', () => {
437
+ it('should emit history change events', async () => {
438
+ const historyHandler = vi.fn()
439
+ service.addEventListener('historychange', historyHandler)
440
+
441
+ const mockLLMResponse = {
442
+ choices: [{
443
+ message: {
444
+ tool_calls: [{
445
+ function: {
446
+ name: 'AgentOutput',
447
+ arguments: JSON.stringify({
448
+ evaluation_previous_goal: 'Done',
449
+ memory: '',
450
+ next_goal: 'Finish',
451
+ action: { done: { success: true, answer: 'Done' } },
452
+ }),
453
+ },
454
+ }],
455
+ },
456
+ }],
457
+ }
458
+
459
+ mockFetch.mockResolvedValue({
460
+ ok: true,
461
+ json: () => Promise.resolve(mockLLMResponse),
462
+ })
463
+
464
+ vi.mocked(browserSnapshot).mockResolvedValue({
465
+ ok: true,
466
+ url: 'http://example.com',
467
+ snapshot: 'Test content',
468
+ format: 'ai',
469
+ targetId: 'test-target',
470
+ })
471
+
472
+ await service.execute('test task')
473
+
474
+ expect(historyHandler).toHaveBeenCalled()
475
+ })
476
+
477
+ it('should emit activity events', async () => {
478
+ const activityHandler = vi.fn()
479
+ service.addEventListener('activity', activityHandler)
480
+
481
+ const mockLLMResponse = {
482
+ choices: [{
483
+ message: {
484
+ tool_calls: [{
485
+ function: {
486
+ name: 'AgentOutput',
487
+ arguments: JSON.stringify({
488
+ evaluation_previous_goal: 'Done',
489
+ memory: '',
490
+ next_goal: 'Finish',
491
+ action: { done: { success: true, answer: 'Done' } },
492
+ }),
493
+ },
494
+ }],
495
+ },
496
+ }],
497
+ }
498
+
499
+ mockFetch.mockResolvedValue({
500
+ ok: true,
501
+ json: () => Promise.resolve(mockLLMResponse),
502
+ })
503
+
504
+ vi.mocked(browserSnapshot).mockResolvedValue({
505
+ ok: true,
506
+ url: 'http://example.com',
507
+ snapshot: 'Test content',
508
+ format: 'ai',
509
+ targetId: 'test-target',
510
+ })
511
+
512
+ await service.execute('test task')
513
+
514
+ expect(activityHandler).toHaveBeenCalled()
515
+ })
516
+ })
517
+ })