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.
- package/README.md +62 -5
- package/dist/agent/agent-loop.d.ts +8 -2
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +138 -86
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/config.d.ts +5 -0
- package/dist/agent/config.d.ts.map +1 -1
- package/dist/agent/config.js +5 -0
- package/dist/agent/config.js.map +1 -1
- package/dist/agent/content-budget.d.ts +11 -0
- package/dist/agent/content-budget.d.ts.map +1 -0
- package/dist/agent/content-budget.js +129 -0
- package/dist/agent/content-budget.js.map +1 -0
- package/dist/agent/conversation-manager.d.ts +48 -0
- package/dist/agent/conversation-manager.d.ts.map +1 -0
- package/dist/agent/conversation-manager.js +157 -0
- package/dist/agent/conversation-manager.js.map +1 -0
- package/dist/agent/error-recovery.d.ts +29 -0
- package/dist/agent/error-recovery.d.ts.map +1 -0
- package/dist/agent/error-recovery.js +72 -0
- package/dist/agent/error-recovery.js.map +1 -0
- package/dist/agent/page-state-cache.d.ts +22 -0
- package/dist/agent/page-state-cache.d.ts.map +1 -0
- package/dist/agent/page-state-cache.js +71 -0
- package/dist/agent/page-state-cache.js.map +1 -0
- package/dist/agent/progress-estimator.d.ts +17 -0
- package/dist/agent/progress-estimator.d.ts.map +1 -0
- package/dist/agent/progress-estimator.js +67 -0
- package/dist/agent/progress-estimator.js.map +1 -0
- package/dist/agent/prompt.d.ts +1 -1
- package/dist/agent/prompt.d.ts.map +1 -1
- package/dist/agent/prompt.js +83 -48
- package/dist/agent/prompt.js.map +1 -1
- package/dist/agent/task-agent.d.ts +89 -0
- package/dist/agent/task-agent.d.ts.map +1 -0
- package/dist/agent/task-agent.js +448 -0
- package/dist/agent/task-agent.js.map +1 -0
- package/dist/agent/token-tracker.d.ts +22 -0
- package/dist/agent/token-tracker.d.ts.map +1 -0
- package/dist/agent/token-tracker.js +29 -0
- package/dist/agent/token-tracker.js.map +1 -0
- package/dist/agent/tool-usage-tracker.d.ts +45 -0
- package/dist/agent/tool-usage-tracker.d.ts.map +1 -0
- package/dist/agent/tool-usage-tracker.js +145 -0
- package/dist/agent/tool-usage-tracker.js.map +1 -0
- package/dist/agent/types.d.ts +24 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +305 -1
- package/dist/api/routes.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/ai-markdown.d.ts +2 -0
- package/dist/mcp/ai-markdown.d.ts.map +1 -0
- package/dist/mcp/ai-markdown.js +1739 -0
- package/dist/mcp/ai-markdown.js.map +1 -0
- package/dist/mcp/browser-mcp-server.d.ts.map +1 -1
- package/dist/mcp/browser-mcp-server.js +279 -49
- package/dist/mcp/browser-mcp-server.js.map +1 -1
- package/dist/mcp/task-tools.d.ts.map +1 -1
- package/dist/mcp/task-tools.js +107 -13
- package/dist/mcp/task-tools.js.map +1 -1
- package/dist/task/tool-actions.d.ts +4 -0
- package/dist/task/tool-actions.d.ts.map +1 -1
- package/dist/task/tool-actions.js +72 -0
- package/dist/task/tool-actions.js.map +1 -1
- package/package.json +5 -2
- package/public/index.html +593 -41
- package/public/task-result.html +135 -0
- 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"}
|