@coolkiller007/my-page-agent 0.1.15 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +35 -3
- package/dist/index.js +263 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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_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); }})();
|
|
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_194hg_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_194hg_1 {\n from {\n transform: translateX(-100%);\n }\n to {\n transform: translateX(100%);\n }\n}\n\n/* 状态条 + 输入区的外层容器;.background 光效挂在这一层,.shellInner 负责裁出圆角 */\n._shell_194hg_57 {\n position: relative;\n width: 100%;\n}\n\n._background_194hg_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_194hg_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_194hg_1 2s linear infinite;\n animation-delay: 1s;\n }\n}\n\n/* 可视区域:靠 overflow:hidden + border-radius 统一裁角,\n * header 单独存在(运行中输入区隐藏)或 header+输入区一起存在时,四角都自动是圆的,\n * 不用再像以前那样给 header 写一条\"输入区隐藏时补圆角\"的特判规则。 */\n._shellInner_194hg_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_194hg_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_194hg_140 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-height: 24px; /* 确保垂直居中 */\n\n ._indicator_194hg_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_194hg_156 {\n background: rgb(57, 182, 255);\n animation: _pulse_194hg_1 0.8s ease-in-out infinite;\n }\n\n &._tool_executing_194hg_161 {\n background: rgb(189, 69, 251);\n animation: _pulse_194hg_1 0.6s ease-in-out infinite;\n }\n\n &._retry_194hg_166 {\n background: rgb(255, 214, 0);\n animation: _retryPulse_194hg_1 1s ease-in-out infinite;\n }\n\n /* 静止状态 - 无动画 */\n &._completed_194hg_172,\n &._input_194hg_173,\n &._output_194hg_174 {\n background: rgb(34, 197, 94);\n animation: none;\n }\n\n &._error_194hg_179 {\n background: rgb(239, 68, 68);\n animation: none;\n }\n }\n\n ._statusText_194hg_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_194hg_197 {\n animation: _statusTextFadeOut_194hg_1 0.3s ease forwards;\n }\n\n &._fadeIn_194hg_201 {\n animation: _statusTextFadeIn_194hg_1 0.3s ease forwards;\n }\n }\n }\n\n ._controls_194hg_207 {\n display: flex;\n align-items: center;\n gap: 4px;\n\n ._controlButton_194hg_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_194hg_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_194hg_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_194hg_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_194hg_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_194hg_1._expanded_194hg_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_194hg_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_194hg_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_194hg_172,\n &._input_194hg_173,\n &._output_194hg_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_194hg_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_194hg_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_194hg_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_194hg_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_194hg_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_194hg_1 2s ease-in-out infinite;\n }\n\n ._historyContent_194hg_410 {\n ._statusIcon_194hg_411 {\n font-size: 16px;\n animation: _celebrate_194hg_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_194hg_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_194hg_410 {\n ._statusIcon_194hg_411 {\n font-size: 16px;\n filter: drop-shadow(0 2px 4px rgba(239, 68, 68, 0.5));\n }\n }\n }\n\n ._historyContent_194hg_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_194hg_411 {\n font-size: 12px;\n flex-shrink: 0;\n line-height: 1;\n transition: all 0.3s ease;\n }\n\n ._reflectionLines_194hg_470 {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n }\n\n ._historyMeta_194hg_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_194hg_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_194hg_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_194hg_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_194hg_1 {\n 0% {\n left: -100%;\n }\n 100% {\n left: 100%;\n }\n}\n\n/* 输入区域样式 */\n._inputSectionWrapper_194hg_547 {\n width: 100%;\n margin: 0 auto;\n\n overflow: hidden;\n max-height: 0; /* 由 JS 同步为真实内容高度(含附件条、错误提示),见 #syncInputHeight */\n\n transition: max-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_194hg_563 {\n max-height: 0;\n }\n\n ._inputSection_194hg_547 {\n position: relative;\n display: flex;\n align-items: center;\n height: var(--input-height);\n padding: 8px; /* 与上方状态条 padding 保持一致 */\n\n ._attachButton_194hg_574 {\n position: absolute;\n right: 14px;\n bottom: 12px;\n z-index: 1;\n width: 26px;\n height: 26px;\n border: none;\n border-radius: 4px;\n background: transparent;\n color: rgba(255, 255, 255, 0.85);\n font-size: 13px;\n line-height: 1;\n cursor: pointer;\n }\n\n ._taskInput_194hg_590 {\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 40px 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 ._attachmentsBar_194hg_618 {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 8px 0;\n\n &:empty {\n display: none;\n }\n }\n\n ._attachmentChip_194hg_629 {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-width: 160px;\n padding: 3px 4px 3px 8px;\n border-radius: 10px;\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.85);\n font-size: 12px;\n white-space: nowrap;\n\n span {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n }\n\n ._attachmentChipRemove_194hg_647 {\n flex-shrink: 0;\n border: none;\n background: transparent;\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n font-size: 13px;\n line-height: 1;\n padding: 0 4px;\n\n &:hover {\n color: rgba(255, 255, 255, 0.95);\n }\n }\n\n ._attachError_194hg_662 {\n padding: 4px 8px 0;\n color: rgb(255, 138, 138);\n font-size: 12px;\n\n &:empty {\n display: none;\n padding: 0;\n }\n }\n\n ._fileInput_194hg_673 {\n display: none;\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
|
|
@@ -2480,6 +2480,11 @@ var locales = {
|
|
|
2480
2480
|
expand: "Expand history",
|
|
2481
2481
|
collapse: "Collapse history",
|
|
2482
2482
|
step: "Step {{number}}",
|
|
2483
|
+
attachButtonTitle: "Attach files",
|
|
2484
|
+
attachTooMany: "You can attach up to {{max}} files",
|
|
2485
|
+
attachTooLarge: "\"{{name}}\" exceeds the {{maxMB}}MB size limit",
|
|
2486
|
+
attachUnsupportedType: "\"{{name}}\" is not a supported file type",
|
|
2487
|
+
attachmentsLabel: "📎 Attachments: {{names}}",
|
|
2483
2488
|
tools: {
|
|
2484
2489
|
clicking: "Clicking element [{{index}}]...",
|
|
2485
2490
|
inputting: "Inputting text to element [{{index}}]...",
|
|
@@ -2522,6 +2527,11 @@ var locales = {
|
|
|
2522
2527
|
expand: "展开历史",
|
|
2523
2528
|
collapse: "收起历史",
|
|
2524
2529
|
step: "步骤 {{number}}",
|
|
2530
|
+
attachButtonTitle: "添加附件",
|
|
2531
|
+
attachTooMany: "最多可添加 {{max}} 个文件",
|
|
2532
|
+
attachTooLarge: "\"{{name}}\" 超过 {{maxMB}}MB 大小限制",
|
|
2533
|
+
attachUnsupportedType: "\"{{name}}\" 不是支持的文件类型",
|
|
2534
|
+
attachmentsLabel: "📎 附件: {{names}}",
|
|
2525
2535
|
tools: {
|
|
2526
2536
|
clicking: "正在点击元素 [{{index}}]...",
|
|
2527
2537
|
inputting: "正在输入文本到元素 [{{index}}]...",
|
|
@@ -2555,8 +2565,8 @@ var locales = {
|
|
|
2555
2565
|
var I18n = class {
|
|
2556
2566
|
language;
|
|
2557
2567
|
translations;
|
|
2558
|
-
constructor(language = "
|
|
2559
|
-
this.language = language in locales ? language : "
|
|
2568
|
+
constructor(language = "zh-CN") {
|
|
2569
|
+
this.language = language in locales ? language : "zh-CN";
|
|
2560
2570
|
this.translations = locales[this.language];
|
|
2561
2571
|
}
|
|
2562
2572
|
t(key, params) {
|
|
@@ -2597,49 +2607,55 @@ function escapeHtml(text) {
|
|
|
2597
2607
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2598
2608
|
}
|
|
2599
2609
|
var UI_module_default = {
|
|
2600
|
-
wrapper: "
|
|
2601
|
-
shell: "
|
|
2602
|
-
background: "
|
|
2603
|
-
"mask-running": "_mask-
|
|
2604
|
-
shellInner: "
|
|
2605
|
-
header: "
|
|
2606
|
-
pulse: "
|
|
2607
|
-
retryPulse: "
|
|
2608
|
-
statusTextFadeOut: "
|
|
2609
|
-
statusTextFadeIn: "
|
|
2610
|
-
statusSection: "
|
|
2611
|
-
indicator: "
|
|
2612
|
-
thinking: "
|
|
2613
|
-
tool_executing: "
|
|
2614
|
-
retry: "
|
|
2615
|
-
completed: "
|
|
2616
|
-
input: "
|
|
2617
|
-
output: "
|
|
2618
|
-
error: "
|
|
2619
|
-
statusText: "
|
|
2620
|
-
fadeOut: "
|
|
2621
|
-
fadeIn: "
|
|
2622
|
-
controls: "
|
|
2623
|
-
controlButton: "
|
|
2624
|
-
stopButton: "
|
|
2625
|
-
historySectionWrapper: "
|
|
2626
|
-
shimmer: "
|
|
2627
|
-
celebrate: "
|
|
2628
|
-
expanded: "
|
|
2629
|
-
historySection: "
|
|
2630
|
-
historyItem: "
|
|
2631
|
-
observation: "
|
|
2632
|
-
question: "
|
|
2633
|
-
doneSuccess: "
|
|
2634
|
-
historyContent: "
|
|
2635
|
-
statusIcon: "
|
|
2636
|
-
doneError: "
|
|
2637
|
-
reflectionLines: "
|
|
2638
|
-
historyMeta: "
|
|
2639
|
-
inputSectionWrapper: "
|
|
2640
|
-
hidden: "
|
|
2641
|
-
inputSection: "
|
|
2642
|
-
|
|
2610
|
+
wrapper: "_wrapper_194hg_1",
|
|
2611
|
+
shell: "_shell_194hg_57",
|
|
2612
|
+
background: "_background_194hg_57",
|
|
2613
|
+
"mask-running": "_mask-running_194hg_1",
|
|
2614
|
+
shellInner: "_shellInner_194hg_57",
|
|
2615
|
+
header: "_header_194hg_124",
|
|
2616
|
+
pulse: "_pulse_194hg_1",
|
|
2617
|
+
retryPulse: "_retryPulse_194hg_1",
|
|
2618
|
+
statusTextFadeOut: "_statusTextFadeOut_194hg_1",
|
|
2619
|
+
statusTextFadeIn: "_statusTextFadeIn_194hg_1",
|
|
2620
|
+
statusSection: "_statusSection_194hg_140",
|
|
2621
|
+
indicator: "_indicator_194hg_147",
|
|
2622
|
+
thinking: "_thinking_194hg_156",
|
|
2623
|
+
tool_executing: "_tool_executing_194hg_161",
|
|
2624
|
+
retry: "_retry_194hg_166",
|
|
2625
|
+
completed: "_completed_194hg_172",
|
|
2626
|
+
input: "_input_194hg_173",
|
|
2627
|
+
output: "_output_194hg_174",
|
|
2628
|
+
error: "_error_194hg_179",
|
|
2629
|
+
statusText: "_statusText_194hg_185",
|
|
2630
|
+
fadeOut: "_fadeOut_194hg_197",
|
|
2631
|
+
fadeIn: "_fadeIn_194hg_201",
|
|
2632
|
+
controls: "_controls_194hg_207",
|
|
2633
|
+
controlButton: "_controlButton_194hg_212",
|
|
2634
|
+
stopButton: "_stopButton_194hg_231",
|
|
2635
|
+
historySectionWrapper: "_historySectionWrapper_194hg_268",
|
|
2636
|
+
shimmer: "_shimmer_194hg_1",
|
|
2637
|
+
celebrate: "_celebrate_194hg_1",
|
|
2638
|
+
expanded: "_expanded_194hg_290",
|
|
2639
|
+
historySection: "_historySection_194hg_268",
|
|
2640
|
+
historyItem: "_historyItem_194hg_309",
|
|
2641
|
+
observation: "_observation_194hg_363",
|
|
2642
|
+
question: "_question_194hg_368",
|
|
2643
|
+
doneSuccess: "_doneSuccess_194hg_374",
|
|
2644
|
+
historyContent: "_historyContent_194hg_410",
|
|
2645
|
+
statusIcon: "_statusIcon_194hg_411",
|
|
2646
|
+
doneError: "_doneError_194hg_420",
|
|
2647
|
+
reflectionLines: "_reflectionLines_194hg_470",
|
|
2648
|
+
historyMeta: "_historyMeta_194hg_477",
|
|
2649
|
+
inputSectionWrapper: "_inputSectionWrapper_194hg_547",
|
|
2650
|
+
hidden: "_hidden_194hg_563",
|
|
2651
|
+
inputSection: "_inputSection_194hg_547",
|
|
2652
|
+
attachButton: "_attachButton_194hg_574",
|
|
2653
|
+
taskInput: "_taskInput_194hg_590",
|
|
2654
|
+
attachmentsBar: "_attachmentsBar_194hg_618",
|
|
2655
|
+
attachmentChip: "_attachmentChip_194hg_629",
|
|
2656
|
+
attachmentChipRemove: "_attachmentChipRemove_194hg_647",
|
|
2657
|
+
attachError: "_attachError_194hg_662",
|
|
2658
|
+
fileInput: "_fileInput_194hg_673"
|
|
2643
2659
|
};
|
|
2644
2660
|
//#endregion
|
|
2645
2661
|
//#region src/ui/cards.ts
|
|
@@ -2670,6 +2686,17 @@ function createReflectionLines(reflection) {
|
|
|
2670
2686
|
}
|
|
2671
2687
|
//#endregion
|
|
2672
2688
|
//#region src/ui/UI.ts
|
|
2689
|
+
/** 单个附件最大体积(5MB) */
|
|
2690
|
+
var MAX_ATTACHMENT_SIZE = 5242880;
|
|
2691
|
+
/** 单次任务最多允许携带的附件数量 */
|
|
2692
|
+
var MAX_ATTACHMENTS = 5;
|
|
2693
|
+
/** 支持的文本类附件扩展名(图片按 MIME 类型单独判断) */
|
|
2694
|
+
var TEXT_ATTACHMENT_EXTENSIONS = [
|
|
2695
|
+
".txt",
|
|
2696
|
+
".md",
|
|
2697
|
+
".json",
|
|
2698
|
+
".csv"
|
|
2699
|
+
];
|
|
2673
2700
|
/**
|
|
2674
2701
|
* Agent 控制 UI
|
|
2675
2702
|
*
|
|
@@ -2690,6 +2717,10 @@ var UI = class {
|
|
|
2690
2717
|
#actionButton;
|
|
2691
2718
|
#inputSection;
|
|
2692
2719
|
#taskInput;
|
|
2720
|
+
#attachButton;
|
|
2721
|
+
#fileInput;
|
|
2722
|
+
#attachmentsBar;
|
|
2723
|
+
#attachError;
|
|
2693
2724
|
#agent;
|
|
2694
2725
|
#config;
|
|
2695
2726
|
#isExpanded = false;
|
|
@@ -2699,6 +2730,8 @@ var UI = class {
|
|
|
2699
2730
|
#userAnswerSignal = null;
|
|
2700
2731
|
#userAnswerAbortHandler = null;
|
|
2701
2732
|
#isWaitingForUserAnswer = false;
|
|
2733
|
+
#pendingAttachments = [];
|
|
2734
|
+
#lastSubmission = null;
|
|
2702
2735
|
#headerUpdateTimer = null;
|
|
2703
2736
|
#timers = /* @__PURE__ */ new Set();
|
|
2704
2737
|
#pendingHeaderText = null;
|
|
@@ -2721,7 +2754,7 @@ var UI = class {
|
|
|
2721
2754
|
constructor(agent, config = {}) {
|
|
2722
2755
|
this.#agent = agent;
|
|
2723
2756
|
this.#config = config;
|
|
2724
|
-
this.#i18n = new I18n(config.language ?? "
|
|
2757
|
+
this.#i18n = new I18n(config.language ?? "zh-CN");
|
|
2725
2758
|
this.#agent.onAskUser = this.#askUserCallback;
|
|
2726
2759
|
this.#wrapper = this.#createWrapper();
|
|
2727
2760
|
this.#indicator = this.#wrapper.querySelector(`.${UI_module_default.indicator}`);
|
|
@@ -2732,6 +2765,10 @@ var UI = class {
|
|
|
2732
2765
|
this.#actionButton = this.#wrapper.querySelector(`.${UI_module_default.stopButton}`);
|
|
2733
2766
|
this.#inputSection = this.#wrapper.querySelector(`.${UI_module_default.inputSectionWrapper}`);
|
|
2734
2767
|
this.#taskInput = this.#wrapper.querySelector(`.${UI_module_default.taskInput}`);
|
|
2768
|
+
this.#attachButton = this.#wrapper.querySelector(`.${UI_module_default.attachButton}`);
|
|
2769
|
+
this.#fileInput = this.#wrapper.querySelector(`.${UI_module_default.fileInput}`);
|
|
2770
|
+
this.#attachmentsBar = this.#wrapper.querySelector(`.${UI_module_default.attachmentsBar}`);
|
|
2771
|
+
this.#attachError = this.#wrapper.querySelector(`.${UI_module_default.attachError}`);
|
|
2735
2772
|
this.#agent.addEventListener("statuschange", this.#onStatusChange);
|
|
2736
2773
|
this.#agent.addEventListener("historychange", this.#onHistoryChange);
|
|
2737
2774
|
this.#agent.addEventListener("activity", this.#onActivity);
|
|
@@ -2874,6 +2911,9 @@ var UI = class {
|
|
|
2874
2911
|
this.#updateStatusIndicator("thinking");
|
|
2875
2912
|
this.#renderHistory();
|
|
2876
2913
|
this.#collapse();
|
|
2914
|
+
this.#pendingAttachments = [];
|
|
2915
|
+
this.#renderAttachments();
|
|
2916
|
+
this.#setAttachError("");
|
|
2877
2917
|
this.#showInputArea();
|
|
2878
2918
|
}
|
|
2879
2919
|
/** 展开历史弹窗(公开方法) */
|
|
@@ -2930,12 +2970,32 @@ var UI = class {
|
|
|
2930
2970
|
const input = this.#taskInput.value.trim();
|
|
2931
2971
|
if (!input) return;
|
|
2932
2972
|
this.#hideInputArea();
|
|
2933
|
-
if (this.#isWaitingForUserAnswer)
|
|
2934
|
-
|
|
2973
|
+
if (this.#isWaitingForUserAnswer) {
|
|
2974
|
+
this.#handleUserAnswer(input);
|
|
2975
|
+
return;
|
|
2976
|
+
}
|
|
2977
|
+
const attachments = this.#pendingAttachments;
|
|
2978
|
+
this.#lastSubmission = {
|
|
2979
|
+
task: input,
|
|
2980
|
+
attachments
|
|
2981
|
+
};
|
|
2982
|
+
this.#pendingAttachments = [];
|
|
2983
|
+
this.#renderAttachments();
|
|
2984
|
+
this.#setAttachError("");
|
|
2985
|
+
const onExecuteError = (error) => {
|
|
2935
2986
|
if (error?.name === "AbortError") return;
|
|
2936
2987
|
console.error("[UI] Failed to execute task:", error);
|
|
2937
2988
|
if (!this.#disposed) this.#showInputArea();
|
|
2938
|
-
}
|
|
2989
|
+
};
|
|
2990
|
+
(attachments.length > 0 ? this.#agent.execute(input, attachments) : this.#agent.execute(input)).catch(onExecuteError);
|
|
2991
|
+
}
|
|
2992
|
+
/** 将上一次提交的文本和附件回填到输入框,供 ↑ 键触发 */
|
|
2993
|
+
#restoreLastSubmission() {
|
|
2994
|
+
const last = this.#lastSubmission;
|
|
2995
|
+
if (!last) return;
|
|
2996
|
+
this.#taskInput.value = last.task;
|
|
2997
|
+
this.#pendingAttachments = [...last.attachments];
|
|
2998
|
+
this.#renderAttachments();
|
|
2939
2999
|
}
|
|
2940
3000
|
/**
|
|
2941
3001
|
* 处理用户回答
|
|
@@ -2953,6 +3013,8 @@ var UI = class {
|
|
|
2953
3013
|
this.#taskInput.value = "";
|
|
2954
3014
|
this.#taskInput.placeholder = placeholder || this.#i18n.t("ui.taskInput");
|
|
2955
3015
|
this.#inputSection.classList.remove(UI_module_default.hidden);
|
|
3016
|
+
this.#attachButton.style.display = this.#isWaitingForUserAnswer ? "none" : "";
|
|
3017
|
+
this.#syncInputHeight();
|
|
2956
3018
|
this.#setTimer(() => {
|
|
2957
3019
|
this.#taskInput.focus();
|
|
2958
3020
|
}, 100);
|
|
@@ -2962,6 +3024,84 @@ var UI = class {
|
|
|
2962
3024
|
*/
|
|
2963
3025
|
#hideInputArea() {
|
|
2964
3026
|
this.#inputSection.classList.add(UI_module_default.hidden);
|
|
3027
|
+
this.#inputSection.style.maxHeight = "0px";
|
|
3028
|
+
}
|
|
3029
|
+
/** 将输入区域外层容器的 max-height 同步为当前真实内容高度(含附件条、错误提示) */
|
|
3030
|
+
#syncInputHeight() {
|
|
3031
|
+
if (this.#inputSection.classList.contains(UI_module_default.hidden)) return;
|
|
3032
|
+
this.#inputSection.style.maxHeight = `${this.#inputSection.scrollHeight}px`;
|
|
3033
|
+
}
|
|
3034
|
+
/** 设置(或清空)附件校验错误提示,并同步输入区域高度 */
|
|
3035
|
+
#setAttachError(message) {
|
|
3036
|
+
this.#attachError.textContent = message;
|
|
3037
|
+
this.#syncInputHeight();
|
|
3038
|
+
}
|
|
3039
|
+
/** 判断文件是否为支持的附件类型:图片,或指定扩展名的文本文件 */
|
|
3040
|
+
#isSupportedAttachment(file) {
|
|
3041
|
+
if (file.type.startsWith("image/")) return true;
|
|
3042
|
+
const name = file.name.toLowerCase();
|
|
3043
|
+
return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => name.endsWith(ext));
|
|
3044
|
+
}
|
|
3045
|
+
/** 将文件读取为 base64 data URL */
|
|
3046
|
+
#readFileAsDataUrl(file) {
|
|
3047
|
+
return new Promise((resolve, reject) => {
|
|
3048
|
+
const reader = new FileReader();
|
|
3049
|
+
reader.onload = () => resolve(reader.result);
|
|
3050
|
+
reader.onerror = () => reject(reader.error);
|
|
3051
|
+
reader.readAsDataURL(file);
|
|
3052
|
+
});
|
|
3053
|
+
}
|
|
3054
|
+
/**
|
|
3055
|
+
* 校验并读取用户选中的文件,追加为待提交附件。
|
|
3056
|
+
* 任一文件超出数量/大小/类型限制时,拒绝本次整批选择并提示错误。
|
|
3057
|
+
*/
|
|
3058
|
+
async #handleFileSelection(files) {
|
|
3059
|
+
const incoming = Array.from(files);
|
|
3060
|
+
if (this.#pendingAttachments.length + incoming.length > MAX_ATTACHMENTS) {
|
|
3061
|
+
this.#setAttachError(this.#i18n.t("ui.attachTooMany", { max: MAX_ATTACHMENTS }));
|
|
3062
|
+
return;
|
|
3063
|
+
}
|
|
3064
|
+
for (const file of incoming) {
|
|
3065
|
+
if (file.size > MAX_ATTACHMENT_SIZE) {
|
|
3066
|
+
this.#setAttachError(this.#i18n.t("ui.attachTooLarge", {
|
|
3067
|
+
name: file.name,
|
|
3068
|
+
maxMB: MAX_ATTACHMENT_SIZE / 1048576
|
|
3069
|
+
}));
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
if (!this.#isSupportedAttachment(file)) {
|
|
3073
|
+
this.#setAttachError(this.#i18n.t("ui.attachUnsupportedType", { name: file.name }));
|
|
3074
|
+
return;
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
this.#setAttachError("");
|
|
3078
|
+
const dataUrls = await Promise.all(incoming.map((file) => this.#readFileAsDataUrl(file)));
|
|
3079
|
+
incoming.forEach((file, index) => {
|
|
3080
|
+
this.#pendingAttachments.push({
|
|
3081
|
+
name: file.name,
|
|
3082
|
+
mimeType: file.type,
|
|
3083
|
+
dataUrl: dataUrls[index]
|
|
3084
|
+
});
|
|
3085
|
+
});
|
|
3086
|
+
this.#renderAttachments();
|
|
3087
|
+
}
|
|
3088
|
+
/** 重新渲染已选附件的预览条 */
|
|
3089
|
+
#renderAttachments() {
|
|
3090
|
+
this.#attachmentsBar.innerHTML = this.#pendingAttachments.map((attachment, index) => {
|
|
3091
|
+
const icon = attachment.mimeType.startsWith("image/") ? "🖼️" : "📄";
|
|
3092
|
+
return `
|
|
3093
|
+
<span class="${UI_module_default.attachmentChip}">
|
|
3094
|
+
<span>${icon} ${escapeHtml(truncate$1(attachment.name, 20))}</span>
|
|
3095
|
+
<button type="button" class="${UI_module_default.attachmentChipRemove}" data-remove-index="${index}">×</button>
|
|
3096
|
+
</span>
|
|
3097
|
+
`;
|
|
3098
|
+
}).join("");
|
|
3099
|
+
this.#syncInputHeight();
|
|
3100
|
+
}
|
|
3101
|
+
/** 移除一个已选附件 */
|
|
3102
|
+
#removeAttachment(index) {
|
|
3103
|
+
this.#pendingAttachments.splice(index, 1);
|
|
3104
|
+
this.#renderAttachments();
|
|
2965
3105
|
}
|
|
2966
3106
|
/**
|
|
2967
3107
|
* 检查是否应显示输入区域
|
|
@@ -3010,7 +3150,21 @@ var UI = class {
|
|
|
3010
3150
|
</div>
|
|
3011
3151
|
</div>
|
|
3012
3152
|
<div class="${UI_module_default.inputSectionWrapper} ${UI_module_default.hidden}">
|
|
3153
|
+
<div class="${UI_module_default.attachmentsBar}"></div>
|
|
3154
|
+
<div class="${UI_module_default.attachError}"></div>
|
|
3013
3155
|
<div class="${UI_module_default.inputSection}">
|
|
3156
|
+
<button
|
|
3157
|
+
type="button"
|
|
3158
|
+
class="${UI_module_default.attachButton}"
|
|
3159
|
+
title="${this.#i18n.t("ui.attachButtonTitle")}"
|
|
3160
|
+
>📎</button>
|
|
3161
|
+
<input
|
|
3162
|
+
type="file"
|
|
3163
|
+
class="${UI_module_default.fileInput}"
|
|
3164
|
+
accept="image/*,${TEXT_ATTACHMENT_EXTENSIONS.join(",")}"
|
|
3165
|
+
multiple
|
|
3166
|
+
hidden
|
|
3167
|
+
/>
|
|
3014
3168
|
<textarea
|
|
3015
3169
|
class="${UI_module_default.taskInput}"
|
|
3016
3170
|
maxlength="${taskInputMaxLength}"
|
|
@@ -3043,11 +3197,27 @@ var UI = class {
|
|
|
3043
3197
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
3044
3198
|
e.preventDefault();
|
|
3045
3199
|
this.#submitTask();
|
|
3200
|
+
} else if (e.key === "ArrowUp" && !this.#isWaitingForUserAnswer && this.#lastSubmission) {
|
|
3201
|
+
e.preventDefault();
|
|
3202
|
+
this.#restoreLastSubmission();
|
|
3046
3203
|
}
|
|
3047
3204
|
});
|
|
3048
3205
|
this.#inputSection.addEventListener("click", (e) => {
|
|
3049
3206
|
e.stopPropagation();
|
|
3050
3207
|
});
|
|
3208
|
+
this.#attachButton.addEventListener("click", () => {
|
|
3209
|
+
this.#fileInput.click();
|
|
3210
|
+
});
|
|
3211
|
+
this.#fileInput.addEventListener("change", () => {
|
|
3212
|
+
const files = this.#fileInput.files;
|
|
3213
|
+
if (files?.length) this.#handleFileSelection(files);
|
|
3214
|
+
this.#fileInput.value = "";
|
|
3215
|
+
});
|
|
3216
|
+
this.#attachmentsBar.addEventListener("click", (e) => {
|
|
3217
|
+
const removeButton = e.target.closest(`.${UI_module_default.attachmentChipRemove}`);
|
|
3218
|
+
if (!(removeButton instanceof HTMLElement)) return;
|
|
3219
|
+
this.#removeAttachment(Number(removeButton.dataset.removeIndex));
|
|
3220
|
+
});
|
|
3051
3221
|
}
|
|
3052
3222
|
/** 在展开/收起状态之间切换 */
|
|
3053
3223
|
#toggle() {
|
|
@@ -3164,20 +3334,25 @@ var UI = class {
|
|
|
3164
3334
|
this.#scrollToBottom();
|
|
3165
3335
|
this.#syncHistoryHeight();
|
|
3166
3336
|
}
|
|
3167
|
-
/** 生成任务卡片 HTML */
|
|
3168
|
-
#createTaskCard(task) {
|
|
3169
|
-
return createCard({
|
|
3337
|
+
/** 生成任务卡片 HTML;若任务附带附件,附加一行文件名列表 */
|
|
3338
|
+
#createTaskCard(task, attachmentNames) {
|
|
3339
|
+
if (!attachmentNames?.length) return createCard({
|
|
3170
3340
|
icon: "🎯",
|
|
3171
3341
|
content: task,
|
|
3172
3342
|
type: "input"
|
|
3173
3343
|
});
|
|
3344
|
+
return createCard({
|
|
3345
|
+
icon: "🎯",
|
|
3346
|
+
content: [task, this.#i18n.t("ui.attachmentsLabel", { names: attachmentNames.join(", ") })],
|
|
3347
|
+
type: "input"
|
|
3348
|
+
});
|
|
3174
3349
|
}
|
|
3175
3350
|
/** 为一条历史事件生成卡片 */
|
|
3176
3351
|
#createHistoryCards(event) {
|
|
3177
3352
|
const cards = [];
|
|
3178
3353
|
const meta = event.type === "step" && event.stepIndex !== void 0 ? this.#i18n.t("ui.step", { number: (event.stepIndex + 1).toString() }) : void 0;
|
|
3179
3354
|
if (event.type === "task_start") {
|
|
3180
|
-
if (event.task) cards.push(this.#createTaskCard(event.task));
|
|
3355
|
+
if (event.task) cards.push(this.#createTaskCard(event.task, event.attachmentNames));
|
|
3181
3356
|
} else if (event.type === "step") {
|
|
3182
3357
|
if (event.reflection) {
|
|
3183
3358
|
const lines = createReflectionLines(event.reflection);
|
|
@@ -3735,7 +3910,7 @@ function parseLLMConfig(config) {
|
|
|
3735
3910
|
}
|
|
3736
3911
|
//#endregion
|
|
3737
3912
|
//#region src/agent/prompts/system_prompt.md?raw
|
|
3738
|
-
var system_prompt_default = "You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\n\n<intro>\nYou excel at following tasks:\n1. Navigating complex websites and extracting precise information\n2. Automating form submissions and interactive web actions\n3. Gathering and saving information \n4. Operate effectively in an agent loop\n5. Efficiently performing diverse web tasks\n</intro>\n\n<language_settings>\n- Default working language: **English**\n- Use the language that user is using. Return in user's language.\n</language_settings>\n\n<input>\nAt every step, your input will consist of: \n1. <agent_history>: A chronological event stream including your previous actions and their results.\n2. <agent_state>: Current <user_request> and <step_info>.\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\n</input>\n\n<agent_history>\nAgent history will be given as a list of step information as follows:\n\n<step_{step_number}>:\nEvaluation of Previous Step: Assessment of last action\nMemory: Your memory of this step\nNext Goal: Your goal for this step\nAction Results: Your actions and their results\n</step_{step_number}>\n\nand system messages wrapped in <sys> tag.\n</agent_history>\n\n<user_request>\nUSER REQUEST: This is your ultimate objective and always remains visible.\n- This has the highest priority. Make the user happy.\n- If the user request is very specific - then carefully follow each step and don't skip or hallucinate steps.\n- If the task is open ended you can plan yourself how to get it done.\n</user_request>\n\n<browser_state>\n1. Browser State will be given as:\n\nCurrent URL: URL of the page you are currently viewing.\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\n- index: Numeric identifier for interaction\n- type: HTML element type (button, input, etc.)\n- text: Element description\n\nExamples:\n[33]<div>User form</div>\n\\t*[35]<button aria-label='Submit form'>Submit</button>\n\nNote that:\n- Only elements with numeric indexes in [] are interactive\n- (stacked) indentation (with \\t) is important and means that the element is a (html) child of the element above (with a lower index)\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\n- Pure text elements without [] are not interactive.\n</browser_state>\n\n<browser_rules>\nStrictly follow these rules while using the browser and navigating the web:\n- Only interact with elements that have a numeric [index] assigned.\n- Only use indexes that are explicitly provided.\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\n- If a captcha appears, tell user you can not solve captcha. Finish the task and ask user to solve it.\n- If the page is not fully loaded, use the `wait` action.\n- Do not repeat one action for more than 3 times unless some conditions changed.\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\n- Don't login into a page if you don't have to. Don't login if you don't have the credentials. \n- There are 2 types of tasks always first think which type of request you are dealing with:\n1. Very specific step by step instructions:\n- Follow them as very precise and don't skip steps. Try to complete everything as requested.\n2. Open ended tasks. Plan yourself, be creative in achieving them.\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\n</browser_rules>\n\n<capability>\n- You can only handle single page app. Do not jump out of current page.\n- Do not click on link if it will open in a new page (e.g., <a target=\"_blank\">)\n- It is ok to fail the task.\n - User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\n - Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\n - Trying too hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted results and harmful side-effects. User would rather you complete the task with a fail.\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\n</capability>\n\n<task_completion_rules>\nYou must call the `done` action in one of three cases:\n- When you have fully completed the USER REQUEST.\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\n\nThe `done` action is your opportunity to terminate and share your findings with the user.\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\n- You are ONLY ALLOWED to call `done` as a single action. Don't call it together with other actions.\n- If the user asks for specified format, such as \"return JSON with following structure\", \"return a list of format...\", MAKE sure to use the right format in your answer.\n- If the user asks for a structured output, your `done` action's schema may be modified. Take this schema into account when solving the task!\n</task_completion_rules>\n\n<reasoning_rules>\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\n\n- Reason about <agent_history> to track progress and context toward <user_request>.\n- Analyze the most recent \"Next Goal\" and \"Action Result\" in <agent_history> and clearly state what you previously tried to achieve.\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\n- Ask user for help if you have any difficulty. Keep user in the loop.\n- If you see information relevant to <user_request>, plan saving the information to memory.\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\n</reasoning_rules>\n\n<examples>\nHere are examples of good output patterns. Use them as reference but never copy them directly.\n\n<evaluation_examples>\n\"evaluation_previous_goal\": \"Successfully navigated to the product page and found the target information. Verdict: Success\"\n\"evaluation_previous_goal\": \"Clicked the login button and user authentication form appeared. Verdict: Success\"\n</evaluation_examples>\n\n<memory_examples>\n\"memory\": \"Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports.\"\n</memory_examples>\n\n<next_goal_examples>\n\"next_goal\": \"Click on the 'Add to Cart' button to proceed with the purchase flow.\"\n</next_goal_examples>\n</examples>\n\n<output>\n{\n \"evaluation_previous_goal\": \"Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.\",\n \"memory\": \"1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.\",\n \"next_goal\": \"State the next immediate goal and action to achieve it, in one clear sentence.\",\n \"action\":{\n \"Action name\": {// Action parameters}\n }\n}\n</output>\n";
|
|
3913
|
+
var system_prompt_default = "You are an AI agent designed to operate in an iterative loop to automate browser tasks. Your ultimate goal is accomplishing the task provided in <user_request>.\n\n<intro>\nYou excel at following tasks:\n1. Navigating complex websites and extracting precise information\n2. Automating form submissions and interactive web actions\n3. Gathering and saving information \n4. Operate effectively in an agent loop\n5. Efficiently performing diverse web tasks\n</intro>\n\n<language_settings>\n- Default working language: **Chinese (Simplified)**\n- Use the language that user is using. Return in user's language.\n</language_settings>\n\n<input>\nAt every step, your input will consist of: \n1. <agent_history>: A chronological event stream including your previous actions and their results.\n2. <agent_state>: Current <user_request> and <step_info>.\n3. <browser_state>: Current URL, interactive elements indexed for actions, and visible page content.\n</input>\n\n<agent_history>\nAgent history will be given as a list of step information as follows:\n\n<step_{step_number}>:\nEvaluation of Previous Step: Assessment of last action\nMemory: Your memory of this step\nNext Goal: Your goal for this step\nAction Results: Your actions and their results\n</step_{step_number}>\n\nand system messages wrapped in <sys> tag.\n</agent_history>\n\n<user_request>\nUSER REQUEST: This is your ultimate objective and always remains visible.\n- This has the highest priority. Make the user happy.\n- If the user request is very specific - then carefully follow each step and don't skip or hallucinate steps.\n- If the task is open ended you can plan yourself how to get it done.\n</user_request>\n\n<browser_state>\n1. Browser State will be given as:\n\nCurrent URL: URL of the page you are currently viewing.\nInteractive Elements: All interactive elements will be provided in format as [index]<type>text</type> where\n- index: Numeric identifier for interaction\n- type: HTML element type (button, input, etc.)\n- text: Element description\n\nExamples:\n[33]<div>User form</div>\n\\t*[35]<button aria-label='Submit form'>Submit</button>\n\nNote that:\n- Only elements with numeric indexes in [] are interactive\n- (stacked) indentation (with \\t) is important and means that the element is a (html) child of the element above (with a lower index)\n- Elements tagged with `*[` are the new clickable elements that appeared on the website since the last step - if url has not changed.\n- Pure text elements without [] are not interactive.\n</browser_state>\n\n<browser_rules>\nStrictly follow these rules while using the browser and navigating the web:\n- Only interact with elements that have a numeric [index] assigned.\n- Only use indexes that are explicitly provided.\n- If the page changes after, for example, an input text action, analyze if you need to interact with new elements, e.g. selecting the right option from the list.\n- By default, only elements in the visible viewport are listed. Use scrolling actions if you suspect relevant content is offscreen which you need to interact with. Scroll ONLY if there are more pixels below or above the page.\n- You can scroll by a specific number of pages using the num_pages parameter (e.g., 0.5 for half page, 2.0 for two pages).\n- All the elements that are scrollable are marked with `data-scrollable` attribute. Including the scrollable distance in every directions. You can scroll *the element* in case some area are overflowed.\n- If a captcha appears, tell user you can not solve captcha. Finish the task and ask user to solve it.\n- If the page is not fully loaded, use the `wait` action.\n- Do not repeat one action for more than 3 times unless some conditions changed.\n- If you fill an input field and your action sequence is interrupted, most often something changed e.g. suggestions popped up under the field.\n- If the <user_request> includes specific page information such as product type, rating, price, location, etc., try to apply filters to be more efficient.\n- The <user_request> is the ultimate goal. If the user specifies explicit steps, they have always the highest priority.\n- If you input_text into a field, you might need to press enter, click the search button, or select from dropdown for completion.\n- Don't login into a page if you don't have to. Don't login if you don't have the credentials. \n- There are 2 types of tasks always first think which type of request you are dealing with:\n1. Very specific step by step instructions:\n- Follow them as very precise and don't skip steps. Try to complete everything as requested.\n2. Open ended tasks. Plan yourself, be creative in achieving them.\n- If you get stuck e.g. with logins or captcha in open-ended tasks you can re-evaluate the task and try alternative ways, e.g. sometimes accidentally login pops up, even though there some part of the page is accessible or you get some information via web search.\n</browser_rules>\n\n<capability>\n- You can only handle single page app. Do not jump out of current page.\n- Do not click on link if it will open in a new page (e.g., <a target=\"_blank\">)\n- It is ok to fail the task.\n - User can be wrong. If the request of user is not achievable, inappropriate or you do not have enough information or tools to achieve it. Tell user to make a better request.\n - Webpage can be broken. All webpages or apps have bugs. Some bug will make it hard for your job. It's encouraged to tell user the problem of current page. Your feedbacks (including failing) are valuable for user.\n - Trying too hard can be harmful. Repeating some action back and forth or pushing for a complex procedure with little knowledge can cause unwanted results and harmful side-effects. User would rather you complete the task with a fail.\n- If you do not have knowledge for the current webpage or task. You must require user to give specific instructions and detailed steps.\n</capability>\n\n<task_completion_rules>\nYou must call the `done` action in one of three cases:\n- When you have fully completed the USER REQUEST.\n- When you reach the final allowed step (`max_steps`), even if the task is incomplete.\n- When you feel stuck or unable to solve user request. Or user request is not clear or contains inappropriate content.\n- If it is ABSOLUTELY IMPOSSIBLE to continue.\n\nThe `done` action is your opportunity to terminate and share your findings with the user.\n- Set `success` to `true` only if the full USER REQUEST has been completed with no missing components.\n- If any part of the request is missing, incomplete, or uncertain, set `success` to `false`.\n- You can use the `text` field of the `done` action to communicate your findings and to provide a coherent reply to the user and fulfill the USER REQUEST.\n- You are ONLY ALLOWED to call `done` as a single action. Don't call it together with other actions.\n- If the user asks for specified format, such as \"return JSON with following structure\", \"return a list of format...\", MAKE sure to use the right format in your answer.\n- If the user asks for a structured output, your `done` action's schema may be modified. Take this schema into account when solving the task!\n</task_completion_rules>\n\n<reasoning_rules>\nExhibit the following reasoning patterns to successfully achieve the <user_request>:\n\n- Reason about <agent_history> to track progress and context toward <user_request>.\n- Analyze the most recent \"Next Goal\" and \"Action Result\" in <agent_history> and clearly state what you previously tried to achieve.\n- Analyze all relevant items in <agent_history> and <browser_state> to understand your state.\n- Explicitly judge success/failure/uncertainty of the last action. Never assume an action succeeded just because it appears to be executed in your last step in <agent_history>. If the expected change is missing, mark the last action as failed (or uncertain) and plan a recovery.\n- Analyze whether you are stuck, e.g. when you repeat the same actions multiple times without any progress. Then consider alternative approaches e.g. scrolling for more context or ask user for help.\n- Ask user for help if you have any difficulty. Keep user in the loop.\n- If you see information relevant to <user_request>, plan saving the information to memory.\n- Always reason about the <user_request>. Make sure to carefully analyze the specific steps and information required. E.g. specific filters, specific form fields, specific information to search. Make sure to always compare the current trajectory with the user request and think carefully if thats how the user requested it.\n</reasoning_rules>\n\n<examples>\nHere are examples of good output patterns. Use them as reference but never copy them directly.\n\n<evaluation_examples>\n\"evaluation_previous_goal\": \"Successfully navigated to the product page and found the target information. Verdict: Success\"\n\"evaluation_previous_goal\": \"Clicked the login button and user authentication form appeared. Verdict: Success\"\n</evaluation_examples>\n\n<memory_examples>\n\"memory\": \"Found many pending reports that need to be analyzed in the main page. Successfully processed the first 2 reports on quarterly sales data and moving on to inventory analysis and customer feedback reports.\"\n</memory_examples>\n\n<next_goal_examples>\n\"next_goal\": \"Click on the 'Add to Cart' button to proceed with the purchase flow.\"\n</next_goal_examples>\n</examples>\n\n<output>\n{\n \"evaluation_previous_goal\": \"Concise one-sentence analysis of your last action. Clearly state success, failure, or uncertain.\",\n \"memory\": \"1-3 concise sentences of specific memory of this step and overall progress. You should put here everything that will help you track progress in future steps. Like counting pages visited, items found, etc.\",\n \"next_goal\": \"State the next immediate goal and action to achieve it, in one clear sentence.\",\n \"action\":{\n \"Action name\": {// Action parameters}\n }\n}\n</output>\n";
|
|
3739
3914
|
//#endregion
|
|
3740
3915
|
//#region src/agent/utils/autoFixer.ts
|
|
3741
3916
|
var log = console.log.bind(console, formatTerminalText("[autoFixer]", "yellow"));
|
|
@@ -4082,6 +4257,8 @@ tools.set("execute_javascript", tool({
|
|
|
4082
4257
|
}));
|
|
4083
4258
|
//#endregion
|
|
4084
4259
|
//#region src/agent/AgentRuntime.ts
|
|
4260
|
+
/** 文本类附件注入 prompt 时的最大字符数,避免超大文件把上下文撑爆 */
|
|
4261
|
+
var ATTACHMENT_TEXT_MAX_LENGTH = 2e4;
|
|
4085
4262
|
/**
|
|
4086
4263
|
* 用于浏览器自动化的 AI 智能体。
|
|
4087
4264
|
*
|
|
@@ -4148,6 +4325,8 @@ var AgentRuntime = class extends EventTarget {
|
|
|
4148
4325
|
#abortController = new AbortController();
|
|
4149
4326
|
/** 本轮任务收集的观察消息(暂存,稍后统一写入历史) */
|
|
4150
4327
|
#observations = [];
|
|
4328
|
+
/** 本次任务上传的附件;仅在任务第一步注入 LLM prompt,之后步骤不重复携带原文件以节省 token */
|
|
4329
|
+
#taskAttachments = [];
|
|
4151
4330
|
/** 当前任务在 history 数组中的起始下标(用于跨任务保留历史时,把 prompt/循环检测限定在当前任务范围内) */
|
|
4152
4331
|
#taskHistoryStart = 0;
|
|
4153
4332
|
/** 当前一次运行完全结束时 resolve。由 `stop()` 等待。 */
|
|
@@ -4259,16 +4438,18 @@ var AgentRuntime = class extends EventTarget {
|
|
|
4259
4438
|
* 外部错误(前置检查/配置/钩子)会直接抛出;
|
|
4260
4439
|
* Agent 内部错误会被捕获并加入历史,同时返回失败结果
|
|
4261
4440
|
*/
|
|
4262
|
-
async execute(task) {
|
|
4441
|
+
async execute(task, attachments = []) {
|
|
4263
4442
|
if (this.disposed) throw new Error("PageAgent has been disposed. Create a new instance.");
|
|
4264
4443
|
if (this.#status === "running") throw new Error("A task is already running.");
|
|
4265
4444
|
if (!task) throw new Error("Task is required");
|
|
4266
4445
|
this.task = task;
|
|
4267
4446
|
this.taskId = uid();
|
|
4447
|
+
this.#taskAttachments = attachments;
|
|
4268
4448
|
this.#taskHistoryStart = this.history.length;
|
|
4269
4449
|
this.#emitHistoryChange({
|
|
4270
4450
|
type: "task_start",
|
|
4271
|
-
task
|
|
4451
|
+
task,
|
|
4452
|
+
...attachments.length > 0 ? { attachmentNames: attachments.map((a) => a.name) } : {}
|
|
4272
4453
|
});
|
|
4273
4454
|
this.#observations = [];
|
|
4274
4455
|
this.#states = {
|
|
@@ -4589,8 +4770,33 @@ var AgentRuntime = class extends EventTarget {
|
|
|
4589
4770
|
prompt += pageContent + "\n";
|
|
4590
4771
|
prompt += browserState.footer + "\n\n";
|
|
4591
4772
|
prompt += "</browser_state>\n\n";
|
|
4773
|
+
if (stepCount === 0 && this.#taskAttachments.length > 0) return await this.#injectAttachments(prompt, this.#taskAttachments);
|
|
4592
4774
|
return prompt;
|
|
4593
4775
|
}
|
|
4776
|
+
/**
|
|
4777
|
+
* 把附件内容注入 prompt:图片转为 image_url 片段;文本类文件解码后截断拼进文字部分。
|
|
4778
|
+
* 仅当存在图片附件时才返回多模态数组,纯文本附件保持返回字符串(不影响不支持 vision 的模型)。
|
|
4779
|
+
*/
|
|
4780
|
+
async #injectAttachments(prompt, attachments) {
|
|
4781
|
+
const textSegments = [prompt];
|
|
4782
|
+
const imageParts = [];
|
|
4783
|
+
for (const attachment of attachments) {
|
|
4784
|
+
if (attachment.mimeType.startsWith("image/")) {
|
|
4785
|
+
imageParts.push({
|
|
4786
|
+
type: "image_url",
|
|
4787
|
+
image_url: { url: attachment.dataUrl }
|
|
4788
|
+
});
|
|
4789
|
+
continue;
|
|
4790
|
+
}
|
|
4791
|
+
const text = await suppress(() => fetch(attachment.dataUrl).then((r) => r.text()));
|
|
4792
|
+
textSegments.push(`<uploaded_file name="${attachment.name}">\n${truncate(text ?? "", ATTACHMENT_TEXT_MAX_LENGTH)}\n</uploaded_file>`);
|
|
4793
|
+
}
|
|
4794
|
+
if (imageParts.length === 0) return textSegments.join("\n\n");
|
|
4795
|
+
return [{
|
|
4796
|
+
type: "text",
|
|
4797
|
+
text: textSegments.join("\n\n")
|
|
4798
|
+
}, ...imageParts];
|
|
4799
|
+
}
|
|
4594
4800
|
/** 销毁 Agent:中止任务、释放浏览器控制器,并触发 dispose 事件(一次性) */
|
|
4595
4801
|
dispose() {
|
|
4596
4802
|
if (this.disposed) return;
|