Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input

# Conflicts:
#	docs/module-graph.md
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/client/ui-conversation/src/client/chat/MessageItem.tsx
#	packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx
#	packages/client/ui-conversation/src/client/skeleton/InputBar.tsx
#	packages/client/ui-conversation/tests/input-bar.spec.tsx
#	packages/client/ui-trajectory/tests/client-bundle.spec.ts
This commit is contained in:
creatixchu
2026-07-31 03:12:38 +08:00
172 changed files with 2834 additions and 1160 deletions

View File

@@ -151,7 +151,7 @@ describe('web e2e: approval takeover keeps its actions reachable', () => {
await page.setViewportSize(original)
}
await panel.getByRole('button', { name: '允许一次' }).click()
await panel.getByRole('button', { name: 'Allow once' }).click()
const sessionId = await settled
if (MODE === 'record') {

View File

@@ -60,6 +60,9 @@ let unmount: (() => void) | undefined
beforeEach(() => {
localStorage.clear()
// English pinned before boot: role/text locators stay deterministic across
// localized component migrations (the newEnglishPage e2e convention).
localStorage.setItem('dsh.locale', 'en')
document.title = 'DeepSeek Harness'
vi.stubGlobal('ResizeObserver', ResizeObserverStub)
vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) =>

View File

@@ -98,7 +98,7 @@ describe.skipIf(MODE === 'record')('web e2e: details panel follows the current S
await page.getByText('LIGHTHOUSE', { exact: true }).waitFor({ timeout: 15_000 })
await expect.poll(() => detailsTrack(page), { timeout: 5_000 }).toBe(0)
expect(await page.getByText('详情', { exact: true }).isVisible()).toBe(false)
expect(await page.getByText('Details', { exact: true }).isVisible()).toBe(false)
await compareOrRefreshGolden(HANDLES_EXPECTED, await handleSnapshot(page), MODE)
const sidebarBefore = await sidebarTrack(page)
@@ -118,18 +118,18 @@ describe.skipIf(MODE === 'record')('web e2e: details panel follows the current S
await appFrame(page).waitFor({ timeout: 30_000 })
await page.getByText('LIGHTHOUSE', { exact: true }).waitFor({ timeout: 15_000 })
await expect.poll(() => detailsTrack(page), { timeout: 5_000 }).toBe(0)
expect(await page.getByText('详情', { exact: true }).isVisible()).toBe(false)
expect(await page.getByText('Details', { exact: true }).isVisible()).toBe(false)
await page.getByRole('button', { name: /^(?:New session|新.*会话)$/ }).last().click()
await page.getByText("Let's start building", { exact: false }).waitFor({ timeout: 15_000 })
await expect.poll(() => detailsTrack(page), { timeout: 5_000 }).toBe(0)
expect(await page.getByText('详情', { exact: true }).isVisible()).toBe(false)
expect(await page.getByText('Details', { exact: true }).isVisible()).toBe(false)
const original = page.locator('[role=treeitem]').filter({ hasText: 'Reply with the single word' }).first()
await original.click()
await page.getByText('LIGHTHOUSE', { exact: true }).waitFor({ timeout: 15_000 })
await expect.poll(() => detailsTrack(page), { timeout: 5_000 }).toBe(0)
expect(await page.getByText('详情', { exact: true }).isVisible()).toBe(false)
expect(await page.getByText('Details', { exact: true }).isVisible()).toBe(false)
const ungrouped = page.getByText('Ungrouped', { exact: true })
const ungroupedRow = ungrouped.locator('..').locator('..')

View File

@@ -66,12 +66,12 @@ describe('web e2e: message IconActions and clocks on settled history', () => {
// Focus-reveal the footers (hover:hover keeps them opacity-hidden until
// hover/focus-within). User has three actions; each turn's last content
// assistant has copy + branch.
const copyButtons = page.getByRole('button', { name: '复制' })
const copyButtons = page.getByRole('button', { name: 'Copy' })
await expect.poll(() => copyButtons.count(), { timeout: 10_000 }).toBeGreaterThanOrEqual(2)
await copyButtons.first().focus()
await expect.poll(() => page.getByRole('button', { name: '在新对话中分支' }).count(), { timeout: 5_000 })
await expect.poll(() => page.getByRole('button', { name: 'Branch into a new conversation' }).count(), { timeout: 5_000 })
.toBeGreaterThanOrEqual(2)
await expect.poll(() => page.getByRole('button', { name: '编辑' }).count(), { timeout: 5_000 }).toBe(1)
await expect.poll(() => page.getByRole('button', { name: 'Edit' }).count(), { timeout: 5_000 }).toBe(1)
}, 60_000)
it.skipIf(MODE === 'record')('matches the conversation aria golden with IconActions and clocks', async () => {
@@ -81,7 +81,7 @@ describe('web e2e: message IconActions and clocks on settled history', () => {
}).waitFor({ timeout: 10_000 })
// Keep a footer focused so opacity-hidden actions stay in the a11y tree
// as an active/focused control during the capture.
await page.getByRole('button', { name: '复制' }).first().focus()
await page.getByRole('button', { name: 'Copy' }).first().focus()
const snapshot = (await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd))
.split(SEED_ID).join('{{seededId}}')
await compareOrRefreshGolden(UI_EXPECTED, snapshot, MODE)
@@ -91,7 +91,7 @@ describe('web e2e: message IconActions and clocks on settled history', () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-message-fork'))
// Exercise the assistant action specifically; package coverage pins the
// user action separately at its own event seq.
await page.getByRole('button', { name: '在新对话中分支' }).last().click()
await page.getByRole('button', { name: 'Branch into a new conversation' }).last().click()
await expect.poll(
() => scaffold.ctx.agents.list().find(agent => agent.session.header.parentSession === SessionId(SEED_ID)),
{ timeout: 15_000 },

View File

@@ -253,7 +253,7 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
}
})
expect(dot.state).toBe('done')
expect(dot.label).toBe('已完成')
expect(dot.label).toBe('Done')
expect(dot.beforePrompt).toBe(true)
expect(dot.insideCard).toBe(true)
expect(dot.leftOfPrompt).toBe(true)
@@ -270,7 +270,7 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
await page.context().grantPermissions(['clipboard-read', 'clipboard-write'])
await card.locator('[class*="_copyButton_"]').first().click()
await expect.poll(() => card.locator('[class*="_copyButton_"]').first().textContent(), { timeout: 5_000 })
.toBe('复制成功')
.toBe('Copied')
expect(await page.evaluate(() => navigator.clipboard.readText())).toContain('NAVIGATION_OK')
}, 60_000)

View File

@@ -81,7 +81,7 @@ describe('web e2e: queue row actions', () => {
await input.fill(text)
await input.press('Enter')
}
const queueHeader = page.getByRole('button', { name: '2 条排队消息' })
const queueHeader = page.getByRole('button', { name: '2 queued messages' })
await expect.poll(() => queueHeader.getAttribute('aria-expanded'), { timeout: 10_000 })
.toBe('false')
const collapsedSnapshot = await captureStableAria(
@@ -92,21 +92,21 @@ describe('web e2e: queue row actions', () => {
await compareOrRefreshGolden(COLLAPSED_EXPECTED, collapsedSnapshot, MODE)
await queueHeader.click()
await expect.poll(
() => page.getByRole('button', { name: '删除排队消息' }).count(),
() => page.getByRole('button', { name: 'Remove queued message' }).count(),
{ timeout: 10_000 },
).toBe(2)
const editRow = page.getByText(EDIT, { exact: true }).locator('..')
await editRow.getByRole('button', { name: '编辑排队消息' }).click()
const editor = page.getByRole('textbox', { name: '编辑排队消息' })
await editRow.getByRole('button', { name: 'Edit queued message' }).click()
const editor = page.getByRole('textbox', { name: 'Edit queued message' })
await editor.fill(EDITED)
const editingSnapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
await compareOrRefreshGolden(EDITING_EXPECTED, editingSnapshot, MODE)
await page.getByRole('button', { name: '保存排队消息' }).click()
await page.getByRole('button', { name: 'Save queued message' }).click()
await page.getByText(EDITED, { exact: true }).waitFor()
const removeRow = page.getByText(REMOVE, { exact: true }).locator('..')
await removeRow.getByRole('button', { name: '删除排队消息' }).click()
await removeRow.getByRole('button', { name: 'Remove queued message' }).click()
await expect.poll(() => page.getByText(REMOVE, { exact: true }).count()).toBe(0)
const snapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
@@ -116,7 +116,7 @@ describe('web e2e: queue row actions', () => {
expect(tripwire.warnings).toEqual([])
const editedRow = page.getByText(EDITED, { exact: true }).locator('..')
await editedRow.getByRole('button', { name: '删除排队消息' }).click()
await editedRow.getByRole('button', { name: 'Remove queued message' }).click()
await expect.poll(() => page.getByText(EDITED, { exact: true }).count()).toBe(0)
await page.getByRole('button', { name: 'Stop generating' }).click()
await settled

View File

@@ -147,7 +147,7 @@ describe('web e2e: seeded history renders through cold resume', () => {
}],
},
}))
await page.getByRole('button', { name: '上下文注入' }).waitFor({ timeout: 10_000 })
await page.getByRole('button', { name: 'Context injection' }).waitFor({ timeout: 10_000 })
}, 60_000)
it.skipIf(MODE === 'record')('matches the historical conversation aria golden', async () => {
@@ -165,7 +165,7 @@ describe('web e2e: seeded history renders through cold resume', () => {
it.skipIf(MODE === 'record')('matches the Figma context disclosure geometry', async () => {
onTestFailed(() => saveFailureShot(page, 'web-e2e-context-injection'))
const disclosure = page.getByRole('button', { name: '上下文注入' })
const disclosure = page.getByRole('button', { name: 'Context injection' })
expect(await disclosure.getAttribute('aria-expanded')).toBe('false')
const collapsedIcon = disclosure.locator('svg').first()
const collapsedIconBox = await collapsedIcon.boundingBox()

View File

@@ -1,4 +1,4 @@
- text: 等待审批
- group "审批详情": "escalate sandbox to workspace-write: Need to write the notes.txt file as requested by the user. echo 'tok63z tokc7y tokibx tokofw tokujv tok10nu tok16rt tok1cvs tok1izr tok1p3q tok1v7p tok21bo tok2a4 tok8e3 tokei2 tokkm1 tokqq0 tokwtz tok12xy tok191x tok1f5w tok1l9v tok1rdu tok1xht tok23ls tok4k8 tokao7 tokgs6 tokmw5 tokt04 tokz43 tok1582 tok1bc1 tok1hg0 tok1njz tok1tny tok1zrx tokqd tok6uc tokcyb tokj2a tokp69 tokva8 tok11e7 tok17i6 tok1dm5 tok1jq4 tok1pu3 tok1vy2 tok2221 tok30h tok94g tokf8f toklce tokrgd tokxkc tok13ob tok19sa tok1fw9 tok1m08 tok1s47 tok1y86 tok24c5 tok5al tokbek tokhij toknmi toktqh tokzug tok15yf tok1c2e tok1i6d tok1oac tok1ueb tok20ia tok1gq tok7kp tokdoo tokjsn tokpwm tokw0l tok124k tok188j tok1eci tok1kgh tok1qkg tok1wof tok22se tok3qu tok9ut tokfys tokm2r toks6q tokyap tok14eo tok1ain tok1gmm tok1mql tok1suk tok1yyj tok252i tok60y tokc4x toki8w tokocv tokugu tok10kt tok16os tok1csr tok1iwq tok1p0p tok1v4o tok218n tok273 tok8b2 tokef1 tokkj0 tokqmz tokwqy tok12ux tok18yw tok1f2v tok1l6u tok1rat tok1xes tok23ir tok4h7 tokal6 tokgp5 tokmt4 toksx3 tokz12 tok1551 tok1b90 tok1hcz tok1ngy tok1tkx tok1zow toknc tok6rb tokcva tokiz9 tokp38 tokv77 tok11b6 tok17f5 tok1dj4 tok1jn3 tok1pr2 tok1vv1 tok21z0 tok2xg tok91f tokf5e tokl9d tokrdc tokxhb tok13la tok19p9 tok1ft8 tok1lx7 tok1s16 tok1y55 tok2494 tok57k tokbbj tokhfi toknjh tokktng tokzrf tok15ve tok1bzd tok1i3c tok1o7b tok1uba tok20f9 tok1dp tok7ho tokdln tokjpm tokptl tokvxk tok121j tok185i tok1e9h tok1kdg tok1qhf tok1wle tok22pd tok3nt tok9rs tokfvr toklzq toks3p toky7o tok14bn tok1afm tok1gjl tok1mnk tok1srj tok1yvi tok24zh tok5xx tokc1w toki5v toko9u tokudt tok10hs tok16lr tok1cpq tok1itp tok1oxo tok1v1n tok215m tok242 tok881 tokec0 tokfz tokqjy tokwnx' > notes.txt"
- button "拒绝"
- button "允许一次"
- text: Waiting for approval
- group "Approval details": "escalate sandbox to workspace-write: Need to write the notes.txt file as requested by the user. echo 'tok63z tokc7y tokibx tokofw tokujv tok10nu tok16rt tok1cvs tok1izr tok1p3q tok1v7p tok21bo tok2a4 tok8e3 tokei2 tokkm1 tokqq0 tokwtz tok12xy tok191x tok1f5w tok1l9v tok1rdu tok1xht tok23ls tok4k8 tokao7 tokgs6 tokmw5 tokt04 tokz43 tok1582 tok1bc1 tok1hg0 tok1njz tok1tny tok1zrx tokqd tok6uc tokcyb tokj2a tokp69 tokva8 tok11e7 tok17i6 tok1dm5 tok1jq4 tok1pu3 tok1vy2 tok2221 tok30h tok94g tokf8f toklce tokrgd tokxkc tok13ob tok19sa tok1fw9 tok1m08 tok1s47 tok1y86 tok24c5 tok5al tokbek tokhij toknmi toktqh tokzug tok15yf tok1c2e tok1i6d tok1oac tok1ueb tok20ia tok1gq tok7kp tokdoo tokjsn tokpwm tokw0l tok124k tok188j tok1eci tok1kgh tok1qkg tok1wof tok22se tok3qu tok9ut tokfys tokm2r toks6q tokyap tok14eo tok1ain tok1gmm tok1mql tok1suk tok1yyj tok252i tok60y tokc4x toki8w tokocv tokugu tok10kt tok16os tok1csr tok1iwq tok1p0p tok1v4o tok218n tok273 tok8b2 tokef1 tokkj0 tokqmz tokwqy tok12ux tok18yw tok1f2v tok1l6u tok1rat tok1xes tok23ir tok4h7 tokal6 tokgp5 tokmt4 toksx3 tokz12 tok1551 tok1b90 tok1hcz tok1ngy tok1tkx tok1zow toknc tok6rb tokcva tokiz9 tokp38 tokv77 tok11b6 tok17f5 tok1dj4 tok1jn3 tok1pr2 tok1vv1 tok21z0 tok2xg tok91f tokf5e tokl9d tokrdc tokxhb tok13la tok19p9 tok1ft8 tok1lx7 tok1s16 tok1y55 tok2494 tok57k tokbbj tokhfi toknjh tokktng tokzrf tok15ve tok1bzd tok1i3c tok1o7b tok1uba tok20f9 tok1dp tok7ho tokdln tokjpm tokptl tokvxk tok121j tok185i tok1e9h tok1kdg tok1qhf tok1wle tok22pd tok3nt tok9rs tokfvr toklzq toks3p toky7o tok14bn tok1afm tok1gjl tok1mnk tok1srj tok1yvi tok24zh tok5xx tokc1w toki5v toko9u tokudt tok10hs tok16lr tok1cpq tok1itp tok1oxo tok1v1n tok215m tok242 tok881 tokec0 tokfz tokqjy tokwnx' > notes.txt"
- button "Reject"
- button "Allow once"

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Using ONE run_code program: run bash `echo CODE_ROUND_OK`, then read the file missing.txt catching its error in the program. Return an object with both outcomes. Then reply DONE and stop. {{clock}}"
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- 'button "Think The user wants me to write a single `run_code` program that:"':
- img
@@ -27,9 +27,9 @@
- img
- text: Think The program ran successfully. Let me now reply DONE as instructed.
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use only Cordis tools. First call cordis_inspect with what \"temporary\". Then call cordis_mount with this exact code: \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\". Read its returned id and call cordis_unmount with that exact id. After all three calls succeed, reply exactly CORDIS_UI_DONE and stop. {{clock}}"
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to:":
- img
@@ -26,7 +26,7 @@
- button [expanded]:
- img
- text: Mount temporary Plugin typescript
- button "复制"
- button "Copy"
- code: "return { name: \"snapshot-noop\", apply(ctx) {} }"
- 'button "Think The id is \"dyn-1\". Now step 3: call cordis_unmount with that id."':
- img
@@ -41,9 +41,9 @@
- img
- text: Think All three calls succeeded. I should now reply exactly "CORDIS_UI_DONE" and stop.
- paragraph: CORDIS_UI_DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,28 +5,28 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use the bash tool to run exactly: echo WEB_E2E_OK. Then reply with the single word DONE and stop. {{clock}}"
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to run a simple bash command and reply with \"DONE\".":
- img
- img
- text: Think The user wants me to run a simple bash command and reply with "DONE".
- img
- text: Bash Echo the test string 已完成 workspace echo WEB_E2E_OK
- button "复制"
- text: Bash Echo the test string Done workspace echo WEB_E2E_OK
- button "Copy"
- text: WEB_E2E_OK
- button "Think The command executed successfully and output \"WEB_E2E_OK\". I just need to reply with \"DONE\".":
- img
- img
- text: Think The command executed successfully and output "WEB_E2E_OK". I just need to reply with "DONE".
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -34,6 +34,6 @@
- text: DeepSeek-V4-Flash
- img
- button "Send message" [disabled]
- text: 详情
- button "关闭详情"
- text: 点击消息流中的工具行查看详情
- text: Details
- button "Close details"
- text: Click a tool row in the message flow to view its details

View File

@@ -5,20 +5,20 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with the single word LIGHTHOUSE and stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to reply with a single word. Let me comply.":
- img
- img
- text: Think The user wants me to reply with a single word. Let me comply.
- paragraph: LIGHTHOUSE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,17 +5,17 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- paragraph: partial
- text: 已停止
- button "复制":
- text: Stopped
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- textbox "Message the agent"
- button "Add attachment":

View File

@@ -5,20 +5,20 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user is asking for a one-sentence description of event sourcing. This is a straightforward knowledge question that doesn't require any skill loading or tool calls.":
- img
- img
- text: Think The user is asking for a one-sentence description of event sourcing. This is a straightforward knowledge question that doesn't require any skill loading or tool calls.
- paragraph: Event sourcing is a pattern where all changes to an application's state are stored as an immutable, append-only sequence of events, rather than persisting only the current state, enabling full auditability, temporal queries, and event-driven architectures.
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -4,13 +4,13 @@
- tablist:
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. {{clock}}"
- button "复制":
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. 7/25 {{clock}}"
- button "Copy":
- img
- tooltip "复制"
- button "在新对话中分支":
- tooltip "Copy"
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to read a.txt and b.txt, then reply with \"DONE\". Let me do both reads in parallel.":
- img
@@ -27,11 +27,11 @@
- img
- text: Think Both files have been read. a.txt contains "alpha" and b.txt contains "beta". I'll now reply with DONE as instructed.
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- text: 7/25 {{clock}}
- textbox "Message the agent"
- button "Add attachment":
- img

View File

@@ -1,3 +1,3 @@
- text: 已完成 {{workspace}} echo NAVIGATION_OK
- button "复制"
- text: Done {{workspace}} echo NAVIGATION_OK
- button "Copy"
- text: NAVIGATION_OK

View File

@@ -6,11 +6,11 @@
- tab "Trajectory"
- img
- text: "plan Plan mode on. Use /plan off to leave. Plan a small change: add a --greeting flag to a CLI. Do not read or write any files. Call exit_plan_mode with a short plan of at most five bullet points. Once the plan is approved, reply with the single word DONE and stop. {{clock}}"
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- 'button "Think The user wants me to plan a small change to add a `--greeting` flag to a CLI. They explicitly told me not to read or write any files, and to call exit_plan_mode with a short plan. Let me do that directly."':
- img
@@ -29,9 +29,9 @@
- img
- text: "Think The plan was approved. The user's last instruction says: \"Once the plan is approved, reply with the single word DONE and stop.\" So I should just reply with DONE and stop."
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use the ask_user_question tool to ask me exactly one question with id \"color\", question \"Which color do you prefer?\", header \"Pick one\", and two options: label \"Blue\" with description \"A cool recessive hue that reads as calm and trustworthy in long reading sessions and dense dashboards.\", and label \"Green\" with description \"A restful mid-spectrum hue with the highest perceived brightness, easiest on the eye over long sessions.\" After I answer, reply with the single word DONE and stop. {{clock}}"
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to use the ask_user_question tool with specific parameters. Let me do exactly that.":
- img
@@ -24,9 +24,9 @@
- img
- text: Think The user answered "Blue". I should now reply with the single word DONE and stop.
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -5,14 +5,14 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- paragraph: partial
- button "2 条排队消息"
- button "2 queued messages"
- textbox "Message the agent"
- button "Add attachment":
- img

View File

@@ -5,26 +5,26 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- paragraph: partial
- button "2 条排队消息" [disabled] [expanded]
- button "2 queued messages" [disabled] [expanded]
- list:
- listitem:
- text: Queue item to remove
- button "编辑排队消息":
- button "Edit queued message":
- img
- button "删除排队消息":
- button "Remove queued message":
- img
- listitem:
- textbox "编辑排队消息": Edited queue item
- button "保存排队消息":
- textbox "Edit queued message": Edited queue item
- button "Save queued message":
- img
- button "取消编辑":
- button "Cancel editing":
- img
- textbox "Message the agent"
- button "Add attachment":

View File

@@ -5,19 +5,19 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Reply with a one-sentence description of event sourcing, then stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- paragraph: partial
- list:
- listitem:
- text: Edited queue item
- button "编辑排队消息":
- button "Edit queued message":
- img
- button "删除排队消息":
- button "Remove queued message":
- img
- textbox "Message the agent"
- button "Add attachment":

View File

@@ -4,12 +4,12 @@
- tablist:
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. {{clock}}"
- button "复制":
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. 7/25 {{clock}}"
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to read a.txt and b.txt, then reply with \"DONE\". Let me do both reads in parallel.":
- img
@@ -26,15 +26,15 @@
- img
- text: Think Both files have been read. a.txt contains "alpha" and b.txt contains "beta". I'll now reply with DONE as instructed.
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- button "上下文注入":
- text: 7/25 {{clock}}
- button "Context injection":
- img
- img
- text: 上下文注入
- text: Context injection
- img
- text: permission preset workspace-write
- textbox "Message the agent"

View File

@@ -4,12 +4,12 @@
- tablist:
- tab "Chat" [selected]
- tab "Trajectory"
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. {{clock}}"
- button "复制":
- text: "Use the read tool twice in one assistant message: read a.txt and b.txt. Then reply with the single word DONE and stop. 7/25 {{clock}}"
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to read a.txt and b.txt, then reply with \"DONE\". Let me do both reads in parallel.":
- img
@@ -26,15 +26,15 @@
- img
- text: Think Both files have been read. a.txt contains "alpha" and b.txt contains "beta". I'll now reply with DONE as instructed.
- paragraph: DONE
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- button "上下文注入":
- text: 7/25 {{clock}}
- button "Context injection":
- img
- img
- text: 上下文注入
- text: Context injection
- textbox "Message the agent"
- button "Add attachment":
- img

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Use the ask_user_question tool to ask me exactly one question with id "checkpoint", question "Ready to continue?", header "Checkpoint", and options labeled "Yes" and "No". After I answer, reply with one short sentence acknowledging my answer and stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to use the ask_user_question tool to ask them a specific question with the given parameters. Let me do exactly that.":
- img

View File

@@ -5,11 +5,11 @@
- tab "Chat" [selected]
- tab "Trajectory"
- text: Use the ask_user_question tool to ask me exactly one question with id "checkpoint", question "Ready to continue?", header "Checkpoint", and options labeled "Yes" and "No". After I answer, reply with one short sentence acknowledging my answer and stop. {{clock}}
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- button "编辑":
- button "Edit":
- img
- button "Think The user wants me to use the ask_user_question tool to ask them a specific question with the given parameters. Let me do exactly that.":
- img
@@ -18,15 +18,15 @@
- button:
- img
- img
- text: "Ask question 1/1 answered 插话 Interjection: include the word BANANA in your final reply."
- text: "Ask question 1/1 answered Interjection Interjection: include the word BANANA in your final reply."
- button "Think The user selected \"Yes\" and wants me to include the word \"BANANA\" in my final reply. Let me acknowledge their answer.":
- img
- img
- text: Think The user selected "Yes" and wants me to include the word "BANANA" in my final reply. Let me acknowledge their answer.
- paragraph: Great, let's move forward. BANANA!
- button "复制":
- button "Copy":
- img
- button "在新对话中分支":
- button "Branch into a new conversation":
- img
- text: {{clock}}
- textbox "Message the agent"

View File

@@ -121,9 +121,9 @@ describe('web e2e: mid-turn steering lands durably and visibly', () => {
// exists yet and no interjection bubble renders — the composer still
// blocks, alone. The DOM is stable here (no further SSE frames can
// arrive until the question is answered), making this state capturable.
expect(await page.getByText('插话').count()).toBe(0)
expect(await page.getByText('Interjection', { exact: true }).count()).toBe(0)
expect(await page.getByText(STEER, { exact: true }).count()).toBe(0)
expect(await page.getByRole('button', { name: '编辑排队消息' }).count()).toBe(0)
expect(await page.getByRole('button', { name: 'Edit queued message' }).count()).toBe(0)
const snapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold.workspaceCwd)
await compareOrRefreshGolden(MID_EXPECTED, snapshot, MODE)
}
@@ -157,7 +157,7 @@ describe('web e2e: mid-turn steering lands durably and visibly', () => {
// Visible: the badged interjection bubble plus the reply that obeys it
// (steer text + final reply each contain the marker word).
await expect.poll(() => page.getByText('插话').count(), { timeout: 15_000 }).toBe(1)
await expect.poll(() => page.getByText('Interjection', { exact: true }).count(), { timeout: 15_000 }).toBe(1)
await expect.poll(() => page.getByText('Interjection:', { exact: false }).count(), { timeout: 10_000 }).toBe(1)
await expect.poll(() => page.getByText('BANANA', { exact: false }).count(), { timeout: 10_000 }).toBeGreaterThanOrEqual(2)
expect(await page.locator('[data-question-key]').count()).toBe(0)