@coolkiller007/my-page-agent 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- (function() { try { if (typeof document != "undefined") { var elementStyle = document.createElement("style"); elementStyle.appendChild(document.createTextNode("._wrapper_ur79v_1 {\n position: fixed;\n inset: 0;\n z-index: 2147483641; /* 确保在所有元素之上,除了 Agent UI */\n cursor: wait;\n overflow: hidden;\n\n display: none;\n}\n\n._wrapper_ur79v_1._visible_ur79v_11 {\n display: block;\n}\n/* AI 光标样式 */\n._cursor_eh09s_2 {\n position: absolute;\n width: var(--cursor-size, 48px);\n height: var(--cursor-size, 48px);\n pointer-events: none;\n z-index: 10000;\n}\n\n._cursorBorder_eh09s_10 {\n position: absolute;\n width: 100%;\n height: 100%;\n background: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));\n mask-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%20fill='none'%3e%3cpath%20d='M287.232%20128l514.752%20387.008L574.912%20576l149.376%20299.52-103.04%2051.392L472.32%20628.544l-185.856%20143.424z'%20stroke='%23000000'%20stroke-width='56'%20stroke-linejoin='miter'/%3e%3c/svg%3e\");\n mask-size: 100% 100%;\n mask-repeat: no-repeat;\n margin-left: -16px;\n margin-top: -7px;\n}\n\n._cursorFilling_eh09s_22 {\n position: absolute;\n width: 100%;\n height: 100%;\n background: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20d='M287.232%20128l514.752%20387.008L574.912%20576l149.376%20299.52-103.04%2051.392L472.32%20628.544l-185.856%20143.424z'%20fill='%23ffffff'/%3e%3c/svg%3e\");\n background-size: 100% 100%;\n background-repeat: no-repeat;\n margin-left: -16px;\n margin-top: -7px;\n}\n\n._cursorRipple_eh09s_33 {\n position: absolute;\n width: 100%;\n height: 100%;\n pointer-events: none;\n margin-left: -50%;\n margin-top: -50%;\n\n &::after {\n content: '';\n opacity: 0;\n position: absolute;\n inset: 0;\n border: 4px solid rgba(57, 182, 255, 1);\n border-radius: 50%;\n }\n}\n\n._cursor_eh09s_2._clicking_eh09s_51 ._cursorRipple_eh09s_33::after {\n animation: _cursor-ripple_eh09s_1 300ms ease-out forwards;\n}\n\n@keyframes _cursor-ripple_eh09s_1 {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n._wrapper_h452n_1 {\n position: fixed;\n bottom: 100px;\n left: 50%;\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n z-index: 2147483642; /* 比 SimulatorMask 高一层 */\n box-sizing: border-box;\n\n /* 普通流布局:历史弹窗、面板依次纵向排列,靠子元素自身尺寸撑开,\n * 不再用 position:absolute + 手算偏移量拼位置(这套算法之前连续出过两次 bug:\n * 弹窗被状态条盖住、状态条运行态时下方角没跟着圆)。 */\n display: flex;\n flex-direction: column;\n align-items: center;\n\n * {\n box-sizing: border-box;\n }\n\n /* 宽度取窗口 40%,用 clamp 防止超窄/超宽窗口下过小或过大 */\n --width: clamp(280px, 40vw, 640px);\n --height: 40px; /* 状态条高度 */\n --input-height: 80px; /* 输入区高度 */\n --border-radius: 16px;\n\n --side-space: 12px; /* 控制栏两侧的间距 */\n --history-width: calc(var(--width) - var(--side-space) * 2);\n\n --color-1: rgb(57, 182, 255);\n --color-2: rgb(189, 69, 251);\n --color-3: rgb(255, 87, 51);\n --color-4: rgb(255, 214, 0);\n\n width: var(--width);\n\n transition:\n opacity 0.3s ease-in-out,\n transform 0.3s ease-in-out;\n\n /* 响应式设计 */\n @media (max-width: 480px) {\n width: calc(100vw - 40px);\n --width: calc(100vw - 40px);\n }\n}\n\n@keyframes _mask-running_h452n_1 {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n/* 状态条 + 输入区的面板容器;.background 光效挂在这一层,.panelInner 负责裁出圆角 */\n._panel_h452n_57 {\n position: relative;\n width: 100%;\n}\n\n._background_h452n_57 {\n position: absolute;\n inset: -2px;\n border-radius: calc(var(--border-radius) + 4px);\n filter: blur(4px);\n overflow: hidden;\n pointer-events: none;\n\n &::before {\n content: '';\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-1),\n var(--color-2),\n var(--color-1)\n );\n animation: _mask-running_h452n_1 2s linear infinite;\n }\n &::after {\n content: '';\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-2),\n var(--color-1),\n var(--color-2)\n );\n animation: _mask-running_h452n_1 2s linear infinite;\n animation-delay: 1s;\n }\n}\n\n/* 面板可视区域:靠 overflow:hidden + border-radius 统一裁角,\n * header 单独存在(运行中输入区隐藏)或 header+输入区一起存在时,四角都自动是圆的,\n * 不用再像以前那样给 header 写一条\"输入区隐藏时补圆角\"的特判规则。 */\n._panelInner_h452n_57 {\n position: relative;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-radius: var(--border-radius);\n border: 2px solid rgba(255, 255, 255, 0.4);\n box-shadow:\n 0 0 5px 1px rgba(255, 255, 255, 0.3),\n 0 4px 20px rgba(0, 0, 0, 0.5);\n}\n\n/* 控制栏 */\n._header_h452n_124 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n user-select: none;\n\n height: var(--height);\n flex-shrink: 0; /* 防止 header 被压缩 */\n\n cursor: pointer;\n\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(10px);\n background-clip: padding-box;\n\n ._statusSection_h452n_140 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-height: 24px; /* 确保垂直居中 */\n\n ._indicator_h452n_147 {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.5);\n flex-shrink: 0;\n animation: none; /* 默认无动画 */\n\n /* 运行状态 - 有动画 */\n &._thinking_h452n_156 {\n background: rgb(57, 182, 255);\n animation: _pulse_h452n_1 0.8s ease-in-out infinite;\n }\n\n &._tool_executing_h452n_161 {\n background: rgb(189, 69, 251);\n animation: _pulse_h452n_1 0.6s ease-in-out infinite;\n }\n\n &._retry_h452n_166 {\n background: rgb(255, 214, 0);\n animation: _retryPulse_h452n_1 1s ease-in-out infinite;\n }\n\n /* 静止状态 - 无动画 */\n &._completed_h452n_172,\n &._input_h452n_173,\n &._output_h452n_174 {\n background: rgb(34, 197, 94);\n animation: none;\n }\n\n &._error_h452n_179 {\n background: rgb(239, 68, 68);\n animation: none;\n }\n }\n\n ._statusText_h452n_185 {\n color: white;\n font-size: 12px;\n line-height: 1;\n font-weight: 500;\n transition: all 0.3s ease-in-out;\n position: relative;\n overflow: hidden;\n display: flex;\n align-items: center;\n min-height: 24px; /* 确保垂直居中 */\n\n &._fadeOut_h452n_197 {\n animation: _statusTextFadeOut_h452n_1 0.3s ease forwards;\n }\n\n &._fadeIn_h452n_201 {\n animation: _statusTextFadeIn_h452n_1 0.3s ease forwards;\n }\n }\n }\n\n ._controls_h452n_207 {\n display: flex;\n align-items: center;\n gap: 4px;\n\n ._controlButton_h452n_212 {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.1);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n\n ._stopButton_h452n_231 {\n background: rgba(239, 68, 68, 0.2);\n color: rgb(255, 41, 41);\n font-weight: 600;\n\n &:hover {\n background: rgba(239, 68, 68, 0.3);\n }\n }\n }\n}\n\n@keyframes _statusTextFadeIn_h452n_1 {\n 0% {\n opacity: 0;\n transform: translateY(5px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _statusTextFadeOut_h452n_1 {\n 0% {\n opacity: 1;\n transform: translateY(0);\n }\n 100% {\n opacity: 0;\n transform: translateY(-5px);\n }\n}\n\n/* 历史记录弹窗:普通流里排在面板前面(视觉上在上方),默认收起为 0 高度,\n * 展开时靠 JS 量出的真实内容高度做 max-height 动画(不用固定封顶值),\n * 撑开多高、要不要出现,跟面板本身完全无关,不用再算\"面板一共多高、弹窗该挂在哪个 bottom 偏移\"。 */\n._historySectionWrapper_h452n_268 {\n width: 100%;\n overflow: hidden;\n max-height: 0;\n margin-bottom: 0;\n\n background: rgba(2, 0, 20, 0.5);\n backdrop-filter: blur(10px);\n\n text-shadow: 0 0 1px rgba(0, 0, 0, 0.2);\n\n border-radius: calc(var(--border-radius) + 4px);\n border: 0 solid rgba(255, 255, 255, 0);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0);\n\n transition:\n max-height 0.2s,\n margin-bottom 0.2s,\n border-width 0.2s,\n border-color 0.2s,\n box-shadow 0.2s;\n\n ._wrapper_h452n_1._expanded_h452n_290 & {\n margin-bottom: 8px;\n border-width: 2px;\n border-color: rgba(255, 255, 255, 0.4);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);\n }\n\n ._historySection_h452n_268 {\n max-height: min(\n 500px,\n calc(100vh - 200px - var(--height))\n ); /* 列表本身的滚动上限,跟展开/收起动画解耦 */\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: none;\n /* 底部留白用 padding 撑,不依赖最后一项 margin-bottom:\n * overflow:auto 容器会裁掉末尾子元素的 margin,导致最后一条记录贴底 */\n padding: 8px;\n\n ._historyItem_h452n_309 {\n /* backdrop-filter: blur(10px); */\n padding: 8px 10px;\n margin-bottom: 8px;\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));\n border-radius: 8px;\n border-left: 2px solid rgba(57, 182, 255, 0.5);\n font-size: 12px;\n color: white;\n /* color: black; */\n line-height: 1.3;\n position: relative;\n overflow: hidden;\n\n /* 微妙的内阴影 */\n box-shadow:\n 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 1px 3px rgba(0, 0, 0, 0.1);\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);\n }\n\n &:hover {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));\n /* transform: translateY(-1px); */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.15),\n 0 2px 4px rgba(0, 0, 0, 0.15);\n }\n\n &._completed_h452n_172,\n &._input_h452n_173,\n &._output_h452n_174 {\n border-left-color: rgb(34, 197, 94);\n background: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(34, 197, 94, 0.05));\n }\n\n &._error_h452n_179 {\n border-left-color: rgb(239, 68, 68);\n background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05));\n }\n\n &._retry_h452n_166 {\n border-left-color: rgb(255, 214, 0);\n background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));\n }\n\n &._observation_h452n_363 {\n border-left-color: rgb(147, 51, 234);\n background: linear-gradient(135deg, rgba(147, 51, 234, 0.1), rgba(147, 51, 234, 0.05));\n }\n\n &._question_h452n_368 {\n border-left-color: rgb(255, 159, 67);\n background: linear-gradient(135deg, rgba(255, 159, 67, 0.15), rgba(255, 159, 67, 0.08));\n }\n\n /* 突出显示 done 成功结果 */\n &._doneSuccess_h452n_374 {\n background: linear-gradient(\n 135deg,\n rgba(34, 197, 94, 0.25),\n rgba(34, 197, 94, 0.15),\n rgba(34, 197, 94, 0.08)\n );\n border: none;\n border-left: 2px solid rgb(34, 197, 94);\n box-shadow:\n 0 4px 12px rgba(34, 197, 94, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(34, 197, 94, 0.1);\n font-weight: 600;\n color: rgb(220, 252, 231);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(34, 197, 94, 0.4), transparent);\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 0;\n left: -100%;\n width: 100%;\n height: 100%;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n animation: _shimmer_h452n_1 2s ease-in-out infinite;\n }\n\n ._historyContent_h452n_410 {\n ._statusIcon_h452n_411 {\n font-size: 16px;\n animation: _celebrate_h452n_1 0.8s ease-in-out;\n filter: drop-shadow(0 2px 4px rgba(34, 197, 94, 0.5));\n }\n }\n }\n\n /* 突出显示 done 失败结果 */\n &._doneError_h452n_420 {\n background: linear-gradient(\n 135deg,\n rgba(239, 68, 68, 0.25),\n rgba(239, 68, 68, 0.15),\n rgba(239, 68, 68, 0.08)\n );\n border: none;\n border-left: 2px solid rgb(239, 68, 68);\n box-shadow:\n 0 4px 12px rgba(239, 68, 68, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(239, 68, 68, 0.1);\n font-weight: 600;\n color: rgb(254, 226, 226);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.4), transparent);\n }\n\n ._historyContent_h452n_410 {\n ._statusIcon_h452n_411 {\n font-size: 16px;\n filter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n }\n }\n }\n\n ._historyContent_h452n_410 {\n display: flex;\n align-items: center;\n gap: 8px;\n\n word-break: break-all;\n white-space: pre-wrap;\n\n /* overflow-x: auto; */\n\n ._statusIcon_h452n_411 {\n font-size: 12px;\n flex-shrink: 0;\n line-height: 1;\n transition: all 0.3s ease;\n }\n\n ._reflectionLines_h452n_470 {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n }\n\n ._historyMeta_h452n_477 {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.6);\n /* color: rgb(61, 61, 61); */\n margin-top: 8px;\n line-height: 1;\n }\n }\n }\n}\n\n/* 动画关键帧 - 更快的闪烁 */\n@keyframes _pulse_h452n_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.4;\n transform: scale(1.3);\n }\n}\n\n/* 重试动画 - 旋转脉冲 */\n@keyframes _retryPulse_h452n_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1) rotate(0deg);\n }\n 25% {\n opacity: 0.6;\n transform: scale(1.2) rotate(90deg);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.1) rotate(180deg);\n }\n 75% {\n opacity: 0.6;\n transform: scale(1.2) rotate(270deg);\n }\n}\n\n/* 庆祝动画 */\n@keyframes _celebrate_h452n_1 {\n 0%,\n 100% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2) rotate(-5deg);\n }\n 75% {\n transform: scale(1.2) rotate(5deg);\n }\n}\n\n/* done 卡片的光泽效果 */\n@keyframes _shimmer_h452n_1 {\n 0% {\n left: -100%;\n }\n 100% {\n left: 100%;\n }\n}\n\n/* 输入区域样式 */\n._inputSectionWrapper_h452n_547 {\n width: 100%;\n margin: 0 auto;\n\n overflow: hidden;\n height: var(--input-height);\n\n transition: height 0.2s;\n\n /* 与 header 保持同色调,让面板看起来是一体的深色玻璃卡片 */\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(10px);\n\n border-bottom-left-radius: calc(var(--border-radius) + 4px);\n border-bottom-right-radius: calc(var(--border-radius) + 4px);\n\n &._hidden_h452n_563 {\n height: 0;\n }\n\n ._inputSection_h452n_547 {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n padding: 8px; /* 与上方状态条 padding 保持一致 */\n\n ._taskInput_h452n_574 {\n flex: 1;\n height: 100%;\n background: rgba(255, 255, 255, 0.08);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 12px;\n padding: 8px 14px;\n color: rgb(240, 240, 245);\n font-family: inherit;\n font-size: 14px;\n line-height: 1.4;\n outline: none;\n resize: none;\n overflow-y: auto;\n transition: all 0.2s ease;\n\n &::placeholder {\n color: rgba(255, 255, 255, 0.45);\n }\n\n &:focus {\n background: rgba(255, 255, 255, 0.14);\n border-color: rgba(57, 182, 255, 0.6);\n box-shadow: 0 0 0 2px rgba(57, 182, 255, 0.2);\n }\n }\n }\n}\n/*$vite$:1*/")); document.head.appendChild(elementStyle); } } catch (e) { console.error("vite-plugin-css-injected-by-js", e); }})();
1
+ (function() { try { if (typeof document != "undefined") { var elementStyle = document.createElement("style"); elementStyle.appendChild(document.createTextNode("._wrapper_ur79v_1 {\n position: fixed;\n inset: 0;\n z-index: 2147483641; /* 确保在所有元素之上,除了 Agent UI */\n cursor: wait;\n overflow: hidden;\n\n display: none;\n}\n\n._wrapper_ur79v_1._visible_ur79v_11 {\n display: block;\n}\n/* AI 光标样式 */\n._cursor_eh09s_2 {\n position: absolute;\n width: var(--cursor-size, 48px);\n height: var(--cursor-size, 48px);\n pointer-events: none;\n z-index: 10000;\n}\n\n._cursorBorder_eh09s_10 {\n position: absolute;\n width: 100%;\n height: 100%;\n background: linear-gradient(45deg, rgb(57, 182, 255), rgb(189, 69, 251));\n mask-image: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%20fill='none'%3e%3cpath%20d='M287.232%20128l514.752%20387.008L574.912%20576l149.376%20299.52-103.04%2051.392L472.32%20628.544l-185.856%20143.424z'%20stroke='%23000000'%20stroke-width='56'%20stroke-linejoin='miter'/%3e%3c/svg%3e\");\n mask-size: 100% 100%;\n mask-repeat: no-repeat;\n margin-left: -16px;\n margin-top: -7px;\n}\n\n._cursorFilling_eh09s_22 {\n position: absolute;\n width: 100%;\n height: 100%;\n background: url(\"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%201024%201024'%3e%3cpath%20d='M287.232%20128l514.752%20387.008L574.912%20576l149.376%20299.52-103.04%2051.392L472.32%20628.544l-185.856%20143.424z'%20fill='%23ffffff'/%3e%3c/svg%3e\");\n background-size: 100% 100%;\n background-repeat: no-repeat;\n margin-left: -16px;\n margin-top: -7px;\n}\n\n._cursorRipple_eh09s_33 {\n position: absolute;\n width: 100%;\n height: 100%;\n pointer-events: none;\n margin-left: -50%;\n margin-top: -50%;\n\n &::after {\n content: '';\n opacity: 0;\n position: absolute;\n inset: 0;\n border: 4px solid rgba(57, 182, 255, 1);\n border-radius: 50%;\n }\n}\n\n._cursor_eh09s_2._clicking_eh09s_51 ._cursorRipple_eh09s_33::after {\n animation: _cursor-ripple_eh09s_1 300ms ease-out forwards;\n}\n\n@keyframes _cursor-ripple_eh09s_1 {\n 0% {\n transform: scale(0);\n opacity: 1;\n }\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n}\n._wrapper_18lru_1 {\n position: fixed;\n bottom: 100px;\n left: 50%;\n transform: translateX(-50%) translateY(20px);\n opacity: 0;\n z-index: 2147483642; /* 比 SimulatorMask 高一层 */\n box-sizing: border-box;\n\n /* 普通流布局:历史弹窗、面板依次纵向排列,靠子元素自身尺寸撑开,\n * 不再用 position:absolute + 手算偏移量拼位置(这套算法之前连续出过两次 bug:\n * 弹窗被状态条盖住、状态条运行态时下方角没跟着圆)。 */\n display: flex;\n flex-direction: column;\n align-items: center;\n\n * {\n box-sizing: border-box;\n }\n\n /* 宽度取窗口 40%,用 clamp 防止超窄/超宽窗口下过小或过大 */\n --width: clamp(280px, 40vw, 640px);\n --height: 40px; /* 状态条高度 */\n --input-height: 80px; /* 输入区高度 */\n --border-radius: 16px;\n\n --side-space: 12px; /* 控制栏两侧的间距 */\n --history-width: calc(var(--width) - var(--side-space) * 2);\n\n --color-1: rgb(57, 182, 255);\n --color-2: rgb(189, 69, 251);\n --color-3: rgb(255, 87, 51);\n --color-4: rgb(255, 214, 0);\n\n width: var(--width);\n\n transition:\n opacity 0.3s ease-in-out,\n transform 0.3s ease-in-out;\n\n /* 响应式设计 */\n @media (max-width: 480px) {\n width: calc(100vw - 40px);\n --width: calc(100vw - 40px);\n }\n}\n\n@keyframes _mask-running_18lru_1 {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n/* 状态条 + 输入区的外层容器;.background 光效挂在这一层,.shellInner 负责裁出圆角 */\n._shell_18lru_57 {\n position: relative;\n width: 100%;\n}\n\n._background_18lru_57 {\n position: absolute;\n inset: -2px;\n border-radius: calc(var(--border-radius) + 4px);\n filter: blur(4px);\n overflow: hidden;\n pointer-events: none;\n\n &::before {\n content: '';\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-1),\n var(--color-2),\n var(--color-1)\n );\n animation: _mask-running_18lru_1 2s linear infinite;\n }\n &::after {\n content: '';\n pointer-events: none;\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n\n background-image: linear-gradient(\n to bottom left,\n var(--color-2),\n var(--color-1),\n var(--color-2)\n );\n animation: _mask-running_18lru_1 2s linear infinite;\n animation-delay: 1s;\n }\n}\n\n/* 可视区域:靠 overflow:hidden + border-radius 统一裁角,\n * header 单独存在(运行中输入区隐藏)或 header+输入区一起存在时,四角都自动是圆的,\n * 不用再像以前那样给 header 写一条\"输入区隐藏时补圆角\"的特判规则。 */\n._shellInner_18lru_57 {\n position: relative;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border-radius: var(--border-radius);\n border: 2px solid rgba(255, 255, 255, 0.4);\n box-shadow:\n 0 0 5px 1px rgba(255, 255, 255, 0.3),\n 0 4px 20px rgba(0, 0, 0, 0.5);\n}\n\n/* 控制栏 */\n._header_18lru_124 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n user-select: none;\n\n height: var(--height);\n flex-shrink: 0; /* 防止 header 被压缩 */\n\n cursor: pointer;\n\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(10px);\n background-clip: padding-box;\n\n ._statusSection_18lru_140 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-height: 24px; /* 确保垂直居中 */\n\n ._indicator_18lru_147 {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.5);\n flex-shrink: 0;\n animation: none; /* 默认无动画 */\n\n /* 运行状态 - 有动画 */\n &._thinking_18lru_156 {\n background: rgb(57, 182, 255);\n animation: _pulse_18lru_1 0.8s ease-in-out infinite;\n }\n\n &._tool_executing_18lru_161 {\n background: rgb(189, 69, 251);\n animation: _pulse_18lru_1 0.6s ease-in-out infinite;\n }\n\n &._retry_18lru_166 {\n background: rgb(255, 214, 0);\n animation: _retryPulse_18lru_1 1s ease-in-out infinite;\n }\n\n /* 静止状态 - 无动画 */\n &._completed_18lru_172,\n &._input_18lru_173,\n &._output_18lru_174 {\n background: rgb(34, 197, 94);\n animation: none;\n }\n\n &._error_18lru_179 {\n background: rgb(239, 68, 68);\n animation: none;\n }\n }\n\n ._statusText_18lru_185 {\n color: white;\n font-size: 12px;\n line-height: 1;\n font-weight: 500;\n transition: all 0.3s ease-in-out;\n position: relative;\n overflow: hidden;\n display: flex;\n align-items: center;\n min-height: 24px; /* 确保垂直居中 */\n\n &._fadeOut_18lru_197 {\n animation: _statusTextFadeOut_18lru_1 0.3s ease forwards;\n }\n\n &._fadeIn_18lru_201 {\n animation: _statusTextFadeIn_18lru_1 0.3s ease forwards;\n }\n }\n }\n\n ._controls_18lru_207 {\n display: flex;\n align-items: center;\n gap: 4px;\n\n ._controlButton_18lru_212 {\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.1);\n color: white;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n line-height: 1;\n\n &:hover {\n background: rgba(255, 255, 255, 0.2);\n }\n }\n\n ._stopButton_18lru_231 {\n background: rgba(239, 68, 68, 0.2);\n color: rgb(255, 41, 41);\n font-weight: 600;\n\n &:hover {\n background: rgba(239, 68, 68, 0.3);\n }\n }\n }\n}\n\n@keyframes _statusTextFadeIn_18lru_1 {\n 0% {\n opacity: 0;\n transform: translateY(5px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _statusTextFadeOut_18lru_1 {\n 0% {\n opacity: 1;\n transform: translateY(0);\n }\n 100% {\n opacity: 0;\n transform: translateY(-5px);\n }\n}\n\n/* 历史记录弹窗:普通流里排在面板前面(视觉上在上方),默认收起为 0 高度,\n * 展开时靠 JS 量出的真实内容高度做 max-height 动画(不用固定封顶值),\n * 撑开多高、要不要出现,跟面板本身完全无关,不用再算\"面板一共多高、弹窗该挂在哪个 bottom 偏移\"。 */\n._historySectionWrapper_18lru_268 {\n width: 100%;\n overflow: hidden;\n max-height: 0;\n margin-bottom: 0;\n\n background: rgba(2, 0, 20, 0.5);\n backdrop-filter: blur(10px);\n\n text-shadow: 0 0 1px rgba(0, 0, 0, 0.2);\n\n border-radius: calc(var(--border-radius) + 4px);\n border: 0 solid rgba(255, 255, 255, 0);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0);\n\n transition:\n max-height 0.2s,\n margin-bottom 0.2s,\n border-width 0.2s,\n border-color 0.2s,\n box-shadow 0.2s;\n\n ._wrapper_18lru_1._expanded_18lru_290 & {\n margin-bottom: 8px;\n border-width: 2px;\n border-color: rgba(255, 255, 255, 0.4);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);\n }\n\n ._historySection_18lru_268 {\n max-height: min(\n 500px,\n calc(100vh - 200px - var(--height))\n ); /* 列表本身的滚动上限,跟展开/收起动画解耦 */\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-width: none;\n /* 底部留白用 padding 撑,不依赖最后一项 margin-bottom:\n * overflow:auto 容器会裁掉末尾子元素的 margin,导致最后一条记录贴底 */\n padding: 8px;\n\n ._historyItem_18lru_309 {\n /* backdrop-filter: blur(10px); */\n padding: 8px 10px;\n margin-bottom: 8px;\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));\n border-radius: 8px;\n border-left: 2px solid rgba(57, 182, 255, 0.5);\n font-size: 12px;\n color: white;\n /* color: black; */\n line-height: 1.3;\n position: relative;\n overflow: hidden;\n\n /* 微妙的内阴影 */\n box-shadow:\n 0 1px 0 rgba(255, 255, 255, 0.1),\n 0 1px 3px rgba(0, 0, 0, 0.1);\n\n &::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);\n }\n\n &:hover {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.06));\n /* transform: translateY(-1px); */\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.15),\n 0 2px 4px rgba(0, 0, 0, 0.15);\n }\n\n &._completed_18lru_172,\n &._input_18lru_173,\n &._output_18lru_174 {\n border-left-color: rgb(34, 197, 94);\n background: linear-gradient(135deg, rgba(34, 197, 94, 0.1), rgba(34, 197, 94, 0.05));\n }\n\n &._error_18lru_179 {\n border-left-color: rgb(239, 68, 68);\n background: linear-gradient(135deg, rgba(239, 68, 68, 0.1), rgba(239, 68, 68, 0.05));\n }\n\n &._retry_18lru_166 {\n border-left-color: rgb(255, 214, 0);\n background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));\n }\n\n &._observation_18lru_363 {\n border-left-color: rgb(147, 51, 234);\n background: linear-gradient(135deg, rgba(147, 51, 234, 0.1), rgba(147, 51, 234, 0.05));\n }\n\n &._question_18lru_368 {\n border-left-color: rgb(255, 159, 67);\n background: linear-gradient(135deg, rgba(255, 159, 67, 0.15), rgba(255, 159, 67, 0.08));\n }\n\n /* 突出显示 done 成功结果 */\n &._doneSuccess_18lru_374 {\n background: linear-gradient(\n 135deg,\n rgba(34, 197, 94, 0.25),\n rgba(34, 197, 94, 0.15),\n rgba(34, 197, 94, 0.08)\n );\n border: none;\n border-left: 2px solid rgb(34, 197, 94);\n box-shadow:\n 0 4px 12px rgba(34, 197, 94, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(34, 197, 94, 0.1);\n font-weight: 600;\n color: rgb(220, 252, 231);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(34, 197, 94, 0.4), transparent);\n }\n\n &::after {\n content: '';\n position: absolute;\n top: 0;\n left: -100%;\n width: 100%;\n height: 100%;\n background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);\n animation: _shimmer_18lru_1 2s ease-in-out infinite;\n }\n\n ._historyContent_18lru_410 {\n ._statusIcon_18lru_411 {\n font-size: 16px;\n animation: _celebrate_18lru_1 0.8s ease-in-out;\n filter: drop-shadow(0 2px 4px rgba(34, 197, 94, 0.5));\n }\n }\n }\n\n /* 突出显示 done 失败结果 */\n &._doneError_18lru_420 {\n background: linear-gradient(\n 135deg,\n rgba(239, 68, 68, 0.25),\n rgba(239, 68, 68, 0.15),\n rgba(239, 68, 68, 0.08)\n );\n border: none;\n border-left: 2px solid rgb(239, 68, 68);\n box-shadow:\n 0 4px 12px rgba(239, 68, 68, 0.3),\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 20px rgba(239, 68, 68, 0.1);\n font-weight: 600;\n color: rgb(254, 226, 226);\n padding: 10px 12px;\n margin-bottom: 8px;\n border-radius: 8px;\n position: relative;\n overflow: hidden;\n\n &::before {\n background: linear-gradient(90deg, transparent, rgba(239, 68, 68, 0.4), transparent);\n }\n\n ._historyContent_18lru_410 {\n ._statusIcon_18lru_411 {\n font-size: 16px;\n filter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n }\n }\n }\n\n ._historyContent_18lru_410 {\n display: flex;\n align-items: center;\n gap: 8px;\n\n word-break: break-all;\n white-space: pre-wrap;\n\n /* overflow-x: auto; */\n\n ._statusIcon_18lru_411 {\n font-size: 12px;\n flex-shrink: 0;\n line-height: 1;\n transition: all 0.3s ease;\n }\n\n ._reflectionLines_18lru_470 {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n }\n\n ._historyMeta_18lru_477 {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.6);\n /* color: rgb(61, 61, 61); */\n margin-top: 8px;\n line-height: 1;\n }\n }\n }\n}\n\n/* 动画关键帧 - 更快的闪烁 */\n@keyframes _pulse_18lru_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.4;\n transform: scale(1.3);\n }\n}\n\n/* 重试动画 - 旋转脉冲 */\n@keyframes _retryPulse_18lru_1 {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1) rotate(0deg);\n }\n 25% {\n opacity: 0.6;\n transform: scale(1.2) rotate(90deg);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.1) rotate(180deg);\n }\n 75% {\n opacity: 0.6;\n transform: scale(1.2) rotate(270deg);\n }\n}\n\n/* 庆祝动画 */\n@keyframes _celebrate_18lru_1 {\n 0%,\n 100% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2) rotate(-5deg);\n }\n 75% {\n transform: scale(1.2) rotate(5deg);\n }\n}\n\n/* done 卡片的光泽效果 */\n@keyframes _shimmer_18lru_1 {\n 0% {\n left: -100%;\n }\n 100% {\n left: 100%;\n }\n}\n\n/* 输入区域样式 */\n._inputSectionWrapper_18lru_547 {\n width: 100%;\n margin: 0 auto;\n\n overflow: hidden;\n height: var(--input-height);\n\n transition: height 0.2s;\n\n /* 与 header 保持同色调,让面板看起来是一体的深色玻璃卡片 */\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(10px);\n\n border-bottom-left-radius: calc(var(--border-radius) + 4px);\n border-bottom-right-radius: calc(var(--border-radius) + 4px);\n\n &._hidden_18lru_563 {\n height: 0;\n }\n\n ._inputSection_18lru_547 {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n padding: 8px; /* 与上方状态条 padding 保持一致 */\n\n ._taskInput_18lru_574 {\n flex: 1;\n height: 100%;\n background: rgba(255, 255, 255, 0.08);\n border: 1px solid rgba(255, 255, 255, 0.15);\n border-radius: 12px;\n padding: 8px 14px;\n color: rgb(240, 240, 245);\n font-family: inherit;\n font-size: 14px;\n line-height: 1.4;\n outline: none;\n resize: none;\n overflow-y: auto;\n transition: all 0.2s ease;\n\n &::placeholder {\n color: rgba(255, 255, 255, 0.45);\n }\n\n &:focus {\n background: rgba(255, 255, 255, 0.14);\n border-color: rgba(57, 182, 255, 0.6);\n box-shadow: 0 0 0 2px rgba(57, 182, 255, 0.2);\n }\n }\n }\n}\n/*$vite$:1*/")); document.head.appendChild(elementStyle); } } catch (e) { console.error("vite-plugin-css-injected-by-js", e); }})();
2
2
  import { Motion } from "ai-motion";
