Skip to content

Let each provider choose whether finished turns collapse - #3729

Merged
SawyerHood merged 1 commit into
mainfrom
bb/right-now-we-have-a-behavior-where-basically-if-thr_ijt7ix8c5k
Sep 15, 2026
Merged

SawyerHood merged 1 commit into
mainfrom
bb/right-now-we-have-a-behavior-where-basically-if-thr_ijt7ix8c5k

Conversation

@SawyerHood

@SawyerHood SawyerHood commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Human comments

What was wrong

When a turn finished, the thread timeline always folded its work into one "Worked for" row and left only the final answer visible. groupCompletedTurnMessages in @bb/thread-view ran for every completed turn, and there was no provider declaration field or user setting to turn it off. For agents that narrate their work as they go, such as Claude Code, the narration and tool rows disappeared from view as soon as the turn ended. #3144 reports this for Claude Code turns shaped text, tool, text, ...: prose the user was reading while the turn ran collapses into the summary row at completion.

What changed

  • Provider default. bb.providers.register accepts completedTurnDisplay: "collapse" | "flat", defaulting to "collapse". Host policy validates it and it is projected onto ProviderInfo.completedTurnDisplay. Claude Code declares "flat". The field has no experimental_ prefix, so an older server ignores it instead of refusing to load the plugin. Plugin SDK 0.4.95.
  • User setting. New general setting providerCompletedTurnDisplay, a map of provider id to collapse or flat. A provider without an entry uses its default.
    • Settings → Providers has a "Collapse finished turns" section with one switch per provider. Setting a switch to the provider's default removes the entry.
    • bb settings completed-turns [provider-id] [collapse|flat|default] lists each provider's display and where it comes from, or sets one; default removes the entry.
  • Server. The timeline, turn-summary details, and conversation outline routes resolve the display once per request (setting, then provider default, then collapse) and pass it to the @bb/thread-view builders. It is part of the timeline response cache key, the cursor surface, and the outline projection key, so a setting change rebuilds at the same sequence. A cursor minted under one display returns 400 under the other. A flat build keeps full turn detail, so summary pages still carry every finished-turn row.
  • Client. Timeline responses include completedTurnDisplay. resolveLoadedTimelineSurfaceKey (@bb/client-core) folds it into the thread timeline controller's surface key. Since Keep older timeline pages loaded while a thread streams #3686 a refresh keeps older loaded pages, and without this a display change left those pages in the previous display until reload.
  • Docs. docs/configuration.md, docs/provider-plugin-api.md, docs/timeline-pagination.md, the bb-cli skill references, the customization guide template, and the plugin-authoring references.
  • No server/daemon wire change; HOST_DAEMON_PROTOCOL_VERSION is unchanged.

How you verified

  • New tests:
    • packages/thread-view/test/completed-turn-summary-rendering.test.ts: a flat finished turn keeps the rows it had while running, including a turn whose work summary detail would otherwise drop; a turn-details request in flat mode returns the ungrouped rows. Removing the flat branch or the full-detail override makes these fail.
    • apps/server/test/public/public-thread-timeline-completed-turn-display.test.ts: Claude Code threads render flat by default and Codex threads collapse; a setting change applies to the timeline, turn details, and outline at the same maxSeq; with several loaded pages, switching the display replaces the loaded pages and reloading older pages matches the canonical timeline. Removing the display from the cache key, the outline key, or the surface key makes these fail.
    • apps/app/src/components/thread/timeline/useThreadTimelineController.test.tsx: loaded older rows are replaced when the display changes.
    • Declaration validation, first-party registration defaults, bb settings completed-turns, and the Providers switches.
  • pnpm exec turbo run typecheck across the repo.
  • pnpm exec turbo run test for @bb/domain, @get-bb/plugin-sdk, @bb/thread-view, @bb/server, @bb/cli, @bb/app, @bb/client-core, @bb/db, @bb/sdk, @bb/server-contract, @bb/provider-parity, @bb/templates, @bb/demo-server, @bb/plugin-api-map, @bb/provider-bridge-protocol, and bb-plugin-provider-claude-code. Everything passed except two @bb/server timeouts under parallel load (public-thread-data, timeline-in-turn-window), which pass when run alone. On this machine the @bb/server run also logs ENOSPC watcher errors from builtin-plugins.test.ts, which happen on clean main too because the machine's inotify watch budget is exhausted.
  • node .github/workflows/check-plugin-sdk-version.mjs and node packages/plugin-sdk/scripts/check-npm-version-guard.mjs pass.
  • Provider corpus: row snapshots from the base commit and from this branch are identical in row content for all 340 threads. The only differences are timelinePage.historySnapshot and olderCursor, whose cursor surface now includes the display.
  • Manual, in a dev app: a real Claude Code turn with narration and two file reads stayed flat when it finished. Switching Claude Code to collapse in Settings → Providers folded it into "Worked for 2s", expanding that row loaded its details, and switching back removed the stored entry and survived a reload. bb settings completed-turns set and cleared the same setting.

Fixes #3144
Fixes #3283

Related: #1656 reported the same disappear-on-completion effect for replies to mid-turn messages.

🤖 Generated with Claude Code

AGENT GENERATED

A finished turn always folded its work into one "Worked for" row. Providers
now declare a default with `completedTurnDisplay: "collapse" | "flat"` on
`bb.providers.register`, and the user can override it per provider through
the new `providerCompletedTurnDisplay` general setting (Settings → Providers,
`bb settings completed-turns`). Claude Code defaults to flat.

The server resolves the effective display once per request and passes it to
the timeline, turn-summary details, and conversation outline builds; it is
part of the timeline cache key, the cursor surface, and the outline projection
key, so a setting change rebuilds rows at the same sequence. A flat build keeps
full turn detail so summary-mode pages still carry every finished-turn row.

Timeline responses report `completedTurnDisplay`, and the thread timeline
controller folds it into the loaded surface key through
`resolveLoadedTimelineSurfaceKey`. Since #3686 a refresh keeps older loaded
pages; without this, switching the display left older pages in the previous
display until reload.

Plugin SDK 0.4.95.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@SawyerHood
SawyerHood merged commit d7db24b into main Sep 15, 2026
16 checks passed
@SawyerHood
SawyerHood deleted the bb/right-now-we-have-a-behavior-where-basically-if-thr_ijt7ix8c5k branch September 15, 2026 17:56
albrand added a commit to albrand/bb that referenced this pull request Sep 17, 2026
An earlier whole-file fork resolution dropped upstream get-bb#3729's validation from
the plugin SDK host policy while its tests stayed, so a declaration got no
default and an invalid value was accepted. The validator, its constant, the
normalized field and the call site are restored verbatim from upstream; every
other host-policy rule the fork carries is untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant