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

# Conflicts:
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/src/client/api.ts
#	packages/client/connection/src/client/fixture.ts
#	packages/client/connection/src/client/index.ts
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/src/client/sessions/service.ts
#	packages/client/ui-conversation/src/client/apply.ts
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/client/ui-conversation/src/client/contract/slots.ts
#	packages/client/ui-conversation/src/client/stores.ts
#	packages/client/ui-conversation/tests/chat-view.spec.tsx
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/index.ts
#	packages/host/apiproxy/src/api/sessions.ts
This commit is contained in:
creatixchu
2026-07-31 10:46:45 +08:00
149 changed files with 4522 additions and 625 deletions

View File

@@ -97,7 +97,7 @@ function boot(search = '?fixture'): void {
/** Open the fixture history session (the alpha log carrying the turn-65 image pair) and wait for its gallery. */
async function openFixtureSession(): Promise<void> {
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
const tree = await screen.findByRole('tree', { name: '会话' }, { timeout: 10_000 })
const group = (await within(tree).findAllByText('fixture'))
.map(el => el.closest<HTMLElement>('[role="treeitem"]'))
.find(el => el?.getAttribute('aria-expanded') !== null)
@@ -164,19 +164,19 @@ it('renders the history image pair through the authorized attachment route and o
it('accepts pasted images into the composer rail in order and removes them', async () => {
boot('?fixture=empty')
await screen.findByPlaceholderText('Choose a workspace to start', {}, { timeout: 10_000 })
fireEvent.click(screen.getAllByRole('button', { name: 'Choose workspace' })
await screen.findByPlaceholderText('选择一个工作区开始', {}, { timeout: 10_000 })
fireEvent.click(screen.getAllByRole('button', { name: '选择工作区' })
.find(el => el.getAttribute('aria-haspopup') === 'menu')!)
fireEvent.click(await screen.findByRole('menuitem', { name: 'Create a new workspace' }))
const dialog = await screen.findByRole('dialog', { name: 'Create a new workspace' })
fireEvent.change(within(dialog).getByRole('textbox', { name: 'New workspace name' }), {
fireEvent.click(await screen.findByRole('menuitem', { name: '新建工作区' }))
const dialog = await screen.findByRole('dialog', { name: '新建工作区' })
fireEvent.change(within(dialog).getByRole('textbox', { name: '新工作区名称' }), {
target: { value: 'image-input' },
})
fireEvent.click(within(dialog).getByRole('button', { name: 'Create workspace' }))
fireEvent.click(within(dialog).getByRole('button', { name: '创建工作区' }))
// Image-only send arming is pinned at package level (input-bar.spec.tsx);
// this assembled lane pins the intake chain over the built graph.
const textarea = await screen.findByPlaceholderText('Describe what you want to build', {}, { timeout: 10_000 })
const textarea = await screen.findByPlaceholderText('描述你想要构建的内容', {}, { timeout: 10_000 })
const image = new File([new Uint8Array([137, 80, 78, 71])], 'pasted.png', { type: 'image/png' })
fireEvent.paste(textarea, {
clipboardData: {