ai-browser 0.2.3 → 0.2.5

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 (72) hide show
  1. package/README.md +62 -5
  2. package/dist/agent/agent-loop.d.ts +8 -2
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +138 -86
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/config.d.ts +5 -0
  7. package/dist/agent/config.d.ts.map +1 -1
  8. package/dist/agent/config.js +5 -0
  9. package/dist/agent/config.js.map +1 -1
  10. package/dist/agent/content-budget.d.ts +11 -0
  11. package/dist/agent/content-budget.d.ts.map +1 -0
  12. package/dist/agent/content-budget.js +129 -0
  13. package/dist/agent/content-budget.js.map +1 -0
  14. package/dist/agent/conversation-manager.d.ts +48 -0
  15. package/dist/agent/conversation-manager.d.ts.map +1 -0
  16. package/dist/agent/conversation-manager.js +157 -0
  17. package/dist/agent/conversation-manager.js.map +1 -0
  18. package/dist/agent/error-recovery.d.ts +29 -0
  19. package/dist/agent/error-recovery.d.ts.map +1 -0
  20. package/dist/agent/error-recovery.js +72 -0
  21. package/dist/agent/error-recovery.js.map +1 -0
  22. package/dist/agent/page-state-cache.d.ts +22 -0
  23. package/dist/agent/page-state-cache.d.ts.map +1 -0
  24. package/dist/agent/page-state-cache.js +71 -0
  25. package/dist/agent/page-state-cache.js.map +1 -0
  26. package/dist/agent/progress-estimator.d.ts +17 -0
  27. package/dist/agent/progress-estimator.d.ts.map +1 -0
  28. package/dist/agent/progress-estimator.js +67 -0
  29. package/dist/agent/progress-estimator.js.map +1 -0
  30. package/dist/agent/prompt.d.ts +1 -1
  31. package/dist/agent/prompt.d.ts.map +1 -1
  32. package/dist/agent/prompt.js +83 -48
  33. package/dist/agent/prompt.js.map +1 -1
  34. package/dist/agent/task-agent.d.ts +89 -0
  35. package/dist/agent/task-agent.d.ts.map +1 -0
  36. package/dist/agent/task-agent.js +448 -0
  37. package/dist/agent/task-agent.js.map +1 -0
  38. package/dist/agent/token-tracker.d.ts +22 -0
  39. package/dist/agent/token-tracker.d.ts.map +1 -0
  40. package/dist/agent/token-tracker.js +29 -0
  41. package/dist/agent/token-tracker.js.map +1 -0
  42. package/dist/agent/tool-usage-tracker.d.ts +45 -0
  43. package/dist/agent/tool-usage-tracker.d.ts.map +1 -0
  44. package/dist/agent/tool-usage-tracker.js +145 -0
  45. package/dist/agent/tool-usage-tracker.js.map +1 -0
  46. package/dist/agent/types.d.ts +24 -0
  47. package/dist/agent/types.d.ts.map +1 -1
  48. package/dist/api/routes.d.ts.map +1 -1
  49. package/dist/api/routes.js +305 -1
  50. package/dist/api/routes.js.map +1 -1
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +1 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/mcp/ai-markdown.d.ts +2 -0
  56. package/dist/mcp/ai-markdown.d.ts.map +1 -0
  57. package/dist/mcp/ai-markdown.js +1739 -0
  58. package/dist/mcp/ai-markdown.js.map +1 -0
  59. package/dist/mcp/browser-mcp-server.d.ts.map +1 -1
  60. package/dist/mcp/browser-mcp-server.js +279 -49
  61. package/dist/mcp/browser-mcp-server.js.map +1 -1
  62. package/dist/mcp/task-tools.d.ts.map +1 -1
  63. package/dist/mcp/task-tools.js +107 -13
  64. package/dist/mcp/task-tools.js.map +1 -1
  65. package/dist/task/tool-actions.d.ts +4 -0
  66. package/dist/task/tool-actions.d.ts.map +1 -1
  67. package/dist/task/tool-actions.js +72 -0
  68. package/dist/task/tool-actions.js.map +1 -1
  69. package/package.json +5 -2
  70. package/public/index.html +593 -41
  71. package/public/task-result.html +135 -0
  72. package/public/tasks.html +126 -0
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tool-aware content budget system for formatting MCP results for LLM consumption.
3
+ * Prioritizes aiMarkdown/aiSummary fields from the MCP enrichment layer.
4
+ */
5
+ export declare function getToolBudget(toolName: string): number;
6
+ /**
7
+ * Format MCP tool result for LLM consumption.
8
+ * Priority: aiMarkdown > aiSummary > raw JSON, all within budget.
9
+ */
10
+ export declare function formatToolResult(rawText: string, toolName: string): string;
11
+ //# sourceMappingURL=content-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-budget.d.ts","sourceRoot":"","sources":["../../src/agent/content-budget.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwDH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CA6B1E"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Tool-aware content budget system for formatting MCP results for LLM consumption.
3
+ * Prioritizes aiMarkdown/aiSummary fields from the MCP enrichment layer.
4
+ */
5
+ /** Budget limits by tool category (in characters) */
6
+ const TOOL_BUDGETS = {
7
+ // Navigation/action tools — concise results
8
+ navigate: 2000,
9
+ click: 2000,
10
+ type_text: 2000,
11
+ press_key: 2000,
12
+ scroll: 2000,
13
+ go_back: 2000,
14
+ select_option: 2000,
15
+ hover: 2000,
16
+ set_value: 2000,
17
+ wait: 2000,
18
+ wait_for_stable: 2000,
19
+ handle_dialog: 2000,
20
+ upload_file: 2000,
21
+ switch_tab: 2000,
22
+ close_tab: 2000,
23
+ create_tab: 2000,
24
+ create_session: 2000,
25
+ close_session: 2000,
26
+ // Content extraction tools — need more space
27
+ get_page_content: 6000,
28
+ execute_javascript: 4000,
29
+ get_network_logs: 4000,
30
+ get_console_logs: 4000,
31
+ // Page info tools — moderate space
32
+ get_page_info: 4000,
33
+ find_element: 3000,
34
+ list_tabs: 3000,
35
+ screenshot: 2000,
36
+ get_dialog_info: 3000,
37
+ get_downloads: 3000,
38
+ // Task tools
39
+ list_task_templates: 3000,
40
+ run_task_template: 2000,
41
+ get_task_run: 4000,
42
+ list_task_runs: 3000,
43
+ cancel_task_run: 2000,
44
+ get_artifact: 6000,
45
+ get_runtime_profile: 2000,
46
+ // Composite tools
47
+ fill_form: 4000,
48
+ click_and_wait: 4000,
49
+ navigate_and_extract: 6000,
50
+ };
51
+ const DEFAULT_BUDGET = 4000;
52
+ const SAFETY_MAX = 8000;
53
+ export function getToolBudget(toolName) {
54
+ return TOOL_BUDGETS[toolName] ?? DEFAULT_BUDGET;
55
+ }
56
+ /**
57
+ * Format MCP tool result for LLM consumption.
58
+ * Priority: aiMarkdown > aiSummary > raw JSON, all within budget.
59
+ */
60
+ export function formatToolResult(rawText, toolName) {
61
+ const budget = getToolBudget(toolName);
62
+ try {
63
+ const data = JSON.parse(rawText);
64
+ // Priority 1: Use aiMarkdown if available and within budget
65
+ if (typeof data.aiMarkdown === 'string' && data.aiMarkdown.length > 0) {
66
+ const md = data.aiMarkdown;
67
+ if (md.length <= budget)
68
+ return md;
69
+ // Over budget — try aiSummary as fallback
70
+ if (typeof data.aiSummary === 'string' && data.aiSummary.length > 0) {
71
+ return truncate(data.aiSummary, budget);
72
+ }
73
+ // Truncate aiMarkdown as last resort
74
+ return truncate(md, budget);
75
+ }
76
+ // Priority 2: Use aiSummary if available
77
+ if (typeof data.aiSummary === 'string' && data.aiSummary.length > 0) {
78
+ return truncate(data.aiSummary, budget);
79
+ }
80
+ // Priority 3: Tool-specific formatting for legacy/non-enriched responses
81
+ const formatted = formatLegacy(data, toolName);
82
+ return truncate(formatted, SAFETY_MAX);
83
+ }
84
+ catch {
85
+ return truncate(rawText, SAFETY_MAX);
86
+ }
87
+ }
88
+ function formatLegacy(data, toolName) {
89
+ if (toolName === 'get_page_info' && data?.elements) {
90
+ const summary = {
91
+ page: data.page,
92
+ elementCount: data.elements.length,
93
+ elements: data.elements.slice(0, 30).map((e) => ({
94
+ id: e.id,
95
+ type: e.type,
96
+ label: e.label,
97
+ })),
98
+ intents: data.intents,
99
+ };
100
+ if (data.stability)
101
+ summary.stability = data.stability;
102
+ if (data.pendingDialog)
103
+ summary.pendingDialog = data.pendingDialog;
104
+ if (data.elements.length > 30) {
105
+ summary.note = `显示前30个元素,共${data.elements.length}个`;
106
+ }
107
+ return JSON.stringify(summary, null, 2);
108
+ }
109
+ if (toolName === 'get_page_content') {
110
+ let md = `# ${data.title || ''}\n\n`;
111
+ const sections = Array.isArray(data.sections) ? data.sections : [];
112
+ for (const s of sections) {
113
+ const stars = s.attention >= 0.7 ? '***'
114
+ : s.attention >= 0.4 ? '**'
115
+ : '*';
116
+ md += `[${stars}] ${s.text}\n\n`;
117
+ }
118
+ if (sections.length === 0)
119
+ md += '(未提取到内容)\n';
120
+ return md;
121
+ }
122
+ return JSON.stringify(data);
123
+ }
124
+ function truncate(text, max) {
125
+ if (text.length <= max)
126
+ return text;
127
+ return text.slice(0, max) + `\n...(已截断,共${text.length}字符)`;
128
+ }
129
+ //# sourceMappingURL=content-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-budget.js","sourceRoot":"","sources":["../../src/agent/content-budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Manages conversation history with compression to prevent token explosion.
3
+ * Keeps system prompt + recent messages intact, compresses older tool results.
4
+ */
5
+ import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions.js';
6
+ export interface ConversationManagerOptions {
7
+ maxMessages?: number;
8
+ compressThreshold?: number;
9
+ keepRecent?: number;
10
+ }
11
+ export declare class ConversationManager {
12
+ private messages;
13
+ private maxMessages;
14
+ private compressThreshold;
15
+ private keepRecent;
16
+ constructor(options?: ConversationManagerOptions);
17
+ /**
18
+ * Initialize with system prompt and optional initial messages.
19
+ * - Merges any system-role messages into the main system prompt (avoids mid-conversation system messages)
20
+ * - Strips trailing orphaned tool_calls without matching tool results
21
+ */
22
+ init(systemPrompt: string, initialMessages: ChatCompletionMessageParam[], userTask: string): void;
23
+ /**
24
+ * Add a message to the conversation.
25
+ */
26
+ push(message: ChatCompletionMessageParam): void;
27
+ /**
28
+ * Get all messages for LLM consumption.
29
+ */
30
+ getMessages(): ChatCompletionMessageParam[];
31
+ /**
32
+ * Get current message count.
33
+ */
34
+ get length(): number;
35
+ /**
36
+ * Estimate total token count (~4 chars per token).
37
+ */
38
+ estimateTokens(): number;
39
+ /**
40
+ * Compress older messages to stay within bounds.
41
+ * Strategy: keep system prompt (index 0) + keepRecent most recent messages.
42
+ * Middle messages get compressed: tool results become one-line summaries,
43
+ * consecutive tool_call + tool_result pairs become grouped summaries.
44
+ */
45
+ private compress;
46
+ private compressMessages;
47
+ }
48
+ //# sourceMappingURL=conversation-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-manager.d.ts","sourceRoot":"","sources":["../../src/agent/conversation-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAEvF,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,CAAC,EAAE,0BAA0B;IAMhD;;;;OAIG;IACH,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,0BAA0B,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwCjG;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,0BAA0B,GAAG,IAAI;IAO/C;;OAEG;IACH,WAAW,IAAI,0BAA0B,EAAE;IAI3C;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;OAEG;IACH,cAAc,IAAI,MAAM;IAgBxB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,gBAAgB;CAyCzB"}
@@ -0,0 +1,157 @@
1
+ const DEFAULT_MAX_MESSAGES = 40;
2
+ const DEFAULT_COMPRESS_THRESHOLD = 30;
3
+ const DEFAULT_KEEP_RECENT = 20;
4
+ const CHARS_PER_TOKEN = 4; // rough heuristic
5
+ export class ConversationManager {
6
+ messages = [];
7
+ maxMessages;
8
+ compressThreshold;
9
+ keepRecent;
10
+ constructor(options) {
11
+ this.maxMessages = options?.maxMessages ?? DEFAULT_MAX_MESSAGES;
12
+ this.compressThreshold = options?.compressThreshold ?? DEFAULT_COMPRESS_THRESHOLD;
13
+ this.keepRecent = options?.keepRecent ?? DEFAULT_KEEP_RECENT;
14
+ }
15
+ /**
16
+ * Initialize with system prompt and optional initial messages.
17
+ * - Merges any system-role messages into the main system prompt (avoids mid-conversation system messages)
18
+ * - Strips trailing orphaned tool_calls without matching tool results
19
+ */
20
+ init(systemPrompt, initialMessages, userTask) {
21
+ const extraSystemParts = [];
22
+ const filtered = [];
23
+ for (const msg of initialMessages) {
24
+ if (msg.role === 'system') {
25
+ if (typeof msg.content === 'string')
26
+ extraSystemParts.push(msg.content);
27
+ }
28
+ else {
29
+ filtered.push(msg);
30
+ }
31
+ }
32
+ // Strip trailing assistant message with tool_calls if no matching tool results follow
33
+ while (filtered.length > 0) {
34
+ const last = filtered[filtered.length - 1];
35
+ if (last.role === 'assistant' && 'tool_calls' in last && last.tool_calls?.length) {
36
+ filtered.pop();
37
+ }
38
+ else if (last.role === 'tool') {
39
+ // Check if there's a matching assistant tool_calls before this tool message
40
+ const hasMatchingAssistant = filtered.some((m, idx) => idx < filtered.length - 1 && m.role === 'assistant' && 'tool_calls' in m);
41
+ if (!hasMatchingAssistant)
42
+ filtered.pop();
43
+ else
44
+ break;
45
+ }
46
+ else {
47
+ break;
48
+ }
49
+ }
50
+ const fullSystem = extraSystemParts.length > 0
51
+ ? systemPrompt + '\n\n' + extraSystemParts.join('\n\n')
52
+ : systemPrompt;
53
+ this.messages = [
54
+ { role: 'system', content: fullSystem },
55
+ ...filtered,
56
+ { role: 'user', content: userTask },
57
+ ];
58
+ }
59
+ /**
60
+ * Add a message to the conversation.
61
+ */
62
+ push(message) {
63
+ this.messages.push(message);
64
+ if (this.messages.length > this.compressThreshold) {
65
+ this.compress();
66
+ }
67
+ }
68
+ /**
69
+ * Get all messages for LLM consumption.
70
+ */
71
+ getMessages() {
72
+ return this.messages;
73
+ }
74
+ /**
75
+ * Get current message count.
76
+ */
77
+ get length() {
78
+ return this.messages.length;
79
+ }
80
+ /**
81
+ * Estimate total token count (~4 chars per token).
82
+ */
83
+ estimateTokens() {
84
+ let chars = 0;
85
+ for (const msg of this.messages) {
86
+ if (typeof msg.content === 'string') {
87
+ chars += msg.content.length;
88
+ }
89
+ else if (Array.isArray(msg.content)) {
90
+ for (const part of msg.content) {
91
+ if ('text' in part && typeof part.text === 'string') {
92
+ chars += part.text.length;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ return Math.ceil(chars / CHARS_PER_TOKEN);
98
+ }
99
+ /**
100
+ * Compress older messages to stay within bounds.
101
+ * Strategy: keep system prompt (index 0) + keepRecent most recent messages.
102
+ * Middle messages get compressed: tool results become one-line summaries,
103
+ * consecutive tool_call + tool_result pairs become grouped summaries.
104
+ */
105
+ compress() {
106
+ if (this.messages.length <= this.keepRecent + 1)
107
+ return;
108
+ const systemMsg = this.messages[0]; // always keep system prompt
109
+ const recentStart = this.messages.length - this.keepRecent;
110
+ const middleMessages = this.messages.slice(1, recentStart);
111
+ const recentMessages = this.messages.slice(recentStart);
112
+ // Compress middle messages into a summary
113
+ const summary = this.compressMessages(middleMessages);
114
+ this.messages = [
115
+ systemMsg,
116
+ { role: 'user', content: `[对话历史摘要] ${summary}` },
117
+ ...recentMessages,
118
+ ];
119
+ }
120
+ compressMessages(messages) {
121
+ const parts = [];
122
+ let i = 0;
123
+ while (i < messages.length) {
124
+ const msg = messages[i];
125
+ if (msg.role === 'assistant' && 'tool_calls' in msg && msg.tool_calls) {
126
+ // Group assistant tool_calls with their tool results
127
+ const toolNames = msg.tool_calls.map((tc) => tc.function?.name || 'unknown');
128
+ const thinking = typeof msg.content === 'string' && msg.content ? msg.content : '';
129
+ // Collect subsequent tool results
130
+ const results = [];
131
+ let j = i + 1;
132
+ while (j < messages.length && messages[j].role === 'tool') {
133
+ const rawContent = messages[j].content;
134
+ const content = typeof rawContent === 'string' ? rawContent : '';
135
+ results.push(content.slice(0, 80));
136
+ j++;
137
+ }
138
+ const thinkPart = thinking ? `思考:"${thinking.slice(0, 60)}" ` : '';
139
+ parts.push(`${thinkPart}调用 ${toolNames.join(',')} → ${results.join('; ').slice(0, 120)}`);
140
+ i = j;
141
+ continue;
142
+ }
143
+ if (msg.role === 'user' && typeof msg.content === 'string') {
144
+ parts.push(`用户: ${msg.content.slice(0, 80)}`);
145
+ }
146
+ else if (msg.role === 'system' && typeof msg.content === 'string') {
147
+ parts.push(`系统: ${msg.content.slice(0, 60)}`);
148
+ }
149
+ else if (msg.role === 'assistant' && typeof msg.content === 'string') {
150
+ parts.push(`助手: ${msg.content.slice(0, 80)}`);
151
+ }
152
+ i++;
153
+ }
154
+ return parts.join(' | ');
155
+ }
156
+ }
157
+ //# sourceMappingURL=conversation-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-manager.js","sourceRoot":"","sources":["../../src/agent/conversation-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Smart error recovery strategies based on error type.
3
+ */
4
+ export type RecoveryAction = {
5
+ type: 'retry';
6
+ delayMs: number;
7
+ } | {
8
+ type: 'inject_hint';
9
+ message: string;
10
+ } | {
11
+ type: 'abort';
12
+ reason: string;
13
+ };
14
+ interface ErrorContext {
15
+ errorCode?: string;
16
+ errorMessage: string;
17
+ toolName: string;
18
+ consecutiveErrors: number;
19
+ }
20
+ /**
21
+ * Determine recovery action based on error context.
22
+ */
23
+ export declare function determineRecovery(ctx: ErrorContext): RecoveryAction;
24
+ /**
25
+ * Extract errorCode from MCP tool result text.
26
+ */
27
+ export declare function extractErrorCode(rawText: string): string | undefined;
28
+ export {};
29
+ //# sourceMappingURL=error-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-recovery.d.ts","sourceRoot":"","sources":["../../src/agent/error-recovery.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAID;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,cAAc,CAqDnE;AAQD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOpE"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Smart error recovery strategies based on error type.
3
+ */
4
+ const MAX_RETRY_DELAY = 16000;
5
+ /**
6
+ * Determine recovery action based on error context.
7
+ */
8
+ export function determineRecovery(ctx) {
9
+ const { errorCode, errorMessage, consecutiveErrors } = ctx;
10
+ // Fatal errors — abort immediately
11
+ if (errorCode === 'PAGE_CRASHED' || errorCode === 'SESSION_NOT_FOUND') {
12
+ return { type: 'abort', reason: `不可恢复的错误: ${errorMessage}` };
13
+ }
14
+ // Element not found — hint to refresh
15
+ if (errorCode === 'ELEMENT_NOT_FOUND') {
16
+ return {
17
+ type: 'inject_hint',
18
+ message: '元素未找到,ID 可能已过期。请调用 get_page_info 刷新元素列表后重试。',
19
+ };
20
+ }
21
+ // Navigation timeout — exponential backoff + hint
22
+ if (errorCode === 'NAVIGATION_TIMEOUT') {
23
+ const delay = Math.min(2000 * Math.pow(2, consecutiveErrors - 1), MAX_RETRY_DELAY);
24
+ if (consecutiveErrors >= 3) {
25
+ return {
26
+ type: 'inject_hint',
27
+ message: '导航多次超时。页面可能已部分加载,请尝试 wait_for_stable 或直接用 get_page_info 检查当前页面状态。',
28
+ };
29
+ }
30
+ return { type: 'retry', delayMs: delay };
31
+ }
32
+ // Execution error — hint
33
+ if (errorCode === 'EXECUTION_ERROR') {
34
+ return {
35
+ type: 'inject_hint',
36
+ message: 'JavaScript 执行失败。请检查脚本语法,确保使用 return 返回数据。',
37
+ };
38
+ }
39
+ // Invalid parameter — hint
40
+ if (errorCode === 'INVALID_PARAMETER') {
41
+ return {
42
+ type: 'inject_hint',
43
+ message: `参数错误: ${errorMessage}。请检查参数后重试。`,
44
+ };
45
+ }
46
+ // LLM API errors — exponential backoff
47
+ if (isLLMError(errorMessage)) {
48
+ const delay = Math.min(2000 * Math.pow(2, consecutiveErrors - 1), MAX_RETRY_DELAY);
49
+ return { type: 'retry', delayMs: delay };
50
+ }
51
+ // Default: exponential backoff for unknown errors
52
+ const delay = Math.min(2000 * Math.pow(2, consecutiveErrors - 1), MAX_RETRY_DELAY);
53
+ return { type: 'retry', delayMs: delay };
54
+ }
55
+ function isLLMError(message) {
56
+ const patterns = ['ECONNREFUSED', 'ETIMEDOUT', 'rate limit', '429', '500', '502', '503'];
57
+ const lower = message.toLowerCase();
58
+ return patterns.some(p => lower.includes(p.toLowerCase()));
59
+ }
60
+ /**
61
+ * Extract errorCode from MCP tool result text.
62
+ */
63
+ export function extractErrorCode(rawText) {
64
+ try {
65
+ const data = JSON.parse(rawText);
66
+ return data.errorCode || undefined;
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ }
72
+ //# sourceMappingURL=error-recovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-recovery.js","sourceRoot":"","sources":["../../src/agent/error-recovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Caches page element state per session to compute diffs between get_page_info calls.
3
+ * When the page hasn't changed much, returns only added/removed/changed elements.
4
+ */
5
+ export interface PageDiff {
6
+ isNewPage: boolean;
7
+ added: any[];
8
+ removed: string[];
9
+ changed: any[];
10
+ unchangedCount: number;
11
+ }
12
+ export declare class PageStateCache {
13
+ private snapshots;
14
+ /**
15
+ * Update cache and compute diff for a session.
16
+ * Returns null if this is the first call or a new page (caller should use full list).
17
+ */
18
+ update(sessionId: string, elements: any[], url: string): PageDiff;
19
+ clear(sessionId: string): void;
20
+ private hasChanged;
21
+ }
22
+ //# sourceMappingURL=page-state-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-state-cache.d.ts","sourceRoot":"","sources":["../../src/agent/page-state-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,GAAG,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB;AASD,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAmC;IAEpD;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ;IAuDjE,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI9B,OAAO,CAAC,UAAU;CAQnB"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Caches page element state per session to compute diffs between get_page_info calls.
3
+ * When the page hasn't changed much, returns only added/removed/changed elements.
4
+ */
5
+ const FULL_REFRESH_THRESHOLD = 0.5; // >50% change → return full list
6
+ export class PageStateCache {
7
+ snapshots = new Map();
8
+ /**
9
+ * Update cache and compute diff for a session.
10
+ * Returns null if this is the first call or a new page (caller should use full list).
11
+ */
12
+ update(sessionId, elements, url) {
13
+ const prev = this.snapshots.get(sessionId);
14
+ const currentMap = new Map();
15
+ for (const el of elements) {
16
+ if (el?.id)
17
+ currentMap.set(el.id, el);
18
+ }
19
+ // Store new snapshot
20
+ this.snapshots.set(sessionId, { url, elementMap: currentMap });
21
+ // No previous snapshot → new page
22
+ if (!prev) {
23
+ return { isNewPage: true, added: elements, removed: [], changed: [], unchangedCount: 0 };
24
+ }
25
+ // URL changed → new page
26
+ if (prev.url !== url) {
27
+ return { isNewPage: true, added: elements, removed: [], changed: [], unchangedCount: 0 };
28
+ }
29
+ // Compute diff
30
+ const added = [];
31
+ const changed = [];
32
+ const removed = [];
33
+ let unchangedCount = 0;
34
+ // Find added and changed
35
+ for (const [id, el] of currentMap) {
36
+ const prevEl = prev.elementMap.get(id);
37
+ if (!prevEl) {
38
+ added.push(el);
39
+ }
40
+ else if (this.hasChanged(prevEl, el)) {
41
+ changed.push(el);
42
+ }
43
+ else {
44
+ unchangedCount++;
45
+ }
46
+ }
47
+ // Find removed
48
+ for (const id of prev.elementMap.keys()) {
49
+ if (!currentMap.has(id)) {
50
+ removed.push(id);
51
+ }
52
+ }
53
+ // If too many changes, treat as new page
54
+ const totalPrev = prev.elementMap.size;
55
+ const changedCount = added.length + removed.length + changed.length;
56
+ if (totalPrev > 0 && changedCount / totalPrev > FULL_REFRESH_THRESHOLD) {
57
+ return { isNewPage: true, added: elements, removed: [], changed: [], unchangedCount: 0 };
58
+ }
59
+ return { isNewPage: false, added, removed, changed, unchangedCount };
60
+ }
61
+ clear(sessionId) {
62
+ this.snapshots.delete(sessionId);
63
+ }
64
+ hasChanged(prev, curr) {
65
+ // Compare key properties that matter for interaction
66
+ return (prev.label !== curr.label ||
67
+ prev.type !== curr.type ||
68
+ JSON.stringify(prev.state) !== JSON.stringify(curr.state));
69
+ }
70
+ }
71
+ //# sourceMappingURL=page-state-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-state-cache.js","sourceRoot":"","sources":["../../src/agent/page-state-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Heuristic progress estimator based on tool call patterns.
3
+ * Maps tool usage sequences to approximate task completion phases.
4
+ */
5
+ export interface ProgressInfo {
6
+ phase: 'navigating' | 'observing' | 'acting' | 'extracting' | 'completing';
7
+ percent: number;
8
+ stepsRemaining: number | null;
9
+ }
10
+ export declare class ProgressEstimator {
11
+ private history;
12
+ private maxIterations;
13
+ constructor(maxIterations?: number);
14
+ record(toolName: string): ProgressInfo;
15
+ estimate(): ProgressInfo;
16
+ }
17
+ //# sourceMappingURL=progress-estimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-estimator.d.ts","sourceRoot":"","sources":["../../src/agent/progress-estimator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AA6BD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,SAAK;IAI9B,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY;IAKtC,QAAQ,IAAI,YAAY;CAiCzB"}