mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(web): pluralize singular subagent counts
The localized catalog exposed one count.total and one count.running string for every cardinality. The English dictionary therefore rendered both the visible trigger and its accessibility label as 1 subagents, and the assembled Web golden had begun preserving that grammar error. Split both count families into explicit one and other keys, following the existing client locale convention. SubagentCatalogAction selects the pair from the effective descendant count; English uses subagent for one and subagents otherwise, while Chinese keeps its unchanged classifier text under the same key domain. Add a component regression proving a single running descendant selects both singular keys. Update the real Web E2E locator and keyless assembled aria golden from 1 subagents to 1 subagent. Both ui-subagent test files pass all 28 tests and the package TypeScript project builds cleanly.
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
- button "Ask a research subagent to"
|
||||
- text: /
|
||||
- button "event-sourcing researcher" [disabled]
|
||||
- button "1 subagents":
|
||||
- text: 1 subagents
|
||||
- button "1 subagent":
|
||||
- text: 1 subagent
|
||||
- img
|
||||
- tablist:
|
||||
- tab "Chat" [selected]
|
||||
|
||||
@@ -331,7 +331,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
|
||||
|
||||
it('opens an unavailable persisted grandchild after recording the available child', async () => {
|
||||
onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-grandchild'))
|
||||
await page.getByRole('button', { name: '1 subagents' }).click()
|
||||
await page.getByRole('button', { name: '1 subagent' }).click()
|
||||
await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).click()
|
||||
await page.getByText('The parent session is offline; reopen it to continue sending messages.').waitFor()
|
||||
const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' })
|
||||
|
||||
@@ -324,6 +324,8 @@ export function SubagentCatalogAction({
|
||||
// The catalog can arrive before the session-list baseline; never undercount
|
||||
// the already-visible direct rows during that short bootstrap window.
|
||||
const descendantCount = Math.max(healthy.length, descendants.count)
|
||||
const totalCountKey = descendantCount === 1 ? 'count.total.one' : 'count.total.other'
|
||||
const runningCountKey = descendantCount === 1 ? 'count.running.one' : 'count.running.other'
|
||||
|
||||
const observeCatalog = (parentSessionId: SessionId, next: boolean): void => {
|
||||
if (next) observedCatalogs.current.add(parentSessionId)
|
||||
@@ -432,7 +434,7 @@ export function SubagentCatalogAction({
|
||||
className={css.trigger}
|
||||
aria-haspopup="tree"
|
||||
aria-expanded={open}
|
||||
aria-label={t(descendants.running ? 'count.running' : 'count.total', { count: descendantCount })}
|
||||
aria-label={t(descendants.running ? runningCountKey : totalCountKey, { count: descendantCount })}
|
||||
onClick={() => { changeOpen(!open) }}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key !== 'ArrowDown') return
|
||||
@@ -444,7 +446,7 @@ export function SubagentCatalogAction({
|
||||
<span className={css.activitySlot}>
|
||||
{descendants.running && <StateDot state="ongoing" />}
|
||||
</span>
|
||||
<span className={css.count}>{t('count.total', { count: descendantCount })}</span>
|
||||
<span className={css.count}>{t(totalCountKey, { count: descendantCount })}</span>
|
||||
<IconChevronDownOutline14 className={open ? css.triggerOpen : undefined} />
|
||||
</button>
|
||||
{open && (
|
||||
|
||||
@@ -24,8 +24,10 @@ export const zh = {
|
||||
'activity.inactive': '当前未运行',
|
||||
'branch.collapse': '收起 {label} 的下级子代理',
|
||||
'branch.expand': '展开 {label} 的下级子代理',
|
||||
'count.total': '{count} 个子代理',
|
||||
'count.running': '{count} 个子代理,正在运行',
|
||||
'count.total.one': '{count} 个子代理',
|
||||
'count.total.other': '{count} 个子代理',
|
||||
'count.running.one': '{count} 个子代理,正在运行',
|
||||
'count.running.other': '{count} 个子代理,正在运行',
|
||||
'tree.aria': '子代理会话',
|
||||
'readonly.oneShot.title': '一次性子代理记录',
|
||||
'readonly.title': '此子代理暂时只读',
|
||||
@@ -54,8 +56,10 @@ export const en: Record<SubagentKey, string> = {
|
||||
'activity.inactive': 'not running',
|
||||
'branch.collapse': 'Collapse {label} descendants',
|
||||
'branch.expand': 'Expand {label} descendants',
|
||||
'count.total': '{count} subagents',
|
||||
'count.running': '{count} subagents running',
|
||||
'count.total.one': '{count} subagent',
|
||||
'count.total.other': '{count} subagents',
|
||||
'count.running.one': '{count} subagent running',
|
||||
'count.running.other': '{count} subagents running',
|
||||
'tree.aria': 'Subagent sessions',
|
||||
'readonly.oneShot.title': 'One-shot subagent record',
|
||||
'readonly.title': 'This subagent is read-only for now',
|
||||
|
||||
@@ -167,6 +167,24 @@ describe('SubagentCatalogAction', () => {
|
||||
expect(input.setCatalogOpen).toHaveBeenLastCalledWith(PARENT, false)
|
||||
})
|
||||
|
||||
it('selects singular count keys for one descendant', () => {
|
||||
const base = props(catalog({
|
||||
entries: [{
|
||||
kind: 'child', id: CHILD, mode: 'continuable', label: 'worker',
|
||||
activity: 'running', hasChildren: false,
|
||||
}],
|
||||
}), {}, {
|
||||
[CHILD]: {
|
||||
...summary(CHILD, Date.now()), parentId: PARENT, origin: 'subagent', running: true,
|
||||
},
|
||||
})
|
||||
const translate = vi.fn(base.t)
|
||||
render(<SubagentCatalogAction {...base} t={translate} />)
|
||||
|
||||
expect(translate).toHaveBeenCalledWith('count.running.one', { count: 1 })
|
||||
expect(translate).toHaveBeenCalledWith('count.total.one', { count: 1 })
|
||||
})
|
||||
|
||||
it('supports trigger/menu keyboard traversal, Escape focus restore, and outside close', async () => {
|
||||
const input = props(catalog())
|
||||
render(<SubagentCatalogAction {...input} />)
|
||||
|
||||
Reference in New Issue
Block a user