Skip to content

Show each Agent inbox card's tool-call count (#471) - #669

Merged
Birfy merged 1 commit into
mainfrom
feat/471-inbox-board
Oct 22, 2026
Merged

Birfy merged 1 commit into
mainfrom
feat/471-inbox-board

Conversation

@Birfy

@Birfy Birfy commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #471 — the v1 count board from the spec of record (triage 2026-10-21): one N tool calls line per card, for that card's own place. The three-column board with a List/Board toggle stays v2 and needs the owner, so this PR does not close the issue.

Reproduce

On main c74e1207 no inbox card can show a tool-call count: inboxModel builds its cards from approvals, running turns, tasks and ended turns, but neither workView() nor endedView() in core/src/host/turns.js records how many tools a turn ran, so there is nothing to render. (Failed turns and the Latest line from #491 stay exactly as they are.)

What changed

  • core/src/host/turns.js: counts tool/call events per turn (entry.toolCalls, reset at turn/start). The running turn's count rides work.bots[id].calls and its work.rooms[roomId][] entry (only above 0); a turn that ended keeps its own count as calls on its endedView() entry. One source — the events the activity feed already folds; no new endpoint, no new polling.
  • core/src/client/inbox.js: toolCalls(card) reads the count for the card's own place — the turn running there now (the Bot's own chat, or that one group), else the newest ended turn there — never summed across places, 0 when unknown; InboxCard draws one muted N tool calls line (bt-inbox-calls) only when it is above 0. Grouping, the 7-day Done cap, needsCount, the latest-activity line and the read-only Open action are unchanged.
  • core/src/client/i18n.js: {count} tool calls / {count} 次工具调用.
  • docs/subsystems/core-client.md and core-host.md; the inbox model and host tests, plus the Group dock and member list show a Bot's work from another room #553 work-view expectation in core/test/group-work.test.js.
  • Generated, not hand-edited: core/client.js (npm run build) and patches/ds-bot/ (generate then check).

What I ran