3
3
  import * as z from "zod/v4";
4
4
  //#region \0rolldown/runtime.js
@@ -22,22 +22,27 @@ var __exportAll = (all, no_symbols) => {
22
22
  };
23
23
  //#endregion
24
24
  //#region src/browser/utils/index.ts
25
+ /** 判断值是否为 HTMLElement(type guard)。 */
25
26
  function isHTMLElement(el) {
26
27
  return !!el && el.nodeType === 1;
27
28
  }
29
+ /** 判断元素是否为 <input>(type guard)。 */
28
30
  function isInputElement(el) {
29
31
  return el?.nodeType === 1 && el.tagName === "INPUT";
30
32
  }
33
+ /** 判断元素是否为 <textarea>(type guard)。 */
31
34
  function isTextAreaElement(el) {
32
35
  return el?.nodeType === 1 && el.tagName === "TEXTAREA";
33
36
  }
37
+ /** 判断元素是否为 <select>(type guard)。 */
34
38
  function isSelectElement(el) {
35
39
  return el?.nodeType === 1 && el.tagName === "SELECT";
36
40
  }
41
+ /** 判断元素是否为 <a>(type guard)。 */
37
42
  function isAnchorElement(el) {
38
43
  return el?.nodeType === 1 && el.tagName === "A";
39
44
  }
