Merge pull request #114 from alibaba/feat/user-takeover

feat: remove `pause`
This commit is contained in:
Simon
2026-01-15 21:51:01 +08:00
committed by GitHub
6 changed files with 24 additions and 87 deletions

View File

@@ -12,7 +12,7 @@ import type { PageAgentConfig } from './config'
import { MAX_STEPS } from './config/constants' import { MAX_STEPS } from './config/constants'
import SYSTEM_PROMPT from './prompts/system_prompt.md?raw' import SYSTEM_PROMPT from './prompts/system_prompt.md?raw'
import { tools } from './tools' import { tools } from './tools'
import { normalizeResponse, trimLines, uid, waitUntil } from './utils' import { normalizeResponse, trimLines, uid } from './utils'
import { assert } from './utils/assert' import { assert } from './utils/assert'
/** /**
@@ -104,7 +104,6 @@ export class PageAgent extends EventTarget {
id = uid() id = uid()
panel: Panel panel: Panel
tools: typeof tools tools: typeof tools
paused = false
disposed = false disposed = false
task = '' task = ''
taskId = '' taskId = ''
@@ -138,11 +137,6 @@ export class PageAgent extends EventTarget {
language: this.config.language, language: this.config.language,
onExecuteTask: (task) => this.execute(task), onExecuteTask: (task) => this.execute(task),
onStop: () => this.dispose(), onStop: () => this.dispose(),
onPauseToggle: () => {
this.paused = !this.paused
return this.paused
},
getPaused: () => this.paused,
}) })
this.tools = new Map(tools) this.tools = new Map(tools)
@@ -190,6 +184,7 @@ export class PageAgent extends EventTarget {
*/ */
pushObservation(content: string): void { pushObservation(content: string): void {
this.history.push({ type: 'observation', content }) this.history.push({ type: 'observation', content })
this.panel.update({ type: 'observation', content })
} }
async execute(task: string): Promise<ExecutionResult> { async execute(task: string): Promise<ExecutionResult> {
@@ -237,8 +232,6 @@ export class PageAgent extends EventTarget {
// abort // abort
if (this.#abortController.signal.aborted) throw new Error('AbortError') if (this.#abortController.signal.aborted) throw new Error('AbortError')
// pause
await waitUntil(() => !this.paused)
// Update status to thinking // Update status to thinking
console.log(chalk.blue('Thinking...')) console.log(chalk.blue('Thinking...'))
@@ -362,8 +355,6 @@ export class PageAgent extends EventTarget {
execute: async (input: MacroToolInput): Promise<MacroToolResult> => { execute: async (input: MacroToolInput): Promise<MacroToolResult> => {
// abort // abort
if (this.#abortController.signal.aborted) throw new Error('AbortError') if (this.#abortController.signal.aborted) throw new Error('AbortError')
// pause
await waitUntil(() => !this.paused)
console.log(chalk.blue.bold('MacroTool execute'), input) console.log(chalk.blue.bold('MacroTool execute'), input)
const action = input.action const action = input.action

View File

@@ -6,8 +6,6 @@ export interface PageAgentEventMap {
// PageAgent status events // PageAgent status events
// 'agent:execute': { params: { task: string } } // 'agent:execute': { params: { task: string } }
// 'agent:done': { params: { text: string; success: boolean } } // 'agent:done': { params: { text: string; success: boolean } }
// 'agent:paused': { params: undefined }
// 'agent:resumed': { params: undefined }
// 'agent:disposed': { params: undefined } // 'agent:disposed': { params: undefined }
// 'agent:error': { params: { error: string | Error } } // 'agent:error': { params: { error: string | Error } }

View File

@@ -209,18 +209,6 @@
} }
} }
.pauseButton {
font-weight: 600;
&.paused {
background: rgba(34, 197, 94, 0.2); /* 绿色背景表示可以继续 */
color: rgb(34, 197, 94);
&:hover {
background: rgba(34, 197, 94, 0.3);
}
}
}
.stopButton { .stopButton {
background: rgba(239, 68, 68, 0.2); background: rgba(239, 68, 68, 0.2);
color: rgb(255, 41, 41); color: rgb(255, 41, 41);
@@ -364,6 +352,11 @@
background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05)); background: linear-gradient(135deg, rgba(255, 214, 0, 0.1), rgba(255, 214, 0, 0.05));
} }
&.observation {
border-left-color: rgb(147, 51, 234);
background: linear-gradient(135deg, rgba(147, 51, 234, 0.1), rgba(147, 51, 234, 0.05));
}
/* 突出显示 done 成功结果 */ /* 突出显示 done 成功结果 */
&.doneSuccess { &.doneSuccess {
background: linear-gradient( background: linear-gradient(

View File

@@ -11,8 +11,6 @@ export interface PanelConfig {
language?: SupportedLanguage language?: SupportedLanguage
onExecuteTask: (task: string) => void onExecuteTask: (task: string) => void
onStop: () => void onStop: () => void
onPauseToggle: () => boolean // returns new paused state
getPaused: () => boolean
} }
/** /**
@@ -29,6 +27,7 @@ export type PanelUpdate =
| { type: 'completed' } | { type: 'completed' }
| { type: 'toolExecuting'; toolName: string; args: any } | { type: 'toolExecuting'; toolName: string; args: any }
| { type: 'toolCompleted'; toolName: string; args: any; result?: string; duration?: number } | { type: 'toolCompleted'; toolName: string; args: any; result?: string; duration?: number }
| { type: 'observation'; content: string }
/** /**
* Agent control panel * Agent control panel
@@ -39,7 +38,6 @@ export class Panel {
#statusText: HTMLElement #statusText: HTMLElement
#historySection: HTMLElement #historySection: HTMLElement
#expandButton: HTMLElement #expandButton: HTMLElement
#pauseButton: HTMLElement
#stopButton: HTMLElement #stopButton: HTMLElement
#inputSection: HTMLElement #inputSection: HTMLElement
#taskInput: HTMLInputElement #taskInput: HTMLInputElement
@@ -66,7 +64,6 @@ export class Panel {
this.#statusText = this.#wrapper.querySelector(`.${styles.statusText}`)! this.#statusText = this.#wrapper.querySelector(`.${styles.statusText}`)!
this.#historySection = this.#wrapper.querySelector(`.${styles.historySection}`)! this.#historySection = this.#wrapper.querySelector(`.${styles.historySection}`)!
this.#expandButton = this.#wrapper.querySelector(`.${styles.expandButton}`)! this.#expandButton = this.#wrapper.querySelector(`.${styles.expandButton}`)!
this.#pauseButton = this.#wrapper.querySelector(`.${styles.pauseButton}`)!
this.#stopButton = this.#wrapper.querySelector(`.${styles.stopButton}`)! this.#stopButton = this.#wrapper.querySelector(`.${styles.stopButton}`)!
this.#inputSection = this.#wrapper.querySelector(`.${styles.inputSectionWrapper}`)! this.#inputSection = this.#wrapper.querySelector(`.${styles.inputSectionWrapper}`)!
this.#taskInput = this.#wrapper.querySelector(`.${styles.taskInput}`)! this.#taskInput = this.#wrapper.querySelector(`.${styles.taskInput}`)!
@@ -120,11 +117,6 @@ export class Panel {
this.#updateStatusIndicator('thinking') this.#updateStatusIndicator('thinking')
this.#updateHistory() this.#updateHistory()
this.#collapse() this.#collapse()
// Reset pause state via callback
if (this.#config.getPaused()) {
this.#config.onPauseToggle()
}
this.#updatePauseButton()
// Reset user input state // Reset user input state
this.#isWaitingForUserAnswer = false this.#isWaitingForUserAnswer = false
this.#userAnswerResolver = null this.#userAnswerResolver = null
@@ -205,6 +197,8 @@ export class Panel {
duration: data.duration, duration: data.duration,
} }
} }
case 'observation':
return { type: 'observation', displayText: data.content }
} }
} }
@@ -277,39 +271,6 @@ export class Panel {
} }
} }
/**
* Toggle pause state
*/
#togglePause(): void {
const paused = this.#config.onPauseToggle()
this.#updatePauseButton()
// Update status display
if (paused) {
this.#statusText.textContent = this.#i18n.t('ui.panel.paused')
this.#updateStatusIndicator('thinking')
} else {
this.#statusText.textContent = this.#i18n.t('ui.panel.continueExecution')
this.#updateStatusIndicator('tool_executing')
}
}
/**
* Update pause button state
*/
#updatePauseButton(): void {
const paused = this.#config.getPaused()
if (paused) {
this.#pauseButton.textContent = '▶'
this.#pauseButton.title = this.#i18n.t('ui.panel.continue')
this.#pauseButton.classList.add(styles.paused)
} else {
this.#pauseButton.textContent = '⏸︎'
this.#pauseButton.title = this.#i18n.t('ui.panel.pause')
this.#pauseButton.classList.remove(styles.paused)
}
}
/** /**
* Stop Agent * Stop Agent
*/ */
@@ -426,9 +387,6 @@ export class Panel {
<button class="${styles.controlButton} ${styles.expandButton}" title="${this.#i18n.t('ui.panel.expand')}"> <button class="${styles.controlButton} ${styles.expandButton}" title="${this.#i18n.t('ui.panel.expand')}">
</button> </button>
<button class="${styles.controlButton} ${styles.pauseButton}" title="${this.#i18n.t('ui.panel.pause')}">
⏸︎
</button>
<button class="${styles.controlButton} ${styles.stopButton}" title="${this.#i18n.t('ui.panel.stop')}"> <button class="${styles.controlButton} ${styles.stopButton}" title="${this.#i18n.t('ui.panel.stop')}">
X X
</button> </button>
@@ -466,12 +424,6 @@ export class Panel {
this.#toggle() this.#toggle()
}) })
// Pause/continue button
this.#pauseButton.addEventListener('click', (e) => {
e.stopPropagation()
this.#togglePause()
})
// Stop button // Stop button
this.#stopButton.addEventListener('click', (e) => { this.#stopButton.addEventListener('click', (e) => {
e.stopPropagation() e.stopPropagation()
@@ -632,7 +584,7 @@ export class Panel {
typeClass = styles.error typeClass = styles.error
statusIcon = '❌' statusIcon = '❌'
} else if (step.type === 'tool_executing') { } else if (step.type === 'tool_executing') {
statusIcon = '⚙️' statusIcon = '🔨'
} else if (step.type === 'output') { } else if (step.type === 'output') {
typeClass = styles.output typeClass = styles.output
statusIcon = '🤖' statusIcon = '🤖'
@@ -642,6 +594,9 @@ export class Panel {
} else if (step.type === 'retry') { } else if (step.type === 'retry') {
typeClass = styles.retry typeClass = styles.retry
statusIcon = '🔄' statusIcon = '🔄'
} else if (step.type === 'observation') {
typeClass = styles.observation
statusIcon = '👁️'
} else { } else {
statusIcon = '🧠' statusIcon = '🧠'
} }

