Merge remote-tracking branch 'origin/master' into fix/stats
This commit is contained in:
@@ -283,6 +283,7 @@ describe('web e2e: agent-preset selection', () => {
|
||||
expect(snapshot).toContain('Minimal mode')
|
||||
expect(snapshot).toContain('button "1 subagent"')
|
||||
expect(snapshot.indexOf('Minimal mode')).toBeLessThan(snapshot.indexOf('button "1 subagent"'))
|
||||
expect(snapshot.indexOf('button "1 subagent"')).toBeLessThan(snapshot.indexOf('button "Session log"'))
|
||||
// Static chrome, not a control: the header can only report a composition
|
||||
// the host would refuse to change.
|
||||
expect(snapshot).not.toContain('button "Minimal mode"')
|
||||
|
||||
@@ -43,6 +43,7 @@ const PLUGINS: readonly (WebBootEntry & { bundlePath: string })[] = [
|
||||
'@deepseek-ai/dsh-client-ui-sidebar',
|
||||
],
|
||||
},
|
||||
{ id: '@deepseek-ai/dsh-session-export', bundlePath: 'packages/session-query/session-export/lib/client.js', url: '/plugins/session-export.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-command', '@deepseek-ai/dsh-client-ui-conversation'] },
|
||||
{ id: '@deepseek-ai/dsh-client-ui-trajectory', bundlePath: 'packages/client/ui-trajectory/lib/client.js', url: '/plugins/ui-trajectory.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-conversation'] },
|
||||
]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @vitest-environment jsdom
|
||||
// Multimodal image surfaces over the BUILT client graph (the code-mode-fixture
|
||||
// idiom: real bundles via AppWebEntry, keyless FixtureApiClient transport).
|
||||
// Opens the fixture history session whose turn 72 carries an image in BOTH a
|
||||
// Opens the fixture history session whose turn 73 carries an image in BOTH a
|
||||
// user message and an assistant message, and pins the product surfaces: the
|
||||
// history ImageGallery loading real fixture bytes through the authorized
|
||||
// sessions.attachment route, the single-click ImageLightbox, and the composer
|
||||
@@ -143,8 +143,55 @@ it('accepts pasted images into the composer rail in order and removes them', asy
|
||||
},
|
||||
})
|
||||
const toast = await screen.findByRole('alert')
|
||||
expect(toast.textContent).toContain('Unsupported image format: text/plain')
|
||||
expect(toast.textContent).toContain('Only PNG, JPG, WebP, and GIF images are supported')
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByRole('alert')).toBeNull()
|
||||
}, { timeout: 6_000 })
|
||||
})
|
||||
|
||||
it('accepts a whole-page drop under the limits-labeled overlay and refuses an over-limit batch at intake', async () => {
|
||||
mountAssembledApp()
|
||||
|
||||
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
|
||||
const start = tree.querySelector<HTMLButtonElement>('button[aria-label="New session in fixture"]')
|
||||
if (start === null) throw new Error('fixture Workspace new-session action missing')
|
||||
fireEvent.click(start)
|
||||
const textarea = await screen.findByPlaceholderText('Describe what you want to build', {}, { timeout: 10_000 })
|
||||
|
||||
// A file drag anywhere over the page raises the full-viewport overlay whose
|
||||
// desc line carries the projected limits — copy that can only render after
|
||||
// the imageLimits projection crossed the real fixture transport.
|
||||
const image = new File([new Uint8Array([137, 80, 78, 71])], 'dropped.png', { type: 'image/png' })
|
||||
const dataTransfer = { types: ['Files'], files: [image], dropEffect: 'none' }
|
||||
fireEvent.dragEnter(document.body, { dataTransfer })
|
||||
const overlay = await screen.findByRole('status')
|
||||
expect(overlay.textContent).toContain('Drag images here to add them')
|
||||
await waitFor(() => {
|
||||
expect(overlay.textContent).toContain('Up to 20 images, 5MB each')
|
||||
})
|
||||
|
||||
// Dropping on the transcript area (not the composer card) lands in the rail.
|
||||
fireEvent.drop(document.body, { dataTransfer })
|
||||
await waitFor(() => {
|
||||
const rail = document.querySelector('[role="group"][aria-label="Pending images"]')
|
||||
if (rail === null) throw new Error('attachment rail missing after page drop')
|
||||
expect([...rail.querySelectorAll('img')].map(img => img.getAttribute('alt'))).toEqual(['dropped.png'])
|
||||
}, { timeout: 5_000 })
|
||||
expect(screen.queryByRole('status')).toBeNull()
|
||||
|
||||
// An intake that would exceed the projected per-message count is refused as
|
||||
// a whole batch at add time: the banner names the limit and the rail keeps
|
||||
// only the previously accepted thumbnail — no submit-time rollback.
|
||||
const batch = Array.from({ length: 20 }, (_, i) =>
|
||||
new File([new Uint8Array([137, 80, 78, 71])], `bulk-${String(i)}.png`, { type: 'image/png' }))
|
||||
fireEvent.paste(textarea, {
|
||||
clipboardData: {
|
||||
items: batch.map(file => ({ kind: 'file', type: 'image/png', getAsFile: () => file })),
|
||||
getData: () => '',
|
||||
},
|
||||
})
|
||||
const banner = await screen.findByRole('alert')
|
||||
expect(banner.textContent).toContain('A message can include up to 20 images')
|
||||
const rail = document.querySelector('[role="group"][aria-label="Pending images"]')
|
||||
expect([...(rail?.querySelectorAll('img') ?? [])]).toHaveLength(1)
|
||||
})
|
||||
|
||||
56
apps/web/tests/max-tokens-notice.snapshot.ts
Normal file
56
apps/web/tests/max-tokens-notice.snapshot.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
// @vitest-environment jsdom
|
||||
// Assembled max-tokens snapshot: boots the real built `packages/client/*/lib/
|
||||
// client.js` bundles through AppWebEntry's ModuleLoader path against the
|
||||
// keyless FixtureApiClient transport, opens the fixture session, and pins the
|
||||
// surface its max-tokens turn (72) reaches — the turn-end notice row that a
|
||||
// provider output-cap truncation must render instead of ending silently.
|
||||
//
|
||||
// The dot state is pinned beside the copy on purpose: `dot=warning` is what
|
||||
// distinguishes this notice from the error row, so a regression that routes
|
||||
// max-tokens through the turn-error presentation changes this file even when
|
||||
// its own copy still renders.
|
||||
import { mkdirSync, writeFileSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fireEvent, screen, waitFor, within } from '@testing-library/react'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { hasClass, installAssembledBootEnv, mountAssembledApp, REFRESHING_GOLDEN } from './assembled-boot.ts'
|
||||
|
||||
const EXPECTED = join(process.cwd(), 'apps/web/tests/snapshots/max-tokens-notice/history-turn.expected.txt')
|
||||
|
||||
installAssembledBootEnv()
|
||||
|
||||
/** Normalize the notice row to stable fields: its dot state, title, and hint. */
|
||||
function noticeShape(row: Element): string {
|
||||
const first = (name: string): string =>
|
||||
[...row.querySelectorAll('*')].filter(el => hasClass(el, name))[0]?.textContent?.trim() ?? '<absent>'
|
||||
return [
|
||||
`dot=${row.querySelector('[data-state]')?.getAttribute('data-state') ?? '<absent>'}`,
|
||||
`title=${first('maxTokensTitle')}`,
|
||||
`hint=${first('turnErrorMessage')}`,
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
describe('assembled max-tokens turn-end notice', () => {
|
||||
it('renders the localized truncation notice after the cut-off answer instead of ending silently', async () => {
|
||||
mountAssembledApp()
|
||||
|
||||
const tree = await screen.findByRole('tree', { name: 'Sessions' }, { timeout: 10_000 })
|
||||
fireEvent.click(await within(tree).findByText('Fixture 历史会话'))
|
||||
// The truncated answer itself stays in the flow: the notice supplements the
|
||||
// partial output, it never replaces it.
|
||||
await screen.findByText(/条目 3:这一条写到一半被/, undefined, { timeout: 10_000 })
|
||||
const row = await waitFor(() => {
|
||||
const found = [...document.querySelectorAll('[role="status"]')]
|
||||
.find(candidate => [...candidate.querySelectorAll('*')].some(el => hasClass(el, 'maxTokensTitle')))
|
||||
expect(found).not.toBeUndefined()
|
||||
return found!
|
||||
}, { timeout: 10_000 })
|
||||
|
||||
const shape = noticeShape(row)
|
||||
if (REFRESHING_GOLDEN) {
|
||||
mkdirSync(dirname(EXPECTED), { recursive: true })
|
||||
writeFileSync(EXPECTED, shape)
|
||||
}
|
||||
await expect(shape).toMatchFileSnapshot(EXPECTED)
|
||||
})
|
||||
})
|
||||
121
apps/web/tests/message-feedback.e2e.ts
Normal file
121
apps/web/tests/message-feedback.e2e.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
// Keyless browser regression for durable per-message feedback. Cold-seeds a
|
||||
// settled two-turn transcript (zero model calls), rates one assistant message,
|
||||
// attaches a note, proves both survive a full page reload from the Host's
|
||||
// message-feedback sidecar, then retracts the rating.
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import type { Browser, Page } from 'playwright'
|
||||
import { chromium } from 'playwright'
|
||||
import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest'
|
||||
import {
|
||||
acknowledgeReloadConnectionLoss, launchWebScaffold,
|
||||
seedSession, watchConsole, webSnapshotMode, type WebScaffold,
|
||||
} from './scaffold.ts'
|
||||
import { newEnglishPage, saveFailureShot } from './support.ts'
|
||||
|
||||
// Borrowed read-only: this scenario needs any settled assistant message to
|
||||
// address, not a new recording (message-actions / sidebar-scrollbar pattern).
|
||||
const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url))
|
||||
const MODE = webSnapshotMode()
|
||||
const SEED_ID = 'message-feedback-web-e2e'
|
||||
const NOTE = 'Read both files before answering.'
|
||||
|
||||
describe('web e2e: durable per-message feedback', () => {
|
||||
let scaffold: WebScaffold
|
||||
let browser: Browser
|
||||
let page: Page
|
||||
let tripwire: ReturnType<typeof watchConsole>
|
||||
|
||||
beforeAll(async () => {
|
||||
scaffold = await launchWebScaffold({})
|
||||
await seedSession(scaffold, await readFile(SEED, 'utf8'), SEED_ID)
|
||||
browser = await chromium.launch()
|
||||
page = await newEnglishPage(browser)
|
||||
tripwire = watchConsole(page)
|
||||
await page.goto(scaffold.baseUrl, { waitUntil: 'load' })
|
||||
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
|
||||
}, 120_000)
|
||||
|
||||
afterAll(async () => {
|
||||
await browser?.close()
|
||||
await scaffold?.close()
|
||||
})
|
||||
|
||||
/**
|
||||
* Open the seeded transcript. The first treeitem is the collapsible group
|
||||
* row; the session itself is the row beneath it. The group is already
|
||||
* expanded on a fresh load, so clicking it unconditionally would collapse it
|
||||
* and hide the session row.
|
||||
*/
|
||||
async function openSeededSession(): Promise<void> {
|
||||
const groupRow = page.locator('[role="treeitem"]').first()
|
||||
await groupRow.waitFor({ timeout: 15_000 })
|
||||
if (await groupRow.getAttribute('aria-expanded') !== 'true') await groupRow.click()
|
||||
const sessionRow = page.locator('[role="treeitem"]').nth(1)
|
||||
await sessionRow.waitFor({ timeout: 15_000 })
|
||||
await sessionRow.click()
|
||||
}
|
||||
|
||||
it.skipIf(MODE === 'record')('persists a rating and its note across a reload, then retracts', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-message-feedback'))
|
||||
await openSeededSession()
|
||||
|
||||
// The controls live in the assistant message's IconActions row, which the
|
||||
// transcript reveals on hover/focus like copy and branch. Wait for the
|
||||
// settled closing text first: the strip mounts with that turn's tail.
|
||||
await page.getByText('DONE', { exact: true }).waitFor({ timeout: 30_000 })
|
||||
const like = page.getByRole('button', { name: 'Good response' }).first()
|
||||
await like.waitFor({ timeout: 30_000 })
|
||||
await like.scrollIntoViewIfNeeded()
|
||||
await like.hover()
|
||||
await like.click()
|
||||
// A recorded rating relabels the button to what the next click would do,
|
||||
// so the pressed control is addressed by the retract label from here on.
|
||||
const rated = page.getByRole('button', { name: 'Remove rating' }).first()
|
||||
await expect.poll(() => rated.getAttribute('aria-pressed'), { timeout: 10_000 }).toBe('true')
|
||||
|
||||
// A rated message offers the note editor; an unrated one does not.
|
||||
await page.getByRole('button', { name: 'Add a note' }).first().click()
|
||||
const editor = page.getByRole('textbox', { name: 'Feedback note' })
|
||||
await editor.fill(NOTE)
|
||||
await page.getByRole('button', { name: 'Save', exact: true }).click()
|
||||
await expect.poll(() => editor.count(), { timeout: 10_000 }).toBe(0)
|
||||
await page.getByText(NOTE, { exact: true }).waitFor({ timeout: 10_000 })
|
||||
|
||||
// The durable assertion: a cold browser re-reads the sidecar over the wire.
|
||||
const warningStart = tripwire.warnings.length
|
||||
await page.reload({ waitUntil: 'load' })
|
||||
acknowledgeReloadConnectionLoss(tripwire, warningStart)
|
||||
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
|
||||
await openSeededSession()
|
||||
await page.getByText('DONE', { exact: true }).waitFor({ timeout: 30_000 })
|
||||
|
||||
// The controller defers its list read to the first hover or focus, so a
|
||||
// cold reload shows the unrated label until the strip is touched. Hovering
|
||||
// the unrated control is what triggers the authoritative re-read.
|
||||
const cold = page.getByRole('button', { name: 'Good response' }).first()
|
||||
await cold.waitFor({ timeout: 30_000 })
|
||||
await cold.scrollIntoViewIfNeeded()
|
||||
await cold.hover()
|
||||
|
||||
const restored = page.getByRole('button', { name: 'Remove rating' }).first()
|
||||
await restored.waitFor({ timeout: 30_000 })
|
||||
await restored.scrollIntoViewIfNeeded()
|
||||
await restored.hover()
|
||||
await expect.poll(() => restored.getAttribute('aria-pressed'), { timeout: 15_000 }).toBe('true')
|
||||
await page.getByText(NOTE, { exact: true }).waitFor({ timeout: 10_000 })
|
||||
|
||||
// Re-clicking the active rating retracts it, and the note goes with it.
|
||||
await restored.click()
|
||||
await expect.poll(
|
||||
() => page.getByRole('button', { name: 'Good response' }).first().getAttribute('aria-pressed'),
|
||||
{ timeout: 10_000 },
|
||||
).toBe('false')
|
||||
await expect.poll(() => page.getByText(NOTE, { exact: true }).count(), { timeout: 10_000 }).toBe(0)
|
||||
}, 90_000)
|
||||
|
||||
it.skipIf(MODE === 'record')('kept the console clean', () => {
|
||||
expect(tripwire.pageErrors).toEqual([])
|
||||
expect(tripwire.warnings).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -52,6 +52,11 @@ async function assertBaselineSucceeded(response: Response, method: string): Prom
|
||||
}
|
||||
|
||||
async function ensureSeedOpen(page: Page): Promise<void> {
|
||||
const welcome = page.locator('[class*="onboardingOverlay"]')
|
||||
if (await welcome.count() > 0) {
|
||||
await welcome.getByRole('button').click()
|
||||
await welcome.waitFor({ state: 'detached', timeout: 15_000 })
|
||||
}
|
||||
const chat = page.getByRole('tab', { name: 'Chat', exact: true })
|
||||
// Search is a collapsed header action; expand it so the input is actionable.
|
||||
const searchButton = page.getByRole('button', { name: 'Search sessions' })
|
||||
@@ -283,14 +288,30 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
|
||||
await details.getByRole('button', { name: 'Close details' }).click()
|
||||
}, 60_000)
|
||||
|
||||
it.skipIf(MODE === 'record')('downloads the session-log ZIP from the trajectory toolbar', async () => {
|
||||
it.skipIf(MODE === 'record')('downloads through the Session Header and /export with one dialog', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-navigation-export'))
|
||||
await ensureSeedOpen(page)
|
||||
await page.getByRole('tab', { name: 'Trajectory' }).click()
|
||||
const exportButton = page.getByRole('button', { name: 'Session log' })
|
||||
expect(await exportButton.isDisabled()).toBe(false)
|
||||
const header = exportButton.locator('xpath=ancestor::header[1]')
|
||||
const [buttonBox, headerBox] = await Promise.all([
|
||||
exportButton.boundingBox(), header.boundingBox(),
|
||||
])
|
||||
if (buttonBox === null || headerBox === null) {
|
||||
throw new Error('Session Header export geometry is unavailable')
|
||||
}
|
||||
expect(headerBox.x + headerBox.width - (buttonBox.x + buttonBox.width)).toBeLessThanOrEqual(32)
|
||||
const responsePromise = page.waitForResponse(response =>
|
||||
response.request().method() === 'HEAD'
|
||||
&& new URL(response.url()).pathname === '/api/session.export', { timeout: 30_000 })
|
||||
const downloadPromise = page.waitForEvent('download', { timeout: 30_000 })
|
||||
await page.getByRole('button', { name: 'Export session log' }).click()
|
||||
await exportButton.click()
|
||||
const response = await responsePromise
|
||||
expect(response.status()).toBe(200)
|
||||
const download = await downloadPromise
|
||||
expect(download.suggestedFilename()).toMatch(/^dsh-session-.+\.zip$/)
|
||||
const dialog = page.getByRole('dialog', { name: 'Session download started' })
|
||||
await dialog.waitFor({ timeout: 30_000 })
|
||||
// The real host streamed the ZIP; its root entry is the persisted log
|
||||
// text verbatim (the assembled seam: real route, real persistence read).
|
||||
const files = unzipSync(await readFile(await download.path()))
|
||||
@@ -298,7 +319,63 @@ describe('web e2e: navigation & panes over a rich seeded session', () => {
|
||||
const content = strFromU8(files['session.jsonl'] as Uint8Array)
|
||||
expect(content.split('\n')[0]).toContain(SEED_ID)
|
||||
expect(content).toContain('FIRST_DONE')
|
||||
}, 60_000)
|
||||
await dialog.getByText('Close', { exact: true }).click()
|
||||
|
||||
const observer = await newEnglishPage(browser)
|
||||
const observerTripwire = watchConsole(observer)
|
||||
const observerSlotErrors: string[] = []
|
||||
let observerDownloads = 0
|
||||
observer.on('download', () => { observerDownloads += 1 })
|
||||
observer.on('console', (message) => {
|
||||
if (message.type() === 'error' && /slot entry crashed/i.test(message.text())) {
|
||||
observerSlotErrors.push(message.text())
|
||||
}
|
||||
})
|
||||
const observerSessionBaseline = baselineResponse(observer, 'session.list')
|
||||
const observerWorkspaceBaseline = baselineResponse(observer, 'workspace.list')
|
||||
const [, observerSessionResponse, observerWorkspaceResponse] = await Promise.all([
|
||||
observer.goto(scaffold.baseUrl, { waitUntil: 'load' }),
|
||||
observerSessionBaseline,
|
||||
observerWorkspaceBaseline,
|
||||
])
|
||||
await Promise.all([
|
||||
assertBaselineSucceeded(observerSessionResponse, 'observer session.list'),
|
||||
assertBaselineSucceeded(observerWorkspaceResponse, 'observer workspace.list'),
|
||||
])
|
||||
await observer.getByText('Ungrouped', { exact: true }).waitFor({ timeout: 30_000 })
|
||||
await ensureSeedOpen(observer)
|
||||
|
||||
try {
|
||||
const input = page.locator('textarea').first()
|
||||
const slashDownloadPromise = page.waitForEvent('download', { timeout: 30_000 })
|
||||
await input.fill('/export')
|
||||
await page.getByRole('option', { name: /export/u }).waitFor({ timeout: 10_000 })
|
||||
await input.press('Enter')
|
||||
const slashDownload = await slashDownloadPromise
|
||||
expect(slashDownload.suggestedFilename()).toBe(download.suggestedFilename())
|
||||
const slashFiles = unzipSync(await readFile(await slashDownload.path()))
|
||||
const slashContent = strFromU8(slashFiles['session.jsonl'] as Uint8Array)
|
||||
const slashEvents = parseSessionLog(slashContent)
|
||||
const exportRun = slashEvents.findLast(event => event.type === 'command/run' && event.data.name === 'export')
|
||||
if (exportRun?.type !== 'command/run') throw new Error('slash ZIP has no export command/run')
|
||||
const exportDone = slashEvents.find(event =>
|
||||
event.type === 'command/done' && event.data.commandId === exportRun.data.commandId)
|
||||
expect(exportDone?.type).toBe('command/done')
|
||||
await page.getByRole('dialog', { name: 'Session download started' }).waitFor({ timeout: 30_000 })
|
||||
await page.getByRole('dialog', { name: 'Session download started' })
|
||||
.getByText('Close', { exact: true }).click()
|
||||
await observer.getByText('Session log download requested.', { exact: true }).waitFor({ timeout: 30_000 })
|
||||
expect(observerDownloads).toBe(0)
|
||||
expect(await observer.getByRole('dialog', { name: 'Session download started' }).count()).toBe(0)
|
||||
expect({
|
||||
pageErrors: observerTripwire.pageErrors,
|
||||
slotErrors: observerSlotErrors,
|
||||
warnings: observerTripwire.warnings,
|
||||
}).toEqual({ pageErrors: [], slotErrors: [], warnings: [] })
|
||||
} finally {
|
||||
await observer.close()
|
||||
}
|
||||
}, 120_000)
|
||||
|
||||
it.skipIf(MODE === 'record')('focuses the ledger by dragging an overview interval', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-navigation-timeline'))
|
||||
|
||||
@@ -56,9 +56,9 @@ describe('web e2e: plugin configuration section', () => {
|
||||
await page.getByRole('button', { name: '设置', exact: true }).click()
|
||||
const dialog = page.getByRole('dialog', { name: '设置' })
|
||||
await dialog.waitFor({ timeout: 10_000 })
|
||||
await dialog.getByRole('button', { name: '插件' }).click()
|
||||
await dialog.getByRole('button', { name: '插件配置', exact: true }).click()
|
||||
await expect
|
||||
.poll(() => dialog.getByRole('button', { name: '插件' }).getAttribute('aria-current'), { timeout: 5_000 })
|
||||
.poll(() => dialog.getByRole('button', { name: '插件配置', exact: true }).getAttribute('aria-current'), { timeout: 5_000 })
|
||||
.toBe('true')
|
||||
return dialog
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import { dshHomePath } from '@deepseek-ai/dsh-paths'
|
||||
// } from '@deepseek-ai/dsh-client-ui-settings-general'
|
||||
export const WELCOME_NOTICE_SETTINGS_NAMESPACE = 'ui-onboarding'
|
||||
export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion'
|
||||
export const WELCOME_NOTICE_VERSION = '2026-07-30.7'
|
||||
export const WELCOME_NOTICE_VERSION = '2026-08-11.1'
|
||||
export const WELCOME_NOTICE_COPY = { zh: { title: '内测声明', continueLabel: '继续' } } as const
|
||||
|
||||
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
||||
@@ -421,7 +421,14 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
|
||||
// disclosure passes a local dead endpoint instead of disabling the row.
|
||||
options.telemetryUrl === undefined
|
||||
? { id: 'telemetry-otel', disabled: true }
|
||||
: { id: 'telemetry-otel', config: { exporter: { url: options.telemetryUrl }, shutdownTimeoutMillis: 1_000 } },
|
||||
: {
|
||||
id: 'telemetry-otel',
|
||||
config: {
|
||||
mode: 'FULL',
|
||||
exporter: { url: options.telemetryUrl },
|
||||
shutdownTimeoutMillis: 1_000,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'webserver',
|
||||
config: { host: '127.0.0.1', port: 0 },
|
||||
|
||||
@@ -23,6 +23,8 @@ import { ZH_BROWSER_LOCALE, saveFailureShot } from './support.ts'
|
||||
|
||||
const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/settings-chrome', import.meta.url))
|
||||
const DIALOG_EXPECTED = join(SNAPSHOT_DIR, 'dialog.expected.md')
|
||||
const PLUGINS_EXPECTED = join(SNAPSHOT_DIR, 'plugins.expected.md')
|
||||
const PLUGIN_ROW_SELECTOR = '[data-plugin-entry$="ui-settings"]'
|
||||
const MODE = webSnapshotMode()
|
||||
|
||||
describe('web e2e: settings modal and General preferences', () => {
|
||||
@@ -92,6 +94,28 @@ describe('web e2e: settings modal and General preferences', () => {
|
||||
await dialog.getByRole('button', { name: '模型' }).click()
|
||||
await expect.poll(() => dialog.getByRole('button', { name: '模型' }).getAttribute('aria-current'), { timeout: 5_000 }).toBe('true')
|
||||
expect(await dialog.getByRole('button', { name: '通用设置' }).getAttribute('aria-current')).toBeNull()
|
||||
// Plugins is a read-only projection of the same assembled Loader tree.
|
||||
// Capture one stable shipped row rather than the whole inventory so adding
|
||||
// an unrelated plugin does not rewrite this surface's golden.
|
||||
await dialog.getByRole('button', { name: '插件', exact: true }).click()
|
||||
await dialog.getByRole('heading', { name: '插件', exact: true }).waitFor({ timeout: 10_000 })
|
||||
const pluginRow = dialog.locator(PLUGIN_ROW_SELECTOR)
|
||||
await pluginRow.waitFor({ timeout: 10_000 })
|
||||
const expectedPluginCount = [...scaffold.ctx.loader.entries()]
|
||||
.filter(entry => !entry.options.group)
|
||||
.length
|
||||
expect(await dialog.getByRole('searchbox', { name: '搜索插件' }).count()).toBe(1)
|
||||
expect(await dialog.locator('[data-plugin-entry]').count()).toBe(expectedPluginCount)
|
||||
expect(await dialog.locator('[data-plugin-count]').getAttribute('data-plugin-count'))
|
||||
.toBe(String(expectedPluginCount))
|
||||
expect(await dialog.getByRole('button', { name: '插件', exact: true }).getAttribute('aria-current')).toBe('true')
|
||||
expect(await dialog.getByRole('button', { name: '模型' }).getAttribute('aria-current')).toBeNull()
|
||||
const pluginsSnapshot = await captureStableAria(
|
||||
page,
|
||||
PLUGIN_ROW_SELECTOR,
|
||||
scaffold.workspaceCwd,
|
||||
)
|
||||
await compareOrRefreshGolden(PLUGINS_EXPECTED, pluginsSnapshot, MODE)
|
||||
// Close path 1: Escape.
|
||||
await page.keyboard.press('Escape')
|
||||
await expect.poll(() => page.getByRole('dialog', { name: '设置' }).count(), { timeout: 5_000 }).toBe(0)
|
||||
@@ -454,6 +478,6 @@ describe('web e2e: settings modal and General preferences', () => {
|
||||
|
||||
it.skipIf(MODE === 'record')('keeps the fixture inventory closed', async () => {
|
||||
expect(tripwire.warnings).toEqual([])
|
||||
await assertFixtureInventory(SNAPSHOT_DIR, ['dialog.expected.md'])
|
||||
await assertFixtureInventory(SNAPSHOT_DIR, ['dialog.expected.md', 'plugins.expected.md'])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -138,13 +138,13 @@ async function detailsTrack(page: Page): Promise<number> {
|
||||
return Number(cols.split(' ').pop()!.replace('px', ''))
|
||||
}
|
||||
|
||||
// Readiness gate: `dsh web` serves all ten production manifest plugins; until every UI
|
||||
// Readiness gate: `dsh web` serves every production manifest plugin; until every UI
|
||||
// plugin's client bundle exists and exports apply, the loader fail-louds and
|
||||
// the frame never appears.
|
||||
const UI_PLUGIN_DIRS = [
|
||||
'connection', 'runtime', 'ui-theme', 'locale', 'ui-layout', 'ui-sidebar',
|
||||
'ui-settings', 'ui-settings-general', 'ui-models', 'ui-conversation',
|
||||
'ui-model', 'ui-question', 'ui-trajectory',
|
||||
'ui-model', 'ui-question', 'ui-trajectory', '../session-query/session-export',
|
||||
]
|
||||
const ROUND_DONE_MARKER = 'WEB_ROUND_DONE'
|
||||
const notReady = UI_PLUGIN_DIRS.filter((dir) => {
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -5,3 +5,6 @@
|
||||
- button "1 subagent":
|
||||
- text: 1 subagent
|
||||
- img
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- 'button "Run two shell commands: wait" [disabled]'
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- 'button "Using ONE run_code program: run" [disabled]'
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -33,6 +36,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use only Cordis tools. First" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -48,6 +51,10 @@
|
||||
- paragraph: CORDIS_UI_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with the single word" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -20,6 +23,10 @@
|
||||
- paragraph: LIGHTHOUSE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the bash tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -28,6 +31,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "workspace" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "workspace" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -78,6 +81,10 @@
|
||||
- paragraph: 这是一个很典型的轻量 TypeScript 包结构:入口 + 实现 + 测试。这一轮到此结束,等系统开启下一个 turn。
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
@@ -187,6 +194,10 @@
|
||||
- text: )的结构,或者其他格式的输出(比如带文件大小的树形图),随时告诉我。
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- tooltip "Branch into a new conversation"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
- listbox "Trigger suggestions":
|
||||
- text: Commands
|
||||
- option "compact Compact older conversation history" [selected]
|
||||
- option "export Download this Session log as a ZIP archive"
|
||||
- option "feedback record feedback about this session"
|
||||
- option "goal set or view the goal for a long-running task"
|
||||
- option "permission Switch the permission preset (sandbox mode + approval policy)"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with the single word" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -20,6 +23,10 @@
|
||||
- paragraph: LIGHTHOUSE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -22,6 +25,10 @@
|
||||
- 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 "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "CJK strong emphasis" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -35,6 +38,10 @@
|
||||
- paragraph: CJK_STRONG_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Markdown image policy" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -14,6 +17,10 @@
|
||||
- paragraph: REMOTE_IMAGE_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Inline code links" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -26,6 +29,10 @@
|
||||
- paragraph: INLINE_CODE_LINK_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Math rendering" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -30,6 +33,10 @@
|
||||
- paragraph: MATH_RENDERING_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
dot=warning
|
||||
title=Output token limit reached
|
||||
hint=The reply was cut off; earlier output is preserved in the conversation. Send "continue" to let the model resume.
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Use the read tool twice" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -15,6 +18,10 @@
|
||||
- paragraph: I will read both files before answering.
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation" [disabled]:
|
||||
- img
|
||||
- text: Available only on the last message of a completed turn 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
@@ -38,6 +45,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
- button "Use actual duration": Duration
|
||||
- button "Collapse turns": Turns
|
||||
- button "Collapse calls": Calls
|
||||
- button "Export session log": Export
|
||||
- img
|
||||
- searchbox "Search trajectory"
|
||||
- region "Trajectory timeline":
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
- paragraph: 感谢您愿意拨冗试用 DeepSeek Harness。当前版本仍处于内部测试阶段,功能仍待完善,体验难免有些粗糙。
|
||||
- blockquote: “如切如磋,如琢如磨。” 产品的成长,离不开一次次真实的碰撞与坦诚的反馈。您在真实使用中发现的问题,也可能促使我们重新审视,甚至推翻已有的设计。
|
||||
- paragraph:
|
||||
- text: 为了帮助我们更准确地还原您真实使用中的问题,内测版本默认会上传所有 Session Log;如需关闭,可以设置环境变量 DSH_TELEMETRY_DISABLED=1。另外,
|
||||
- text: 内测版本默认不会上传 Session Log。如需在提交反馈时共享会话日志,可以设置环境变量 DSH_TELEMETRY_MODE=FEEDBACK_ONLY;如需持续上传,可以设置 DSH_TELEMETRY_MODE=FULL,但该模式同时会启用 dsh-sdk 命令遥测,上报匿名 ID、命令结果以及脱敏后的项目配置。另外,
|
||||
- strong: 如果您有任何反馈与建议,请在企业微信群中留言告诉我们
|
||||
- text: 。每一条反馈,都会帮助我们把它打磨得更好。
|
||||
- button "继续"
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- 'button "Plan a small change: add" [disabled]'
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -33,6 +36,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the ask_user_question tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -28,6 +31,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "workspace" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Reply with a one-sentence description" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Use the read tool twice" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -28,6 +31,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Use the read tool twice" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -28,6 +31,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Use the read tool twice" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -28,6 +31,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
- button "模型":
|
||||
- img
|
||||
- text: 模型
|
||||
- button "插件":
|
||||
- img
|
||||
- text: 插件
|
||||
- button "Agent 预设":
|
||||
- img
|
||||
- text: Agent 预设
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
- listitem:
|
||||
- button "ui-settings, 已挂载, 已启用":
|
||||
- strong: ui-settings
|
||||
- img "已挂载"
|
||||
- text: 已启用
|
||||
- img
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "Load the snapshot-skill skill with" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -31,6 +34,10 @@
|
||||
- paragraph: DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{date}} {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "/user-invoke-demo and confirm the fixtur" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -20,6 +23,10 @@
|
||||
- paragraph: USER_INVOKE_REPLY acknowledged; following the injected skill.
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
- banner:
|
||||
- navigation "Session hierarchy":
|
||||
- button "{{workspace}}" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -10,6 +13,10 @@
|
||||
- paragraph: r1
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m2 7/25 {{clock}}
|
||||
@@ -18,6 +25,10 @@
|
||||
- paragraph: r2
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m3 7/25 {{clock}}
|
||||
@@ -26,6 +37,10 @@
|
||||
- paragraph: r3
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m4 7/25 {{clock}}
|
||||
@@ -34,6 +49,10 @@
|
||||
- paragraph: r4
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m5 7/25 {{clock}}
|
||||
@@ -42,6 +61,10 @@
|
||||
- paragraph: r5
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m6 7/25 {{clock}}
|
||||
@@ -50,6 +73,10 @@
|
||||
- paragraph: r6
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m7 7/25 {{clock}}
|
||||
@@ -58,6 +85,10 @@
|
||||
- paragraph: r7
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m8 7/25 {{clock}}
|
||||
@@ -66,6 +97,10 @@
|
||||
- paragraph: r8
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m9 7/25 {{clock}}
|
||||
@@ -74,6 +109,10 @@
|
||||
- paragraph: r9
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m10 7/25 {{clock}}
|
||||
@@ -82,6 +121,10 @@
|
||||
- paragraph: r10
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m11 7/25 {{clock}}
|
||||
@@ -90,6 +133,10 @@
|
||||
- paragraph: r11
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m12 7/25 {{clock}}
|
||||
@@ -98,6 +145,10 @@
|
||||
- paragraph: r12
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m13 7/25 {{clock}}
|
||||
@@ -106,6 +157,10 @@
|
||||
- paragraph: r13
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m14 7/25 {{clock}}
|
||||
@@ -114,6 +169,10 @@
|
||||
- paragraph: r14
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m15 7/25 {{clock}}
|
||||
@@ -122,6 +181,10 @@
|
||||
- paragraph: r15
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m16 7/25 {{clock}}
|
||||
@@ -130,6 +193,10 @@
|
||||
- paragraph: r16
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m17 7/25 {{clock}}
|
||||
@@ -138,6 +205,10 @@
|
||||
- paragraph: r17
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m18 7/25 {{clock}}
|
||||
@@ -146,6 +217,10 @@
|
||||
- paragraph: r18
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m19 7/25 {{clock}}
|
||||
@@ -154,6 +229,10 @@
|
||||
- paragraph: r19
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m20 7/25 {{clock}}
|
||||
@@ -162,6 +241,10 @@
|
||||
- paragraph: r20
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m21 7/25 {{clock}}
|
||||
@@ -170,6 +253,10 @@
|
||||
- paragraph: r21
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m22 7/25 {{clock}}
|
||||
@@ -178,6 +265,10 @@
|
||||
- paragraph: r22
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m23 7/25 {{clock}}
|
||||
@@ -186,6 +277,10 @@
|
||||
- paragraph: r23
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m24 7/25 {{clock}}
|
||||
@@ -194,6 +289,10 @@
|
||||
- paragraph: r24
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m25 7/25 {{clock}}
|
||||
@@ -202,6 +301,10 @@
|
||||
- paragraph: r25
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m26 7/25 {{clock}}
|
||||
@@ -210,6 +313,10 @@
|
||||
- paragraph: r26
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m27 7/25 {{clock}}
|
||||
@@ -218,6 +325,10 @@
|
||||
- paragraph: r27
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}} m28 7/25 {{clock}}
|
||||
@@ -226,6 +337,10 @@
|
||||
- paragraph: r28
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: 7/25 {{clock}} Ran for {{duration}}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the ask_user_question tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the ask_user_question tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -30,6 +33,10 @@
|
||||
- paragraph: "Got it: BANANA and ORANGE."
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the ask_user_question tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use the ask_user_question tool to" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -31,6 +34,10 @@
|
||||
- paragraph: Great, let's move forward. BANANA!
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
- button "event-sourcing researcher"
|
||||
- text: /
|
||||
- button "example editor" [disabled]
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
- button "1 subagent":
|
||||
- text: 1 subagent
|
||||
- img
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -25,6 +28,10 @@
|
||||
- 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 "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s Now give the same explanation to a human reader. {{clock}}
|
||||
@@ -37,6 +44,10 @@
|
||||
- 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 "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
- button "event-sourcing researcher" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Begin your reply with the" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Begin your reply with the" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
- button "Use web_search to search exactly" [disabled]
|
||||
- img
|
||||
- text: Standard mode
|
||||
- button "Session log":
|
||||
- text: Session log
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
- tab "Trajectory"
|
||||
@@ -20,6 +23,10 @@
|
||||
- paragraph: SEARCH_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
- paragraph: WORKFLOW_DONE
|
||||
- button "Copy":
|
||||
- img
|
||||
- button "Good response":
|
||||
- img
|
||||
- button "Bad response":
|
||||
- img
|
||||
- button "Branch into a new conversation":
|
||||
- img
|
||||
- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Assembled todo snapshot: boots the real built `packages/client/*/lib/
|
||||
// client.js` bundles through AppWebEntry's ModuleLoader path against the
|
||||
// keyless FixtureApiClient transport, opens the fixture session, and pins the
|
||||
// two surfaces the fixture's parallel plan (turn 73, two items `in_progress`)
|
||||
// two surfaces the fixture's parallel plan (turn 74, two items `in_progress`)
|
||||
// reaches — the `todo_write` tool row and the dock's plan strip.
|
||||
//
|
||||
// The row is pinned as three separate fields on purpose. `summary=` is the
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
"tests/cordis-tool-round.e2e.ts",
|
||||
"tests/web-search-round.e2e.ts",
|
||||
"tests/message-actions.e2e.ts",
|
||||
"tests/message-feedback.e2e.ts",
|
||||
"tests/markdown-images.e2e.ts",
|
||||
"tests/math-rendering.e2e.ts",
|
||||
"tests/markdown-cjk-strong.e2e.ts",
|
||||
|
||||
Reference in New Issue
Block a user