40
- /** Iframe offset for translating element coordinates to top-frame viewport. */
45
+ /** 用于将元素坐标换算为顶层视口坐标的 iframe 偏移量。 */
41
46
  function getIframeOffset(element) {
42
47
  const frame = element.ownerDocument.defaultView?.frameElement;
43
48
  if (!frame) return {
@@ -51,19 +56,20 @@ function getIframeOffset(element) {
51
56
  };
52
57
  }
53
58
  /**
54
- * Get native value setter from the element's own prototype (iframe-safe).
55
- * @note for React
59
+ * 从元素自身的原型上获取原生 value setter(iframe 安全)。
60
+ * @note 用于 React
56
61
  */
57
62
  function getNativeValueSetter(element) {
58
63
  return Object.getOwnPropertyDescriptor(Object.getPrototypeOf(element), "value").set;
59
64
  }
65
+ /** 等待指定的秒数。 */
60
66
  async function waitFor$1(seconds) {
61
67
  await new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
62
68
  }
63
69
  /**
64
- * Move the visual pointer to a position within an element.
65
- * @param x - x coordinate in the element's document viewport
66
- * @param y - y coordinate in the element's document viewport
70
+ * 将视觉指针移动到元素内的某个位置。
71
+ * @param x - 元素所属文档视口内的 x 坐标
72
+ * @param y - 元素所属文档视口内的 y 坐标
67
73
  */
68
74
  async function movePointerToElement(element, x, y) {
69
75
  const offset = getIframeOffset(element);
@@ -73,20 +79,23 @@ async function movePointerToElement(element, x, y) {
73
79
  } }));
74
80
  await waitFor$1(.3);
75
81
  }
82
+ /** 触发一次模拟光标点击动画。 */
76
83
  async function clickPointer() {
77
84
  window.dispatchEvent(new CustomEvent("PageAgent::ClickPointer"));
78
85
  }
86
+ /** 开启遮罩穿透,鼠标事件不再被遮罩拦截。 */
79
87
  async function enablePassThrough() {
80
88
  window.dispatchEvent(new CustomEvent("PageAgent::EnablePassThrough"));
81
89
  }
90
+ /** 关闭遮罩穿透,遮罩重新拦截鼠标事件。 */
82
91
  async function disablePassThrough() {
83
92
  window.dispatchEvent(new CustomEvent("PageAgent::DisablePassThrough"));
84
93
  }
85
94
  //#endregion
86
95
  //#region src/browser/actions.ts
87
96
  /**
88
- * Get the HTMLElement by index from a selectorMap.
89
- * @private Internal method, subject to change at any time.
97
+ * 根据索引从 selectorMap 中获取对应的 HTMLElement
98
+ * @private 内部方法,随时可能变更。
90
99
  */
