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

View File

@@ -6,8 +6,6 @@ export interface PageAgentEventMap {
// PageAgent status events
// 'agent:execute': { params: { task: string } }
// 'agent:done': { params: { text: string; success: boolean } }
// 'agent:paused': { params: undefined }
// 'agent:resumed': { params: undefined }
// 'agent:disposed': { params: undefined }
// '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 {
background: rgba(239, 68, 68, 0.2);
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));
}
&.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 成功结果 */
&.doneSuccess {
background: linear-gradient(

View File

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

View File

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

View File

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