@poolzin/pool-bot 2026.3.11 → 2026.3.14
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/CHANGELOG.md +121 -0
- package/dist/.buildstamp +1 -1
- package/dist/agents/checkpoint-manager.js +291 -0
- package/dist/agents/poolbot-tools.js +5 -0
- package/dist/agents/subagent-announce-reliability.js +160 -0
- package/dist/agents/tool-result-truncation.js +299 -0
- package/dist/agents/tools/nodes-file-tool.js +197 -0
- package/dist/build-info.json +3 -3
- package/dist/cli/config-cli.js +60 -0
- package/dist/cron/cron-improvements.js +195 -0
- package/dist/discord/discord-improvements.js +167 -0
- package/dist/gateway/auth-rate-limit.js +19 -0
- package/dist/gateway/auth.js +41 -0
- package/dist/gateway/gateway-improvements.js +294 -0
- package/dist/gateway/node-command-policy.js +7 -2
- package/dist/infra/net/ssrf.js +15 -2
- package/dist/infra/shell-security.js +201 -0
- package/dist/memory/memory-improvements.js +239 -0
- package/dist/node-host/runner.js +146 -79
- package/dist/security/prototype-pollution.js +141 -0
- package/dist/security/webhook-security.js +253 -0
- package/dist/shared/net/ip.js +52 -1
- package/dist/slack/slack-improvements.js +225 -0
- package/dist/telegram/telegram-improvements.js +220 -0
- package/dist/ui-plugins/ui-plugins-improvements.js +191 -0
- package/docs/ANALISE_OPENCLAW_PROFISSIONAL.md +520 -0
- package/docs/competitive-analysis.md +421 -0
- package/docs/implementation-analysis.md +393 -0
- package/docs/plans/2026-03-11-file-operations-security-hardening.md +307 -0
- package/docs/plans/2026-03-11-integracao-projetos-poolbot.md +666 -0
- package/docs/refactor/plugin-development-guide.md +281 -0
- package/extensions/agency-agents/README.md +301 -0
- package/extensions/agency-agents/agents/CONTRIBUTING.md +353 -0
- package/extensions/agency-agents/agents/README.md +602 -0
- package/extensions/agency-agents/agents/design/design-brand-guardian.md +320 -0
- package/extensions/agency-agents/agents/design/design-image-prompt-engineer.md +234 -0
- package/extensions/agency-agents/agents/design/design-ui-designer.md +381 -0
- package/extensions/agency-agents/agents/design/design-ux-architect.md +467 -0
- package/extensions/agency-agents/agents/design/design-ux-researcher.md +327 -0
- package/extensions/agency-agents/agents/design/design-visual-storyteller.md +147 -0
- package/extensions/agency-agents/agents/design/design-whimsy-injector.md +436 -0
- package/extensions/agency-agents/agents/engineering/engineering-ai-engineer.md +144 -0
- package/extensions/agency-agents/agents/engineering/engineering-backend-architect.md +233 -0
- package/extensions/agency-agents/agents/engineering/engineering-devops-automator.md +374 -0
- package/extensions/agency-agents/agents/engineering/engineering-frontend-developer.md +223 -0
- package/extensions/agency-agents/agents/engineering/engineering-mobile-app-builder.md +491 -0
- package/extensions/agency-agents/agents/engineering/engineering-rapid-prototyper.md +460 -0
- package/extensions/agency-agents/agents/engineering/engineering-security-engineer.md +275 -0
- package/extensions/agency-agents/agents/engineering/engineering-senior-developer.md +174 -0
- package/extensions/agency-agents/agents/examples/README.md +48 -0
- package/extensions/agency-agents/agents/examples/nexus-spatial-discovery.md +852 -0
- package/extensions/agency-agents/agents/examples/workflow-landing-page.md +119 -0
- package/extensions/agency-agents/agents/examples/workflow-startup-mvp.md +155 -0
- package/extensions/agency-agents/agents/integrations/README.md +117 -0
- package/extensions/agency-agents/agents/integrations/aider/README.md +38 -0
- package/extensions/agency-agents/agents/integrations/antigravity/README.md +49 -0
- package/extensions/agency-agents/agents/integrations/claude-code/README.md +31 -0
- package/extensions/agency-agents/agents/integrations/cursor/README.md +38 -0
- package/extensions/agency-agents/agents/integrations/gemini-cli/README.md +36 -0
- package/extensions/agency-agents/agents/integrations/opencode/README.md +58 -0
- package/extensions/agency-agents/agents/integrations/windsurf/README.md +26 -0
- package/extensions/agency-agents/agents/marketing/marketing-app-store-optimizer.md +319 -0
- package/extensions/agency-agents/agents/marketing/marketing-content-creator.md +52 -0
- package/extensions/agency-agents/agents/marketing/marketing-growth-hacker.md +52 -0
- package/extensions/agency-agents/agents/marketing/marketing-instagram-curator.md +111 -0
- package/extensions/agency-agents/agents/marketing/marketing-reddit-community-builder.md +121 -0
- package/extensions/agency-agents/agents/marketing/marketing-social-media-strategist.md +123 -0
- package/extensions/agency-agents/agents/marketing/marketing-tiktok-strategist.md +123 -0
- package/extensions/agency-agents/agents/marketing/marketing-twitter-engager.md +124 -0
- package/extensions/agency-agents/agents/marketing/marketing-wechat-official-account.md +143 -0
- package/extensions/agency-agents/agents/marketing/marketing-xiaohongshu-specialist.md +136 -0
- package/extensions/agency-agents/agents/marketing/marketing-zhihu-strategist.md +160 -0
- package/extensions/agency-agents/agents/product/product-feedback-synthesizer.md +117 -0
- package/extensions/agency-agents/agents/product/product-sprint-prioritizer.md +152 -0
- package/extensions/agency-agents/agents/product/product-trend-researcher.md +157 -0
- package/extensions/agency-agents/agents/project-management/project-management-experiment-tracker.md +196 -0
- package/extensions/agency-agents/agents/project-management/project-management-project-shepherd.md +192 -0
- package/extensions/agency-agents/agents/project-management/project-management-studio-operations.md +198 -0
- package/extensions/agency-agents/agents/project-management/project-management-studio-producer.md +201 -0
- package/extensions/agency-agents/agents/project-management/project-manager-senior.md +133 -0
- package/extensions/agency-agents/agents/scripts/convert.sh +362 -0
- package/extensions/agency-agents/agents/scripts/install.sh +465 -0
- package/extensions/agency-agents/agents/scripts/lint-agents.sh +115 -0
- package/extensions/agency-agents/agents/spatial-computing/macos-spatial-metal-engineer.md +335 -0
- package/extensions/agency-agents/agents/spatial-computing/terminal-integration-specialist.md +68 -0
- package/extensions/agency-agents/agents/spatial-computing/visionos-spatial-engineer.md +52 -0
- package/extensions/agency-agents/agents/spatial-computing/xr-cockpit-interaction-specialist.md +30 -0
- package/extensions/agency-agents/agents/spatial-computing/xr-immersive-developer.md +30 -0
- package/extensions/agency-agents/agents/spatial-computing/xr-interface-architect.md +30 -0
- package/extensions/agency-agents/agents/specialized/agentic-identity-trust.md +367 -0
- package/extensions/agency-agents/agents/specialized/agents-orchestrator.md +365 -0
- package/extensions/agency-agents/agents/specialized/data-analytics-reporter.md +52 -0
- package/extensions/agency-agents/agents/specialized/data-consolidation-agent.md +58 -0
- package/extensions/agency-agents/agents/specialized/lsp-index-engineer.md +312 -0
- package/extensions/agency-agents/agents/specialized/report-distribution-agent.md +63 -0
- package/extensions/agency-agents/agents/specialized/sales-data-extraction-agent.md +65 -0
- package/extensions/agency-agents/agents/strategy/EXECUTIVE-BRIEF.md +95 -0
- package/extensions/agency-agents/agents/strategy/QUICKSTART.md +194 -0
- package/extensions/agency-agents/agents/strategy/coordination/agent-activation-prompts.md +401 -0
- package/extensions/agency-agents/agents/strategy/coordination/handoff-templates.md +357 -0
- package/extensions/agency-agents/agents/strategy/nexus-strategy.md +1110 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-0-discovery.md +178 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-1-strategy.md +238 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-2-foundation.md +278 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-3-build.md +286 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-4-hardening.md +332 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-5-launch.md +277 -0
- package/extensions/agency-agents/agents/strategy/playbooks/phase-6-operate.md +318 -0
- package/extensions/agency-agents/agents/strategy/runbooks/scenario-enterprise-feature.md +157 -0
- package/extensions/agency-agents/agents/strategy/runbooks/scenario-incident-response.md +217 -0
- package/extensions/agency-agents/agents/strategy/runbooks/scenario-marketing-campaign.md +187 -0
- package/extensions/agency-agents/agents/strategy/runbooks/scenario-startup-mvp.md +154 -0
- package/extensions/agency-agents/agents/support/support-analytics-reporter.md +363 -0
- package/extensions/agency-agents/agents/support/support-executive-summary-generator.md +210 -0
- package/extensions/agency-agents/agents/support/support-finance-tracker.md +440 -0
- package/extensions/agency-agents/agents/support/support-infrastructure-maintainer.md +616 -0
- package/extensions/agency-agents/agents/support/support-legal-compliance-checker.md +586 -0
- package/extensions/agency-agents/agents/support/support-support-responder.md +583 -0
- package/extensions/agency-agents/agents/testing/testing-accessibility-auditor.md +313 -0
- package/extensions/agency-agents/agents/testing/testing-api-tester.md +304 -0
- package/extensions/agency-agents/agents/testing/testing-evidence-collector.md +208 -0
- package/extensions/agency-agents/agents/testing/testing-performance-benchmarker.md +266 -0
- package/extensions/agency-agents/agents/testing/testing-reality-checker.md +236 -0
- package/extensions/agency-agents/agents/testing/testing-test-results-analyzer.md +303 -0
- package/extensions/agency-agents/agents/testing/testing-tool-evaluator.md +392 -0
- package/extensions/agency-agents/agents/testing/testing-workflow-optimizer.md +448 -0
- package/extensions/agency-agents/index.ts +733 -0
- package/extensions/agency-agents/node_modules/.bin/jiti +21 -0
- package/extensions/agency-agents/node_modules/.bin/tsc +21 -0
- package/extensions/agency-agents/node_modules/.bin/tsserver +21 -0
- package/extensions/agency-agents/node_modules/.bin/tsx +21 -0
- package/extensions/agency-agents/node_modules/.bin/vite +21 -0
- package/extensions/agency-agents/node_modules/.bin/vitest +21 -0
- package/extensions/agency-agents/node_modules/.bin/yaml +21 -0
- package/extensions/agency-agents/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/extensions/agency-agents/package.json +25 -0
- package/extensions/agency-agents/src/AgencyAgentsService.test.ts +443 -0
- package/extensions/agency-agents/src/AgencyAgentsService.ts +288 -0
- package/extensions/agency-agents/src/types.ts +147 -0
- package/extensions/agency-agents/vitest.config.ts +8 -0
- package/extensions/hexstrike-ai/README.md +98 -0
- package/extensions/hexstrike-ai/node_modules/.bin/tsc +21 -0
- package/extensions/hexstrike-ai/node_modules/.bin/tsserver +21 -0
- package/extensions/hexstrike-ai/package.json +29 -0
- package/extensions/hexstrike-ai/poolbot.plugin.json +31 -0
- package/extensions/hexstrike-ai/src/client.ts +91 -0
- package/extensions/hexstrike-ai/src/index.ts +170 -0
- package/extensions/hexstrike-ai/src/server/hexstrike_mcp.py +5470 -0
- package/extensions/hexstrike-ai/src/server/hexstrike_server.py +17289 -0
- package/extensions/hexstrike-ai/src/server/requirements.txt +84 -0
- package/extensions/hexstrike-ai/src/server-manager.ts +83 -0
- package/extensions/hexstrike-ai/tsconfig.json +20 -0
- package/extensions/hexstrike-bridge/package.json +1 -1
- package/extensions/hexstrike-bridge/poolbot.plugin.json +23 -0
- package/extensions/mcp-server/poolbot.plugin.json +10 -0
- package/extensions/page-agent/README.md +159 -0
- package/extensions/page-agent/index.ts +595 -0
- package/extensions/page-agent/node_modules/.bin/jiti +21 -0
- package/extensions/page-agent/node_modules/.bin/playwright +21 -0
- package/extensions/page-agent/node_modules/.bin/tsc +21 -0
- package/extensions/page-agent/node_modules/.bin/tsserver +21 -0
- package/extensions/page-agent/node_modules/.bin/tsx +21 -0
- package/extensions/page-agent/node_modules/.bin/vitest +21 -0
- package/extensions/page-agent/node_modules/.bin/yaml +21 -0
- package/extensions/page-agent/package.json +43 -0
- package/extensions/page-agent/src/PageAgentService.test.ts +517 -0
- package/extensions/page-agent/src/PageAgentService.ts +636 -0
- package/extensions/page-agent/src/PoolBotPageController.test.ts +358 -0
- package/extensions/page-agent/src/PoolBotPageController.ts +245 -0
- package/extensions/page-agent/src/index.ts +20 -0
- package/extensions/page-agent/src/tools.test.ts +231 -0
- package/extensions/page-agent/src/tools.ts +167 -0
- package/extensions/page-agent/src/types.ts +198 -0
- package/extensions/template/README.md +101 -0
- package/extensions/template/index.ts +38 -0
- package/extensions/template/package.json +15 -0
- package/extensions/template/poolbot.plugin.json +10 -0
- package/extensions/xyops/README.md +227 -0
- package/extensions/xyops/index.ts +342 -0
- package/extensions/xyops/node_modules/.bin/jiti +21 -0
- package/extensions/xyops/node_modules/.bin/tsc +21 -0
- package/extensions/xyops/node_modules/.bin/tsserver +21 -0
- package/extensions/xyops/node_modules/.bin/tsx +21 -0
- package/extensions/xyops/node_modules/.bin/vitest +21 -0
- package/extensions/xyops/node_modules/.bin/yaml +21 -0
- package/extensions/xyops/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/extensions/xyops/package.json +39 -0
- package/extensions/xyops/src/client.test.ts +467 -0
- package/extensions/xyops/src/client.ts +157 -0
- package/extensions/xyops/src/types.ts +147 -0
- package/extensions/xyops/vitest.config.ts +8 -0
- package/package.json +1 -1
- package/extensions/mavalie/README.md +0 -97
- package/extensions/mavalie/package.json +0 -15
- package/extensions/mavalie/src/index.ts +0 -62
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageAgentService - ReAct Agent Loop for PoolBot
|
|
3
|
+
*
|
|
4
|
+
* Implements the core agent loop:
|
|
5
|
+
* - observe (gather information about current environment)
|
|
6
|
+
* - think (LLM calling with reflection and action planning)
|
|
7
|
+
* - act (execute the action via tools)
|
|
8
|
+
*
|
|
9
|
+
* This is a native PoolBot service that uses the browser client
|
|
10
|
+
* and LLM infrastructure already available in PoolBot.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { PoolBotPageController } from './PoolBotPageController.js'
|
|
14
|
+
import type {
|
|
15
|
+
PageAgentConfig,
|
|
16
|
+
PageAgentExecutionResult,
|
|
17
|
+
AgentActivity,
|
|
18
|
+
AgentHistoryEvent,
|
|
19
|
+
PageAgentTool,
|
|
20
|
+
} from './types.js'
|
|
21
|
+
import { createPageAgentTools } from './tools.js'
|
|
22
|
+
|
|
23
|
+
// System prompt for the agent
|
|
24
|
+
const SYSTEM_PROMPT = `You are an AI agent that can control a web browser to complete tasks.
|
|
25
|
+
|
|
26
|
+
Your job is to:
|
|
27
|
+
1. Analyze the current browser state
|
|
28
|
+
2. Reflect on previous actions and their results
|
|
29
|
+
3. Plan the next action to progress toward the goal
|
|
30
|
+
4. Execute the action using available tools
|
|
31
|
+
|
|
32
|
+
Available tools:
|
|
33
|
+
- navigate: Navigate to a URL
|
|
34
|
+
- click: Click on an element
|
|
35
|
+
- type: Type text into an input field
|
|
36
|
+
- scroll: Scroll the page
|
|
37
|
+
- wait: Wait for a specified time
|
|
38
|
+
- screenshot: Take a screenshot
|
|
39
|
+
- get_text: Get text content from the page
|
|
40
|
+
- done: Complete the task with success/failure
|
|
41
|
+
|
|
42
|
+
Rules:
|
|
43
|
+
- Always evaluate your previous action before planning the next one
|
|
44
|
+
- Keep track of important information in your memory
|
|
45
|
+
- Be concise but thorough in your reasoning
|
|
46
|
+
- If stuck, try a different approach
|
|
47
|
+
- Call 'done' when the task is complete or if you cannot proceed
|
|
48
|
+
|
|
49
|
+
Default working language: **English**`
|
|
50
|
+
|
|
51
|
+
// Tool output type
|
|
52
|
+
interface ToolOutput {
|
|
53
|
+
success: boolean
|
|
54
|
+
data?: unknown
|
|
55
|
+
error?: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// LLM message type
|
|
59
|
+
interface LLMMessage {
|
|
60
|
+
role: 'system' | 'user' | 'assistant'
|
|
61
|
+
content: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Agent status type
|
|
65
|
+
type AgentStatus = 'idle' | 'running' | 'completed' | 'error'
|
|
66
|
+
|
|
67
|
+
// Historical event types
|
|
68
|
+
interface AgentStepEvent {
|
|
69
|
+
type: 'step'
|
|
70
|
+
stepIndex: number
|
|
71
|
+
reflection: {
|
|
72
|
+
evaluation_previous_goal?: string
|
|
73
|
+
memory?: string
|
|
74
|
+
next_goal?: string
|
|
75
|
+
}
|
|
76
|
+
action: {
|
|
77
|
+
name: string
|
|
78
|
+
input: unknown
|
|
79
|
+
output: unknown
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface ObservationEvent {
|
|
84
|
+
type: 'observation'
|
|
85
|
+
content: string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface ErrorEvent {
|
|
89
|
+
type: 'error'
|
|
90
|
+
message: string
|
|
91
|
+
rawResponse?: unknown
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type HistoricalEvent = AgentStepEvent | ObservationEvent | ErrorEvent
|
|
95
|
+
|
|
96
|
+
// Macro tool types
|
|
97
|
+
interface MacroToolInput {
|
|
98
|
+
evaluation_previous_goal?: string
|
|
99
|
+
memory?: string
|
|
100
|
+
next_goal?: string
|
|
101
|
+
action: Record<string, unknown>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export class PageAgentService extends EventTarget {
|
|
105
|
+
readonly id: string
|
|
106
|
+
readonly config: PageAgentConfig
|
|
107
|
+
private readonly controller: PoolBotPageController
|
|
108
|
+
private readonly tools: PageAgentTool[]
|
|
109
|
+
|
|
110
|
+
task = ''
|
|
111
|
+
taskId = ''
|
|
112
|
+
history: HistoricalEvent[] = []
|
|
113
|
+
status: AgentStatus = 'idle'
|
|
114
|
+
disposed = false
|
|
115
|
+
|
|
116
|
+
private abortController = new AbortController()
|
|
117
|
+
private observations: string[] = []
|
|
118
|
+
private currentStep = 0
|
|
119
|
+
private maxSteps: number
|
|
120
|
+
|
|
121
|
+
// Internal state tracking
|
|
122
|
+
private states = {
|
|
123
|
+
totalWaitTime: 0,
|
|
124
|
+
lastURL: '',
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
constructor(config: PageAgentConfig, controller: PoolBotPageController) {
|
|
128
|
+
super()
|
|
129
|
+
|
|
130
|
+
this.id = this.generateId()
|
|
131
|
+
this.config = config
|
|
132
|
+
this.controller = controller
|
|
133
|
+
this.maxSteps = config.maxSteps ?? 40
|
|
134
|
+
|
|
135
|
+
// Initialize tools
|
|
136
|
+
this.tools = createPageAgentTools()
|
|
137
|
+
|
|
138
|
+
// Apply custom tools
|
|
139
|
+
if (this.config.customTools) {
|
|
140
|
+
for (const [name, tool] of Object.entries(this.config.customTools)) {
|
|
141
|
+
if (tool === null) {
|
|
142
|
+
const idx = this.tools.findIndex((t) => t.name === name)
|
|
143
|
+
if (idx >= 0) this.tools.splice(idx, 1)
|
|
144
|
+
} else {
|
|
145
|
+
const idx = this.tools.findIndex((t) => t.name === name)
|
|
146
|
+
if (idx >= 0) {
|
|
147
|
+
this.tools[idx] = tool as PageAgentTool
|
|
148
|
+
} else {
|
|
149
|
+
this.tools.push(tool as PageAgentTool)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Execute a task using the ReAct loop
|
|
158
|
+
*/
|
|
159
|
+
async execute(task: string): Promise<PageAgentExecutionResult> {
|
|
160
|
+
if (this.disposed) {
|
|
161
|
+
throw new Error('PageAgentService has been disposed. Create a new instance.')
|
|
162
|
+
}
|
|
163
|
+
if (!task) {
|
|
164
|
+
throw new Error('Task is required')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.task = task
|
|
168
|
+
this.taskId = this.generateId()
|
|
169
|
+
this.currentStep = 0
|
|
170
|
+
|
|
171
|
+
await this.config.onBeforeTask?.(this)
|
|
172
|
+
|
|
173
|
+
// Reset state
|
|
174
|
+
this.abortController = new AbortController()
|
|
175
|
+
this.history = []
|
|
176
|
+
this.observations = []
|
|
177
|
+
this.states = { totalWaitTime: 0, lastURL: '' }
|
|
178
|
+
|
|
179
|
+
this.setStatus('running')
|
|
180
|
+
this.emitHistoryChange()
|
|
181
|
+
|
|
182
|
+
const startTime = Date.now()
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
while (true) {
|
|
186
|
+
console.group(`Step: ${this.currentStep}`)
|
|
187
|
+
|
|
188
|
+
await this.config.onBeforeStep?.(this, this.currentStep)
|
|
189
|
+
|
|
190
|
+
// OBSERVE: Gather information about current state
|
|
191
|
+
console.log('👀 Observing...')
|
|
192
|
+
await this.observe()
|
|
193
|
+
|
|
194
|
+
// THINK: Call LLM to decide next action
|
|
195
|
+
console.log('🧠 Thinking...')
|
|
196
|
+
this.emitActivity({ type: 'thinking' })
|
|
197
|
+
|
|
198
|
+
const messages = await this.buildMessages()
|
|
199
|
+
const tools = this.buildMacroTool()
|
|
200
|
+
|
|
201
|
+
const llmResult = await this.callLLM(messages, tools)
|
|
202
|
+
|
|
203
|
+
// Parse the result
|
|
204
|
+
const parsed = this.parseLLMResponse(llmResult)
|
|
205
|
+
if (!parsed) {
|
|
206
|
+
throw new Error('Failed to parse LLM response')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Extract reflection and action
|
|
210
|
+
const reflection = {
|
|
211
|
+
evaluation_previous_goal: parsed.evaluation_previous_goal,
|
|
212
|
+
memory: parsed.memory,
|
|
213
|
+
next_goal: parsed.next_goal,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const actionName = Object.keys(parsed.action)[0]
|
|
217
|
+
const actionInput = parsed.action[actionName]
|
|
218
|
+
|
|
219
|
+
// ACT: Execute the tool
|
|
220
|
+
console.log(`🎬 Executing: ${actionName}`)
|
|
221
|
+
this.emitActivity({ type: 'executing', tool: actionName, input: actionInput })
|
|
222
|
+
|
|
223
|
+
const stepStartTime = Date.now()
|
|
224
|
+
const toolResult = await this.executeTool(actionName, actionInput)
|
|
225
|
+
const duration = Date.now() - stepStartTime
|
|
226
|
+
|
|
227
|
+
console.log(`✅ Tool (${actionName}) executed in ${duration}ms`, toolResult)
|
|
228
|
+
this.emitActivity({
|
|
229
|
+
type: 'executed',
|
|
230
|
+
tool: actionName,
|
|
231
|
+
input: actionInput,
|
|
232
|
+
output: toolResult.data,
|
|
233
|
+
duration,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// Track wait time
|
|
237
|
+
if (actionName === 'wait') {
|
|
238
|
+
this.states.totalWaitTime += ((actionInput as { seconds?: number })?.seconds) || 0
|
|
239
|
+
} else {
|
|
240
|
+
this.states.totalWaitTime = 0
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Record step in history
|
|
244
|
+
const stepEvent: AgentStepEvent = {
|
|
245
|
+
type: 'step',
|
|
246
|
+
stepIndex: this.currentStep,
|
|
247
|
+
reflection,
|
|
248
|
+
action: {
|
|
249
|
+
name: actionName,
|
|
250
|
+
input: actionInput,
|
|
251
|
+
output: toolResult.data,
|
|
252
|
+
},
|
|
253
|
+
}
|
|
254
|
+
this.history.push(stepEvent)
|
|
255
|
+
this.emitHistoryChange()
|
|
256
|
+
|
|
257
|
+
await this.config.onAfterStep?.(this, this.history)
|
|
258
|
+
|
|
259
|
+
console.groupEnd()
|
|
260
|
+
|
|
261
|
+
// Check if done
|
|
262
|
+
if (actionName === 'done') {
|
|
263
|
+
const input = actionInput as { success?: boolean; answer?: string }
|
|
264
|
+
const success = input?.success ?? false
|
|
265
|
+
const text = input?.answer || 'Task completed'
|
|
266
|
+
console.log('Task completed:', success, text)
|
|
267
|
+
|
|
268
|
+
this.setStatus(success ? 'completed' : 'error')
|
|
269
|
+
const result: PageAgentExecutionResult = {
|
|
270
|
+
success,
|
|
271
|
+
data: text,
|
|
272
|
+
history: this.history as AgentHistoryEvent[],
|
|
273
|
+
totalSteps: this.currentStep + 1,
|
|
274
|
+
duration: Date.now() - startTime,
|
|
275
|
+
}
|
|
276
|
+
await this.config.onAfterTask?.(this, result)
|
|
277
|
+
return result
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Increment step
|
|
281
|
+
this.currentStep++
|
|
282
|
+
|
|
283
|
+
// Check max steps
|
|
284
|
+
if (this.currentStep >= this.maxSteps) {
|
|
285
|
+
const errorMessage = 'Step count exceeded maximum limit'
|
|
286
|
+
this.history.push({ type: 'error', message: errorMessage })
|
|
287
|
+
this.emitHistoryChange()
|
|
288
|
+
this.setStatus('error')
|
|
289
|
+
const result: PageAgentExecutionResult = {
|
|
290
|
+
success: false,
|
|
291
|
+
data: errorMessage,
|
|
292
|
+
history: this.history as AgentHistoryEvent[],
|
|
293
|
+
totalSteps: this.currentStep,
|
|
294
|
+
duration: Date.now() - startTime,
|
|
295
|
+
error: errorMessage,
|
|
296
|
+
}
|
|
297
|
+
await this.config.onAfterTask?.(this, result)
|
|
298
|
+
return result
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Small delay between steps
|
|
302
|
+
await this.wait(400)
|
|
303
|
+
}
|
|
304
|
+
} catch (error: unknown) {
|
|
305
|
+
console.groupEnd()
|
|
306
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
307
|
+
console.error('Task failed:', errorMessage)
|
|
308
|
+
|
|
309
|
+
this.emitActivity({ type: 'error', message: errorMessage })
|
|
310
|
+
this.history.push({ type: 'error', message: errorMessage })
|
|
311
|
+
this.emitHistoryChange()
|
|
312
|
+
this.setStatus('error')
|
|
313
|
+
|
|
314
|
+
const result: PageAgentExecutionResult = {
|
|
315
|
+
success: false,
|
|
316
|
+
data: errorMessage,
|
|
317
|
+
history: this.history as AgentHistoryEvent[],
|
|
318
|
+
totalSteps: this.currentStep,
|
|
319
|
+
duration: Date.now() - startTime,
|
|
320
|
+
error: errorMessage,
|
|
321
|
+
}
|
|
322
|
+
await this.config.onAfterTask?.(this, result)
|
|
323
|
+
return result
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Observe the current browser state and gather information
|
|
329
|
+
*/
|
|
330
|
+
private async observe(): Promise<void> {
|
|
331
|
+
// Get current browser state
|
|
332
|
+
const browserState = await this.controller.getBrowserState()
|
|
333
|
+
|
|
334
|
+
// Check accumulated wait time
|
|
335
|
+
if (this.states.totalWaitTime >= 3) {
|
|
336
|
+
this.pushObservation(
|
|
337
|
+
`You have waited ${this.states.totalWaitTime} seconds accumulatively. DO NOT wait any longer unless you have a good reason.`
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Detect URL change
|
|
342
|
+
if (browserState.url !== this.states.lastURL) {
|
|
343
|
+
this.pushObservation(`Page navigated to → ${browserState.url}`)
|
|
344
|
+
this.states.lastURL = browserState.url
|
|
345
|
+
await this.wait(500) // Wait for page to stabilize
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Remaining steps warning
|
|
349
|
+
const remaining = this.maxSteps - this.currentStep
|
|
350
|
+
if (remaining === 5) {
|
|
351
|
+
this.pushObservation(
|
|
352
|
+
`⚠️ Only ${remaining} steps remaining. Consider wrapping up or calling done with partial results.`
|
|
353
|
+
)
|
|
354
|
+
} else if (remaining === 2) {
|
|
355
|
+
this.pushObservation(
|
|
356
|
+
`⚠️ Critical: Only ${remaining} steps left! You must finish the task or call done immediately.`
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Push observations to history
|
|
361
|
+
if (this.observations.length > 0) {
|
|
362
|
+
for (const content of this.observations) {
|
|
363
|
+
this.history.push({ type: 'observation', content })
|
|
364
|
+
console.log('Observation:', content)
|
|
365
|
+
}
|
|
366
|
+
this.observations = []
|
|
367
|
+
this.emitHistoryChange()
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Push an observation to be included in the next step
|
|
373
|
+
*/
|
|
374
|
+
pushObservation(content: string): void {
|
|
375
|
+
this.observations.push(content)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Build the messages for the LLM
|
|
380
|
+
*/
|
|
381
|
+
private async buildMessages(): Promise<LLMMessage[]> {
|
|
382
|
+
const systemPrompt = this.config.customSystemPrompt || SYSTEM_PROMPT
|
|
383
|
+
const userPrompt = await this.buildUserPrompt()
|
|
384
|
+
|
|
385
|
+
return [
|
|
386
|
+
{ role: 'system', content: systemPrompt },
|
|
387
|
+
{ role: 'user', content: userPrompt },
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Build the user prompt with current state and history
|
|
393
|
+
*/
|
|
394
|
+
private async buildUserPrompt(): Promise<string> {
|
|
395
|
+
const browserState = await this.controller.getBrowserState()
|
|
396
|
+
let prompt = ''
|
|
397
|
+
|
|
398
|
+
// Agent state
|
|
399
|
+
const stepCount = this.history.filter((e) => e.type === 'step').length
|
|
400
|
+
|
|
401
|
+
prompt += '<agent_state>\n'
|
|
402
|
+
prompt += '<user_request>\n'
|
|
403
|
+
prompt += `${this.task}\n`
|
|
404
|
+
prompt += '</user_request>\n'
|
|
405
|
+
prompt += '<step_info>\n'
|
|
406
|
+
prompt += `Step ${stepCount + 1} of ${this.maxSteps} max possible steps\n`
|
|
407
|
+
prompt += `Current time: ${new Date().toLocaleString()}\n`
|
|
408
|
+
prompt += '</step_info>\n'
|
|
409
|
+
prompt += '</agent_state>\n\n'
|
|
410
|
+
|
|
411
|
+
// History
|
|
412
|
+
prompt += '<agent_history>\n'
|
|
413
|
+
|
|
414
|
+
let stepIndex = 0
|
|
415
|
+
for (const event of this.history) {
|
|
416
|
+
if (event.type === 'step') {
|
|
417
|
+
stepIndex++
|
|
418
|
+
prompt += `<step_${stepIndex}>\n`
|
|
419
|
+
prompt += `Evaluation of Previous Step: ${event.reflection.evaluation_previous_goal}\n`
|
|
420
|
+
prompt += `Memory: ${event.reflection.memory}\n`
|
|
421
|
+
prompt += `Next Goal: ${event.reflection.next_goal}\n`
|
|
422
|
+
prompt += `Action Results: ${JSON.stringify(event.action.output)}\n`
|
|
423
|
+
prompt += `</step_${stepIndex}>\n`
|
|
424
|
+
} else if (event.type === 'observation') {
|
|
425
|
+
prompt += `<sys>${event.content}</sys>\n`
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
prompt += '</agent_history>\n\n'
|
|
430
|
+
|
|
431
|
+
// Browser state
|
|
432
|
+
prompt += '<browser_state>\n'
|
|
433
|
+
prompt += `URL: ${browserState.url}\n`
|
|
434
|
+
prompt += `Title: ${browserState.title}\n`
|
|
435
|
+
prompt += `Content:\n${browserState.content}\n`
|
|
436
|
+
prompt += '</browser_state>\n\n'
|
|
437
|
+
|
|
438
|
+
return prompt
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Build the macro tool schema for the LLM
|
|
443
|
+
*/
|
|
444
|
+
private buildMacroTool(): Record<string, unknown> {
|
|
445
|
+
// Build action schema from available tools
|
|
446
|
+
const actionProperties: Record<string, unknown> = {}
|
|
447
|
+
|
|
448
|
+
for (const tool of this.tools) {
|
|
449
|
+
actionProperties[tool.name] = {
|
|
450
|
+
type: 'object',
|
|
451
|
+
properties: (tool.inputSchema as { properties?: Record<string, unknown> }).properties || {},
|
|
452
|
+
required: (tool.inputSchema as { required?: string[] }).required || [],
|
|
453
|
+
description: tool.description,
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// OneOf for action selection
|
|
458
|
+
const actionAnyOf = Object.entries(actionProperties).map(([toolName, schema]) => ({
|
|
459
|
+
type: 'object',
|
|
460
|
+
properties: {
|
|
461
|
+
[toolName]: schema,
|
|
462
|
+
},
|
|
463
|
+
required: [toolName],
|
|
464
|
+
}))
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
AgentOutput: {
|
|
468
|
+
type: 'object',
|
|
469
|
+
properties: {
|
|
470
|
+
evaluation_previous_goal: {
|
|
471
|
+
type: 'string',
|
|
472
|
+
description: 'Evaluate if the previous step achieved its goal',
|
|
473
|
+
},
|
|
474
|
+
memory: {
|
|
475
|
+
type: 'string',
|
|
476
|
+
description: 'Important information to remember for future steps',
|
|
477
|
+
},
|
|
478
|
+
next_goal: {
|
|
479
|
+
type: 'string',
|
|
480
|
+
description: 'What you aim to accomplish in the next step',
|
|
481
|
+
},
|
|
482
|
+
action: {
|
|
483
|
+
anyOf: actionAnyOf,
|
|
484
|
+
description: 'The action to take - must select one tool',
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
required: ['action'],
|
|
488
|
+
},
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Call the LLM with messages and tools
|
|
494
|
+
*/
|
|
495
|
+
private async callLLM(
|
|
496
|
+
messages: LLMMessage[],
|
|
497
|
+
tools: Record<string, unknown>
|
|
498
|
+
): Promise<string> {
|
|
499
|
+
const { llm } = this.config
|
|
500
|
+
|
|
501
|
+
const response = await fetch(`${llm.baseURL}/chat/completions`, {
|
|
502
|
+
method: 'POST',
|
|
503
|
+
headers: {
|
|
504
|
+
'Content-Type': 'application/json',
|
|
505
|
+
Authorization: `Bearer ${llm.apiKey}`,
|
|
506
|
+
},
|
|
507
|
+
body: JSON.stringify({
|
|
508
|
+
model: llm.model,
|
|
509
|
+
messages,
|
|
510
|
+
tools: [
|
|
511
|
+
{
|
|
512
|
+
type: 'function',
|
|
513
|
+
function: {
|
|
514
|
+
name: 'AgentOutput',
|
|
515
|
+
description: 'You MUST call this tool every step!',
|
|
516
|
+
parameters: tools.AgentOutput,
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
tool_choice: { type: 'function', function: { name: 'AgentOutput' } },
|
|
521
|
+
temperature: llm.temperature ?? 0.7,
|
|
522
|
+
}),
|
|
523
|
+
signal: this.abortController.signal,
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
if (!response.ok) {
|
|
527
|
+
throw new Error(`LLM API error: ${response.status} ${response.statusText}`)
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const data = (await response.json()) as {
|
|
531
|
+
choices: Array<{
|
|
532
|
+
message: {
|
|
533
|
+
tool_calls?: Array<{
|
|
534
|
+
function: {
|
|
535
|
+
name: string
|
|
536
|
+
arguments: string
|
|
537
|
+
}
|
|
538
|
+
}>
|
|
539
|
+
}
|
|
540
|
+
}>
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const toolCall = data.choices[0]?.message?.tool_calls?.[0]
|
|
544
|
+
if (!toolCall) {
|
|
545
|
+
throw new Error('No tool call in LLM response')
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return toolCall.function.arguments
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Parse the LLM response
|
|
553
|
+
*/
|
|
554
|
+
private parseLLMResponse(response: string): MacroToolInput | null {
|
|
555
|
+
try {
|
|
556
|
+
return JSON.parse(response) as MacroToolInput
|
|
557
|
+
} catch {
|
|
558
|
+
return null
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Execute a tool by name
|
|
564
|
+
*/
|
|
565
|
+
private async executeTool(name: string, input: unknown): Promise<ToolOutput> {
|
|
566
|
+
const tool = this.tools.find((t) => t.name === name)
|
|
567
|
+
if (!tool) {
|
|
568
|
+
return { success: false, error: `Tool ${name} not found` }
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
try {
|
|
572
|
+
// Execute the tool with controller
|
|
573
|
+
const result = await tool.execute(this.controller, input)
|
|
574
|
+
return { success: true, data: result }
|
|
575
|
+
} catch (error: unknown) {
|
|
576
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
577
|
+
return { success: false, error: errorMessage }
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Stop the current task
|
|
583
|
+
*/
|
|
584
|
+
stop(): void {
|
|
585
|
+
this.abortController.abort()
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Dispose the agent
|
|
590
|
+
*/
|
|
591
|
+
dispose(): void {
|
|
592
|
+
console.log('Disposing PageAgentService...')
|
|
593
|
+
this.disposed = true
|
|
594
|
+
this.stop()
|
|
595
|
+
this.config.onDispose?.(this)
|
|
596
|
+
this.dispatchEvent(new Event('dispose'))
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Set status and emit event
|
|
601
|
+
*/
|
|
602
|
+
private setStatus(status: AgentStatus): void {
|
|
603
|
+
if (this.status !== status) {
|
|
604
|
+
this.status = status
|
|
605
|
+
this.dispatchEvent(new Event('statuschange'))
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Emit history change event
|
|
611
|
+
*/
|
|
612
|
+
private emitHistoryChange(): void {
|
|
613
|
+
this.dispatchEvent(new Event('historychange'))
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Emit activity event
|
|
618
|
+
*/
|
|
619
|
+
private emitActivity(activity: AgentActivity): void {
|
|
620
|
+
this.dispatchEvent(new CustomEvent('activity', { detail: activity }))
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Generate a unique ID
|
|
625
|
+
*/
|
|
626
|
+
private generateId(): string {
|
|
627
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Wait for a specified time
|
|
632
|
+
*/
|
|
633
|
+
private wait(ms: number): Promise<void> {
|
|
634
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
635
|
+
}
|
|
636
|
+
}
|