View File

@@ -6,7 +6,15 @@ export interface Step {
id: string id: string
stepNumber: number stepNumber: number
timestamp: Date timestamp: Date
type: 'thinking' | 'tool_executing' | 'completed' | 'error' | 'output' | 'input' | 'retry' type:
| 'thinking'
| 'tool_executing'
| 'completed'
| 'error'
| 'output'
| 'input'
| 'retry'
| 'observation'
// Tool execution related // Tool execution related
toolName?: string toolName?: string
@@ -18,7 +26,7 @@ export interface Step {
duration?: number duration?: number
} }
export type AgentStatus = 'idle' | 'running' | 'paused' | 'completed' | 'error' export type AgentStatus = 'idle' | 'running' | 'completed' | 'error'
export class UIState { export class UIState {
private steps: Step[] = [] private steps: Step[] = []

View File

@@ -4,17 +4,13 @@ const enUS = {
panel: { panel: {
ready: 'Ready', ready: 'Ready',
thinking: 'Thinking...', thinking: 'Thinking...',
paused: 'Paused',
taskInput: 'Enter new task, describe steps in detail, press Enter to submit', taskInput: 'Enter new task, describe steps in detail, press Enter to submit',
userAnswerPrompt: 'Please answer the question above, press Enter to submit', userAnswerPrompt: 'Please answer the question above, press Enter to submit',
taskTerminated: 'Task terminated', taskTerminated: 'Task terminated',
taskCompleted: 'Task completed', taskCompleted: 'Task completed',
continueExecution: 'Continue execution',
userAnswer: 'User answer: {{input}}', userAnswer: 'User answer: {{input}}',
question: 'Question: {{question}}', question: 'Question: {{question}}',
waitingPlaceholder: 'Waiting for task to start...', waitingPlaceholder: 'Waiting for task to start...',
pause: 'Pause',
continue: 'Continue',
stop: 'Stop', stop: 'Stop',
expand: 'Expand history', expand: 'Expand history',
collapse: 'Collapse history', collapse: 'Collapse history',
@@ -54,17 +50,13 @@ const zhCN = {
panel: { panel: {
ready: '准备就绪', ready: '准备就绪',
thinking: '正在思考...', thinking: '正在思考...',
paused: '暂停中,稍后',
taskInput: '输入新任务,详细描述步骤,回车提交', taskInput: '输入新任务,详细描述步骤,回车提交',
userAnswerPrompt: '请回答上面问题,回车提交', userAnswerPrompt: '请回答上面问题,回车提交',
taskTerminated: '任务已终止', taskTerminated: '任务已终止',
taskCompleted: '任务结束', taskCompleted: '任务结束',
continueExecution: '继续执行',
userAnswer: '用户回答: {{input}}', userAnswer: '用户回答: {{input}}',
question: '询问: {{question}}', question: '询问: {{question}}',
waitingPlaceholder: '等待任务开始...', waitingPlaceholder: '等待任务开始...',
pause: '暂停',
continue: '继续',
stop: '终止', stop: '终止',
expand: '展开历史', expand: '展开历史',
collapse: '收起历史', collapse: '收起历史',