91
100
  function getElementByIndex(selectorMap, index) {
92
101
  const interactiveNode = selectorMap.get(index);
@@ -97,6 +106,9 @@ function getElementByIndex(selectorMap, index) {
97
106
  return element;
98
107
  }
99
108
  var lastClickedElement = null;
109
+ /**
110
+ * 触发上次点击元素的失焦相关事件(pointerout/pointerleave/mouseout/mouseleave/blur)并清空记录。
111
+ */
100
112
  function blurLastClickedElement() {
101
113
  if (lastClickedElement) {
102
114
  lastClickedElement.dispatchEvent(new PointerEvent("pointerout", { bubbles: true }));
@@ -108,11 +120,11 @@ function blurLastClickedElement() {
108
120
  }
109
121
  }
110
122
  /**
111
- * Simulate a full click following W3C Pointer Events + UI Events spec order:
123
+ * 模拟一次完整的点击,遵循 W3C Pointer Events + UI Events 规范顺序:
112
124
  * pointerover/enter → mouseover/enter → pointerdown → mousedown → [focus] →
113
125
  * pointerup → mouseup → click
114
126
  *
115
- * @private Internal method, subject to change at any time.
127
+ * @private 内部方法,随时可能变更。
116
128
  */
117
129
  async function clickElement(element) {
118
130
  blurLastClickedElement();
@@ -164,7 +176,8 @@ async function clickElement(element) {
164
176
  await waitFor$1(.1);
165
177
  }
166
178
  /**
167
- * @private Internal method, subject to change at any time.
179
+ * 向输入类元素(input / textarea / contenteditable)输入文本,并触发相应的输入事件。
180
+ * @private 内部方法,随时可能变更。
168
181
  */
169
182
  async function inputTextElement(element, text) {
170
183
  const isContentEditable = element.isContentEditable;
@@ -214,8 +227,9 @@ async function inputTextElement(element, text) {
214
227
  blurLastClickedElement();
215
228
  }
216
229
  /**
217
- * @todo browser-use version is very complex and supports menu tags, need to follow up
218
- * @private Internal method, subject to change at any time.
230
+ * 在下拉选择框(select)中按文本匹配并选中对应选项,然后触发 change 事件。
231
+ * @todo browser-use 版本非常复杂且支持菜单标签,需要跟进
232
+ * @private 内部方法,随时可能变更。
219
233
  */
220
234
  async function selectOptionElement(selectElement, optionText) {
221
235
  if (!isSelectElement(selectElement)) throw new Error("Element is not a select element");
@@ -226,7 +240,8 @@ async function selectOptionElement(selectElement, optionText) {
226
240
  await waitFor$1(.05);
227
241
  }
228
242
  /**
229
- * @private Internal method, subject to change at any time.
243
+ * 将元素滚动到可视区域内;优先使用原生 scrollIntoViewIfNeeded,不支持时回退为 scrollIntoView。
244
+ * @private 内部方法,随时可能变更。
230
245
  */
231
246
  async function scrollIntoViewIfNeeded(element) {
232
247
  const el = element;
@@ -237,6 +252,12 @@ async function scrollIntoViewIfNeeded(element) {
237
252
  inline: "nearest"
238
253
  });
239
254
  }
255
+ /**
256
+ * 垂直滚动页面或指定元素容器。
257
+ * @param scroll_amount - 滚动像素数(正数向下,负数向上)
258
+ * @param element - 可选;若传入,则优先滚动该元素及其祖先中最近的可纵向滚动容器,否则滚动页面
259
+ * @returns 滚动结果的描述消息
260
+ */
240
261
  async function scrollVertically(scroll_amount, element) {
241
262
  if (element) {
242
263
  const targetElement = element;
@@ -310,6 +331,12 @@ async function scrollVertically(scroll_amount, element) {
310
331
  return `✅ ${warningMsg} Scrolled container (${el.tagName}) by ${scrolled}px.`;
311
332
  }
312
333
  }
334
+ /**
335
+ * 水平滚动页面或指定元素容器。
336
+ * @param scroll_amount - 滚动像素数(正数向右,负数向左)
337
+ * @param element - 可选;若传入,则优先滚动该元素及其祖先中最近的可横向滚动容器,否则滚动页面
338
+ * @returns 滚动结果的描述消息
339
+ */
313
340
  async function scrollHorizontally(scroll_amount, element) {
314
341
  if (element) {
315
342
  const targetElement = element;
@@ -1426,13 +1453,13 @@ var dom_tree_default = (args = {
1426
1453
  //#endregion
1427
1454
  //#region src/browser/dom/index.ts
1428
1455
  /**
1429
- * Viewport expansion for DOM tree extraction.
1430
- * -1 means full page (no viewport restriction)
1431
- * 0 means viewport only
1432
- * positive values expand the viewport by that many pixels
1456
+ * DOM 树提取时的视口扩展。
1457
+ * -1 表示整页(不受视口限制)
1458
+ * 0 表示仅视口
1459
+ * 正数表示在视口基础上额外扩展的像素数
1433
1460
  *
1434
- * @note Since isTopElement depends on elementFromPoint,
1435
- * it returns null when out of viewport, this feature has no practical use, only differ between -1 and 0
1461
+ * @note 由于 isTopElement 依赖 elementFromPoint
1462
+ * 当元素在视口外时会返回 null,该特性实际用处不大,仅在 -1 0 之间有区别
1436
1463
  */
1437
1464
  var DEFAULT_VIEWPORT_EXPANSION = -1;
1438
1465
  function resolveViewportExpansion(viewportExpansion) {
@@ -1780,13 +1807,13 @@ function patchReact(_browserController) {
1780
1807
  for (const element of reactRootElements) element.setAttribute("data-page-agent-not-interactive", "true");
1781
1808
  }
1782
1809
  /**
1783
- * @todo (Heavy, might have false negatives) Interaction detection, if element width/height equals body offsetWidth/Height, consider it root element and non-interactive (React often attaches many events to root elements, causing false positives)
1810
+ * @todo (较重,可能有漏判)交互检测:如果元素宽高等于 body offsetWidth/Height,则视为根元素并标记为不可交互(React 经常把大量事件绑定在根元素上,导致误判为可交互)
1784
1811
  */
1785
1812
  //#endregion
1786
1813
  //#region src/browser/visual/checkDarkMode.ts
1787
1814
  /**
1788
- * A comprehensive function to determine if the page is currently in a dark theme.
1789
- * Heuristic check. Only work for common patterns. Return false by default.
1815
+ * 判断页面当前是否处于深色主题的综合函数。
1816
+ * 启发式检测,只覆盖常见模式,默认返回 false
1790
1817
  */
1791
1818
  function isPageDark() {
1792
1819
  try {
@@ -1803,7 +1830,7 @@ function isPageDark() {
1803
1830
  }
1804
1831
  }
1805
1832
  /**
1806
- * Checks for common dark mode CSS classes on the html or body elements.
1833
+ * 检查 html body 元素上常见的深色模式 CSS 类名。
1807
1834
  */
1808
1835
  function hasDarkModeClass() {
1809
1836
  const DEFAULT_DARK_MODE_CLASSES = [
@@ -1819,7 +1846,7 @@ function hasDarkModeClass() {
1819
1846
  return false;
1820
1847
  }
1821
1848
  /**
1822
- * Some UI frameworks use data attributes to indicate theme
1849
+ * 某些 UI 框架使用 data 属性来表示主题
1823
1850
  */
1824
1851
  function hasDarkModeDataAttribute() {
1825
1852
  const htmlElement = document.documentElement;
@@ -1837,8 +1864,8 @@ function hasDarkModeDataAttribute() {
1837
1864
  return false;
1838
1865
  }
1839
1866
  /**
1840
- * Checks the CSS `color-scheme` property and `<meta name="color-scheme">` tag.
1841
- * Only "dark"/"only dark" counts as dark; "light dark" is ambiguous and ignored.
1867
+ * 检查 CSS `color-scheme` 属性和 `<meta name="color-scheme">` 标签。
1868
+ * 只有 "dark"/"only dark" 才视为深色;"light dark" 存在歧义,忽略。
1842
1869
  */
1843
1870
  function isColorSchemeDark() {
1844
1871
  const metaContent = document.querySelector("meta[name=\"color-scheme\"]")?.content.toLowerCase();
@@ -1847,7 +1874,7 @@ function isColorSchemeDark() {
1847
1874
  return colorScheme === "dark" || colorScheme === "only dark";
1848
1875
  }
1849
1876
  /**
1850
- * Checks the background color of the body element to determine if the page is dark.
1877
+ * 检查 body 元素的背景色以判断页面是否为深色。
1851
1878
  */
1852
1879
  function isBackgroundDark() {
1853
1880
  const htmlStyle = window.getComputedStyle(document.documentElement);
@@ -1859,18 +1886,18 @@ function isBackgroundDark() {
1859
1886
  return false;
1860
1887
  }
1861
1888
  /**
1862
- * Checks if the text color on the body is light, which implies a dark background.
1889
+ * 检查 body 上的文字颜色是否为浅色,浅色文字通常意味着深色背景。
1863
1890
  */
1864
1891
  function isTextColorLight() {
1865
- /** Luminance (0-255) above which body text is considered light */
1892
+ /** 亮度(0-255)超过该值时认为 body 文字为浅色 */
1866
1893
  const LIGHT_TEXT_LUMINANCE = 200;
1867
1894
  const luminance = getLuminance(window.getComputedStyle(document.body || document.documentElement).color);
1868
1895
  return luminance !== null && luminance > LIGHT_TEXT_LUMINANCE;
1869
1896
  }
1870
1897
  /**
1871
- * Checks the background color of major layout elements (#app, #root, etc.).
1872
- * Many SPAs render into a container that may have its own dark background while
1873
- * <body> remains transparent.
1898
+ * 检查主要布局元素(#app、#root 等)的背景色。
1899
+ * 很多 SPA 会把内容渲染到某个容器中,该容器可能有自己的深色背景,
1900
+ * <body> 仍然是透明的。
1874
1901
  */
1875
1902
  function isMainContentBackgroundDark() {
1876
1903
  const { innerWidth: vw, innerHeight: vh } = window;
@@ -1889,8 +1916,8 @@ function isMainContentBackgroundDark() {
1889
1916
  return false;
1890
1917
  }
1891
1918
  /**
1892
- * Parses an RGB or RGBA color string and returns an object with r, g, b properties.
1893
- * @param {string} colorString - e.g., "rgb(34, 34, 34)" or "rgba(0, 0, 0, 0.5)"
1919
+ * 解析 RGB RGBA 颜色字符串,返回包含 rgb 属性的对象。
1920
+ * @param {string} colorString - 例如 "rgb(34, 34, 34)" "rgba(0, 0, 0, 0.5)"
1894
1921
  * @returns {{r: number, g: number, b: number}|null}
1895
1922
  */
1896
1923
  function parseRgbColor(colorString) {
@@ -1903,9 +1930,9 @@ function parseRgbColor(colorString) {
1903
1930
  };
1904
1931
  }
1905
1932
  /**
1906
- * Calculates the perceived luminance (0-255) of a CSS color string.
1907
- * @param {string} colorString - e.g., "rgb(50, 50, 50)" or "rgba(0, 0, 0, 0.5)"
1908
- * @returns {number|null} - The luminance, or null if the color is transparent or unparseable.
1933
+ * 计算 CSS 颜色字符串的感知亮度(0-255)。
1934
+ * @param {string} colorString - 例如 "rgb(50, 50, 50)" "rgba(0, 0, 0, 0.5)"
1935
+ * @returns {number|null} - 亮度值,若颜色为透明或无法解析则返回 null
1909
1936
  */
1910
1937
  function getLuminance(colorString) {
1911
1938
  if (!colorString || colorString === "transparent" || colorString.startsWith("rgba(0, 0, 0, 0)")) return null;
@@ -1914,9 +1941,9 @@ function getLuminance(colorString) {
1914
1941
  return .299 * rgb.r + .587 * rgb.g + .114 * rgb.b;
1915
1942
  }
1916
1943
  /**
1917
- * Determines if a color is "dark" based on its calculated luminance.
1918
- * @param {string} colorString - The CSS color string (e.g., "rgb(50, 50, 50)").
1919
- * @param {number} threshold - A value between 0 and 255. Colors with luminance below this will be considered dark. Default is 128.
1944
+ * 根据计算出的亮度判断颜色是否为“深色”。
1945
+ * @param {string} colorString - CSS 颜色字符串(例如 "rgb(50, 50, 50)")。
1946
+ * @param {number} threshold - 0 255 之间的值。亮度低于该值的颜色视为深色。默认为 128
1920
1947
  */
1921
1948
  function isColorDark(colorString, threshold = 128) {
1922
1949
  const luminance = getLuminance(colorString);
@@ -1970,6 +1997,9 @@ var init_SimulatorMask = __esmMin((() => {
1970
1997
  #currentCursorY = 0;
1971
1998
  #targetCursorX = 0;
1972
1999
  #targetCursorY = 0;
2000
+ /**
2001
+ * 构造函数:初始化遮罩 DOM、创建 ai-motion 动效、拦截底层事件,并注册全局事件监听。
2002
+ */
1973
2003
  constructor() {
1974
2004
  super();
1975
2005
  this.wrapper.id = "page-agent-runtime_simulator-mask";
@@ -2048,6 +2078,7 @@ var init_SimulatorMask = __esmMin((() => {
2048
2078
  window.removeEventListener("PageAgent::DisablePassThrough", disablePassThroughListener);
2049
2079
  });
2050
2080
  }
2081
+ /** 创建模拟光标的 DOM 结构(包含波纹、填充层、边框层)。 */
2051
2082
  #createCursor() {
2052
2083
  this.#cursor.className = cursor_module_default.cursor;
2053
2084
  const rippleContainer = document.createElement("div");
@@ -2061,6 +2092,7 @@ var init_SimulatorMask = __esmMin((() => {
2061
2092
  this.#cursor.appendChild(borderLayer);
2062
2093
  this.wrapper.appendChild(this.#cursor);
2063
2094
  }
2095
+ /** 每帧将光标向目标位置移动 20% 距离,实现平滑跟随动画。 */
2064
2096
  #moveCursorToTarget() {
2065
2097
  if (this.#disposed) return;
2066
2098
  const newX = this.#currentCursorX + (this.#targetCursorX - this.#currentCursorX) * .2;
@@ -2079,17 +2111,24 @@ var init_SimulatorMask = __esmMin((() => {
2079
2111
  }
2080
2112
  requestAnimationFrame(() => this.#moveCursorToTarget());
2081
2113
  }
2114
+ /**
2115
+ * 设置光标的目标坐标(由外部通过事件触发调用)。
2116
+ * @param x - 目标 X 坐标
2117
+ * @param y - 目标 Y 坐标
2118
+ */
2082
2119
  setCursorPosition(x, y) {
2083
2120
  if (this.#disposed) return;
2084
2121
  this.#targetCursorX = x;
2085
2122
  this.#targetCursorY = y;
2086
2123
  }
2124
+ /** 触发一次光标点击动画(通过重放 clicking class 实现)。 */
2087
2125
  triggerClickAnimation() {
2088
2126
  if (this.#disposed) return;
2089
2127
  this.#cursor.classList.remove(cursor_module_default.clicking);
2090
2128
  this.#cursor.offsetHeight;
2091
2129
  this.#cursor.classList.add(cursor_module_default.clicking);
2092
2130
  }
2131
+ /** 显示遮罩及模拟光标。 */
2093
2132
  show() {
2094
2133
  if (this.shown || this.#disposed) return;
2095
2134
  this.shown = true;
@@ -2103,6 +2142,7 @@ var init_SimulatorMask = __esmMin((() => {
2103
2142
  this.#cursor.style.left = `${this.#currentCursorX}px`;
2104
2143
  this.#cursor.style.top = `${this.#currentCursorY}px`;
2105
2144
  }
2145
+ /** 隐藏遮罩及模拟光标。 */
2106
2146
  hide() {
2107
2147
  if (!this.shown || this.#disposed) return;
2108
2148
  this.shown = false;
@@ -2113,6 +2153,7 @@ var init_SimulatorMask = __esmMin((() => {
2113
2153
  this.wrapper.classList.remove(SimulatorMask_module_default.visible);
2114
2154
  }, 800);
2115
2155
  }
2156
+ /** 销毁遮罩:释放动效、移除 DOM 并触发 dispose 事件。 */
2116
2157
  dispose() {
2117
2158
  this.#disposed = true;
2118
2159
  this.motion?.dispose();
@@ -2124,44 +2165,46 @@ var init_SimulatorMask = __esmMin((() => {
2124
2165
  //#endregion
2125
2166
  //#region src/browser/BrowserController.ts
2126
2167
  /**
2127
- * Copyright (C) 2025 Alibaba Group Holding Limited
2128
- * All rights reserved.
2168
+ * 版权所有 (C) 2025 Alibaba Group Holding Limited
2169
+ * 保留所有权利。
2129
2170
  *
2130
- * BrowserController - Manages DOM operations and element interactions.
2131
- * Designed to be independent of LLM and can be tested in unit tests.
2132
- * All public methods are async for potential remote calling support.
2171
+ * BrowserController - 管理 DOM 操作和元素交互。
2172
+ * 设计上独立于 LLM,可在单元测试中直接测试。
2173
+ * 所有公开方法均为异步,以支持潜在的远程调用。
2133
2174
  */
2134
2175
  /**
2135
- * BrowserController manages DOM state and element interactions.
2136
- * It provides async methods for all DOM operations, keeping state isolated.
2176
+ * BrowserController 管理 DOM 状态和元素交互。
2177
+ * 它为所有 DOM 操作提供异步方法,并保持状态隔离。
2137
2178
  *
2138
2179
  * @lifecycle
2139
- * - beforeUpdate: Emitted before the DOM tree is updated.
2140
- * - afterUpdate: Emitted after the DOM tree is updated.
2180
+ * - beforeUpdate: DOM 树更新之前触发。
2181
+ * - afterUpdate: DOM 树更新之后触发。
2141
2182
  */
2142
2183
  var BrowserController = class extends EventTarget {
2143
2184
  config;
2144
- /** Corresponds to eval_page in browser-use */
2185
+ /** 对应 browser-use 中的 eval_page */
2145
2186
  flatTree = null;
2146
2187
  /**
2147
- * All highlighted index-mapped interactive elements
2148
- * Corresponds to DOMState.selector_map in browser-use
2188
+ * 所有已索引的高亮交互元素
2189
+ * 对应 browser-use 中的 DOMState.selector_map
2149
2190
  */
2150
2191
  selectorMap = /* @__PURE__ */ new Map();
2151
- /** Index -> element text description mapping */
2192
+ /** 索引 -> 元素文本描述映射 */
2152
2193
  elementTextMap = /* @__PURE__ */ new Map();
2153
2194
  /**
2154
- * Simplified HTML for LLM consumption.
2155
- * Corresponds to clickable_elements_to_string in browser-use
2195
+ * LLM 消费的简化 HTML。
2196
+ * 对应 browser-use 中的 clickable_elements_to_string
2156
2197
  */
2157
2198
  simplifiedHTML = "<EMPTY>";
2158
- /** last time the tree was updated */
2199
+ /** 树最后一次更新的时间 */
2159
2200
  lastTimeUpdate = 0;
2160
- /** Whether the tree has been indexed at least once */
2201
+ /** 树是否至少被索引过一次 */
2161
2202
  isIndexed = false;
2162
- /** Visual mask overlay for blocking user interaction during automation */
2203
+ /** 用于在自动化期间阻止用户交互的视觉遮罩层 */
2163
2204
  mask = null;
2205
+ /** mask 异步初始化完成的 Promise,用于在调用前等待初始化完成 */
2164
2206
  maskReady = null;
2207
+ /** 是否已释放资源 */
2165
2208
  disposed = false;
2166
2209
  constructor(config = {}) {
2167
2210
  super();
@@ -2170,7 +2213,7 @@ var BrowserController = class extends EventTarget {
2170
2213
  if (config.enableMask) this.initMask();
2171
2214
  }
2172
2215
  /**
2173
- * Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)
2216
+ * 异步初始化遮罩层(动态导入以避免在 Node 中加载 CSS
2174
2217
  */
2175
2218
  initMask() {
2176
2219
  if (this.disposed || this.maskReady !== null) return;
@@ -2186,20 +2229,20 @@ var BrowserController = class extends EventTarget {
2186
2229
  })();
2187
2230
  }
2188
2231
  /**
2189
- * Get current page URL
2232
+ * 获取当前页面 URL
2190
2233
  */
2191
2234
  async getCurrentUrl() {
2192
2235
  return window.location.href;
2193
2236
  }
2194
2237
  /**
2195
- * Get last tree update timestamp
2238
+ * 获取树最后一次更新的时间戳
2196
2239
  */
2197
2240
  async getLastUpdateTime() {
2198
2241
  return this.lastTimeUpdate;
2199
2242
  }
2200
2243
  /**
2201
- * Get structured browser state for LLM consumption.
2202
- * Automatically calls updateTree() to refresh the DOM state.
2244
+ * 获取供 LLM 消费的结构化浏览器状态。
2245
+ * 自动调用 updateTree() 刷新 DOM 状态。
2203
2246
  */
2204
2247
  async getBrowserState() {
2205
2248
  const url = window.location.href;
@@ -2217,9 +2260,9 @@ var BrowserController = class extends EventTarget {
2217
2260
  };
2218
2261
  }
2219
2262
  /**
2220
- * Update DOM tree, returns simplified HTML for LLM.
2221
- * This is the main method to refresh the page state.
2222
- * Automatically bypasses mask during DOM extraction if enabled.
2263
+ * 更新 DOM 树,返回供 LLM 使用的简化 HTML
2264
+ * 这是刷新页面状态的主要方法。
2265
+ * 若已启用遮罩,DOM 提取期间会自动绕过遮罩。
2223
2266
  */
2224
2267
  async updateTree() {
2225
2268
  this.dispatchEvent(new Event("beforeUpdate"));
@@ -2242,21 +2285,21 @@ var BrowserController = class extends EventTarget {
2242
2285
  return this.simplifiedHTML;
2243
2286
  }
2244
2287
  /**
2245
- * Clean up all element highlights
2288
+ * 清理所有元素高亮
2246
2289
  */
2247
2290
  async cleanUpHighlights() {
2248
2291
  console.log("[BrowserController] cleanUpHighlights");
2249
2292
  cleanUpHighlights();
2250
2293
  }
2251
2294
  /**
2252
- * Ensure the tree has been indexed before any index-based operation.
2253
- * Throws if updateTree() hasn't been called yet.
2295
+ * 在任何基于索引的操作之前确保树已被索引。
2296
+ * 若尚未调用 updateTree() 则抛出异常。
2254
2297
  */
2255
2298
  assertIndexed() {
2256
2299
  if (!this.isIndexed) throw new Error("DOM tree not indexed yet. Can not perform actions on elements.");
2257
2300
  }
2258
2301
  /**
2259
- * Click element by index
2302
+ * 根据索引点击元素
2260
2303
  */
2261
2304
  async clickElement(index) {
2262
2305
  try {
@@ -2280,7 +2323,7 @@ var BrowserController = class extends EventTarget {
2280
2323
  }
2281
2324
  }
2282
2325
  /**
2283
- * Input text into element by index
2326
+ * 根据索引向元素输入文本
2284
2327
  */
2285
2328
  async inputText(index, text) {
2286
2329
  try {
@@ -2300,7 +2343,7 @@ var BrowserController = class extends EventTarget {
2300
2343
  }
2301
2344
  }
2302
2345
  /**
2303
- * Select dropdown option by index and option text
2346
+ * 根据索引和选项文本在下拉框中选中选项
2304
2347
  */
2305
2348
  async selectOption(index, optionText) {
2306
2349
  try {
@@ -2320,7 +2363,7 @@ var BrowserController = class extends EventTarget {
2320
2363
  }
2321
2364
  }
2322
2365
  /**
2323
- * Scroll vertically
2366
+ * 垂直滚动
2324
2367
  */
2325
2368
  async scroll(options) {
2326
2369
  try {
@@ -2338,7 +2381,7 @@ var BrowserController = class extends EventTarget {
2338
2381
  }
2339
2382
  }
2340
2383
  /**
2341
- * Scroll horizontally
2384
+ * 水平滚动
2342
2385
  */
2343
2386
  async scrollHorizontally(options) {
2344
2387
  try {
@@ -2356,9 +2399,8 @@ var BrowserController = class extends EventTarget {
2356
2399
  }
2357
2400
  }
2358
2401
  /**
2359
- * Execute arbitrary JavaScript on the page.
2360
- * The optional `signal` is exposed to the script scope so cooperative code
2361
- * can abort promptly when the task is stopped.
2402
+ * 在页面上执行任意 JavaScript
2403
+ * 可选的 `signal` 会暴露到脚本作用域中,使协作代码能在任务被中止时及时退出。
2362
2404
  */
2363
2405
  async executeJavascript(script, signal) {
2364
2406
  try {
@@ -2374,8 +2416,8 @@ var BrowserController = class extends EventTarget {
2374
2416
  }
2375
2417
  }
2376
2418
  /**
2377
- * Show the visual mask overlay.
2378
- * Only works after mask is setup.
2419
+ * 显示视觉遮罩层。
2420
+ * 仅在遮罩初始化完成后可用。
2379
2421
  */
2380
2422
  async showMask() {
2381
2423
  if (this.disposed) return;
@@ -2384,8 +2426,8 @@ var BrowserController = class extends EventTarget {
2384
2426
  this.mask?.show();
2385
2427
  }
2386
2428
  /**
2387
- * Hide the visual mask overlay.
2388
- * Only works after mask is setup.
2429
+ * 隐藏视觉遮罩层。
2430
+ * 仅在遮罩初始化完成后可用。
2389
2431
  */
2390
2432
  async hideMask() {
2391
2433
  if (this.disposed) return;
@@ -2394,7 +2436,7 @@ var BrowserController = class extends EventTarget {
2394
2436
  this.mask?.hide();
2395
2437
  }
2396
2438
  /**
2397
- * Dispose and clean up resources
2439
+ * 释放资源并清理
2398
2440
  */
2399
2441
  dispose() {
2400
2442
  if (this.disposed) return;
@@ -2421,6 +2463,7 @@ var BrowserController = class extends EventTarget {
2421
2463
  if (errors.length > 1) throw new AggregateError(errors, "BrowserController disposal failed");
2422
2464
  }
2423
2465
  };
2466
+ /** 语言包集合:键为语言代码,值为对应翻译表 */
2424
2467
  var locales = {
2425
2468
  "en-US": { ui: {
2426
2469
  ready: "Ready",
@@ -2525,81 +2568,85 @@ var I18n = class {
2525
2568
  if (params) return this.interpolate(value, params);
2526
2569
  return value;
2527
2570
  }
2571
+ /** 根据点分路径从翻译对象中取值 */
2528
2572
  getNestedValue(obj, path) {
2529
2573
  return path.split(".").reduce((current, key) => current?.[key], obj);
2530
2574
  }
2575
+ /** 将模板中的 {{key}} 占位符替换为参数值 */
2531
2576
  interpolate(template, params) {
2532
2577
  return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
2533
2578
  return params[key] != null ? params[key].toString() : match;
2534
2579
  });
2535
2580
  }
2581
+ /** 获取当前语言代码 */
2536
2582
  getLanguage() {
2537
2583
  return this.language;
2538
2584
  }
2539
2585
  };
2540
2586
  //#endregion
2541
2587
  //#region src/ui/utils.ts
2588
+ /** 截断字符串,超过最大长度时以省略号结尾 */
2542
2589
  function truncate$1(text, maxLength) {
2543
2590
  if (text.length > maxLength) return text.substring(0, maxLength) + "...";
2544
2591
  return text;
2545
2592
  }
2546
2593
  /**
2547
- * Escape HTML special characters to prevent XSS and rendering issues
2594
+ * 转义 HTML 特殊字符,防止 XSS 及渲染问题
2548
2595
  */
2549
2596
  function escapeHtml(text) {
2550
2597
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
2551
2598
  }
2552
2599
  var UI_module_default = {
2553
- wrapper: "_wrapper_h452n_1",
2554
- panel: "_panel_h452n_57",
2555
- background: "_background_h452n_57",
2556
- "mask-running": "_mask-running_h452n_1",
2557
- panelInner: "_panelInner_h452n_57",
2558
- header: "_header_h452n_124",
2559
- pulse: "_pulse_h452n_1",
2560
- retryPulse: "_retryPulse_h452n_1",
2561
- statusTextFadeOut: "_statusTextFadeOut_h452n_1",
2562
- statusTextFadeIn: "_statusTextFadeIn_h452n_1",
2563
- statusSection: "_statusSection_h452n_140",
2564
- indicator: "_indicator_h452n_147",
2565
- thinking: "_thinking_h452n_156",
2566
- tool_executing: "_tool_executing_h452n_161",
2567
- retry: "_retry_h452n_166",
2568
- completed: "_completed_h452n_172",
2569
- input: "_input_h452n_173",
2570
- output: "_output_h452n_174",
2571
- error: "_error_h452n_179",
2572
- statusText: "_statusText_h452n_185",
2573
- fadeOut: "_fadeOut_h452n_197",
2574
- fadeIn: "_fadeIn_h452n_201",
2575
- controls: "_controls_h452n_207",
2576
- controlButton: "_controlButton_h452n_212",
2577
- stopButton: "_stopButton_h452n_231",
2578
- historySectionWrapper: "_historySectionWrapper_h452n_268",
2579
- shimmer: "_shimmer_h452n_1",
2580
- celebrate: "_celebrate_h452n_1",
2581
- expanded: "_expanded_h452n_290",
2582
- historySection: "_historySection_h452n_268",
2583
- historyItem: "_historyItem_h452n_309",
2584
- observation: "_observation_h452n_363",
2585
- question: "_question_h452n_368",
2586
- doneSuccess: "_doneSuccess_h452n_374",
2587
- historyContent: "_historyContent_h452n_410",
2588
- statusIcon: "_statusIcon_h452n_411",
2589
- doneError: "_doneError_h452n_420",
2590
- reflectionLines: "_reflectionLines_h452n_470",
2591
- historyMeta: "_historyMeta_h452n_477",
2592
- inputSectionWrapper: "_inputSectionWrapper_h452n_547",
2593
- hidden: "_hidden_h452n_563",
2594
- inputSection: "_inputSection_h452n_547",
2595
- taskInput: "_taskInput_h452n_574"
2600
+ wrapper: "_wrapper_18lru_1",
2601
+ shell: "_shell_18lru_57",
2602
+ background: "_background_18lru_57",
2603
+ "mask-running": "_mask-running_18lru_1",
2604
+ shellInner: "_shellInner_18lru_57",
2605
+ header: "_header_18lru_124",
2606
+ pulse: "_pulse_18lru_1",
2607
+ retryPulse: "_retryPulse_18lru_1",
2608
+ statusTextFadeOut: "_statusTextFadeOut_18lru_1",
2609
+ statusTextFadeIn: "_statusTextFadeIn_18lru_1",
2610
+ statusSection: "_statusSection_18lru_140",
2611
+ indicator: "_indicator_18lru_147",
2612
+ thinking: "_thinking_18lru_156",
2613
+ tool_executing: "_tool_executing_18lru_161",
2614
+ retry: "_retry_18lru_166",
2615
+ completed: "_completed_18lru_172",
2616
+ input: "_input_18lru_173",
2617
+ output: "_output_18lru_174",
2618
+ error: "_error_18lru_179",
2619
+ statusText: "_statusText_18lru_185",
2620
+ fadeOut: "_fadeOut_18lru_197",
2621
+ fadeIn: "_fadeIn_18lru_201",
2622
+ controls: "_controls_18lru_207",
2623
+ controlButton: "_controlButton_18lru_212",
2624
+ stopButton: "_stopButton_18lru_231",
2625
+ historySectionWrapper: "_historySectionWrapper_18lru_268",
2626
+ shimmer: "_shimmer_18lru_1",
2627
+ celebrate: "_celebrate_18lru_1",
2628
+ expanded: "_expanded_18lru_290",
2629
+ historySection: "_historySection_18lru_268",
2630
+ historyItem: "_historyItem_18lru_309",
2631
+ observation: "_observation_18lru_363",
2632
+ question: "_question_18lru_368",
2633
+ doneSuccess: "_doneSuccess_18lru_374",
2634
+ historyContent: "_historyContent_18lru_410",
2635
+ statusIcon: "_statusIcon_18lru_411",
2636
+ doneError: "_doneError_18lru_420",
2637
+ reflectionLines: "_reflectionLines_18lru_470",
2638
+ historyMeta: "_historyMeta_18lru_477",
2639
+ inputSectionWrapper: "_inputSectionWrapper_18lru_547",
2640
+ hidden: "_hidden_18lru_563",
2641
+ inputSection: "_inputSection_18lru_547",
2642
+ taskInput: "_taskInput_18lru_574"
2596
2643
  };
2597
2644
  //#endregion
2598
2645
  //#region src/ui/cards.ts
2599
2646
  /**
2600
- * Card HTML generation utilities for UI
2647
+ * UI 的卡片 HTML 生成工具
2601
2648
  */
2602
- /** Create a single history card */
2649
+ /** 创建单条历史卡片 */
2603
2650
  function createCard({ icon, content, meta, type }) {
2604
2651
  const typeClass = type ? UI_module_default[type] : "";
2605
2652
  const contentHtml = Array.isArray(content) ? `<div class="${UI_module_default.reflectionLines}">${content.map((line) => `<span>${escapeHtml(line)}</span>`).join("")}</div>` : `<span>${escapeHtml(content)}</span>`;
@@ -2613,7 +2660,7 @@ function createCard({ icon, content, meta, type }) {
2613
2660
  </div>
2614
2661
  `;
2615
2662
  }
2616
- /** Create reflection lines from reflection object */
2663
+ /** 从反思对象生成反思行 */
2617
2664
  function createReflectionLines(reflection) {
2618
2665
  const lines = [];
2619
2666
  if (reflection.evaluation_previous_goal) lines.push(`🔍 ${reflection.evaluation_previous_goal}`);
@@ -2624,14 +2671,14 @@ function createReflectionLines(reflection) {
2624
2671
  //#endregion
2625
2672
  //#region src/ui/UI.ts
2626
2673
  /**
2627
- * Agent control UI
2674
+ * Agent 控制 UI
2628
2675
  *
2629
- * Architecture:
2630
- * - History list: renders directly from agent.history (historical events)
2631
- * - Header bar: shows activity events (transient state) and agent status
2676
+ * 架构:
2677
+ * - 历史列表:直接从 agent.history 渲染(历史事件)
2678
+ * - 头部栏:展示活动事件(瞬时状态)和 agent 状态
2632
2679
  *
2633
- * This separation ensures data consistency - history is the single source of truth
2634
- * for what has been done, while activity shows what is happening now.
2680
+ * 这种分离保证了数据一致性 - 历史是已完成内容的唯一数据源,
2681
+ * 而活动状态展示的是当前正在发生的事情。
2635
2682
  */
2636
2683
  var UI = class {
2637
2684
  #wrapper;
@@ -2662,13 +2709,14 @@ var UI = class {
2662
2709
  #onActivity = (e) => this.#handleActivity(e.detail);
2663
2710
  #onAgentDispose = () => this.dispose();
2664
2711
  #askUserCallback = (question, options) => this.#askUser(question, options?.signal);
2712
+ /** 获取 UI 的根容器元素 */
2665
2713
  get wrapper() {
2666
2714
  return this.#wrapper;
2667
2715
  }
2668
2716
  /**
2669
- * Create a UI bound to an agent
2670
- * @param agent - Agent instance that implements UIAdapter
2671
- * @param config - Optional UI configuration
2717
+ * 创建绑定到某个 agent UI
2718
+ * @param agent - 实现 UIAdapter Agent 实例
2719
+ * @param config - 可选的 UI 配置
2672
2720
  */
2673
2721
  constructor(agent, config = {}) {
2674
2722
  this.#agent = agent;
@@ -2693,7 +2741,7 @@ var UI = class {
2693
2741
  this.#showInputArea();
2694
2742
  this.hide();
2695
2743
  }
2696
- /** Handle agent status change */
2744
+ /** 处理 agent 状态变化 */
2697
2745
  #handleStatusChange() {
2698
2746
  const status = this.#agent.status;
2699
2747
  const failed = status === "completed" && this.#agent.lastResult?.success === false;
@@ -2714,13 +2762,13 @@ var UI = class {
2714
2762
  if (this.#shouldShowInputArea()) this.#showInputArea();
2715
2763
  }
2716
2764
  }
2717
- /** Handle agent history change - re-render history list from agent.history */
2765
+ /** 处理 agent 历史变化 - 根据 agent.history 重新渲染历史列表 */
2718
2766
  #handleHistoryChange() {
2719
2767
  this.#renderHistory();
2720
2768
  }
2721
2769
  /**
2722
- * Handle agent activity - transient state for immediate UI feedback
2723
- * Activity events are NOT persisted in history, only used for header bar updates
2770
+ * 处理 agent 活动 - 用于即时 UI 反馈的瞬时状态
2771
+ * 活动事件不会持久化到历史中,仅用于头部栏更新
2724
2772
  */
2725
2773
  #handleActivity(activity) {
2726
2774
  switch (activity.type) {
@@ -2745,9 +2793,9 @@ var UI = class {
2745
2793
  }
2746
2794
  }
2747
2795
  /**
2748
- * Ask for user input (internal, called by agent via onAskUser).
2749
- * Rejects when `signal` aborts (task stopped or disposed), cleaning up the
2750
- * question card and pending state so the agent loop can settle.
2796
+ * 请求用户输入(内部方法,由 agent 通过 onAskUser 调用)。
2797
+ * `signal` 中止(任务被停止或销毁)时拒绝该请求,
2798
+ * 并清理问题卡片和挂起状态,以便 agent 循环能够收尾。
2751
2799
  */
2752
2800
  #askUser(question, signal) {
2753
2801
  if (this.#disposed) return Promise.reject(this.#createAbortError());
@@ -2777,9 +2825,11 @@ var UI = class {
2777
2825
  }
2778
2826
  });
2779
2827
  }
2828
+ /** 创建标准的中止异常(AbortError) */
2780
2829
  #createAbortError() {
2781
2830
  return new DOMException("The operation was aborted.", "AbortError");
2782
2831
  }
2832
+ /** 清空用户回答相关状态并移除临时卡片 */
2783
2833
  #clearQuestionState() {
2784
2834
  if (this.#userAnswerSignal && this.#userAnswerAbortHandler) this.#userAnswerSignal.removeEventListener("abort", this.#userAnswerAbortHandler);
2785
2835
  this.#userAnswerSignal = null;
@@ -2789,30 +2839,34 @@ var UI = class {
2789
2839
  this.#isWaitingForUserAnswer = false;
2790
2840
  this.#removeTempCards();
2791
2841
  }
2842
+ /** 拒绝挂起的用户问题(存在待回答问题时) */
2792
2843
  #rejectPendingQuestion() {
2793
2844
  const reject = this.#userAnswerRejecter;
2794
2845
  if (!reject) return;
2795
2846
  this.#clearQuestionState();
2796
2847
  reject(this.#createAbortError());
2797
2848
  }
2798
- /** Remove temporary question cards (only direct children for safety) */
2849
+ /** 移除临时问题卡片(为安全起见仅移除直接子节点) */
2799
2850
  #removeTempCards() {
2800
2851
  Array.from(this.#historySection.children).forEach((child) => {
2801
2852
  if (child.getAttribute("data-temp-card") === "true") child.remove();
2802
2853
  });
2803
2854
  this.#syncHistoryHeight();
2804
2855
  }
2856
+ /** 显示 UI(淡入 + 平移效果) */
2805
2857
  show() {
2806
2858
  this.wrapper.style.display = "block";
2807
2859
  this.wrapper.offsetHeight;
2808
2860
  this.wrapper.style.opacity = "1";
2809
2861
  this.wrapper.style.transform = "translateX(-50%) translateY(0)";
2810
2862
  }
2863
+ /** 隐藏 UI(淡出 + 下移效果) */
2811
2864
  hide() {
2812
2865
  this.wrapper.style.opacity = "0";
2813
2866
  this.wrapper.style.transform = "translateX(-50%) translateY(20px)";
2814
2867
  this.wrapper.style.display = "none";
2815
2868
  }
2869
+ /** 重置 UI 状态(拒绝挂起问题、清空状态文本、收起历史并显示输入框) */
2816
2870
  reset() {
2817
2871
  this.#rejectPendingQuestion();
2818
2872
  this.#statusText.textContent = this.#i18n.t("ui.ready");
@@ -2821,14 +2875,16 @@ var UI = class {
2821
2875
  this.#collapse();
2822
2876
  this.#showInputArea();
2823
2877
  }
2878
+ /** 展开历史弹窗(公开方法) */
2824
2879
  expand() {
2825
2880
  this.#expand();
2826
2881
  }
2882
+ /** 收起历史弹窗(公开方法) */
2827
2883
  collapse() {
2828
2884
  this.#collapse();
2829
2885
  }
2830
2886
  /**
2831
- * Dispose UI and clean up event listeners
2887
+ * 销毁 UI 并清理事件监听器
2832
2888
  */
2833
2889
  dispose() {
2834
2890
  if (this.#disposed) return;
@@ -2845,6 +2901,7 @@ var UI = class {
2845
2901
  this.#timers.clear();
2846
2902
  this.wrapper.remove();
2847
2903
  }
2904
+ /** 根据工具名称和参数生成"正在执行"提示文本 */
2848
2905
  #getToolExecutingText(toolName, args) {
2849
2906
  const a = args;
2850
2907
  switch (toolName) {
@@ -2859,14 +2916,14 @@ var UI = class {
2859
2916
  }
2860
2917
  }
2861
2918
  /**
2862
- * Action button handler: stop when running, close (dispose) when idle
2919
+ * 动作按钮处理:运行中则停止,空闲则关闭(销毁)
2863
2920
  */
2864
2921
  #handleActionButton() {
2865
2922
  if (this.#agent.status === "running") this.#agent.stop();
2866
2923
  else this.#agent.dispose();
2867
2924
  }
2868
2925
  /**
2869
- * Submit task
2926
+ * 提交任务
2870
2927
  */
2871
2928
  #submitTask() {
2872
2929
  const input = this.#taskInput.value.trim();
@@ -2880,7 +2937,7 @@ var UI = class {
2880
2937
  });
2881
2938
  }
2882
2939
  /**
2883
- * Handle user answer
2940
+ * 处理用户回答
2884
2941
  */
2885
2942
  #handleUserAnswer(input) {
2886
2943
  this.#removeTempCards();
@@ -2889,7 +2946,7 @@ var UI = class {
2889
2946
  resolve?.(input);
2890
2947
  }
2891
2948
  /**
2892
- * Show input area
2949
+ * 显示输入区域
2893
2950
  */
2894
2951
  #showInputArea(placeholder) {
2895
2952
  this.#taskInput.value = "";
@@ -2900,13 +2957,13 @@ var UI = class {
2900
2957
  }, 100);
2901
2958
  }
2902
2959
  /**
2903
- * Hide input area
2960
+ * 隐藏输入区域
2904
2961
  */
2905
2962
  #hideInputArea() {
2906
2963
  this.#inputSection.classList.add(UI_module_default.hidden);
2907
2964
  }
2908
2965
  /**
2909
- * Check if input area should be shown
2966
+ * 检查是否应显示输入区域
2910
2967
  */
2911
2968
  #shouldShowInputArea() {
2912
2969
  if (this.#isWaitingForUserAnswer) return true;
@@ -2915,6 +2972,7 @@ var UI = class {
2915
2972
  if (status === "completed" || status === "error" || status === "stopped") return this.#config.promptForNextTask ?? true;
2916
2973
  return false;
2917
2974
  }
2975
+ /** 创建 UI 根元素并挂载到 body,返回根容器 */
2918
2976
  #createWrapper() {
2919
2977
  const taskInputMaxLength = 1e3;
2920
2978
  const wrapper = document.createElement("div");
@@ -2933,9 +2991,9 @@ var UI = class {
2933
2991
  </div>
2934
2992
  </div>
2935
2993
  </div>
2936
- <div class="${UI_module_default.panel}">
2994
+ <div class="${UI_module_default.shell}">
2937
2995
  <div class="${UI_module_default.background}"></div>
2938
- <div class="${UI_module_default.panelInner}">
2996
+ <div class="${UI_module_default.shellInner}">
2939
2997
  <div class="${UI_module_default.header}">
2940
2998
  <div class="${UI_module_default.statusSection}">
2941
2999
  <div class="${UI_module_default.indicator} ${UI_module_default.thinking}"></div>
@@ -2965,6 +3023,7 @@ var UI = class {
2965
3023
  document.body.appendChild(wrapper);
2966
3024
  return wrapper;
2967
3025
  }
3026
+ /** 绑定所有 DOM 事件监听器(头部点击、展开按钮、动作按钮、回车提交等) */
2968
3027
  #setupEventListeners() {
2969
3028
  this.wrapper.querySelector(`.${UI_module_default.header}`).addEventListener("click", (e) => {
2970
3029
  if (e.target.closest(`.${UI_module_default.controlButton}`)) return;
@@ -2989,17 +3048,18 @@ var UI = class {
2989
3048
  e.stopPropagation();
2990
3049
  });
2991
3050
  }
3051
+ /** 在展开/收起状态之间切换 */
2992
3052
  #toggle() {
2993
3053
  if (this.#isExpanded) this.#collapse();
2994
3054
  else this.#expand();
2995
3055
  }
2996
3056
  /**
2997
- * Expand the history popup.
3057
+ * 展开历史弹窗。
2998
3058
  *
2999
- * `max-height` is measured in JS (not animated to a fixed CSS cap) so the
3000
- * transition distance always matches the real content height otherwise
3001
- * expand/collapse feel like different speeds (expand reaches its real
3002
- * height early and idles, collapse animates the full cap every time).
3059
+ * `max-height` JS 测量(而非动画到固定的 CSS 上限),因此
3060
+ * 过渡距离始终匹配真实内容高度否则展开/收起会给人
3061
+ * 速度不一致的感觉(展开会提前达到真实高度并停滞,
3062
+ * 而收起每次都按完整上限做动画)。
3003
3063
  */
3004
3064
  #expand() {
3005
3065
  this.#isExpanded = true;
@@ -3007,19 +3067,20 @@ var UI = class {
3007
3067
  this.#expandButton.textContent = "▲";
3008
3068
  this.#syncHistoryHeight();
3009
3069
  }
3070
+ /** 收起历史弹窗 */
3010
3071
  #collapse() {
3011
3072
  this.#isExpanded = false;
3012
3073
  this.wrapper.classList.remove(UI_module_default.expanded);
3013
3074
  this.#expandButton.textContent = "▼";
3014
3075
  this.#historySectionWrapper.style.maxHeight = "0px";
3015
3076
  }
3016
- /** Sync the history popup's max-height to its current (already capped) content height */
3077
+ /** 将历史弹窗的 max-height 同步为当前(已封顶的)内容高度 */
3017
3078
  #syncHistoryHeight() {
3018
3079
  if (!this.#isExpanded) return;
3019
3080
  this.#historySectionWrapper.style.maxHeight = `${this.#historySectionWrapper.scrollHeight}px`;
3020
3081
  }
3021
3082
  /**
3022
- * Start periodic header update loop
3083
+ * 启动周期性的头部更新循环
3023
3084
  */
3024
3085
  #startHeaderUpdateLoop() {
3025
3086
  this.#headerUpdateTimer = setInterval(() => {
@@ -3027,7 +3088,7 @@ var UI = class {
3027
3088
  }, 450);
3028
3089
  }
3029
3090
  /**
3030
- * Stop periodic header update loop
3091
+ * 停止周期性的头部更新循环
3031
3092
  */
3032
3093
  #stopHeaderUpdateLoop() {
3033
3094
  if (this.#headerUpdateTimer) {
@@ -3035,6 +3096,7 @@ var UI = class {
3035
3096
  this.#headerUpdateTimer = null;
3036
3097
  }
3037
3098
  }
3099
+ /** 设置一个受控延时定时器(销毁后自动忽略回调) */
3038
3100
  #setTimer(callback, delay) {
3039
3101
  const timer = setTimeout(() => {
3040
3102
  this.#timers.delete(timer);
@@ -3043,7 +3105,7 @@ var UI = class {
3043
3105
  this.#timers.add(timer);
3044
3106
  }
3045
3107
  /**
3046
- * Check if header needs update and trigger animation if not currently animating
3108
+ * 检查头部是否需要更新,若当前未在动画中则触发动画
3047
3109
  */
3048
3110
  #checkAndUpdateHeader() {
3049
3111
  if (!this.#pendingHeaderText || this.#isAnimating) return;
@@ -3056,7 +3118,7 @@ var UI = class {
3056
3118
  this.#animateTextChange(textToShow);
3057
3119
  }
3058
3120
  /**
3059
- * Animate text change with fade out/in effect
3121
+ * 以淡出/淡入效果动画切换文本
3060
3122
  */
3061
3123
  #animateTextChange(newText) {
3062
3124
  this.#isAnimating = true;
@@ -3071,24 +3133,26 @@ var UI = class {
3071
3133
  }, 300);
3072
3134
  }, 150);
3073
3135
  }
3136
+ /** 更新状态指示器的样式类 */
3074
3137
  #updateStatusIndicator(type) {
3075
3138
  const variant = type === "running" ? "thinking" : type === "executing" ? "tool_executing" : type === "retrying" ? "retry" : type;
3076
3139
  this.#indicator.className = UI_module_default.indicator;
3077
3140
  if (variant !== "idle" && variant !== "stopped") this.#indicator.classList.add(UI_module_default[variant]);
3078
3141
  }
3142
+ /** 将历史区域滚动到底部 */
3079
3143
  #scrollToBottom() {
3080
3144
  this.#setTimer(() => {
3081
3145
  this.#historySection.scrollTop = this.#historySection.scrollHeight;
3082
3146
  }, 0);
3083
3147
  }
3084
3148
  /**
3085
- * Render history directly from agent.history
3149
+ * 直接从 agent.history 渲染历史
3086
3150
  *
3087
- * Renders:
3088
- * 1. Task (first item, from agent.task)
3089
- * 2. Reflection cards (evaluation, memory, next_goal)
3090
- * 3. Tool execution with output
3091
- * 4. Observations
3151
+ * 渲染内容:
3152
+ * 1. 任务(第一项,来自 agent.task
3153
+ * 2. 反思卡片(评估、记忆、下一步目标)
3154
+ * 3. 工具执行及输出
3155
+ * 4. 观察
3092
3156
  */
3093
3157
  #renderHistory() {
3094
3158
  const items = [];
@@ -3100,6 +3164,7 @@ var UI = class {
3100
3164
  this.#scrollToBottom();
3101
3165
  this.#syncHistoryHeight();
3102
3166
  }
3167
+ /** 生成任务卡片 HTML */
3103
3168
  #createTaskCard(task) {
3104
3169
  return createCard({
3105
3170
  icon: "🎯",
@@ -3107,7 +3172,7 @@ var UI = class {
3107
3172
  type: "input"
3108
3173
  });
3109
3174
  }
3110
- /** Create cards for a history event */
3175
+ /** 为一条历史事件生成卡片 */
3111
3176
  #createHistoryCards(event) {
3112
3177
  const cards = [];
3113
3178
  const meta = event.type === "step" && event.stepIndex !== void 0 ? this.#i18n.t("ui.step", { number: (event.stepIndex + 1).toString() }) : void 0;
@@ -3150,7 +3215,7 @@ var UI = class {
3150
3215
  }));
3151
3216
  return cards;
3152
3217
  }
3153
- /** Create cards for an action */
3218
+ /** 为一个动作生成卡片 */
3154
3219
  #createActionCards(action, meta) {
3155
3220
  const cards = [];
3156
3221
  if (action.name === "done") {
@@ -3197,7 +3262,7 @@ var UI = class {
3197
3262
  //#endregion
3198
3263
  //#region src/llm/errors.ts
3199
3264
  /**
3200
- * Error types and error handling for LLM invocations.
3265
+ * LLM 调用相关的错误类型与错误处理。
3201
3266
  */
3202
3267
  var InvokeErrorTypes = {
3203
3268
  NETWORK_ERROR: "network_error",
@@ -3250,19 +3315,30 @@ var colorCodes = {
3250
3315
  red: 31,
3251
3316
  yellow: 33
3252
3317
  };
3253
- /** Format text with standard ANSI terminal color escape sequences. */
3318
+ /**
3319
+ * 使用标准 ANSI 终端颜色转义序列格式化文本。
3320
+ * 给文本添加标准的 ANSI 终端颜色转义序列,使文本在终端中以指定颜色显示。
3321
+ * @param text 需要上色的原始文本
3322
+ * @param color 终端颜色名称
3323
+ * @param bold 是否加粗显示,默认 false
3324
+ * @returns 带 ANSI 颜色转义序列的文本
3325
+ */
3254
3326
  function formatTerminalText(text, color, bold = false) {
3255
3327
  return `${bold ? "\x1B[1m" : ""}\u001B[${colorCodes[color]}m${text}\u001B[0m`;
3256
3328
  }
3257
3329
  //#endregion
3258
3330
  //#region src/llm/utils.ts
3259
3331
  /**
3260
- * Utility functions for LLM integration
3332
+ * LLM 集成的工具函数
3261
3333
  */
3262
3334
  var debug = console.debug.bind(console, formatTerminalText("[LLM]", "gray"));
3263
3335
  /**
3264
- * Convert Zod schema to OpenAI tool format
3265
- * Uses Zod 4 native z.toJSONSchema()
3336
+ * Zod schema 转换为 OpenAI 工具格式
3337
+ * 使用 Zod 4 原生 z.toJSONSchema()
3338
+ *
3339
+ * @param name - 工具名称
3340
+ * @param tool - 工具定义
3341
+ * @returns OpenAI 格式的工具定义
3266
3342
  */
3267
3343
  function zodToOpenAITool(name, tool) {
3268
3344
  return {
@@ -3275,17 +3351,21 @@ function zodToOpenAITool(name, tool) {
3275
3351
  };
3276
3352
  }
3277
3353
  /**
3278
- * Patch model specific parameters. Only patches known models.
3354
+ * 为特定模型打补丁。仅修补已知的模型。
3279
3355
  *
3280
3356
  * @purpose
3281
- * - Reconcile the differences in the parameter schema each model accepts.
3282
- * - Disable thinking/reasoning, or lower it to the minimum where a full disable is impossible.
3283
- * - Minimize returned tokens.
3284
- * - Raise temperature for known smaller models to improve auto-recovery odds.
3285
- * @note Honor temperature if explicitly set by the user
3357
+ * - 调和各模型所接受的参数 schema 之间的差异。
3358
+ * - 禁用思考/推理,或在无法完全禁用时将其降到最低。
3359
+ * - 尽量减少返回的 token。
3360
+ * - 对已知的较小模型提高 temperature,以提升自动恢复的几率。
3361
+ * @note 若用户显式设置了 temperature 则尊重该设置
3362
+ *
3363
+ * @todo 需要针对不同厂商的补丁。
3364
+ * 本地托管和第三方托管的模型可能有不同的 schema。
3286
3365
  *
3287
- * @todo Need vendor-specific patches.
3288
- * Local and 3rd-party hosted models may have different schema.
3366
+ * @param body - 请求体对象(会就地修改)
3367
+ * @param baseURL - 模型服务的基础 URL,用于识别 provider
3368
+ * @returns 修改后的请求体对象
3289
3369
  */
3290
3370
  function modelPatch(body, baseURL) {
3291
3371
  const model = body.model || "";
@@ -3402,19 +3482,25 @@ function modelPatch(body, baseURL) {
3402
3482
  return body;
3403
3483
  }
3404
3484
  /**
3405
- * check if a given model ID fits a specific model name
3485
+ * 检查给定的模型 ID 是否符合某个具体模型名称
3406
3486
  *
3407
3487
  * @note
3408
- * Different model providers may use different model IDs for the same model.
3409
- * For example, openai's `gpt-5.2` may called:
3488
+ * 不同的模型服务商可能对同一模型使用不同的模型 ID。
3489
+ * 例如,OpenAI `gpt-5.2` 可能被命名为:
3410
3490
  *
3411
3491
  * - `gpt-5.2-version`
3412
3492
  * - `gpt-5_2-date`
3413
3493
  * - `GPT-52-version-date`
3414
3494
  * - `openai/gpt-5.2-chat`
3415
3495
  *
3416
- * They should be treated as the same model.
3417
- * Normalize them to `gpt-52`
3496
+ * 它们应被视为同一模型。
3497
+ * 将其归一化为 `gpt-52`
3498
+ */
3499
+ /**
3500
+ * 归一化模型名称,将不同厂商对同一模型的命名统一为同一形式(如 `gpt-5.2` -> `gpt52`)
3501
+ *
3502
+ * @param modelName - 原始模型名称
3503
+ * @returns 归一化后的模型名称(小写、去掉前缀与特殊字符)
3418
3504
  */
3419
3505
  function normalizeModelName(modelName) {
3420
3506
  let normalizedName = modelName.toLowerCase();
@@ -3423,6 +3509,12 @@ function normalizeModelName(modelName) {
3423
3509
  normalizedName = normalizedName.replace(/\./g, "");
3424
3510
  return normalizedName;
3425
3511
  }
3512
+ /**
3513
+ * 根据 baseURL 判断服务提供商(目前仅识别 openrouter)
3514
+ *
3515
+ * @param baseURL - 模型服务的基础 URL
3516
+ * @returns 'openrouter' 或 undefined
3517
+ */
3426
3518
  function getProvider(baseURL) {
3427
3519
  if (!baseURL) return void 0;
3428
3520
  try {
@@ -3435,10 +3527,10 @@ function getProvider(baseURL) {
3435
3527
  //#endregion
3436
3528
  //#region src/llm/OpenAICompatibleClient.ts
3437
3529
  /**
3438
- * OpenAI Client implementation
3530
+ * OpenAI 客户端实现
3439
3531
  */
3440
3532
  /**
3441
- * Client for OpenAI compatible APIs
3533
+ * 兼容 OpenAI API 客户端
3442
3534
  */
3443
3535
  var OpenAICompatibleClient = class {
3444
3536
  config;
@@ -3447,6 +3539,16 @@ var OpenAICompatibleClient = class {
3447
3539
  this.config = config;
3448
3540
  this.fetch = config.customFetch;
3449
3541
  }
3542
+ /**
3543
+ * 调用 LLM 接口并执行模型请求的工具
3544
+ * 流程:转换工具定义 -> 构建并转换请求体 -> 调用 API -> 处理 HTTP 错误 -> 解析并校验响应 -> 执行工具
3545
+ *
3546
+ * @param messages - 对话消息列表
3547
+ * @param tools - 可用工具集合
3548
+ * @param abortSignal - 中止信号,用于取消请求
3549
+ * @param options - 可选的调用选项
3550
+ * @returns 工具调用结果
3551
+ */
3450
3552
  async invoke(messages, tools, abortSignal, options) {
3451
3553
  abortSignal?.throwIfAborted();
3452
3554
  const openaiTools = Object.entries(tools).map(([name, t]) => zodToOpenAITool(name, t));
@@ -3564,7 +3666,7 @@ var OpenAICompatibleClient = class {
3564
3666
  //#endregion
3565
3667
  //#region src/llm/LLM.ts
3566
3668
  /**
3567
- * LLM module
3669
+ * LLM 模块
3568
3670
  */
3569
3671
  var LLM = class extends EventTarget {
3570
3672
  config;
@@ -3575,9 +3677,9 @@ var LLM = class extends EventTarget {
3575
3677
  this.client = new OpenAICompatibleClient(this.config);
3576
3678
  }
3577
3679
  /**
3578
- * - call llm api *once*
3579
- * - invoke tool call *once*
3580
- * - return the result of the tool
3680
+ * - 调用一次 LLM API
3681
+ * - 调用一次工具
3682
+ * - 返回工具执行结果
3581
3683
  */
3582
3684
  async invoke(messages, tools, abortSignal, options) {
3583
3685
  return await withRetry(async () => this.client.invoke(messages, tools, abortSignal, options), {
@@ -3593,7 +3695,7 @@ var LLM = class extends EventTarget {
3593
3695
  }
3594
3696
  };
3595
3697
  /**
3596
- * Retry a function until it succeeds or reaches the maximum number of retries.
3698
+ * 重试某个函数,直到成功或达到最大重试次数。
3597
3699
  */
3598
3700
  async function withRetry(fn, settings) {
3599
3701
  let attempt = 0;
@@ -3609,6 +3711,12 @@ async function withRetry(fn, settings) {
3609
3711
  await new Promise((resolve) => setTimeout(resolve, 100));
3610
3712
  }
3611
3713
  }
3714
+ /**
3715
+ * 解析并校验 LLM 配置,填充默认值后返回完整配置
3716
+ *
3717
+ * @param config - 用户传入的 LLM 配置
3718
+ * @returns 解析后的完整配置
3719
+ */
3612
3720
  function parseLLMConfig(config) {
3613
3721
  if (!config.baseURL || !config.model) throw new Error("[PageAgent] LLM configuration required. Please provide: baseURL, model. See: https://alibaba.github.io/page-agent/docs/features/models");
3614
3722
  if (config.temperature !== void 0) console.warn("[PageAgent] LLMConfig.temperature is deprecated and will be removed in a future version. Use transformRequestBody to set it only for models you have verified accept it.");
@@ -3630,16 +3738,16 @@ var system_prompt_default = "You are an AI agent designed to operate in an itera
3630
3738
  //#region src/agent/utils/autoFixer.ts
3631
3739
  var log = console.log.bind(console, formatTerminalText("[autoFixer]", "yellow"));
3632
3740
  /**
3633
- * Normalize LLM response and fix common format issues.
3741
+ * 规范化 LLM 响应并修复常见的格式问题。
3634
3742
  *
3635
- * Handles:
3636
- * - No tool_calls but JSON in message.content (fallback)
3637
- * - Model returns action name as tool call instead of AgentOutput
3638
- * - Arguments wrapped as double JSON string
3639
- * - Nested function call format
3640
- * - Missing action field (fallback to wait)
3641
- * - Primitive action input for single-field tools (e.g. `{"click_element_by_index": 2}`)
3642
- * - etc.
3743
+ * 处理:
3744
+ * - 没有 tool_calls message.content 中含 JSON(回退)
3745
+ * - 模型将动作名作为工具调用返回而非 AgentOutput
3746
+ * - 参数被双重 JSON 字符串化
3747
+ * - 嵌套的函数调用格式
3748
+ * - 缺少 action 字段(回退为 wait
3749
+ * - 单字段工具的原始动作输入(如 `{"click_element_by_index": 2}`)
3750
+ * - 等等
3643
3751
  */
3644
3752
  function normalizeResponse(response, tools) {
3645
3753
  let resolvedArguments;
@@ -3698,11 +3806,11 @@ function normalizeResponse(response, tools) {
3698
3806
  };
3699
3807
  }
3700
3808
  /**
3701
- * Validate action against tool schemas. Provides clear error messages
3702
- * instead of letting the union schema produce unreadable errors.
3809
+ * 根据工具 schema 校验动作。提供清晰的错误信息,
3810
+ * 而不是让联合 schema 产生难以阅读的错误。
3703
3811
  *
3704
- * Also coerces primitive inputs for single-field tools:
3705
- * e.g. `{"click_element_by_index": 2}` → `{"click_element_by_index": {"index": 2}}`
3812
+ * 同时为单字段工具强制转换原始输入:
3813
+ * `{"click_element_by_index": 2}` → `{"click_element_by_index": {"index": 2}}`
3706
3814
  */
3707
3815
  function validateAction(action, tools) {
3708
3816
  if (typeof action !== "object" || action === null) return action;
@@ -3727,7 +3835,7 @@ function validateAction(action, tools) {
3727
3835
  return { [toolName]: result.data };
3728
3836
  }
3729
3837
  /**
3730
- * Safely parse JSON, return original input if not json.
3838
+ * 安全解析 JSON,如果不是 JSON 则返回原始输入。
3731
3839
  */
3732
3840
  function safeJsonParse(input) {
3733
3841
  if (typeof input === "string") try {
@@ -3738,9 +3846,9 @@ function safeJsonParse(input) {
3738
3846
  return input;
3739
3847
  }
3740
3848
  /**
3741
- * Extract and parse JSON from a string.
3742
- * - Treat content between the first `{` and the last `}` as JSON.
3743
- * - Try to parse that content as JSON and return the parsed value (object/array/primitive) if successful, otherwise return null.
3849
+ * 从字符串中提取并解析 JSON
3850
+ * - 将第一个 `{` 与最后一个 `}` 之间的内容视为 JSON
3851
+ * - 尝试将该内容解析为 JSON 并返回解析后的值(对象/数组/原始值),成功则返回,否则返回 null
3744
3852
  */
3745
3853
  function retrieveJsonFromString(str) {
3746
3854
  try {
@@ -3754,8 +3862,8 @@ function retrieveJsonFromString(str) {
3754
3862
  //#endregion
3755
3863
  //#region src/agent/utils/index.ts
3756
3864
  /**
3757
- * Wait for `seconds`. If a `signal` is provided, the wait is cancellable:
3758
- * aborting rejects with the signal's reason (an `AbortError`).
3865
+ * 等待 `seconds` 秒。若提供了 `signal`,则等待可被取消:
3866
+ * 中止时会以 signal reason(一个 `AbortError`)reject。
3759
3867
  */
3760
3868
  async function waitFor(seconds, signal) {
3761
3869
  if (!signal) {
@@ -3795,8 +3903,8 @@ var _global = globalThis;
3795
3903
  if (!_global.__PAGE_AGENT_IDS__) _global.__PAGE_AGENT_IDS__ = [];
3796
3904
  var ids = _global.__PAGE_AGENT_IDS__;
3797
3905
  /**
3798
- * Generate a random ID.
3799
- * @note Unique within this window.
3906
+ * 生成一个随机 ID
3907
+ * @note 在当前窗口内唯一。
3800
3908
  */
3801
3909
  function uid() {
3802
3910
  const id = randomID(ids);
@@ -3804,7 +3912,7 @@ function uid() {
3804
3912
  return id;
3805
3913
  }
3806
3914
  var llmsTxtCache = /* @__PURE__ */ new Map();
3807
- /** Fetch /llms.txt for a URL's origin. Cached per origin, `null` = tried and not found. */
3915
+ /** 获取某个 URL 源的 /llms.txt。按源缓存,`null` 表示已尝试过但未找到。 */
3808
3916
  async function fetchLlmsTxt(url) {
3809
3917
  let origin;
3810
3918
  try {
@@ -3834,10 +3942,10 @@ async function fetchLlmsTxt(url) {
3834
3942
  return result;
3835
3943
  }
3836
3944
  /**
3837
- * Simple assertion function that throws an error if the condition is falsy
3838
- * @param condition - The condition to assert
3839
- * @param message - Optional error message
3840
- * @throws Error if condition is falsy
3945
+ * 简单的断言函数:条件为假时抛出错误
3946
+ * @param condition - 要断言的条件
3947
+ * @param message - 可选的错误信息
3948
+ * @throws 条件为假时抛出错误
3841
3949
  */
3842
3950
  function assert(condition, message, silent) {
3843
3951
  if (!condition) {
@@ -3847,7 +3955,7 @@ function assert(condition, message, silent) {
3847
3955
  }
3848
3956
  }
3849
3957
  /**
3850
- * Suppress errors from a function.
3958
+ * 抑制函数产生的错误。
3851
3959
  */
3852
3960
  async function suppress(fn) {
3853
3961
  try {
@@ -3860,15 +3968,16 @@ async function suppress(fn) {
3860
3968
  //#endregion
3861
3969
  //#region src/agent/tools/index.ts
3862
3970
  /**
3863
- * Internal tools for PageAgent.
3864
- * @note Adapted from browser-use
3971
+ * PageAgent 的内部工具。
3972
+ * @note 改编自 browser-use
3865
3973
  */
3974
+ /** 创建一个工具定义(直接透传 options) */
3866
3975
  function tool(options) {
3867
3976
  return options;
3868
3977
  }
3869
3978
  /**
3870
- * Internal tools for PageAgent.
3871
- * Note: Using any to allow different parameter types for each tool
3979
+ * PageAgent 的内部工具。
3980
+ * 注:使用 any 以允许每个工具拥有不同的参数类型
3872
3981
  */
3873
3982
  var tools = /* @__PURE__ */ new Map();
3874
3983
  tools.set("done", tool({
@@ -3929,7 +4038,7 @@ tools.set("select_dropdown_option", tool({
3929
4038
  }
3930
4039
  }));
3931
4040
  /**
3932
- * @note Reference from browser-use
4041
+ * @note 参考自 browser-use
3933
4042
  */
3934
4043
  tools.set("scroll", tool({
3935
4044
  description: "Scroll vertically. Without index: scrolls the document. With index: scrolls the container at that index (or its nearest scrollable ancestor). Use index of a data-scrollable element to scroll a specific area.",
@@ -3947,7 +4056,7 @@ tools.set("scroll", tool({
3947
4056
  }
3948
4057
  }));
3949
4058
  /**
3950
- * @todo Tables need a dedicated parser to extract structured data. This tool is useless.
4059
+ * @todo 表格需要专门的解析器来提取结构化数据。这个工具有点鸡肋。
3951
4060
  */
3952
4061
  tools.set("scroll_horizontally", tool({
3953
4062
  description: "Scroll horizontally. Without index: scrolls the document. With index: scrolls the container at that index (or its nearest scrollable ancestor). Use index of a data-scrollable element to scroll a specific area.",
@@ -3972,76 +4081,84 @@ tools.set("execute_javascript", tool({
3972
4081
  //#endregion
3973
4082
  //#region src/agent/AgentRuntime.ts
3974
4083
  /**
3975
- * AI agent for browser automation.
4084
+ * 用于浏览器自动化的 AI 智能体。
3976
4085
  *
3977
4086
  * @remarks
3978
- * ## Re-act Agent Loop
3979
- * - step
3980
- * - observe (gather information about current environment and context)
3981
- * - think (LLM calling)
3982
- * - reflection (evaluate history, generate memory, short-term planning)
3983
- * - action (give the action to approach the next goal)
3984
- * - act (execute the action)
3985
- * - loop
4087
+ * ## 反应式 Agent 循环
4088
+ * - 步骤
4089
+ * - 观察(收集当前环境与上下文信息)
4090
+ * - 思考(调用 LLM
4091
+ * - 反思(评估历史、生成记忆、短期规划)
4092
+ * - 行动(给出接近下一个目标的动作)
4093
+ * - 执行(执行动作)
4094
+ * - 循环
3986
4095
  *
3987
- * ## Event System
3988
- * - `statuschange` - Agent status transitions (idle → running → completed/error/stopped)
3989
- * - `historychange` - History events updated (persistent, part of agent memory)
3990
- * - `activity` - Real-time activity feedback (transient, for UI only)
3991
- * - `dispose` - Agent cleanup triggered
4096
+ * ## 事件系统
4097
+ * - `statuschange` - Agent 状态变更(idle → running → completed/error/stopped
4098
+ * - `historychange` - 历史事件更新(持久化,属于 Agent 记忆的一部分)
4099
+ * - `activity` - 实时活动反馈(瞬态,仅用于 UI
4100
+ * - `dispose` - 触发 Agent 清理
3992
4101
  *
3993
- * ## Information Streams
3994
- * 1. **History Events** (`history` array)
3995
- * - Persistent event stream that forms agent's memory
3996
- * - Included in LLM context across steps
3997
- * - Types: steps, observations, user takeovers, llm errors
4102
+ * ## 信息流
4103
+ * 1. **历史事件**(`history` 数组)
4104
+ * - 构成 Agent 记忆的持久事件流
4105
+ * - 跨步骤包含在 LLM 上下文中
4106
+ * - 类型:步骤、观察、用户接管、LLM 错误
3998
4107
  *
3999
- * 2. **Activity Events** (via `activity` event)
4000
- * - Transient UI feedback during task execution
4001
- * - NOT included in LLM context
4002
- * - Types: thinking, executing, executed, retrying, error
4108
+ * 2. **活动事件**(通过 `activity` 事件)
4109
+ * - 任务执行期间的瞬时 UI 反馈
4110
+ * - 不包含在 LLM 上下文中
4111
+ * - 类型:thinkingexecutingexecutedretryingerror
4003
4112
  */
4004
4113
  var AgentRuntime = class extends EventTarget {
4114
+ /** Agent 唯一 ID */
4005
4115
  id = uid();
4116
+ /** 合并后的 Agent 配置(含最大步数上限) */
4006
4117
  config;
4118
+ /** 内部工具集合(按工具名索引) */
4007
4119
  tools;
4008
- /** BrowserController for DOM operations */
4120
+ /** 用于 DOM 操作的 BrowserController */
4009
4121
  browserController;
4122
+ /** 当前任务描述 */
4010
4123
  task = "";
4124
+ /** 当前任务 ID */
4011
4125
  taskId = "";
4012
- /** History events */
4126
+ /** 历史事件 */
4013
4127
  history = [];
4014
- /** Whether this agent has been disposed */
4128
+ /** Agent 是否已被销毁 */
4015
4129
  disposed = false;
4016
4130
  /**
4017
- * Called when the agent needs to ask the user questions.
4018
- * If unset, the `ask_user` tool will be disabled.
4019
- * Implementations should reject the promise when `signal` aborts.
4131
+ * Agent 需要向用户提问时调用。
4132
+ * 若未设置,`ask_user` 工具将被禁用。
4133
+ * 实现应在 `signal` 中止时 reject Promise。
4020
4134
  * @example onAskUser: (q) => window.prompt(q) || ''
4021
4135
  */
4022
4136
  onAskUser;
4137
+ /** 当前 Agent 状态 */
4023
4138
  #status = "idle";
4139
+ /** LLM 实例(负责模型调用) */
4024
4140
  #llm;
4025
4141
  /**
4026
- * Task cancellation primitive: its signal reaches the LLM fetch, tools
4027
- * (via `ctx.signal`) and async callbacks. Aborted only by `stop`/`dispose`
4028
- * (during a task) or task setup, always WITHOUT a reason so `signal.reason`
4029
- * stays a standard `AbortError`.
4142
+ * 任务取消原语:其 signal 会传递给 LLM fetch、工具(通过 `ctx.signal`)和异步回调。
4143
+ * 仅由 `stop`/`dispose`(任务进行中)或任务初始化时中止,且始终不带 reason,
4144
+ * 这样 `signal.reason` 保持为标准的 `AbortError`。
4030
4145
  */
4031
4146
  #abortController = new AbortController();
4147
+ /** 本轮任务收集的观察消息(暂存,稍后统一写入历史) */
4032
4148
  #observations = [];
4033
- /** Resolves when the current run has fully settled. Awaited by `stop()`. */
4149
+ /** 当前一次运行完全结束时 resolve。由 `stop()` 等待。 */
4034
4150
  #running = Promise.resolve();
4035
4151
  #lastResult = null;
4036
- /** internal states during a single task execution */
4152
+ /** 单次任务执行期间的内部状态 */
4037
4153
  #states = {
4038
- /** Accumulated wait time in seconds */
4154
+ /** 累计等待时间(秒) */
4039
4155
  totalWaitTime: 0,
4040
- /** For detecting navigation */
4156
+ /** 用于检测页面导航 */
4041
4157
  lastURL: "",
4042
- /** Browser state */
4158
+ /** 浏览器状态 */
4043
4159
  browserState: null
4044
4160
  };
4161
+ /** 构造函数:初始化配置、LLM、工具集,并注册重试事件监听与注入自定义工具 */
4045
4162
  constructor(config) {
4046
4163
  super();
4047
4164
  this.config = {
@@ -4080,31 +4197,31 @@ var AgentRuntime = class extends EventTarget {
4080
4197
  }
4081
4198
  if (!this.config.experimentalScriptExecutionTool) this.tools.delete("execute_javascript");
4082
4199
  }
4083
- /** Get current agent status */
4200
+ /** 获取当前 Agent 状态 */
4084
4201
  get status() {
4085
4202
  return this.#status;
4086
4203
  }
4087
- /** Result of the most recent run, or `null` before the first run completes. */
4204
+ /** 最近一次运行的结果,首次运行完成前为 `null`。 */
4088
4205
  get lastResult() {
4089
4206
  return this.#lastResult;
4090
4207
  }
4091
- /** Emit statuschange event */
4208
+ /** 触发 statuschange 事件 */
4092
4209
  #emitStatusChange() {
4093
4210
  this.dispatchEvent(new Event("statuschange"));
4094
4211
  }
4095
- /** Emit historychange event */
4212
+ /** 触发 historychange 事件 */
4096
4213
  #emitHistoryChange(pushHistoricalEvent) {
4097
4214
  if (pushHistoricalEvent) this.history.push(pushHistoricalEvent);
4098
4215
  this.dispatchEvent(new Event("historychange"));
4099
4216
  }
4100
4217
  /**
4101
- * Emit activity event - for transient UI feedback
4102
- * @param activity - Current agent activity
4218
+ * 触发 activity 事件 - 用于瞬态的 UI 反馈
4219
+ * @param activity - 当前的 Agent 活动
4103
4220
  */
4104
4221
  #emitActivity(activity) {
4105
4222
  this.dispatchEvent(new CustomEvent("activity", { detail: activity }));
4106
4223
  }
4107
- /** Update status and emit event */
4224
+ /** 更新状态并触发事件 */
4108
4225
  #setStatus(status) {
4109
4226
  if (this.#status !== status) {
4110
4227
  this.#status = status;
@@ -4112,17 +4229,17 @@ var AgentRuntime = class extends EventTarget {
4112
4229
  }
4113
4230
  }
4114
4231
  /**
4115
- * Push an observation message to the history event stream.
4116
- * This will be visible in <agent_history> and remain persistent in memory across steps.
4232
+ * 向历史事件流推送一条观察消息。
4233
+ * 它会出现在 <agent_history> 中,并在跨步骤的记忆中保持持久。
4117
4234
  * @experimental @internal
4118
- * @note history change will be emitted before next step starts
4235
+ * @note 历史变更会在下一步开始前触发
4119
4236
  */
4120
4237
  pushObservation(content) {
4121
4238
  this.#observations.push(content);
4122
4239
  }
4123
4240
  /**
4124
- * Stop the current task and wait until the run has fully settled (including lifecycle hooks).
4125
- * @note never await .stop() in a lifecycle hook.
4241
+ * 停止当前任务,并等待运行完全结束(包括生命周期钩子)。
4242
+ * @note 切勿在生命周期钩子中 await .stop()
4126
4243
  */
4127
4244
  async stop() {
4128
4245
  if (this.#status !== "running") return;
@@ -4130,8 +4247,8 @@ var AgentRuntime = class extends EventTarget {
4130
4247
  await this.#running;
4131
4248
  }
4132
4249
  /**
4133
- * external errors (pre-checks/config/hooks) will threw;
4134
- * agent errors will be caught and added to history, and return a failed result
4250
+ * 外部错误(前置检查/配置/钩子)会直接抛出;
4251
+ * Agent 内部错误会被捕获并加入历史,同时返回失败结果
4135
4252
  */
4136
4253
  async execute(task) {
4137
4254
  if (this.disposed) throw new Error("PageAgent has been disposed. Create a new instance.");
@@ -4289,13 +4406,13 @@ var AgentRuntime = class extends EventTarget {
4289
4406
  }
4290
4407
  }
4291
4408
  /**
4292
- * Merge all tools into a single MacroTool with the following input:
4409
+ * 将所有工具合并为单个 MacroTool,其输入如下:
4293
4410
  * - thinking: string
4294
4411
  * - evaluation_previous_goal: string
4295
4412
  * - memory: string
4296
4413
  * - next_goal: string
4297
4414
  * - action: { toolName: toolInput }
4298
- * where action must be selected from tools defined in this.tools
4415
+ * 其中 action 必须从 this.tools 中定义的工具中选择
4299
4416
  */
4300
4417
  #packMacroTool() {
4301
4418
  const tools = this.tools;
@@ -4354,7 +4471,7 @@ var AgentRuntime = class extends EventTarget {
4354
4471
  };
4355
4472
  }
4356
4473
  /**
4357
- * Get system prompt, dynamically replace language settings based on configured language
4474
+ * 获取系统提示词,根据配置的语言动态替换语言设置
4358
4475
  */
4359
4476
  #getSystemPrompt() {
4360
4477
  if (this.config.customSystemPrompt) return this.config.customSystemPrompt;
@@ -4362,7 +4479,7 @@ var AgentRuntime = class extends EventTarget {
4362
4479
  return system_prompt_default.replace(/Default working language: \*\*.*?\*\*/, `Default working language: **${targetLanguage}**`);
4363
4480
  }
4364
4481
  /**
4365
- * Get instructions from config
4482
+ * 从配置中获取指令
4366
4483
  */
4367
4484
  async #getInstructions() {
4368
4485
  const { instructions, experimentalLlmsTxt } = this.config;
@@ -4384,8 +4501,8 @@ var AgentRuntime = class extends EventTarget {
4384
4501
  return result;
4385
4502
  }
4386
4503
  /**
4387
- * Generate system observations before each step
4388
- * @todo console error
4504
+ * 在每一步之前生成系统观察
4505
+ * @todo 控制台错误
4389
4506
  */
4390
4507
  async #handleObservations(step) {
4391
4508
  if (this.#states.totalWaitTime >= 3) this.pushObservation(`You have waited ${this.#states.totalWaitTime} seconds accumulatively. DO NOT wait any longer unless you have a good reason.`);
@@ -4415,6 +4532,9 @@ var AgentRuntime = class extends EventTarget {
4415
4532
  this.#emitHistoryChange();
4416
4533
  }
4417
4534
  }
4535
+ /**
4536
+ * 组装发给 LLM 的完整用户提示词(含指令、Agent 状态、历史、浏览器状态)
4537
+ */
4418
4538
  async #assembleUserPrompt() {
4419
4539
  const browserState = this.#states.browserState;
4420
4540
  let prompt = "";
@@ -4457,6 +4577,7 @@ var AgentRuntime = class extends EventTarget {
4457
4577
  prompt += "</browser_state>\n\n";
4458
4578
  return prompt;
4459
4579
  }
4580
+ /** 销毁 Agent:中止任务、释放浏览器控制器,并触发 dispose 事件(一次性) */
4460
4581
  dispose() {
4461
4582
  if (this.disposed) return;
4462
4583
  this.disposed = true;
@@ -4479,8 +4600,13 @@ var AgentRuntime = class extends EventTarget {
4479
4600
  };
4480
4601
  //#endregion
4481
4602
  //#region src/agent/MyPageAgent.ts
4603
+ /**
4604
+ * 完整页面智能体:组合了 AgentRuntime、BrowserController 与 UI
4605
+ */
4482
4606
  var MyPageAgent = class extends AgentRuntime {
4607
+ /** UI 实例(用于用户交互与反馈) */
4483
4608
  ui;
4609
+ /** 构造函数:创建浏览器控制器、父类运行时与 UI 实例 */
4484
4610
  constructor(config) {
4485
4611
  const browserController = new BrowserController({
4486
4612
  ...config,
@@ -4499,6 +4625,11 @@ var MyPageAgent = class extends AgentRuntime {
4499
4625
  };
4500
4626
  //#endregion
4501
4627
  //#region src/index.ts
4628
+ /**
4629
+ * 创建智能体实例的快捷函数,内部直接实例化 MyPageAgent。
4630
+ * @param config 智能体的配置对象
4631
+ * @returns 创建好的 MyPageAgent 实例
4632
+ */
4502
4633
  function createAgent(config) {
4503
4634
  return new MyPageAgent(config);
4504
4635
  }