Tip SHA: 1958157a007ae2809bf7ea82426f985f39b52074 (Node 22.23.3, TZ=UTC):

  • node --import ./test/harness-resolve.mjs --test test/inbox.test.js → 21/21.
  • node --import ./test/harness-resolve.mjs --test test/approval-notices.test.js → 12/12; test/group-work.test.js → 15/15.
  • node --import ./test/harness-resolve.mjs --test --test-concurrency=4 "test/*.test.js" (the CI test job's suite) → 1204/1204, exit 0. --test-concurrency=4 only because this box has a 512-pid cgroup: the default 192-way spawn hits spawn EAGAIN with other benches running; it changes nothing about the tests.
  • cd core && npm run lint → oxlint 0 errors (43 pre-existing warnings), arch-docs: OK (13 changed file(s)).
  • node scripts/build-client.mjs --check → OK; node scripts/ds-bot-patches.mjs check → ds-bot/ = pin (tree 5834c00, v0.1.5), 10 patches apply cleanly, core/ = ds-bot/ + patches.
  • plugins/social 317/317, plugins/timeline 104/104, plugins/tree 89/89.

Red without the source change

With core/src/client/inbox.js, core/src/client/i18n.js and core/src/host/turns.js at main c74e1207 and the new tests kept:

  • test/inbox.test.js → 19/21: both new tests fail (Cannot read properties of undefined — no calls on the model, no bt-inbox-calls row).
  • test/approval-notices.test.js → 11/12: the new host test fails — the running turn and the ended turn carry no calls.

Not run

  • The smoke bench (CONTEXT_WINDOW=100000 CHECK_RATIO=0.45 dev/bench.sh smoke 3096 8796 reset): it stops at pnpm: not found on this box (no pnpm installed), and the desktop/web profile it starts is not available here. The change is a count folded from session/event and read by the client, with the host covered by core/test/approval-notices.test.js; green tests-ok at the tip is the gate.

Risk

  • T2 by risk-rules.json (core/src/host/turns.js; client, tests and docs are T1/T0), so it needs your PASS at this tip plus green tests-ok. Nothing here touches authz, secrets, permissions or saved state.
  • The count is per turn and per place and process-local, like the rest of the work snapshot: after a restart a Done card shows no count until that place's next ended turn. A program's sub-calls (run_code) are not counted — the spec of record says tool/call events.
  • 1 tool calls reads slightly off; the spec of record fixes the copy as {count} tool calls, so it stays that way unless you want a singular key.

The v1 count board of #471 asks for one `N tool calls` line per card, for that card's
own place. turns.js already folds `tool/call` events, so the count rides the existing
work snapshot: the running turn carries it in work.bots / work.rooms, and an ended
turn keeps its own. The inbox reads it for the card's place only, shows nothing for 0
or unknown, and never adds places together. No new polling, no new event source.

Part of #471 (v1 scope of record; the three-column board stays v2).
@Birfy Birfy added the agent-pr Pull request opened by an agent label Oct 22, 2026
@Birfy Birfy self-assigned this Oct 22, 2026
@Birfy Birfy added area:automation Scheduled tasks and automation area:ui Web/desktop UI and copy enhancement New feature or request labels Oct 22, 2026
@Birfy

Birfy commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: PASS at 1958157
Written-by: Reviewer

Reviewed this tip only. Nine checks completed/success, mergeable clean, no earlier conclusion here, so this is the one for 1958157a. Risk tier T2 (it touches core/src/host/turns.js), so it needs a maintainer's approve in addition to this PASS; I have not queued it.

What I checked

  • The count is one place, never summed. toolCalls (core/src/client/inbox.js) asks runningIn(work, botId, roomId) first and falls back to the newest work.ended entry with the same botId and the same roomId ?? ''; own chat (roomId undefined) and a group (roomId = <room id>) cannot borrow each other's count, and a card with no Bot gets 0.
  • The host side carries the count on both shapes. turns.js increments entry.toolCalls on each tool/call, puts it on work.bots[id].calls and on the work.rooms[roomId] entry while it is above 0, captures it before the turn is cleared, and stores it as calls on the endedView() entry. entry.toolCalls is reset at turn/start and cleared at turn/end; it is a separate field from the existing entry.calls (the call-id list), so nothing collides.
  • Tests, locally: the host half of core/test/approval-notices.test.js (I ran it without the client bundle, which cannot load here) → 3/3, including the work view counts each place's tool calls for the inbox, and the ended turn keeps its own (#471); core/test/group-work.test.js → 15/15 with the new calls: 1 expectation.
  • Red without the source change: core/src/host/turns.js reverted to 8005fc9d, tests untouched → the new counting test fails (2/3 pass). Restored → 3/3.
  • Generated files match their sources: core/src/client/inbox.js and patches/ds-bot/files/src/client/inbox.js have the same sha256 (128138ca…), and core/test/inbox.test.js matches patches/ds-bot/files/test/inbox.test.js (bc058e67…). package runs ds-bot-patches.mjs check and is green here.
  • Docs claim what the code does (core-dev/core-host sections, card.calls, work.ended[].calls), and the issue stays open: the PR says Part of #471, the three-column board stays v2.
  • Not verified by me locally: core/test/inbox.test.js and the client half of approval-notices.test.js need esbuild, which this box does not have and cannot install (npm is blocked), so I could not reproduce the author's 21/21 and 12/12, nor the client-side 19/21 and 11/12 red counts. CI's tests-ok / package / Node 24 jobs are green at this tip and run those files.

Non-blocking

  • The English line is 1 tool calls for a single call — the new test pins that wording (textOf(callsRows(countedCard('task:n2'))[0]), '1 tool calls'). Chinese reads fine. A plural form would need a second string ({count} tool call) and a one-line pick in InboxCard.
  • A scheduled run DSH could not deliver joins ended as an entry without calls (turns.js noteRunFailure). If that entry is the newest for a place, the card shows no count instead of the last real turn's number. It only shows nothing, never a wrong number, and I would leave it unless a card is expected to report the last real turn.

Nothing else; the read-only guarantee holds (same single Open action on a counted card), and no new polling.

@Birfy Birfy added the awaiting-approval PR is green and waits for the maintainer's approval (T2/T3) or a review PASS at its tip label Oct 22, 2026
@Birfy
Birfy added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 217bf15 Oct 22, 2026
9 checks passed
@Birfy
Birfy deleted the feat/471-inbox-board branch October 22, 2026 03:50
@Birfy Birfy removed the awaiting-approval PR is green and waits for the maintainer's approval (T2/T3) or a review PASS at its tip label Oct 22, 2026
@Birfy Birfy removed the agent-pr Pull request opened by an agent label Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:automation Scheduled tasks and automation area:ui Web/desktop UI and copy enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant