page-agent 0.0.0 → 0.0.1
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 +29 -9
- package/dist/lib/PageAgent.d.ts +191 -53
- package/dist/lib/page-agent.js +496 -276
- package/dist/lib/page-agent.js.map +1 -1
- package/package.json +47 -34
- package/NOTICE +0 -23
package/dist/lib/page-agent.js
CHANGED
|
@@ -22,19 +22,18 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
22
22
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
23
23
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
24
24
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
25
|
-
var
|
|
26
|
-
import { generateText, stepCountIs, tool } from "ai";
|
|
25
|
+
var _bus, _wrapper, _indicator, _statusText, _historySection, _expandButton, _pauseButton, _stopButton, _inputSection, _taskInput, _bus2, _state, _isExpanded, _pageAgent, _userAnswerResolver, _isWaitingForUserAnswer, _Panel_instances, update_fn, show_fn, hide_fn, reset_fn, togglePause_fn, updatePauseButton_fn, stopAgent_fn, submitTask_fn, handleUserAnswer_fn, showInputArea_fn, hideInputArea_fn, shouldShowInputArea_fn, createWrapper_fn, setupEventListeners_fn, toggle_fn, expand_fn, collapse_fn, animateTextChange_fn, updateStatusIndicator_fn, updateHistory_fn, scrollToBottom_fn, createHistoryItem_fn, _cursor, _currentCursorX, _currentCursorY, _targetCursorX, _targetCursorY, _SimulatorMask_instances, createCursor_fn, moveCursorToTarget_fn, _llm, _totalWaitTime, _abortController, _PageAgent_instances, packMacroTool_fn, getSystemPrompt_fn, assembleUserPrompt_fn, onDone_fn, getBrowserState_fn, updateTree_fn;
|
|
27
26
|
import chalk from "chalk";
|
|
28
|
-
import zod from "zod";
|
|
29
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
27
|
+
import zod, { z } from "zod";
|
|
30
28
|
import { Motion } from "ai-motion";
|
|
31
29
|
const VIEWPORT_EXPANSION = -1;
|
|
32
30
|
const DEFAULT_MODEL_NAME = "gpt-41-mini-0414-global";
|
|
33
31
|
const DEFAULT_API_KEY = "not-needed";
|
|
34
32
|
const DEFAULT_BASE_URL = "http://localhost:3000/api/agent";
|
|
35
|
-
const MACRO_TOOL_NAME = "AgentOutput";
|
|
36
33
|
const LLM_MAX_RETRIES = 2;
|
|
37
34
|
const MAX_STEPS = 20;
|
|
35
|
+
const DEFAULT_TEMPERATURE = 0.7;
|
|
36
|
+
const DEFAULT_MAX_TOKENS = 4096;
|
|
38
37
|
const domTree = /* @__PURE__ */ __name((args = {
|
|
39
38
|
doHighlightElements: true,
|
|
40
39
|
focusHighlightIndex: -1,
|
|
@@ -1396,49 +1395,6 @@ function getPageInfo() {
|
|
|
1396
1395
|
};
|
|
1397
1396
|
}
|
|
1398
1397
|
__name(getPageInfo, "getPageInfo");
|
|
1399
|
-
const zhCN = {
|
|
1400
|
-
ui: {
|
|
1401
|
-
panel: {
|
|
1402
|
-
ready: "准备就绪",
|
|
1403
|
-
thinking: "正在思考...",
|
|
1404
|
-
paused: "暂停中,稍后",
|
|
1405
|
-
taskInput: "输入新任务,详细描述步骤,回车提交",
|
|
1406
|
-
userAnswerPrompt: "请回答上面问题,回车提交",
|
|
1407
|
-
taskTerminated: "任务已终止",
|
|
1408
|
-
taskCompleted: "任务结束",
|
|
1409
|
-
continueExecution: "继续执行",
|
|
1410
|
-
userAnswer: "用户回答: {{input}}",
|
|
1411
|
-
pause: "暂停",
|
|
1412
|
-
continue: "继续",
|
|
1413
|
-
stop: "终止",
|
|
1414
|
-
expand: "展开历史",
|
|
1415
|
-
collapse: "收起历史",
|
|
1416
|
-
step: "步骤 {{number}} · {{time}}{{duration}}"
|
|
1417
|
-
},
|
|
1418
|
-
tools: {
|
|
1419
|
-
clicking: "正在点击元素 [{{index}}]...",
|
|
1420
|
-
inputting: "正在输入文本到元素 [{{index}}]...",
|
|
1421
|
-
selecting: '正在选择选项 "{{text}}"...',
|
|
1422
|
-
scrolling: "正在滚动页面...",
|
|
1423
|
-
waiting: "等待 {{seconds}} 秒...",
|
|
1424
|
-
done: "结束任务",
|
|
1425
|
-
clicked: "🖱️ 已点击元素 [{{index}}]",
|
|
1426
|
-
inputted: '⌨️ 已输入文本 "{{text}}"',
|
|
1427
|
-
selected: '☑️ 已选择选项 "{{text}}"',
|
|
1428
|
-
scrolled: "🛞 页面滚动完成",
|
|
1429
|
-
waited: "⌛️ 等待完成",
|
|
1430
|
-
executing: "正在执行 {{toolName}}..."
|
|
1431
|
-
},
|
|
1432
|
-
errors: {
|
|
1433
|
-
elementNotFound: "未找到索引为 {{index}} 的交互元素",
|
|
1434
|
-
taskRequired: "任务描述不能为空",
|
|
1435
|
-
executionFailed: "任务执行失败",
|
|
1436
|
-
notInputElement: "元素不是输入框或文本域",
|
|
1437
|
-
notSelectElement: "元素不是选择框",
|
|
1438
|
-
optionNotFound: '未找到选项 "{{text}}"'
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
};
|
|
1442
1398
|
const enUS = {
|
|
1443
1399
|
ui: {
|
|
1444
1400
|
panel: {
|
|
@@ -1451,6 +1407,8 @@ const enUS = {
|
|
|
1451
1407
|
taskCompleted: "Task completed",
|
|
1452
1408
|
continueExecution: "Continue execution",
|
|
1453
1409
|
userAnswer: "User answer: {{input}}",
|
|
1410
|
+
question: "Question: {{question}}",
|
|
1411
|
+
waitingPlaceholder: "Waiting for task to start...",
|
|
1454
1412
|
pause: "Pause",
|
|
1455
1413
|
continue: "Continue",
|
|
1456
1414
|
stop: "Stop",
|
|
@@ -1470,7 +1428,10 @@ const enUS = {
|
|
|
1470
1428
|
selected: '☑️ Selected option "{{text}}"',
|
|
1471
1429
|
scrolled: "🛞 Page scrolled",
|
|
1472
1430
|
waited: "⌛️ Wait completed",
|
|
1473
|
-
executing: "
|
|
1431
|
+
executing: "Executing {{toolName}}...",
|
|
1432
|
+
resultSuccess: "success",
|
|
1433
|
+
resultFailure: "failed",
|
|
1434
|
+
resultError: "error"
|
|
1474
1435
|
},
|
|
1475
1436
|
errors: {
|
|
1476
1437
|
elementNotFound: "No interactive element found at index {{index}}",
|
|
@@ -1482,9 +1443,57 @@ const enUS = {
|
|
|
1482
1443
|
}
|
|
1483
1444
|
}
|
|
1484
1445
|
};
|
|
1446
|
+
const zhCN = {
|
|
1447
|
+
ui: {
|
|
1448
|
+
panel: {
|
|
1449
|
+
ready: "准备就绪",
|
|
1450
|
+
thinking: "正在思考...",
|
|
1451
|
+
paused: "暂停中,稍后",
|
|
1452
|
+
taskInput: "输入新任务,详细描述步骤,回车提交",
|
|
1453
|
+
userAnswerPrompt: "请回答上面问题,回车提交",
|
|
1454
|
+
taskTerminated: "任务已终止",
|
|
1455
|
+
taskCompleted: "任务结束",
|
|
1456
|
+
continueExecution: "继续执行",
|
|
1457
|
+
userAnswer: "用户回答: {{input}}",
|
|
1458
|
+
question: "询问: {{question}}",
|
|
1459
|
+
waitingPlaceholder: "等待任务开始...",
|
|
1460
|
+
pause: "暂停",
|
|
1461
|
+
continue: "继续",
|
|
1462
|
+
stop: "终止",
|
|
1463
|
+
expand: "展开历史",
|
|
1464
|
+
collapse: "收起历史",
|
|
1465
|
+
step: "步骤 {{number}} · {{time}}{{duration}}"
|
|
1466
|
+
},
|
|
1467
|
+
tools: {
|
|
1468
|
+
clicking: "正在点击元素 [{{index}}]...",
|
|
1469
|
+
inputting: "正在输入文本到元素 [{{index}}]...",
|
|
1470
|
+
selecting: '正在选择选项 "{{text}}"...',
|
|
1471
|
+
scrolling: "正在滚动页面...",
|
|
1472
|
+
waiting: "等待 {{seconds}} 秒...",
|
|
1473
|
+
done: "结束任务",
|
|
1474
|
+
clicked: "🖱️ 已点击元素 [{{index}}]",
|
|
1475
|
+
inputted: '⌨️ 已输入文本 "{{text}}"',
|
|
1476
|
+
selected: '☑️ 已选择选项 "{{text}}"',
|
|
1477
|
+
scrolled: "🛞 页面滚动完成",
|
|
1478
|
+
waited: "⌛️ 等待完成",
|
|
1479
|
+
executing: "正在执行 {{toolName}}...",
|
|
1480
|
+
resultSuccess: "成功",
|
|
1481
|
+
resultFailure: "失败",
|
|
1482
|
+
resultError: "错误"
|
|
1483
|
+
},
|
|
1484
|
+
errors: {
|
|
1485
|
+
elementNotFound: "未找到索引为 {{index}} 的交互元素",
|
|
1486
|
+
taskRequired: "任务描述不能为空",
|
|
1487
|
+
executionFailed: "任务执行失败",
|
|
1488
|
+
notInputElement: "元素不是输入框或文本域",
|
|
1489
|
+
notSelectElement: "元素不是选择框",
|
|
1490
|
+
optionNotFound: '未找到选项 "{{text}}"'
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1485
1494
|
const locales = {
|
|
1486
|
-
"
|
|
1487
|
-
"
|
|
1495
|
+
"en-US": enUS,
|
|
1496
|
+
"zh-CN": zhCN
|
|
1488
1497
|
};
|
|
1489
1498
|
const _I18n = class _I18n {
|
|
1490
1499
|
language;
|
|
@@ -1510,7 +1519,7 @@ const _I18n = class _I18n {
|
|
|
1510
1519
|
}
|
|
1511
1520
|
interpolate(template, params) {
|
|
1512
1521
|
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
1513
|
-
return params[key]
|
|
1522
|
+
return params[key] != null ? params[key].toString() : match;
|
|
1514
1523
|
});
|
|
1515
1524
|
}
|
|
1516
1525
|
getLanguage() {
|
|
@@ -1519,14 +1528,17 @@ const _I18n = class _I18n {
|
|
|
1519
1528
|
};
|
|
1520
1529
|
__name(_I18n, "I18n");
|
|
1521
1530
|
let I18n = _I18n;
|
|
1522
|
-
function
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1531
|
+
function parseLLMConfig(config) {
|
|
1532
|
+
return {
|
|
1533
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL,
|
|
1534
|
+
apiKey: config.apiKey ?? DEFAULT_API_KEY,
|
|
1535
|
+
model: config.model ?? DEFAULT_MODEL_NAME,
|
|
1536
|
+
temperature: config.temperature ?? DEFAULT_TEMPERATURE,
|
|
1537
|
+
maxTokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
1538
|
+
maxRetries: config.maxRetries ?? LLM_MAX_RETRIES
|
|
1539
|
+
};
|
|
1528
1540
|
}
|
|
1529
|
-
__name(
|
|
1541
|
+
__name(parseLLMConfig, "parseLLMConfig");
|
|
1530
1542
|
const _EventBus = class _EventBus extends EventTarget {
|
|
1531
1543
|
/**
|
|
1532
1544
|
* Listen to built-in events
|
|
@@ -1571,24 +1583,316 @@ function getEventBus(channel) {
|
|
|
1571
1583
|
return bus;
|
|
1572
1584
|
}
|
|
1573
1585
|
__name(getEventBus, "getEventBus");
|
|
1586
|
+
const InvokeErrorType = {
|
|
1587
|
+
// Retryable
|
|
1588
|
+
NETWORK_ERROR: "network_error",
|
|
1589
|
+
// Network error, retry
|
|
1590
|
+
RATE_LIMIT: "rate_limit",
|
|
1591
|
+
// Rate limit, retry
|
|
1592
|
+
SERVER_ERROR: "server_error",
|
|
1593
|
+
// 5xx, retry
|
|
1594
|
+
NO_TOOL_CALL: "no_tool_call",
|
|
1595
|
+
// Model did not call tool
|
|
1596
|
+
INVALID_TOOL_ARGS: "invalid_tool_args",
|
|
1597
|
+
// Tool args don't match schema
|
|
1598
|
+
TOOL_EXECUTION_ERROR: "tool_execution_error",
|
|
1599
|
+
// Tool execution error
|
|
1600
|
+
UNKNOWN: "unknown",
|
|
1601
|
+
// Non-retryable
|
|
1602
|
+
AUTH_ERROR: "auth_error",
|
|
1603
|
+
// Authentication failed
|
|
1604
|
+
CONTEXT_LENGTH: "context_length",
|
|
1605
|
+
// Prompt too long
|
|
1606
|
+
CONTENT_FILTER: "content_filter"
|
|
1607
|
+
// Content filtered
|
|
1608
|
+
};
|
|
1609
|
+
const _InvokeError = class _InvokeError extends Error {
|
|
1610
|
+
type;
|
|
1611
|
+
retryable;
|
|
1612
|
+
statusCode;
|
|
1613
|
+
rawError;
|
|
1614
|
+
constructor(type, message, rawError) {
|
|
1615
|
+
super(message);
|
|
1616
|
+
this.name = "InvokeError";
|
|
1617
|
+
this.type = type;
|
|
1618
|
+
this.retryable = this.isRetryable(type);
|
|
1619
|
+
this.rawError = rawError;
|
|
1620
|
+
}
|
|
1621
|
+
isRetryable(type) {
|
|
1622
|
+
const retryableTypes = [
|
|
1623
|
+
InvokeErrorType.NETWORK_ERROR,
|
|
1624
|
+
InvokeErrorType.RATE_LIMIT,
|
|
1625
|
+
InvokeErrorType.SERVER_ERROR,
|
|
1626
|
+
InvokeErrorType.NO_TOOL_CALL,
|
|
1627
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1628
|
+
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
|
1629
|
+
InvokeErrorType.UNKNOWN
|
|
1630
|
+
];
|
|
1631
|
+
return retryableTypes.includes(type);
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
__name(_InvokeError, "InvokeError");
|
|
1635
|
+
let InvokeError = _InvokeError;
|
|
1636
|
+
function zodToOpenAITool(name, tool2) {
|
|
1637
|
+
return {
|
|
1638
|
+
type: "function",
|
|
1639
|
+
function: {
|
|
1640
|
+
name,
|
|
1641
|
+
description: tool2.description,
|
|
1642
|
+
parameters: z.toJSONSchema(tool2.inputSchema, { target: "openapi-3.0" })
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
__name(zodToOpenAITool, "zodToOpenAITool");
|
|
1647
|
+
function lenientParseMacroToolCall(responseData, inputSchema) {
|
|
1648
|
+
const choice = responseData.choices?.[0];
|
|
1649
|
+
if (!choice) {
|
|
1650
|
+
throw new InvokeError(InvokeErrorType.UNKNOWN, "No choices in response", responseData);
|
|
1651
|
+
}
|
|
1652
|
+
switch (choice.finish_reason) {
|
|
1653
|
+
case "tool_calls":
|
|
1654
|
+
case "stop":
|
|
1655
|
+
break;
|
|
1656
|
+
case "length":
|
|
1657
|
+
throw new InvokeError(
|
|
1658
|
+
InvokeErrorType.CONTEXT_LENGTH,
|
|
1659
|
+
"Response truncated: max tokens reached"
|
|
1660
|
+
);
|
|
1661
|
+
case "content_filter":
|
|
1662
|
+
throw new InvokeError(InvokeErrorType.CONTENT_FILTER, "Content filtered by safety system");
|
|
1663
|
+
default:
|
|
1664
|
+
throw new InvokeError(
|
|
1665
|
+
InvokeErrorType.UNKNOWN,
|
|
1666
|
+
`Unexpected finish_reason: ${choice.finish_reason}`
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
const actionSchema = inputSchema.shape.action;
|
|
1670
|
+
if (!actionSchema) {
|
|
1671
|
+
throw new Error('inputSchema must have an "action" field');
|
|
1672
|
+
}
|
|
1673
|
+
let arg = null;
|
|
1674
|
+
const toolCall = choice.message?.tool_calls?.[0]?.function;
|
|
1675
|
+
arg = toolCall?.arguments ?? null;
|
|
1676
|
+
if (arg && toolCall.name !== "AgentOutput") {
|
|
1677
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #1 fixing incorrect tool call"));
|
|
1678
|
+
let tmpArg;
|
|
1679
|
+
try {
|
|
1680
|
+
tmpArg = JSON.parse(arg);
|
|
1681
|
+
} catch (error2) {
|
|
1682
|
+
throw new InvokeError(
|
|
1683
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1684
|
+
"Failed to parse tool arguments as JSON",
|
|
1685
|
+
error2
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
arg = JSON.stringify({ action: { [toolCall.name]: tmpArg } });
|
|
1689
|
+
}
|
|
1690
|
+
if (!arg) {
|
|
1691
|
+
arg = choice.message?.content.trim() || null;
|
|
1692
|
+
}
|
|
1693
|
+
if (!arg) {
|
|
1694
|
+
throw new InvokeError(
|
|
1695
|
+
InvokeErrorType.NO_TOOL_CALL,
|
|
1696
|
+
"No tool call or content found in response",
|
|
1697
|
+
responseData
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
let parsedArgs;
|
|
1701
|
+
try {
|
|
1702
|
+
parsedArgs = JSON.parse(arg);
|
|
1703
|
+
} catch (error2) {
|
|
1704
|
+
throw new InvokeError(
|
|
1705
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1706
|
+
"Failed to parse tool arguments as JSON",
|
|
1707
|
+
error2
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
if (parsedArgs.action || parsedArgs.evaluation_previous_goal || parsedArgs.next_goal) {
|
|
1711
|
+
if (!parsedArgs.action) {
|
|
1712
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #2 fixing incorrect tool call"));
|
|
1713
|
+
parsedArgs.action = {
|
|
1714
|
+
wait: { seconds: 1 }
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
} else if (parsedArgs.type && parsedArgs.function) {
|
|
1718
|
+
if (parsedArgs.function.name !== "AgentOutput")
|
|
1719
|
+
throw new InvokeError(
|
|
1720
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1721
|
+
`Expected function name "AgentOutput", got "${parsedArgs.function.name}"`,
|
|
1722
|
+
null
|
|
1723
|
+
);
|
|
1724
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #3 fixing incorrect tool call"));
|
|
1725
|
+
parsedArgs = parsedArgs.function.arguments;
|
|
1726
|
+
} else if (parsedArgs.name && parsedArgs.arguments) {
|
|
1727
|
+
if (parsedArgs.name !== "AgentOutput")
|
|
1728
|
+
throw new InvokeError(
|
|
1729
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1730
|
+
`Expected function name "AgentOutput", got "${parsedArgs.name}"`,
|
|
1731
|
+
null
|
|
1732
|
+
);
|
|
1733
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #4 fixing incorrect tool call"));
|
|
1734
|
+
parsedArgs = parsedArgs.arguments;
|
|
1735
|
+
} else {
|
|
1736
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #5 fixing incorrect tool call"));
|
|
1737
|
+
parsedArgs = { action: parsedArgs };
|
|
1738
|
+
}
|
|
1739
|
+
if (typeof parsedArgs === "string") {
|
|
1740
|
+
console.log(chalk.yellow("lenientParseMacroToolCall: #6 fixing incorrect tool call"));
|
|
1741
|
+
try {
|
|
1742
|
+
parsedArgs = JSON.parse(parsedArgs);
|
|
1743
|
+
} catch (error2) {
|
|
1744
|
+
throw new InvokeError(
|
|
1745
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1746
|
+
"Failed to parse nested tool arguments as JSON",
|
|
1747
|
+
error2
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
const validation = inputSchema.safeParse(parsedArgs);
|
|
1752
|
+
if (validation.success) {
|
|
1753
|
+
return validation.data;
|
|
1754
|
+
} else {
|
|
1755
|
+
const action = parsedArgs.action ?? {};
|
|
1756
|
+
const actionName = Object.keys(action)[0] || "unknown";
|
|
1757
|
+
const actionArgs = JSON.stringify(action[actionName] || "unknown");
|
|
1758
|
+
throw new InvokeError(
|
|
1759
|
+
InvokeErrorType.INVALID_TOOL_ARGS,
|
|
1760
|
+
`Tool arguments validation failed: action "${actionName}" with args ${actionArgs}`,
|
|
1761
|
+
validation.error
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
__name(lenientParseMacroToolCall, "lenientParseMacroToolCall");
|
|
1766
|
+
function modelPatch(body) {
|
|
1767
|
+
const model = body.model || "";
|
|
1768
|
+
if (model.toLowerCase().startsWith("claude")) {
|
|
1769
|
+
body.tool_choice = { type: "tool", name: "AgentOutput" };
|
|
1770
|
+
body.thinking = { type: "disabled" };
|
|
1771
|
+
}
|
|
1772
|
+
if (model.toLowerCase().includes("grok")) {
|
|
1773
|
+
console.log("Applying Grok patch: removing tool_choice");
|
|
1774
|
+
delete body.tool_choice;
|
|
1775
|
+
console.log("Applying Grok patch: disable reasoning and thinking");
|
|
1776
|
+
body.thinking = { type: "disabled", effort: "minimal" };
|
|
1777
|
+
body.reasoning = { enabled: false, effort: "low" };
|
|
1778
|
+
}
|
|
1779
|
+
return body;
|
|
1780
|
+
}
|
|
1781
|
+
__name(modelPatch, "modelPatch");
|
|
1782
|
+
const _OpenAIClient = class _OpenAIClient {
|
|
1783
|
+
config;
|
|
1784
|
+
constructor(config) {
|
|
1785
|
+
this.config = config;
|
|
1786
|
+
}
|
|
1787
|
+
async invoke(messages, tools2, abortSignal) {
|
|
1788
|
+
const openaiTools = Object.entries(tools2).map(([name, tool22]) => zodToOpenAITool(name, tool22));
|
|
1789
|
+
let response;
|
|
1790
|
+
try {
|
|
1791
|
+
response = await fetch(`${this.config.baseURL}/chat/completions`, {
|
|
1792
|
+
method: "POST",
|
|
1793
|
+
headers: {
|
|
1794
|
+
"Content-Type": "application/json",
|
|
1795
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
1796
|
+
},
|
|
1797
|
+
body: JSON.stringify(
|
|
1798
|
+
modelPatch({
|
|
1799
|
+
model: this.config.model,
|
|
1800
|
+
temperature: this.config.temperature,
|
|
1801
|
+
max_tokens: this.config.maxTokens,
|
|
1802
|
+
messages,
|
|
1803
|
+
tools: openaiTools,
|
|
1804
|
+
// tool_choice: 'required',
|
|
1805
|
+
tool_choice: { type: "function", function: { name: "AgentOutput" } },
|
|
1806
|
+
// model specific params
|
|
1807
|
+
// reasoning_effort: 'minimal',
|
|
1808
|
+
// verbosity: 'low',
|
|
1809
|
+
parallel_tool_calls: false
|
|
1810
|
+
})
|
|
1811
|
+
),
|
|
1812
|
+
signal: abortSignal
|
|
1813
|
+
});
|
|
1814
|
+
} catch (error2) {
|
|
1815
|
+
throw new InvokeError(InvokeErrorType.NETWORK_ERROR, "Network request failed", error2);
|
|
1816
|
+
}
|
|
1817
|
+
if (!response.ok) {
|
|
1818
|
+
const errorData = await response.json().catch();
|
|
1819
|
+
const errorMessage = errorData.error?.message || response.statusText;
|
|
1820
|
+
if (response.status === 401 || response.status === 403) {
|
|
1821
|
+
throw new InvokeError(
|
|
1822
|
+
InvokeErrorType.AUTH_ERROR,
|
|
1823
|
+
`Authentication failed: ${errorMessage}`,
|
|
1824
|
+
errorData
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
if (response.status === 429) {
|
|
1828
|
+
throw new InvokeError(
|
|
1829
|
+
InvokeErrorType.RATE_LIMIT,
|
|
1830
|
+
`Rate limit exceeded: ${errorMessage}`,
|
|
1831
|
+
errorData
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
if (response.status >= 500) {
|
|
1835
|
+
throw new InvokeError(
|
|
1836
|
+
InvokeErrorType.SERVER_ERROR,
|
|
1837
|
+
`Server error: ${errorMessage}`,
|
|
1838
|
+
errorData
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
throw new InvokeError(
|
|
1842
|
+
InvokeErrorType.UNKNOWN,
|
|
1843
|
+
`HTTP ${response.status}: ${errorMessage}`,
|
|
1844
|
+
errorData
|
|
1845
|
+
);
|
|
1846
|
+
}
|
|
1847
|
+
const data = await response.json();
|
|
1848
|
+
const tool2 = tools2.AgentOutput;
|
|
1849
|
+
const macroToolInput = lenientParseMacroToolCall(data, tool2.inputSchema);
|
|
1850
|
+
let toolResult;
|
|
1851
|
+
try {
|
|
1852
|
+
toolResult = await tool2.execute(macroToolInput);
|
|
1853
|
+
} catch (e) {
|
|
1854
|
+
throw new InvokeError(
|
|
1855
|
+
InvokeErrorType.TOOL_EXECUTION_ERROR,
|
|
1856
|
+
`Tool execution failed: ${e.message}`,
|
|
1857
|
+
e
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
return {
|
|
1861
|
+
toolCall: {
|
|
1862
|
+
// id: toolCall.id,
|
|
1863
|
+
name: "AgentOutput",
|
|
1864
|
+
args: macroToolInput
|
|
1865
|
+
},
|
|
1866
|
+
toolResult,
|
|
1867
|
+
usage: {
|
|
1868
|
+
promptTokens: data.usage?.prompt_tokens ?? 0,
|
|
1869
|
+
completionTokens: data.usage?.completion_tokens ?? 0,
|
|
1870
|
+
totalTokens: data.usage?.total_tokens ?? 0,
|
|
1871
|
+
cachedTokens: data.usage?.prompt_tokens_details?.cached_tokens,
|
|
1872
|
+
reasoningTokens: data.usage?.completion_tokens_details?.reasoning_tokens
|
|
1873
|
+
},
|
|
1874
|
+
rawResponse: data
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
};
|
|
1878
|
+
__name(_OpenAIClient, "OpenAIClient");
|
|
1879
|
+
let OpenAIClient = _OpenAIClient;
|
|
1574
1880
|
const _LLM = class _LLM {
|
|
1575
1881
|
constructor(config, id) {
|
|
1576
1882
|
__publicField(this, "config");
|
|
1577
1883
|
__publicField(this, "id");
|
|
1578
|
-
|
|
1579
|
-
__privateAdd(this, _model);
|
|
1884
|
+
__publicField(this, "client");
|
|
1580
1885
|
__privateAdd(this, _bus);
|
|
1581
|
-
this.config =
|
|
1582
|
-
baseURL: DEFAULT_BASE_URL,
|
|
1583
|
-
apiKey: DEFAULT_API_KEY,
|
|
1584
|
-
modelName: DEFAULT_MODEL_NAME,
|
|
1585
|
-
maxRetries: LLM_MAX_RETRIES,
|
|
1586
|
-
...config
|
|
1587
|
-
};
|
|
1886
|
+
this.config = parseLLMConfig(config);
|
|
1588
1887
|
this.id = id;
|
|
1589
1888
|
__privateSet(this, _bus, getEventBus(id));
|
|
1590
|
-
|
|
1591
|
-
|
|
1889
|
+
this.client = new OpenAIClient({
|
|
1890
|
+
model: this.config.model,
|
|
1891
|
+
apiKey: this.config.apiKey,
|
|
1892
|
+
baseURL: this.config.baseURL,
|
|
1893
|
+
temperature: this.config.temperature,
|
|
1894
|
+
maxTokens: this.config.maxTokens
|
|
1895
|
+
});
|
|
1592
1896
|
}
|
|
1593
1897
|
/**
|
|
1594
1898
|
* - call llm api *once*
|
|
@@ -1596,81 +1900,10 @@ const _LLM = class _LLM {
|
|
|
1596
1900
|
* - return the result of the tool
|
|
1597
1901
|
*/
|
|
1598
1902
|
async invoke(messages, tools2, abortSignal) {
|
|
1599
|
-
const isClaude = this.config.modelName.slice(0, 8).includes("claude");
|
|
1600
|
-
this.config.modelName.slice(0, 6).includes("qwen");
|
|
1601
|
-
this.config.modelName.slice(0, 5).includes("gpt");
|
|
1602
1903
|
return await withRetry(
|
|
1603
1904
|
async () => {
|
|
1604
|
-
const result = await
|
|
1605
|
-
|
|
1606
|
-
messages,
|
|
1607
|
-
tools: tools2,
|
|
1608
|
-
abortSignal,
|
|
1609
|
-
/**
|
|
1610
|
-
* 文档中没有说明,从源码看,@facts
|
|
1611
|
-
* - 只会重试被识别为 retryable 的 API_CALL_ERROR
|
|
1612
|
-
* - 返回无法解析的 json 应该不会重试
|
|
1613
|
-
* - experimental_repairToolCall 只会执行一次,不算作重试
|
|
1614
|
-
* @facts
|
|
1615
|
-
* - 许多 proxy 过的 openAI 兼容接口返回的错误格式并不规范,通常不会被识别为 retryable
|
|
1616
|
-
* @conclusion
|
|
1617
|
-
* - 看起来并不实用,不如完全手工控制粗粒度重试
|
|
1618
|
-
*/
|
|
1619
|
-
// maxRetries: this.config.maxRetries,
|
|
1620
|
-
maxRetries: 0,
|
|
1621
|
-
// toolChoice: 'required',
|
|
1622
|
-
// @note incompatible to Claude
|
|
1623
|
-
toolChoice: isClaude ? void 0 : { type: "tool", toolName: MACRO_TOOL_NAME },
|
|
1624
|
-
/**
|
|
1625
|
-
* controlled by main loop. our method only call api once
|
|
1626
|
-
*/
|
|
1627
|
-
// stopWhen: [hasToolCall('done'), stepCountIs(100)],
|
|
1628
|
-
stopWhen: [stepCountIs(1)],
|
|
1629
|
-
// stopWhen: [hasToolCall('AgentOutput')],
|
|
1630
|
-
providerOptions: {
|
|
1631
|
-
openai: {
|
|
1632
|
-
// @note this one needs all fields in tool schema must be `required`
|
|
1633
|
-
// strictJsonSchema: true,
|
|
1634
|
-
// This way only at most one tool can be called at a time
|
|
1635
|
-
parallelToolCalls: false,
|
|
1636
|
-
reasoningEffort: "minimal",
|
|
1637
|
-
// @note not working
|
|
1638
|
-
// serviceTier: 'priority',
|
|
1639
|
-
textVerbosity: "low",
|
|
1640
|
-
// @note Optimize OpenAI model caching, should be unique per user, currently has no effect
|
|
1641
|
-
promptCacheKey: "page-agent:" + this.id
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
/**
|
|
1645
|
-
* schema 出错时执行一次,不确定是否计入重试
|
|
1646
|
-
* 目前看起来像是会直接抛错,被 withRetry 处理
|
|
1647
|
-
* @note
|
|
1648
|
-
* 如果不提供,则 ai-sdk 会把 tool-error 加入 message 中重新调用一次,
|
|
1649
|
-
* 配合 stepCountIs 或者 hasToolCall 都会导致错误被 silent,toolResults 永远为 0
|
|
1650
|
-
* 遗憾的是,这里没有办法抛错(抛错后回到默认逻辑),只要这里 repair 不好,就会导致 silent error
|
|
1651
|
-
* 更糟糕的是,只要传入了 tools,无论 stopWhen 如何设置,都会被当作 multi-step,
|
|
1652
|
-
* 本质上就和我们 single step 的逻辑冲突
|
|
1653
|
-
* 长远来看必须删掉 ai-sdk,直接用 openAI API 实现
|
|
1654
|
-
*/
|
|
1655
|
-
// experimental_repairToolCall: (options): Promise<LanguageModelV2ToolCall | null> => {
|
|
1656
|
-
// console.error('hahhah', options)
|
|
1657
|
-
// throw options.error
|
|
1658
|
-
// },
|
|
1659
|
-
});
|
|
1660
|
-
console.log(chalk.blue.bold("LLM:invoke finished"), result);
|
|
1661
|
-
const toolError = result.content.find((part) => part.type === "tool-error");
|
|
1662
|
-
if (toolError) throw toolError.error;
|
|
1663
|
-
assert(!result.text, "Model returned text without calling done tool", true);
|
|
1664
|
-
assert(result.toolCalls.length === 1, "Model must call exactly one tool", true);
|
|
1665
|
-
assert(result.toolResults.length === 1, "Step must have exactly one tool result", true);
|
|
1666
|
-
const toolCall = result.toolCalls[0];
|
|
1667
|
-
const toolResult = result.toolResults[0];
|
|
1668
|
-
const usage = result.totalUsage;
|
|
1669
|
-
return {
|
|
1670
|
-
toolCall,
|
|
1671
|
-
toolResult,
|
|
1672
|
-
usage
|
|
1673
|
-
};
|
|
1905
|
+
const result = await this.client.invoke(messages, tools2, abortSignal);
|
|
1906
|
+
return result;
|
|
1674
1907
|
},
|
|
1675
1908
|
// retry settings
|
|
1676
1909
|
{
|
|
@@ -1691,8 +1924,6 @@ const _LLM = class _LLM {
|
|
|
1691
1924
|
);
|
|
1692
1925
|
}
|
|
1693
1926
|
};
|
|
1694
|
-
_openai = new WeakMap();
|
|
1695
|
-
_model = new WeakMap();
|
|
1696
1927
|
_bus = new WeakMap();
|
|
1697
1928
|
__name(_LLM, "LLM");
|
|
1698
1929
|
let LLM = _LLM;
|
|
@@ -1710,6 +1941,7 @@ async function withRetry(fn, settings) {
|
|
|
1710
1941
|
console.error(error2);
|
|
1711
1942
|
settings.onError(error2, retries < settings.maxRetries);
|
|
1712
1943
|
if (error2?.name === "AbortError") throw error2;
|
|
1944
|
+
if (error2 instanceof InvokeError && !error2.retryable) throw error2;
|
|
1713
1945
|
lastError = error2;
|
|
1714
1946
|
retries++;
|
|
1715
1947
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -2049,6 +2281,10 @@ const utils = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
|
|
|
2049
2281
|
waitFor
|
|
2050
2282
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2051
2283
|
window.utils = utils;
|
|
2284
|
+
function tool(options) {
|
|
2285
|
+
return options;
|
|
2286
|
+
}
|
|
2287
|
+
__name(tool, "tool");
|
|
2052
2288
|
const tools = /* @__PURE__ */ new Map();
|
|
2053
2289
|
tools.set(
|
|
2054
2290
|
"done",
|
|
@@ -2058,7 +2294,8 @@ tools.set(
|
|
|
2058
2294
|
text: zod.string(),
|
|
2059
2295
|
success: zod.boolean().default(true)
|
|
2060
2296
|
}),
|
|
2061
|
-
execute: /* @__PURE__ */ __name(function(input2) {
|
|
2297
|
+
execute: /* @__PURE__ */ __name(async function(input2) {
|
|
2298
|
+
return Promise.resolve("Task completed");
|
|
2062
2299
|
}, "execute")
|
|
2063
2300
|
})
|
|
2064
2301
|
);
|
|
@@ -2421,7 +2658,7 @@ const _Panel = class _Panel {
|
|
|
2421
2658
|
__privateSet(this, _userAnswerResolver, resolve);
|
|
2422
2659
|
__privateMethod(this, _Panel_instances, update_fn).call(this, {
|
|
2423
2660
|
type: "output",
|
|
2424
|
-
displayText:
|
|
2661
|
+
displayText: __privateGet(this, _pageAgent).i18n.t("ui.panel.question", { question })
|
|
2425
2662
|
});
|
|
2426
2663
|
if (!__privateGet(this, _isExpanded)) {
|
|
2427
2664
|
__privateMethod(this, _Panel_instances, expand_fn).call(this);
|
|
@@ -2482,7 +2719,7 @@ show_fn = /* @__PURE__ */ __name(function() {
|
|
|
2482
2719
|
this.wrapper.style.transform = "translateX(-50%) translateY(0)";
|
|
2483
2720
|
}, "#show");
|
|
2484
2721
|
/**
|
|
2485
|
-
*
|
|
2722
|
+
* Hide panel
|
|
2486
2723
|
*/
|
|
2487
2724
|
hide_fn = /* @__PURE__ */ __name(function() {
|
|
2488
2725
|
this.wrapper.style.opacity = "0";
|
|
@@ -2490,7 +2727,7 @@ hide_fn = /* @__PURE__ */ __name(function() {
|
|
|
2490
2727
|
this.wrapper.style.display = "none";
|
|
2491
2728
|
}, "#hide");
|
|
2492
2729
|
/**
|
|
2493
|
-
*
|
|
2730
|
+
* Reset state
|
|
2494
2731
|
*/
|
|
2495
2732
|
reset_fn = /* @__PURE__ */ __name(function() {
|
|
2496
2733
|
__privateGet(this, _state).reset();
|
|
@@ -2511,39 +2748,39 @@ togglePause_fn = /* @__PURE__ */ __name(function() {
|
|
|
2511
2748
|
__privateGet(this, _pageAgent).paused = !__privateGet(this, _pageAgent).paused;
|
|
2512
2749
|
__privateMethod(this, _Panel_instances, updatePauseButton_fn).call(this);
|
|
2513
2750
|
if (__privateGet(this, _pageAgent).paused) {
|
|
2514
|
-
__privateGet(this, _statusText).textContent = "
|
|
2751
|
+
__privateGet(this, _statusText).textContent = __privateGet(this, _pageAgent).i18n.t("ui.panel.paused");
|
|
2515
2752
|
__privateMethod(this, _Panel_instances, updateStatusIndicator_fn).call(this, "thinking");
|
|
2516
2753
|
} else {
|
|
2517
|
-
__privateGet(this, _statusText).textContent = "
|
|
2754
|
+
__privateGet(this, _statusText).textContent = __privateGet(this, _pageAgent).i18n.t("ui.panel.continueExecution");
|
|
2518
2755
|
__privateMethod(this, _Panel_instances, updateStatusIndicator_fn).call(this, "tool_executing");
|
|
2519
2756
|
}
|
|
2520
2757
|
}, "#togglePause");
|
|
2521
2758
|
/**
|
|
2522
|
-
*
|
|
2759
|
+
* Update pause button state
|
|
2523
2760
|
*/
|
|
2524
2761
|
updatePauseButton_fn = /* @__PURE__ */ __name(function() {
|
|
2525
2762
|
if (__privateGet(this, _pageAgent).paused) {
|
|
2526
2763
|
__privateGet(this, _pauseButton).textContent = "▶";
|
|
2527
|
-
__privateGet(this, _pauseButton).title = "
|
|
2764
|
+
__privateGet(this, _pauseButton).title = __privateGet(this, _pageAgent).i18n.t("ui.panel.continue");
|
|
2528
2765
|
__privateGet(this, _pauseButton).classList.add(styles$1.paused);
|
|
2529
2766
|
} else {
|
|
2530
2767
|
__privateGet(this, _pauseButton).textContent = "⏸︎";
|
|
2531
|
-
__privateGet(this, _pauseButton).title = "
|
|
2768
|
+
__privateGet(this, _pauseButton).title = __privateGet(this, _pageAgent).i18n.t("ui.panel.pause");
|
|
2532
2769
|
__privateGet(this, _pauseButton).classList.remove(styles$1.paused);
|
|
2533
2770
|
}
|
|
2534
2771
|
}, "#updatePauseButton");
|
|
2535
2772
|
/**
|
|
2536
|
-
*
|
|
2773
|
+
* Stop Agent
|
|
2537
2774
|
*/
|
|
2538
2775
|
stopAgent_fn = /* @__PURE__ */ __name(function() {
|
|
2539
2776
|
__privateMethod(this, _Panel_instances, update_fn).call(this, {
|
|
2540
2777
|
type: "error",
|
|
2541
|
-
displayText: "
|
|
2778
|
+
displayText: __privateGet(this, _pageAgent).i18n.t("ui.panel.taskTerminated")
|
|
2542
2779
|
});
|
|
2543
2780
|
__privateGet(this, _pageAgent).dispose();
|
|
2544
2781
|
}, "#stopAgent");
|
|
2545
2782
|
/**
|
|
2546
|
-
*
|
|
2783
|
+
* Submit task
|
|
2547
2784
|
*/
|
|
2548
2785
|
submitTask_fn = /* @__PURE__ */ __name(function() {
|
|
2549
2786
|
const input2 = __privateGet(this, _taskInput).value.trim();
|
|
@@ -2556,12 +2793,12 @@ submitTask_fn = /* @__PURE__ */ __name(function() {
|
|
|
2556
2793
|
}
|
|
2557
2794
|
}, "#submitTask");
|
|
2558
2795
|
/**
|
|
2559
|
-
*
|
|
2796
|
+
* Handle user answer
|
|
2560
2797
|
*/
|
|
2561
2798
|
handleUserAnswer_fn = /* @__PURE__ */ __name(function(input2) {
|
|
2562
2799
|
__privateMethod(this, _Panel_instances, update_fn).call(this, {
|
|
2563
2800
|
type: "input",
|
|
2564
|
-
displayText:
|
|
2801
|
+
displayText: __privateGet(this, _pageAgent).i18n.t("ui.panel.userAnswer", { input: input2 })
|
|
2565
2802
|
});
|
|
2566
2803
|
__privateSet(this, _isWaitingForUserAnswer, false);
|
|
2567
2804
|
if (__privateGet(this, _userAnswerResolver)) {
|
|
@@ -2570,24 +2807,24 @@ handleUserAnswer_fn = /* @__PURE__ */ __name(function(input2) {
|
|
|
2570
2807
|
}
|
|
2571
2808
|
}, "#handleUserAnswer");
|
|
2572
2809
|
/**
|
|
2573
|
-
*
|
|
2810
|
+
* Show input area
|
|
2574
2811
|
*/
|
|
2575
2812
|
showInputArea_fn = /* @__PURE__ */ __name(function(placeholder) {
|
|
2576
2813
|
__privateGet(this, _taskInput).value = "";
|
|
2577
|
-
__privateGet(this, _taskInput).placeholder = placeholder || "
|
|
2814
|
+
__privateGet(this, _taskInput).placeholder = placeholder || __privateGet(this, _pageAgent).i18n.t("ui.panel.taskInput");
|
|
2578
2815
|
__privateGet(this, _inputSection).classList.remove(styles$1.hidden);
|
|
2579
2816
|
setTimeout(() => {
|
|
2580
2817
|
__privateGet(this, _taskInput).focus();
|
|
2581
2818
|
}, 100);
|
|
2582
2819
|
}, "#showInputArea");
|
|
2583
2820
|
/**
|
|
2584
|
-
*
|
|
2821
|
+
* Hide input area
|
|
2585
2822
|
*/
|
|
2586
2823
|
hideInputArea_fn = /* @__PURE__ */ __name(function() {
|
|
2587
2824
|
__privateGet(this, _inputSection).classList.add(styles$1.hidden);
|
|
2588
2825
|
}, "#hideInputArea");
|
|
2589
2826
|
/**
|
|
2590
|
-
*
|
|
2827
|
+
* Check if input area should be shown
|
|
2591
2828
|
*/
|
|
2592
2829
|
shouldShowInputArea_fn = /* @__PURE__ */ __name(function() {
|
|
2593
2830
|
if (__privateGet(this, _isWaitingForUserAnswer)) return true;
|
|
@@ -2612,23 +2849,23 @@ createWrapper_fn = /* @__PURE__ */ __name(function() {
|
|
|
2612
2849
|
stepNumber: 0,
|
|
2613
2850
|
timestamp: /* @__PURE__ */ new Date(),
|
|
2614
2851
|
type: "thinking",
|
|
2615
|
-
displayText: "
|
|
2852
|
+
displayText: __privateGet(this, _pageAgent).i18n.t("ui.panel.waitingPlaceholder")
|
|
2616
2853
|
})}
|
|
2617
2854
|
</div>
|
|
2618
2855
|
</div>
|
|
2619
2856
|
<div class="${styles$1.header}">
|
|
2620
2857
|
<div class="${styles$1.statusSection}">
|
|
2621
2858
|
<div class="${styles$1.indicator} ${styles$1.thinking}"></div>
|
|
2622
|
-
<div class="${styles$1.statusText}"
|
|
2859
|
+
<div class="${styles$1.statusText}">${__privateGet(this, _pageAgent).i18n.t("ui.panel.ready")}</div>
|
|
2623
2860
|
</div>
|
|
2624
2861
|
<div class="${styles$1.controls}">
|
|
2625
|
-
<button class="${styles$1.controlButton} ${styles$1.expandButton}" title="
|
|
2862
|
+
<button class="${styles$1.controlButton} ${styles$1.expandButton}" title="${__privateGet(this, _pageAgent).i18n.t("ui.panel.expand")}">
|
|
2626
2863
|
▼
|
|
2627
2864
|
</button>
|
|
2628
|
-
<button class="${styles$1.controlButton} ${styles$1.pauseButton}" title="
|
|
2865
|
+
<button class="${styles$1.controlButton} ${styles$1.pauseButton}" title="${__privateGet(this, _pageAgent).i18n.t("ui.panel.pause")}">
|
|
2629
2866
|
⏸︎
|
|
2630
2867
|
</button>
|
|
2631
|
-
<button class="${styles$1.controlButton} ${styles$1.stopButton}" title="
|
|
2868
|
+
<button class="${styles$1.controlButton} ${styles$1.stopButton}" title="${__privateGet(this, _pageAgent).i18n.t("ui.panel.stop")}">
|
|
2632
2869
|
X
|
|
2633
2870
|
</button>
|
|
2634
2871
|
</div>
|
|
@@ -2716,7 +2953,7 @@ updateStatusIndicator_fn = /* @__PURE__ */ __name(function(type) {
|
|
|
2716
2953
|
}, "#updateStatusIndicator");
|
|
2717
2954
|
updateHistory_fn = /* @__PURE__ */ __name(function() {
|
|
2718
2955
|
const steps = __privateGet(this, _state).getAllSteps();
|
|
2719
|
-
__privateGet(this, _historySection).innerHTML = steps.
|
|
2956
|
+
__privateGet(this, _historySection).innerHTML = steps.map((step) => __privateMethod(this, _Panel_instances, createHistoryItem_fn).call(this, step)).join("");
|
|
2720
2957
|
__privateMethod(this, _Panel_instances, scrollToBottom_fn).call(this);
|
|
2721
2958
|
}, "#updateHistory");
|
|
2722
2959
|
scrollToBottom_fn = /* @__PURE__ */ __name(function() {
|
|
@@ -2735,7 +2972,9 @@ createHistoryItem_fn = /* @__PURE__ */ __name(function(step) {
|
|
|
2735
2972
|
let statusIcon2 = "";
|
|
2736
2973
|
if (step.type === "completed") {
|
|
2737
2974
|
if (step.toolName === "done") {
|
|
2738
|
-
const
|
|
2975
|
+
const failureKeyword = __privateGet(this, _pageAgent).i18n.t("ui.tools.resultFailure");
|
|
2976
|
+
const errorKeyword = __privateGet(this, _pageAgent).i18n.t("ui.tools.resultError");
|
|
2977
|
+
const isSuccess = !step.toolResult || !step.toolResult.includes(failureKeyword) && !step.toolResult.includes(errorKeyword);
|
|
2739
2978
|
typeClass = isSuccess ? styles$1.doneSuccess : styles$1.doneError;
|
|
2740
2979
|
statusIcon2 = isSuccess ? "🎉" : "❌";
|
|
2741
2980
|
} else {
|
|
@@ -2759,6 +2998,13 @@ createHistoryItem_fn = /* @__PURE__ */ __name(function(step) {
|
|
|
2759
2998
|
} else {
|
|
2760
2999
|
statusIcon2 = "🧠";
|
|
2761
3000
|
}
|
|
3001
|
+
const durationText = step.duration ? ` · ${step.duration}ms` : "";
|
|
3002
|
+
const stepLabel = __privateGet(this, _pageAgent).i18n.t("ui.panel.step", {
|
|
3003
|
+
number: step.stepNumber.toString(),
|
|
3004
|
+
time,
|
|
3005
|
+
duration: durationText || ""
|
|
3006
|
+
// Explicitly pass empty string to replace template
|
|
3007
|
+
});
|
|
2762
3008
|
return `
|
|
2763
3009
|
<div class="${styles$1.historyItem} ${typeClass}">
|
|
2764
3010
|
<div class="${styles$1.historyContent}">
|
|
@@ -2766,8 +3012,7 @@ createHistoryItem_fn = /* @__PURE__ */ __name(function(step) {
|
|
|
2766
3012
|
<span>${step.displayText}</span>
|
|
2767
3013
|
</div>
|
|
2768
3014
|
<div class="${styles$1.historyMeta}">
|
|
2769
|
-
|
|
2770
|
-
${step.duration ? ` · ${step.duration}ms` : ""}
|
|
3015
|
+
${stepLabel}
|
|
2771
3016
|
</div>
|
|
2772
3017
|
</div>
|
|
2773
3018
|
`;
|
|
@@ -3028,6 +3273,14 @@ moveCursorToTarget_fn = /* @__PURE__ */ __name(function() {
|
|
|
3028
3273
|
}, "#moveCursorToTarget");
|
|
3029
3274
|
__name(_SimulatorMask, "SimulatorMask");
|
|
3030
3275
|
let SimulatorMask = _SimulatorMask;
|
|
3276
|
+
function assert(condition, message, silent) {
|
|
3277
|
+
if (!condition) {
|
|
3278
|
+
const errorMessage = message ?? "Assertion failed";
|
|
3279
|
+
console.error(chalk.red(`❌ assert: ${errorMessage}`));
|
|
3280
|
+
throw new Error(errorMessage);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
__name(assert, "assert");
|
|
3031
3284
|
const _PageAgent = class _PageAgent extends EventTarget {
|
|
3032
3285
|
constructor(config = {}) {
|
|
3033
3286
|
super();
|
|
@@ -3036,6 +3289,7 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
3036
3289
|
__publicField(this, "id", uid());
|
|
3037
3290
|
__publicField(this, "bus", getEventBus(this.id));
|
|
3038
3291
|
__publicField(this, "i18n");
|
|
3292
|
+
__publicField(this, "panel");
|
|
3039
3293
|
__publicField(this, "paused", false);
|
|
3040
3294
|
__publicField(this, "disposed", false);
|
|
3041
3295
|
__publicField(this, "task", "");
|
|
@@ -3059,13 +3313,12 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
3059
3313
|
__publicField(this, "tools", new Map(tools));
|
|
3060
3314
|
/** Fullscreen mask */
|
|
3061
3315
|
__publicField(this, "mask", new SimulatorMask());
|
|
3062
|
-
/** Interactive panel */
|
|
3063
|
-
__publicField(this, "panel", new Panel(this));
|
|
3064
3316
|
/** History records */
|
|
3065
3317
|
__publicField(this, "history", []);
|
|
3066
3318
|
this.config = config;
|
|
3067
3319
|
__privateSet(this, _llm, new LLM(this.config, this.id));
|
|
3068
3320
|
this.i18n = new I18n(this.config.language);
|
|
3321
|
+
this.panel = new Panel(this);
|
|
3069
3322
|
patchReact();
|
|
3070
3323
|
}
|
|
3071
3324
|
/**
|
|
@@ -3108,18 +3361,16 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
3108
3361
|
content: __privateMethod(this, _PageAgent_instances, assembleUserPrompt_fn).call(this)
|
|
3109
3362
|
}
|
|
3110
3363
|
],
|
|
3111
|
-
|
|
3112
|
-
__privateMethod(this, _PageAgent_instances, packMacroTool_fn).call(this),
|
|
3364
|
+
{ AgentOutput: __privateMethod(this, _PageAgent_instances, packMacroTool_fn).call(this) },
|
|
3113
3365
|
__privateGet(this, _abortController).signal
|
|
3114
3366
|
);
|
|
3115
|
-
const
|
|
3116
|
-
const input2 =
|
|
3117
|
-
const output2 =
|
|
3367
|
+
const macroResult = result.toolResult;
|
|
3368
|
+
const input2 = macroResult.input;
|
|
3369
|
+
const output2 = macroResult.output;
|
|
3118
3370
|
const brain = {
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
next_goal: input2.next_goal
|
|
3371
|
+
evaluation_previous_goal: input2.evaluation_previous_goal || "",
|
|
3372
|
+
memory: input2.memory || "",
|
|
3373
|
+
next_goal: input2.next_goal || ""
|
|
3123
3374
|
};
|
|
3124
3375
|
const actionName = Object.keys(input2.action)[0];
|
|
3125
3376
|
const action = {
|
|
@@ -3144,8 +3395,8 @@ const _PageAgent = class _PageAgent extends EventTarget {
|
|
|
3144
3395
|
};
|
|
3145
3396
|
}
|
|
3146
3397
|
if (actionName === "done") {
|
|
3147
|
-
const success = action.input
|
|
3148
|
-
const text = action.input
|
|
3398
|
+
const success = action.input?.success ?? false;
|
|
3399
|
+
const text = action.input?.text || "no text provided";
|
|
3149
3400
|
console.log(chalk.green.bold("Task completed"), success, text);
|
|
3150
3401
|
__privateMethod(this, _PageAgent_instances, onDone_fn).call(this, text, success);
|
|
3151
3402
|
return {
|
|
@@ -3190,42 +3441,6 @@ _PageAgent_instances = new WeakSet();
|
|
|
3190
3441
|
* - next_goal: string
|
|
3191
3442
|
* - action: { toolName: toolInput }
|
|
3192
3443
|
* where action must be selected from tools defined in this.tools
|
|
3193
|
-
*
|
|
3194
|
-
* @topic 要不要合并成一个 tool?
|
|
3195
|
-
* @facts
|
|
3196
|
-
* - 我们需要模型每步返回 evaluation/memory/goal 等思考过程
|
|
3197
|
-
* - browser use 合并成一个巨大的 tool
|
|
3198
|
-
* ```json
|
|
3199
|
-
* {
|
|
3200
|
-
* "memory": "...",
|
|
3201
|
-
* "goal": "...",
|
|
3202
|
-
* "actions": [
|
|
3203
|
-
* {
|
|
3204
|
-
* "name": "...",
|
|
3205
|
-
* "args": "..."
|
|
3206
|
-
* }
|
|
3207
|
-
* // ...
|
|
3208
|
-
* ]
|
|
3209
|
-
* }
|
|
3210
|
-
* ```
|
|
3211
|
-
* - qwen 目前必须指定 function name 来确保 tool call
|
|
3212
|
-
* @reasoning
|
|
3213
|
-
* - 不能为了 qwen 的缺陷而设计系统
|
|
3214
|
-
* - 更复杂的 tool 更容易出错
|
|
3215
|
-
* - 分散的 tool 更容易利用 ai-sdk 的重试机制,也更容易处理错误
|
|
3216
|
-
* - 不能用额外的步骤生成这些数据,不仅性能过差,而且 goal 之类的必须和 call 一起生成
|
|
3217
|
-
* @options
|
|
3218
|
-
* - Plan @A
|
|
3219
|
-
* - 和 browser use 使用完全一致的做法,合并成一个大 tool,要求每次调用
|
|
3220
|
-
* - 会把 tool 定义变得非常复杂,增加出错率
|
|
3221
|
-
* - Plan @B
|
|
3222
|
-
* - 每次调用两个 tool,其中一个用来输出思考
|
|
3223
|
-
* - 很难用提示词 enforce 这么复杂的规则
|
|
3224
|
-
* - Plan @C
|
|
3225
|
-
* - 自动为每个 tool 增加固定的 reasoning/memory/goal 等输入,并自动拦截提取这些数据
|
|
3226
|
-
* - 会让 tool 定义变得很长
|
|
3227
|
-
* @conclusion
|
|
3228
|
-
* - 使用 @A
|
|
3229
3444
|
*/
|
|
3230
3445
|
packMacroTool_fn = /* @__PURE__ */ __name(function() {
|
|
3231
3446
|
const tools2 = this.tools;
|
|
@@ -3234,70 +3449,75 @@ packMacroTool_fn = /* @__PURE__ */ __name(function() {
|
|
|
3234
3449
|
[toolName]: tool2.inputSchema
|
|
3235
3450
|
});
|
|
3236
3451
|
});
|
|
3237
|
-
const actionSchema = zod.union(
|
|
3452
|
+
const actionSchema = zod.union(
|
|
3453
|
+
actionSchemas
|
|
3454
|
+
);
|
|
3455
|
+
const macroToolSchema = zod.object({
|
|
3456
|
+
// thinking: zod.string().optional(),
|
|
3457
|
+
evaluation_previous_goal: zod.string().optional(),
|
|
3458
|
+
memory: zod.string().optional(),
|
|
3459
|
+
next_goal: zod.string().optional(),
|
|
3460
|
+
action: actionSchema
|
|
3461
|
+
});
|
|
3238
3462
|
return {
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
await waitUntil(() => !this.paused);
|
|
3251
|
-
console.log(chalk.blue.bold("MacroTool execute"), input2);
|
|
3252
|
-
const action = input2.action;
|
|
3253
|
-
const toolName = Object.keys(action)[0];
|
|
3254
|
-
const toolInput = action[toolName];
|
|
3255
|
-
const brain = trimLines(`✅: ${input2.evaluation_previous_goal}
|
|
3463
|
+
// name: MACRO_TOOL_NAME,
|
|
3464
|
+
// description: 'Execute agent action', // @todo remote
|
|
3465
|
+
inputSchema: macroToolSchema,
|
|
3466
|
+
execute: /* @__PURE__ */ __name(async (input2) => {
|
|
3467
|
+
if (__privateGet(this, _abortController).signal.aborted) throw new Error("AbortError");
|
|
3468
|
+
await waitUntil(() => !this.paused);
|
|
3469
|
+
console.log(chalk.blue.bold("MacroTool execute"), input2);
|
|
3470
|
+
const action = input2.action;
|
|
3471
|
+
const toolName = Object.keys(action)[0];
|
|
3472
|
+
const toolInput = action[toolName];
|
|
3473
|
+
const brain = trimLines(`✅: ${input2.evaluation_previous_goal}
|
|
3256
3474
|
💾: ${input2.memory}
|
|
3257
3475
|
🎯: ${input2.next_goal}
|
|
3258
3476
|
`);
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3477
|
+
console.log(brain);
|
|
3478
|
+
this.bus.emit("panel:update", {
|
|
3479
|
+
type: "thinking",
|
|
3480
|
+
displayText: brain
|
|
3481
|
+
});
|
|
3482
|
+
const tool2 = tools2.get(toolName);
|
|
3483
|
+
assert(tool2, `Tool ${toolName} not found. (@note should have been caught before this!!!)`);
|
|
3484
|
+
console.log(chalk.blue.bold(`Executing tool: ${toolName}`), toolInput);
|
|
3485
|
+
this.bus.emit("panel:update", {
|
|
3486
|
+
type: "tool_executing",
|
|
3487
|
+
toolName,
|
|
3488
|
+
toolArgs: toolInput,
|
|
3489
|
+
displayText: getToolExecutingText(toolName, toolInput, this.i18n)
|
|
3490
|
+
});
|
|
3491
|
+
const startTime = Date.now();
|
|
3492
|
+
let result = await tool2.execute.bind(this)(toolInput);
|
|
3493
|
+
const duration = Date.now() - startTime;
|
|
3494
|
+
console.log(chalk.green.bold(`Tool (${toolName}) executed for ${duration}ms`), result);
|
|
3495
|
+
if (toolName === "wait") {
|
|
3496
|
+
__privateSet(this, _totalWaitTime, __privateGet(this, _totalWaitTime) + Math.round(toolInput.seconds + duration / 1e3));
|
|
3497
|
+
result += `
|
|
3498
|
+
<sys> You have waited ${__privateGet(this, _totalWaitTime)} seconds accumulatively.`;
|
|
3499
|
+
if (__privateGet(this, _totalWaitTime) >= 3)
|
|
3500
|
+
result += "\nDo NOT wait any longer unless you have a good reason.\n";
|
|
3501
|
+
result += "</sys>";
|
|
3502
|
+
} else {
|
|
3503
|
+
__privateSet(this, _totalWaitTime, 0);
|
|
3504
|
+
}
|
|
3505
|
+
const displayResult = getToolCompletedText(toolName, toolInput, this.i18n);
|
|
3506
|
+
if (displayResult)
|
|
3267
3507
|
this.bus.emit("panel:update", {
|
|
3268
3508
|
type: "tool_executing",
|
|
3269
3509
|
toolName,
|
|
3270
3510
|
toolArgs: toolInput,
|
|
3271
|
-
|
|
3511
|
+
toolResult: result,
|
|
3512
|
+
displayText: displayResult,
|
|
3513
|
+
duration
|
|
3272
3514
|
});
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
result += `
|
|
3280
|
-
<sys> You have waited ${__privateGet(this, _totalWaitTime)} seconds accumulatively.`;
|
|
3281
|
-
if (__privateGet(this, _totalWaitTime) >= 3)
|
|
3282
|
-
result += "\nDo NOT wait any longer unless you have a good reason.\n";
|
|
3283
|
-
result += "</sys>";
|
|
3284
|
-
} else {
|
|
3285
|
-
__privateSet(this, _totalWaitTime, 0);
|
|
3286
|
-
}
|
|
3287
|
-
const displayResult = getToolCompletedText(toolName, toolInput, this.i18n);
|
|
3288
|
-
if (displayResult)
|
|
3289
|
-
this.bus.emit("panel:update", {
|
|
3290
|
-
type: "tool_executing",
|
|
3291
|
-
toolName,
|
|
3292
|
-
toolArgs: toolInput,
|
|
3293
|
-
toolResult: result,
|
|
3294
|
-
displayText: displayResult,
|
|
3295
|
-
duration
|
|
3296
|
-
});
|
|
3297
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3298
|
-
return result;
|
|
3299
|
-
}, "execute")
|
|
3300
|
-
})
|
|
3515
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3516
|
+
return {
|
|
3517
|
+
input: input2,
|
|
3518
|
+
output: result
|
|
3519
|
+
};
|
|
3520
|
+
}, "execute")
|
|
3301
3521
|
};
|
|
3302
3522
|
}, "#packMacroTool");
|
|
3303
3523
|
/**
|