feat: add Chinese UI, Responses models, and mirrored Windows setup
Localize the web console and persist custom model and capability settings. Use OpenAI Responses exclusively and move runtime limits into environment configuration. Bootstrap uv and the virtual environment on Windows, support optional China mirrors, and package source distributions without environments, build output, or credentials. Update regression tests and repository quality checks for the new behavior.
This commit is contained in:
1 parent
371aa6df56
commit
2ddec53954
183 files changed
+3427
-11857
No files matched your search
@@ -24,11 +24,11 @@ limitations under the License.
|
||||
class="vscode-tab-btn"
|
||||
[class.active]="isTaskDropdownOpen()"
|
||||
(click)="toggleTaskDropdown($event)"
|
||||
title="Task Queue"
|
||||
aria-label="Task Queue"
|
||||
title="任务队列"
|
||||
aria-label="任务队列"
|
||||
>
|
||||
<span class="material-symbols-outlined tab-icon">list_alt</span>
|
||||
<span class="tab-label">Task Queue</span>
|
||||
<span class="tab-label">任务队列</span>
|
||||
</button>
|
||||
<button
|
||||
#notesOrigin="cdkOverlayOrigin"
|
||||
@@ -36,11 +36,11 @@ limitations under the License.
|
||||
class="vscode-tab-btn"
|
||||
[class.active]="isNotesDropdownOpen()"
|
||||
(click)="toggleNotesDropdown($event)"
|
||||
title="Notes & Plans"
|
||||
aria-label="Notes & Plans"
|
||||
title="笔记与计划"
|
||||
aria-label="笔记与计划"
|
||||
>
|
||||
<span class="material-symbols-outlined tab-icon">description</span>
|
||||
<span class="tab-label">Notes & Plans</span>
|
||||
<span class="tab-label">笔记与计划</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -57,7 +57,7 @@ limitations under the License.
|
||||
<div class="vscode-dropdown-menu task-dropdown">
|
||||
<div class="popover-title-header">
|
||||
<span class="material-symbols-outlined">list_alt</span>
|
||||
<span>Task Queue</span>
|
||||
<span>任务队列</span>
|
||||
</div>
|
||||
<div class="dropdown-section-label">
|
||||
<span class="material-symbols-outlined icon-bolt">bolt</span>
|
||||
@@ -65,7 +65,8 @@ limitations under the License.
|
||||
</div>
|
||||
@if (activeQueue().length === 0) {
|
||||
<div class="dropdown-empty-state">
|
||||
No active or queued tasks
|
||||
|
||||
没有正在执行或排队的任务
|
||||
</div>
|
||||
}
|
||||
@for (session of activeQueue(); track trackSession($index, session)) {
|
||||
@@ -80,7 +81,7 @@ limitations under the License.
|
||||
@if (getTaskStatus(session) === 'running') {
|
||||
<span class="status-dot"></span>
|
||||
}
|
||||
{{ getTaskStatus(session) | uppercase }}
|
||||
{{ getTaskStatus(session) | uiLabel }}
|
||||
</span>
|
||||
<div class="item-header-actions">
|
||||
@if (getDeviceSerial(session)) {
|
||||
@@ -98,8 +99,8 @@ limitations under the License.
|
||||
type="button"
|
||||
class="btn-stop-card"
|
||||
(click)="stopTask(session.session_id, $event)"
|
||||
title="Stop this task"
|
||||
aria-label="Stop this task"
|
||||
title="停止此任务"
|
||||
aria-label="停止此任务"
|
||||
>
|
||||
<span class="material-symbols-outlined">stop_circle</span>
|
||||
</button>
|
||||
@@ -109,8 +110,8 @@ limitations under the License.
|
||||
type="button"
|
||||
class="btn-delete-card"
|
||||
(click)="deleteTask(session.session_id, $event)"
|
||||
title="Delete this task"
|
||||
aria-label="Delete this task"
|
||||
title="删除此任务"
|
||||
aria-label="删除此任务"
|
||||
>
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
</button>
|
||||
@@ -118,7 +119,7 @@ limitations under the License.
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-goal" title="{{ session.initial_goal }}">
|
||||
{{ session.initial_goal || 'Unnamed Task' }}
|
||||
{{ session.initial_goal || '未命名任务' }}
|
||||
</div>
|
||||
<div class="item-footer">
|
||||
<span class="item-id" [title]="session.session_id">ID: {{ session.session_id }}</span>
|
||||
@@ -132,7 +133,8 @@ limitations under the License.
|
||||
</div>
|
||||
@if (historyTasks().length === 0) {
|
||||
<div class="dropdown-empty-state">
|
||||
No past task history
|
||||
|
||||
暂无历史任务
|
||||
</div>
|
||||
}
|
||||
<div class="dropdown-history-list">
|
||||
@@ -148,7 +150,7 @@ limitations under the License.
|
||||
@if (getTaskStatus(session) === 'running') {
|
||||
<span class="status-dot"></span>
|
||||
}
|
||||
{{ getTaskStatus(session) | uppercase }}
|
||||
{{ getTaskStatus(session) | uiLabel }}
|
||||
</span>
|
||||
<div class="item-header-actions">
|
||||
@if (getDeviceSerial(session)) {
|
||||
@@ -166,8 +168,8 @@ limitations under the License.
|
||||
type="button"
|
||||
class="btn-delete-card"
|
||||
(click)="deleteTask(session.session_id, $event)"
|
||||
title="Delete this task"
|
||||
aria-label="Delete this task"
|
||||
title="删除此任务"
|
||||
aria-label="删除此任务"
|
||||
>
|
||||
<span class="material-symbols-outlined">delete</span>
|
||||
</button>
|
||||
@@ -175,7 +177,7 @@ limitations under the License.
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-goal" title="{{ session.initial_goal }}">
|
||||
{{ session.initial_goal || 'Unnamed Task' }}
|
||||
{{ session.initial_goal || '未命名任务' }}
|
||||
</div>
|
||||
<div class="item-footer">
|
||||
<span class="item-id" [title]="session.session_id">ID: {{ session.session_id }}</span>
|
||||
@@ -200,7 +202,7 @@ limitations under the License.
|
||||
<div class="vscode-dropdown-menu notes-dropdown">
|
||||
<div class="popover-title-header">
|
||||
<span class="material-symbols-outlined">description</span>
|
||||
<span>Notes & Plans</span>
|
||||
<span>笔记与计划</span>
|
||||
</div>
|
||||
<!-- Notes Selector / Pills (Shown if there are note files) -->
|
||||
@if (noteKeys().length > 1) {
|
||||
@@ -222,7 +224,7 @@ limitations under the License.
|
||||
@if (noteKeys().length === 0) {
|
||||
<div class="dropdown-empty-state">
|
||||
<span class="material-symbols-outlined empty-icon">description</span>
|
||||
<span>No notes available for this session.</span>
|
||||
<span>此会话暂无笔记。</span>
|
||||
</div>
|
||||
}
|
||||
<!-- Rich Notes Content Viewer -->
|
||||
@@ -402,7 +404,7 @@ limitations under the License.
|
||||
(click)="toggleRunInfo($event)"
|
||||
>
|
||||
<span class="material-symbols-outlined model-icon">{{ getModelIcon(model.name) }}</span>
|
||||
<span class="model-label">Architecture:</span>
|
||||
<span class="model-label">执行模式:</span>
|
||||
<span class="model-name">{{ getModelDisplayName(model.name) }}</span>
|
||||
</button>
|
||||
|
||||
@@ -415,7 +417,7 @@ limitations under the License.
|
||||
(backdropClick)="isRunInfoOpen.set(false)"
|
||||
[cdkConnectedOverlayPositions]="dropdownPositions"
|
||||
>
|
||||
<div class="vscode-dropdown-menu run-info-dropdown" role="dialog" aria-label="Run info">
|
||||
<div class="vscode-dropdown-menu run-info-dropdown" role="dialog" aria-label="运行信息">
|
||||
<div class="run-info-header">
|
||||
<span class="material-symbols-outlined" [class.is-pro]="runInfoIsPro()">{{ getModelIcon(model.name) }}</span>
|
||||
<span class="run-info-title">{{ getModelDisplayName(model.name) }}</span>
|
||||
@@ -425,16 +427,16 @@ limitations under the License.
|
||||
</div>
|
||||
|
||||
<div class="run-info-row">
|
||||
<span class="run-info-label">Elapsed</span>
|
||||
<span class="run-info-label">已用时间</span>
|
||||
<span class="run-info-value">{{ runInfoElapsed() }}</span>
|
||||
</div>
|
||||
|
||||
<div class="run-info-row">
|
||||
<span class="run-info-label">Tokens</span>
|
||||
<span class="run-info-label">Token 用量</span>
|
||||
@if (runUsage(); as usage) {
|
||||
<span class="run-info-value">
|
||||
{{ formatRunTokens(usage.total_tokens) }}
|
||||
<span class="run-info-sub">{{ formatRunTokens(usage.prompt_tokens) }} in · {{ formatRunTokens(usage.completion_tokens) }} out</span>
|
||||
<span class="run-info-sub">{{ formatRunTokens(usage.prompt_tokens) }} 输入 · {{ formatRunTokens(usage.completion_tokens) }} 输出</span>
|
||||
</span>
|
||||
} @else {
|
||||
<span class="run-info-value is-muted">—</span>
|
||||
@@ -443,11 +445,11 @@ limitations under the License.
|
||||
|
||||
<div class="run-info-row is-stacked">
|
||||
<div class="run-info-line">
|
||||
<span class="run-info-label">Context</span>
|
||||
<span class="run-info-label">上下文</span>
|
||||
@if (runInfoContextPercent() !== null) {
|
||||
<span class="run-info-value">
|
||||
{{ runInfoContextPercent() }}%
|
||||
<span class="run-info-sub-inline">of {{ formatRunTokens(runUsage()?.operator_context_window_tokens) }}</span>
|
||||
<span class="run-info-sub-inline">/ {{ formatRunTokens(runUsage()?.operator_context_window_tokens) }}</span>
|
||||
</span>
|
||||
} @else {
|
||||
<span class="run-info-value is-muted">—</span>
|
||||
@@ -464,15 +466,15 @@ limitations under the License.
|
||||
|
||||
@if (runInfoIsPro()) {
|
||||
<div class="run-info-row">
|
||||
<span class="run-info-label">Result check</span>
|
||||
<span class="run-info-label">结果检查</span>
|
||||
<span class="run-info-value">{{ runTuningLabel('verify', runInfoTuning()?.verification_level) }}</span>
|
||||
</div>
|
||||
<div class="run-info-row">
|
||||
<span class="run-info-label">Screen reading</span>
|
||||
<span class="run-info-label">屏幕识别</span>
|
||||
<span class="run-info-value">{{ runTuningLabel('explore', runInfoTuning()?.explorer_mode) }}</span>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="run-info-note">No extra settings for Flash.</div>
|
||||
<div class="run-info-note">Flash 无需额外设置。</div>
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
@@ -520,22 +522,22 @@ limitations under the License.
|
||||
</span>
|
||||
}
|
||||
@if (agentService.isCurrentSessionRunning()) {
|
||||
<span class="btn-text">Recording...</span>
|
||||
<span class="btn-text">正在录制…</span>
|
||||
}
|
||||
@if (!agentService.isCurrentSessionRunning() && agentService.currentSessionRecordingStatus() === 'processing') {
|
||||
<span class="btn-text">Preparing...</span>
|
||||
<span class="btn-text">正在准备…</span>
|
||||
}
|
||||
@if (!agentService.isCurrentSessionRunning() && agentService.currentSessionRecordingStatus() !== 'processing' && agentService.currentSessionVideoUrl()) {
|
||||
<span class="btn-text">Play Recording</span>
|
||||
<span class="btn-text">播放录像</span>
|
||||
}
|
||||
@if (!agentService.isCurrentSessionRunning() && agentService.currentSessionRecordingStatus() !== 'processing' && !agentService.currentSessionVideoUrl() && agentService.hasCurrentSessionStepFrames()) {
|
||||
<span class="btn-text">Step Replay</span>
|
||||
<span class="btn-text">步骤回放</span>
|
||||
}
|
||||
@if (!agentService.isCurrentSessionRunning() && agentService.currentSessionRecordingStatus() !== 'processing' && !agentService.currentSessionVideoUrl() && !agentService.hasCurrentSessionStepFrames() && agentService.currentSessionRecordingStatus() === 'failed') {
|
||||
<span class="btn-text">Recording Failed</span>
|
||||
<span class="btn-text">录屏失败</span>
|
||||
}
|
||||
@if (!agentService.isCurrentSessionRunning() && agentService.currentSessionRecordingStatus() !== 'processing' && !agentService.currentSessionVideoUrl() && !agentService.hasCurrentSessionStepFrames() && agentService.currentSessionRecordingStatus() !== 'failed') {
|
||||
<span class="btn-text">Screen Recording</span>
|
||||
<span class="btn-text">屏幕录像</span>
|
||||
}
|
||||
@if (agentService.isCurrentSessionRunning()) {
|
||||
<span class="video-pulse-dot red"></span>
|
||||
@@ -554,15 +556,15 @@ limitations under the License.
|
||||
@if (agentService.isSessionContentLoading()) {
|
||||
<div class="session-loading-state" aria-live="polite">
|
||||
<span class="material-symbols-outlined spin-animation">progress_activity</span>
|
||||
<span>Loading run history...</span>
|
||||
<span>正在加载执行历史…</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!agentService.isSessionContentLoading() && consolidatedBlocks().length === 0 && !showPlanningLoader() && startupWorkItems().length === 0) {
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon"><span class="material-symbols-outlined">sensors</span></div>
|
||||
<h3>No Stream Activity Selected</h3>
|
||||
<p>Please select a session from the Task List on the right to view its real-time log payloads.</p>
|
||||
<h3>尚未选择执行记录</h3>
|
||||
<p>请从右侧任务列表选择会话,查看实时执行记录。</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -572,9 +574,9 @@ limitations under the License.
|
||||
@if (startupWorkItems().length > 0) {
|
||||
<div class="phase-container startup-phase" aria-live="polite">
|
||||
<div class="phase-header first-phase">
|
||||
<span class="phase-worked-time">Worked for {{ startupPreparationDuration() }}s</span>
|
||||
<span class="phase-worked-time">准备耗时 {{ startupPreparationDuration() }} 秒</span>
|
||||
</div>
|
||||
<div class="phase-body" aria-label="Task startup progress">
|
||||
<div class="phase-body" aria-label="任务启动进度">
|
||||
<div class="block-item type-stream">
|
||||
<div class="step-body">
|
||||
<div class="step-actions-container">
|
||||
@@ -661,7 +663,7 @@ limitations under the License.
|
||||
[class.collapsed]="isCheckerSegmentCollapsed(block, itemIdx)">
|
||||
<div class="details-summary" (click)="toggleCheckerSegment(block, itemIdx)">
|
||||
<span class="stream-status-dot" [class.streaming]="isCheckerSegmentRunning(block, itemIdx) && !isCheckerSegmentResetNotice(item)" [class.resetting]="isCheckerSegmentResetNotice(item)"></span>
|
||||
<span class="header-label">{{ isCheckerSegmentResetNotice(item) ? getCheckerSegmentResetMessage(item) : 'Thought' }}</span>
|
||||
<span class="header-label">{{ isCheckerSegmentResetNotice(item) ? getCheckerSegmentResetMessage(item) : '思考过程' }}</span>
|
||||
</div>
|
||||
@if (item.data.text && item.data.text.trim()) {
|
||||
<div class="details-content-wrapper">
|
||||
@@ -689,7 +691,7 @@ limitations under the License.
|
||||
[class.is-running]="isCheckerSegmentRunning(block, itemIdx)">
|
||||
<div class="report-header">
|
||||
<span class="stream-status-dot" [class.streaming]="isCheckerSegmentRunning(block, itemIdx)"></span>
|
||||
<span class="header-label">Work</span>
|
||||
<span class="header-label">执行过程</span>
|
||||
</div>
|
||||
<div class="report-content stream-box">
|
||||
<div class="stream-text" [innerHTML]="renderMarkdown(item.data.text, block.id + '-seg-' + itemIdx)"></div>
|
||||
@@ -718,7 +720,7 @@ limitations under the License.
|
||||
[class.collapsed]="collapsedStreams().has(block.data.execution_id || block.data.step_id || block.id)">
|
||||
<div class="details-summary" (click)="toggleCollapse(block.data.execution_id || block.data.step_id || block.id)">
|
||||
<span class="stream-status-dot" [class.streaming]="isBlockRunning(block)"></span>
|
||||
<span class="header-label">Thought</span>
|
||||
<span class="header-label">思考过程</span>
|
||||
</div>
|
||||
@if (getStreamDisplayText(block.id + '-native', item.data.text)) {
|
||||
<div class="details-content-wrapper">
|
||||
@@ -750,7 +752,7 @@ limitations under the License.
|
||||
[class.is-running]="isBlockRunning(block)">
|
||||
<div class="report-header">
|
||||
<span class="stream-status-dot" [class.streaming]="isBlockRunning(block)"></span>
|
||||
<span class="header-label">Work</span>
|
||||
<span class="header-label">执行过程</span>
|
||||
</div>
|
||||
@if (getStreamDisplayText(block.id, item.data.text)) {
|
||||
<div class="report-content stream-box">
|
||||
@@ -772,13 +774,13 @@ limitations under the License.
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? 'cancel' : 'task_alt' }}
|
||||
</span>
|
||||
<span class="action-title">
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? 'Task Execution Failed' : 'Task Completed' }}
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? '任务执行失败' : '任务已完成' }}
|
||||
</span>
|
||||
<span class="action-status-badge" [class.is-failed]="getReportStatusValue(item.data) === 'failed'" [class.is-completed]="getReportStatusValue(item.data) !== 'failed'">
|
||||
<span class="material-symbols-outlined status-icon">
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? 'error' : 'check_circle' }}
|
||||
</span>
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? 'Failed' : 'Completed' }}
|
||||
{{ getReportStatusValue(item.data) === 'failed' ? '失败' : '已完成' }}
|
||||
</span>
|
||||
<span class="action-expand-icon material-symbols-outlined">
|
||||
{{ isActionExpanded('action-' + block.id + '-' + itemIdx) ? 'expand_less' : 'expand_more' }}
|
||||
@@ -788,7 +790,7 @@ limitations under the License.
|
||||
@if (!isActionExpanded('action-' + block.id + '-' + itemIdx) && getReportStatusExplanation(item.data)) {
|
||||
<div class="action-card-body">
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Summary:</span>
|
||||
<span class="detail-label">摘要:</span>
|
||||
<span class="detail-value">"{{ getReportStatusExplanation(item.data) }}"</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -799,7 +801,7 @@ limitations under the License.
|
||||
<div class="expanded-grid">
|
||||
@if (getReportStatusExplanation(item.data); as expText) {
|
||||
<div class="grid-item full-width">
|
||||
<span class="grid-label">Report & Findings</span>
|
||||
<span class="grid-label">报告与发现</span>
|
||||
<span class="grid-value report-markdown-body" [innerHTML]="renderMarkdown(expText, 'report-' + block.id + '-' + itemIdx)"></span>
|
||||
</div>
|
||||
}
|
||||
@@ -809,20 +811,20 @@ limitations under the License.
|
||||
<div class="expanded-screenshots-container">
|
||||
@if (getStepPreImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Final Verified State</span>
|
||||
<span class="screenshot-label">最终验证状态</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPreImageUrl(block.data, item.data)!, item.data, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img [src]="getStepPreImageUrl(block.data, item.data)" alt="Final Screen Screenshot" />
|
||||
<img [src]="getStepPreImageUrl(block.data, item.data)" alt="最终屏幕截图" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (getStepPostImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Post Verification</span>
|
||||
<span class="screenshot-label">操作后验证</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPostImageUrl(block.data, item.data)!, null, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="Post Screenshot" />
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="操作后截图" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -846,7 +848,8 @@ limitations under the License.
|
||||
@if (isActionFailed(item.data, block.data)) {
|
||||
<span class="action-status-badge is-failed">
|
||||
<span class="material-symbols-outlined status-icon">error</span>
|
||||
Failed
|
||||
|
||||
失败
|
||||
</span>
|
||||
}
|
||||
<span class="action-expand-icon material-symbols-outlined">
|
||||
@@ -858,7 +861,7 @@ limitations under the License.
|
||||
<div class="action-card-body">
|
||||
@if (getActionTargetText(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Target:</span>
|
||||
<span class="detail-label">目标:</span>
|
||||
<span class="detail-value">"{{ getActionTargetText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -870,7 +873,7 @@ limitations under the License.
|
||||
}
|
||||
@if (getActionCoords(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Coordinates:</span>
|
||||
<span class="detail-label">坐标:</span>
|
||||
<span class="detail-value coordinate-badge">{{ getActionCoords(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@@ -882,7 +885,7 @@ limitations under the License.
|
||||
<div class="expanded-grid">
|
||||
@if (getActionTargetText(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Target</span>
|
||||
<span class="grid-label">目标</span>
|
||||
<span class="grid-value">"{{ getActionTargetText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -894,19 +897,19 @@ limitations under the License.
|
||||
}
|
||||
@if (getActionCoords(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Coordinates</span>
|
||||
<span class="grid-label">坐标</span>
|
||||
<span class="grid-value code-pill">{{ getActionCoords(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (getActionBounds(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Target Bounds</span>
|
||||
<span class="grid-label">目标边界</span>
|
||||
<span class="grid-value code-pill">[{{ getActionBounds(item.data) }}]</span>
|
||||
</div>
|
||||
}
|
||||
@if (getActionClass(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Target Class</span>
|
||||
<span class="grid-label">目标类型</span>
|
||||
<span class="grid-value code-pill">{{ getActionClass(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@@ -919,7 +922,7 @@ limitations under the License.
|
||||
<!-- Fallback item if all detail fields are empty -->
|
||||
@if (!getActionTargetText(item.data) && !getActionInputText(item.data) && !getActionCoords(item.data) && !getActionBounds(item.data) && !getActionClass(item.data) && getActionExtraParams(item.data).length === 0) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Action</span>
|
||||
<span class="grid-label">操作</span>
|
||||
<span class="grid-value">{{ getActionTitle(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@@ -929,10 +932,10 @@ limitations under the License.
|
||||
<div class="expanded-screenshots-container">
|
||||
@if (getStepPreImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Pre-Action (Before)</span>
|
||||
<span class="screenshot-label">操作前</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPreImageUrl(block.data, item.data)!, item.data, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img #preImg [src]="getStepPreImageUrl(block.data, item.data)" (load)="onImageLoad(preImg, preOverlay, item.data)" alt="Pre-Action Screenshot" />
|
||||
<img #preImg [src]="getStepPreImageUrl(block.data, item.data)" (load)="onImageLoad(preImg, preOverlay, item.data)" alt="操作前截图" />
|
||||
<div #preOverlay class="overlay-layer"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -940,10 +943,10 @@ limitations under the License.
|
||||
}
|
||||
@if (getStepPostImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Post-Action (After)</span>
|
||||
<span class="screenshot-label">操作后</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPostImageUrl(block.data, item.data)!, null, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="Post-Action Screenshot" />
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="操作后截图" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -983,13 +986,15 @@ limitations under the License.
|
||||
<div class="llm-retry-note-text">
|
||||
@if (isLLMRetryEntryWaiting(retry)) {
|
||||
<span class="llm-retry-status-line">
|
||||
LLM temporarily unavailable
|
||||
|
||||
模型暂时不可用
|
||||
@if (getLLMRetryEntryDelay(retry); as retryDelay) {
|
||||
· Retrying in {{ retryDelay }}…
|
||||
}
|
||||
</span>
|
||||
<span class="llm-retry-guidance">
|
||||
Frequent retries may indicate a low API rate limit. Consider increasing the limit or reducing request concurrency.
|
||||
|
||||
频繁重试可能是接口限流导致,可提高调用额度或降低并发数。
|
||||
</span>
|
||||
}
|
||||
@if (!isLLMRetryEntryWaiting(retry)) {
|
||||
@@ -1011,16 +1016,18 @@ limitations under the License.
|
||||
(click)="hasLLMFailureRetryEntries(item.data) && toggleActionExpanded('llm-failure-' + block.id + '-' + itemIdx, $event)">
|
||||
<div class="action-card-header llm-failure-header">
|
||||
<span class="material-symbols-outlined action-icon is-failed">error</span>
|
||||
<span class="action-title">LLM Request Failed</span>
|
||||
<span class="action-title">模型请求失败</span>
|
||||
@if (isTerminalLLMFailure(item.data)) {
|
||||
<span class="action-status-badge is-paused">
|
||||
<span class="material-symbols-outlined status-icon">pause_circle</span>
|
||||
Paused
|
||||
|
||||
已暂停
|
||||
</span>
|
||||
} @else {
|
||||
<span class="action-status-badge is-failed">
|
||||
<span class="material-symbols-outlined status-icon">warning</span>
|
||||
Failed
|
||||
|
||||
失败
|
||||
</span>
|
||||
}
|
||||
@if (hasLLMFailureRetryEntries(item.data)) {
|
||||
@@ -1031,22 +1038,22 @@ limitations under the License.
|
||||
</div>
|
||||
<div class="action-card-body">
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">What happened:</span>
|
||||
<span class="detail-value">The AI request could not be completed after automatic retries.</span>
|
||||
<span class="detail-label">发生了什么:</span>
|
||||
<span class="detail-value">自动重试后仍无法完成模型请求。</span>
|
||||
</div>
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Failure reason:</span>
|
||||
<span class="detail-label">失败原因:</span>
|
||||
<span class="detail-value">{{ getLLMErrorText(item.data) }}</span>
|
||||
</div>
|
||||
@if (getLLMFailureWaited(item.data); as waited) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Waited:</span>
|
||||
<span class="detail-label">已等待:</span>
|
||||
<span class="detail-value">{{ waited }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (isActionExpanded('llm-failure-' + block.id + '-' + itemIdx)) {
|
||||
<div class="failure-retry-details">
|
||||
<div class="failure-retry-title">Retry details</div>
|
||||
<div class="failure-retry-title">重试详情</div>
|
||||
@for (retry of getLLMFailureRetryEntries(item.data); track retry; let retryIndex = $index) {
|
||||
<div class="failure-retry-row">
|
||||
<span>Retry {{ retryIndex + 1 }}</span>
|
||||
@@ -1066,14 +1073,14 @@ limitations under the License.
|
||||
type="button"
|
||||
class="btn-continue-task"
|
||||
(click)="resumePausedTask($event)"
|
||||
title="Continue the paused task"
|
||||
aria-label="Continue the paused task"
|
||||
title="继续已暂停的任务"
|
||||
aria-label="继续已暂停的任务"
|
||||
>
|
||||
<span class="material-symbols-outlined continue-icon">play_arrow</span>
|
||||
<span>Continue task</span>
|
||||
<span>继续任务</span>
|
||||
<span class="material-symbols-outlined continue-arrow">arrow_forward</span>
|
||||
</button>
|
||||
<span class="llm-resume-hint">Task paused · no steps are running</span>
|
||||
<span class="llm-resume-hint">任务已暂停 · 当前没有执行中的步骤</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -1096,7 +1103,7 @@ limitations under the License.
|
||||
<span
|
||||
class="tool-key-pill"
|
||||
(click)="onToolKeyClick(key)"
|
||||
title="Click to view note content"
|
||||
title="点击查看笔记内容"
|
||||
>
|
||||
<span class="material-symbols-outlined pill-icon">draft</span>
|
||||
{{ key }}
|
||||
@@ -1134,7 +1141,8 @@ limitations under the License.
|
||||
@if (isToolFailed(item.data)) {
|
||||
<span class="action-status-badge is-failed">
|
||||
<span class="material-symbols-outlined status-icon">error</span>
|
||||
Failed
|
||||
|
||||
失败
|
||||
</span>
|
||||
}
|
||||
<span class="action-expand-icon material-symbols-outlined">
|
||||
@@ -1148,19 +1156,19 @@ limitations under the License.
|
||||
@if (isAdbCommandTool(item.data)) {
|
||||
@if (getAdbCommandLine(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Command:</span>
|
||||
<span class="detail-label">命令:</span>
|
||||
<span class="detail-value command-value"><code>{{ getAdbCommandLine(item.data) }}</code></span>
|
||||
</div>
|
||||
}
|
||||
@if (getAdbCwd(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Cwd:</span>
|
||||
<span class="detail-label">工作目录:</span>
|
||||
<span class="detail-value">"{{ getAdbCwd(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@if (getAdbTerminalId(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Terminal ID:</span>
|
||||
<span class="detail-label">终端 ID:</span>
|
||||
<span class="detail-value">"{{ getAdbTerminalId(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1169,7 +1177,7 @@ limitations under the License.
|
||||
@if (!isAdbCommandTool(item.data)) {
|
||||
@if (getToolTargetText(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Target:</span>
|
||||
<span class="detail-label">目标:</span>
|
||||
<span class="detail-value">"{{ getToolTargetText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1181,19 +1189,19 @@ limitations under the License.
|
||||
}
|
||||
@if (getToolCoords(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Coordinates:</span>
|
||||
<span class="detail-label">坐标:</span>
|
||||
<span class="detail-value coordinate-badge">{{ getToolCoords(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (getToolAnalysisText(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Analysis:</span>
|
||||
<span class="detail-label">分析:</span>
|
||||
<span class="detail-value">"{{ getToolAnalysisText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@if (getToolGenericDetails(item.data)) {
|
||||
<div class="action-detail-row">
|
||||
<span class="detail-label">Details:</span>
|
||||
<span class="detail-label">详情:</span>
|
||||
<span class="detail-value">"{{ getToolGenericDetails(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1207,19 +1215,19 @@ limitations under the License.
|
||||
@if (isAdbCommandTool(item.data)) {
|
||||
@if (getAdbCommandLine(item.data)) {
|
||||
<div class="grid-item full-width">
|
||||
<span class="grid-label">Command</span>
|
||||
<span class="grid-label">命令</span>
|
||||
<span class="grid-value command-value"><code>{{ getAdbCommandLine(item.data) }}</code></span>
|
||||
</div>
|
||||
}
|
||||
@if (getAdbCwd(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Working Directory</span>
|
||||
<span class="grid-label">工作目录</span>
|
||||
<span class="grid-value">"{{ getAdbCwd(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@if (getAdbTerminalId(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Terminal ID</span>
|
||||
<span class="grid-label">终端 ID</span>
|
||||
<span class="grid-value code-pill">{{ getAdbTerminalId(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1227,7 +1235,7 @@ limitations under the License.
|
||||
@if (!isAdbCommandTool(item.data)) {
|
||||
@if (getToolTargetText(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Target</span>
|
||||
<span class="grid-label">目标</span>
|
||||
<span class="grid-value">"{{ getToolTargetText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1239,19 +1247,19 @@ limitations under the License.
|
||||
}
|
||||
@if (getToolCoords(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Coordinates</span>
|
||||
<span class="grid-label">坐标</span>
|
||||
<span class="grid-value code-pill">{{ getToolCoords(item.data) }}</span>
|
||||
</div>
|
||||
}
|
||||
@if (getToolAnalysisText(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Analysis</span>
|
||||
<span class="grid-label">分析</span>
|
||||
<span class="grid-value">"{{ getToolAnalysisText(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@if (getToolGenericDetails(item.data)) {
|
||||
<div class="grid-item">
|
||||
<span class="grid-label">Details</span>
|
||||
<span class="grid-label">详情</span>
|
||||
<span class="grid-value">"{{ getToolGenericDetails(item.data) }}"</span>
|
||||
</div>
|
||||
}
|
||||
@@ -1268,10 +1276,10 @@ limitations under the License.
|
||||
<div class="expanded-screenshots-container">
|
||||
@if (getStepPreImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Pre-Action (Before)</span>
|
||||
<span class="screenshot-label">操作前</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPreImageUrl(block.data, item.data)!, item.data, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img #preImgTool [src]="getStepPreImageUrl(block.data, item.data)" (load)="onImageLoad(preImgTool, preOverlayTool, item.data)" alt="Pre-Action Screenshot" />
|
||||
<img #preImgTool [src]="getStepPreImageUrl(block.data, item.data)" (load)="onImageLoad(preImgTool, preOverlayTool, item.data)" alt="操作前截图" />
|
||||
<div #preOverlayTool class="overlay-layer"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1279,10 +1287,10 @@ limitations under the License.
|
||||
}
|
||||
@if (getStepPostImageUrl(block.data, item.data)) {
|
||||
<div class="screenshot-column">
|
||||
<span class="screenshot-label">Post-Action (After)</span>
|
||||
<span class="screenshot-label">操作后</span>
|
||||
<div class="image-wrapper" (click)="openImageModal(getStepPostImageUrl(block.data, item.data)!, null, $event)">
|
||||
<div class="img-relative-box">
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="Post-Action Screenshot" />
|
||||
<img [src]="getStepPostImageUrl(block.data, item.data)" alt="操作后截图" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1337,12 +1345,12 @@ limitations under the License.
|
||||
<div class="synthesis-card-header">
|
||||
<div class="header-left">
|
||||
<span class="material-symbols-outlined icon-sparkle">assignment_turned_in</span>
|
||||
<span class="main-title">Task Report</span>
|
||||
<span class="main-title">任务报告</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<button type="button" class="btn-open-note" (click)="openOutputterNote($event)">
|
||||
<span class="material-symbols-outlined">visibility</span>
|
||||
<span>View in Notes</span>
|
||||
<span>在笔记中查看</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1423,11 +1431,11 @@ limitations under the License.
|
||||
@if (selectedZoomImage()) {
|
||||
<div class="image-modal-backdrop" (click)="closeImageModal($event)">
|
||||
<div class="image-modal-content" (click)="$event.stopPropagation()">
|
||||
<button class="image-modal-close" (click)="closeImageModal($event)" aria-label="Close image preview">
|
||||
<button class="image-modal-close" (click)="closeImageModal($event)" aria-label="关闭图片预览">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
<div class="img-relative-box">
|
||||
<img #modalImg [src]="selectedZoomImage()" (load)="onImageLoad(modalImg, modalOverlay, selectedZoomAction())" alt="Zoomed Screenshot" />
|
||||
<img #modalImg [src]="selectedZoomImage()" (load)="onImageLoad(modalImg, modalOverlay, selectedZoomAction())" alt="放大截图" />
|
||||
<div #modalOverlay class="overlay-layer"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user