Skip to content

FE-1828: Add interview length controls to Brunch - #9894

Open
kostandinang wants to merge 44 commits into
mainfrom
ka/fe-1828-interview-budget
Open

kostandinang wants to merge 44 commits into
mainfrom
ka/fe-1828-interview-budget

Conversation

@kostandinang

@kostandinang kostandinang commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

🌟 What is the purpose of this PR?

Add experimental Interview length controls to Brunch Chat and Voice, so people can choose how much questioning to do before wrapping up. Minutes are an estimate derived from replies remaining, not a timer.

🔗 Related links

🚫 Blocked by

  • Run the support-desk-staffing persona at Quick, Standard and Thorough and verify observed question counts. Real-model adherence is not yet verified.

🔍 What does this change?

  • Add a separate, default-disabled Interview length experiment under User settings → Labs → Use Brunch. Remember the chosen level separately; Standard is the initial selection when enabled.
  • Put an icon-only picker at the leading edge of the composer and Voice dock, with five stops: Off, Quick (~5 min), Standard (~10 min), Thorough (~20 min), and Deep (no limit). Preserve the collapsed Voice dock height.
  • Count completed canonical Brunch replies against text caps of 3 / 6 / 10, or Voice caps of 2 / 4 / 7. Confirmations and grouped questions each count once; tool-only messages, hidden messages and Live captions do not count, and the wrap-up summary does not spend a question. Earlier replies carry over when the level changes, including after reload.
  • Show a question-derived estimate, final-question state and wrap-up state; add compact, accessible transcript notes when the level changes.
  • Send the current allowance on every submission as opaque, host-owned submission context. The AI SDK transport gains a generic submissionContext option and a single version-two envelope that it bounds (plain JSON object, finite numbers, depth and size limits) but never interprets. Diagnostics-only bodies stay byte-identical on version one, and the transport's dependency rules are unchanged.
  • The SDCPN plugin owns the allowance: interviewBudgetContextKey, interviewBudgetSchema, parseInterviewBudget and the instruction it mounts. The Brunch app reads the key from the current delivery; an absent or malformed allowance means Off. The allowance is no longer copied into creation-only initialData. The model is told the level, cap and questions remaining, never minutes; minutes are website UI only.
  • At the cap, settle the latest answer and list stated facts, labelled assumptions and open items. Standard does not fill missing essentials with unconfirmed assumptions. Never invent operational facts, ranges or units. Deep offers pauses between topics instead of count-based closure.
  • Pass the Voice level through a validated startup header and quiet session.thinking.append updates, with a non-interrupting warning if an update fails. Keep instructions.append reserved for existing failure redirects.
  • Add generic Petrinaut slots: renderComposerStatus, renderSystemMessage, and inputMode in the composer control context. Petrinaut describes no interview-length behaviour.
  • Preserve the legacy request and instruction path when Off or the experiment is disabled; remove obsolete sweep-stream formatting and its schema.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

  • Modifies an npm-publishable library and includes a patch changeset for @hashintel/petrinaut describing only the new generic slots. The Brunch packages are private.

📜 Does this require a change to the docs?

  • The user guide is in the website's docs, apps/petrinaut-website/docs/interview-length.md, linked from the website README. Petrinaut's model-visible guide (libs/@hashintel/petrinaut/docs/) is unchanged, so the stock assistant never reads about this website Labs feature.

🕸️ Does this require a change to the Turbo Graph?

  • Does not affect the execution graph.

⚠️ Known issues

  • Caps are model instructions, not a hard runtime cutoff. Persona counts and paid live-Voice behaviour remain unverified; browser evidence uses fixture history.
  • Level-change notes are local to the mounted session. Per-question records, durable note storage and disclosure changes are outside this phase.
  • FE-1834: Teach Brunch voice agent custom words #9899 currently defines its own petrinaut-contextual-user-message:v2 with a words payload. Both cannot merge as written; FE-1834: Teach Brunch voice agent custom words #9899 should carry its words as submissionContext.words in this envelope instead of adding a transport option and validator.
  • apps/brunch-agent's provider-accounting.test.ts ("two real processes cannot interleave ledger transactions") fails locally on this branch with or without these changes.

🐾 Next steps

🛡 What tests cover this?

Fresh local checks on the PR head:

Package Checks
AI SDK transport 54 unit tests passed; build, lint and type check pass
SDCPN plugin 29 unit tests passed; build, lint and type check pass
Brunch agent core 69 unit tests passed; build, lint and type check pass
Brunch app 349 of 350 passed (one pre-existing failure, above); lint and type check pass
Petrinaut Core ai.test.ts passed, stock prompt contract unchanged
Petrinaut 304 AI assistant panel tests passed, including docs content
Petrinaut website 867 budget, transport, Labs, Live and server Voice tests passed; type check passes

Tests cover submission-context bounds and version-one byte equality, Off request serialization and instruction equality, malformed allowances falling back to Off, mode-specific caps, canonical counting across wrap-up and reload, level changes, transcript projection, Labs preferences and quiet Voice updates. Browser checks cover picker interaction, keyboard focus, progress text, compact notes and the collapsed dock height.

❓ How to test this?

  1. Start the existing local Brunch development setup with yarn dev:brunch.
  2. Open User settings → Labs, enable Use Brunch, then Interview length. Open Chat and use the icon at the left of the composer.
  3. Select each stop by name, rail or keyboard. Verify that the description follows the hovered stop and Escape returns focus to the trigger.
  4. With fixture history or an approved model session, verify the estimate changes with replies, not elapsed time. Switch to a lower cap and confirm earlier replies still count.
  5. Check the same control in Voice and confirm collapsing the conversation does not increase the dock height. With an approved Live session, change the level and verify it does not interrupt speech.
  6. Select Off, then disable the Labs experiment. Verify Off leaves no estimate, disabling hides the control, and re-enabling restores the saved level.

📹 Demo

interview-length-demo.mp4

kostandinang and others added 22 commits October 1, 2026 10:09
Carry the current allowance alongside immutable Flue birth data, preserve Off requests, and keep budget context separate from human evidence and transcript display.

Co-authored-by: Amp <amp@ampcode.com>
Count canonical replies against per-mode allowances, show question-derived estimates, and carry level changes into Live sessions without interrupting speech. Keep budget notes visible in both modes and remove retired sweep formatting.

Co-authored-by: Amp <amp@ampcode.com>
Restore the compact colored picker, hover previews and quiet estimate with a focusable detail card.

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
…cript note

Co-authored-by: Amp <amp@ampcode.com>
The trigger remounts when its tooltip is re-enabled on close, so the Popover's focus return landed on a detached button and keyboard users were left on the page body.

Co-authored-by: Amp <amp@ampcode.com>
A note anchored to the pending user message vanished when canonical history replaced that message with a new id. Fall back to the anchor's position among messages of the same role.

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Amp <amp@ampcode.com>
@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

4 Skipped Deployments
Project Deployment Actions Updated
hash Ignored Ignored Preview Oct 7, 2026 5:37pm UTC
hashdotdesign-tokens Ignored Ignored Preview Oct 7, 2026 5:37pm UTC
petrinaut Skipped Skipped Oct 7, 2026 5:37pm UTC
petrinaut-docs Skipped Skipped Oct 7, 2026 5:37pm UTC

Request Review

@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/tests New or updated tests area/apps labels Oct 2, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
kostandinang and others added 2 commits October 7, 2026 12:39
…budget

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts
Co-authored-by: Cursor <cursoragent@cursor.com>
…budget

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx
#	apps/petrinaut-website/src/main/app/voice-interview/live-conversation.test.ts
#	apps/petrinaut-website/src/main/app/voice-interview/live-conversation.ts
#	apps/petrinaut-website/src/main/app/voice-interview/voice-interview-control.tsx

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b25edb6. Configure here.

Comment thread apps/brunch-agent/src/agents/chat-agent/agent.ts
kostandinang and others added 5 commits October 7, 2026 17:52
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
kostandinang and others added 3 commits October 7, 2026 18:03
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel
vercel Bot temporarily deployed to Preview – petrinaut October 7, 2026 17:36 Inactive
@vercel
vercel Bot temporarily deployed to Preview – petrinaut-docs October 7, 2026 17:36 Inactive

This branch was successfully deployed

2 active (outdated) and 2 inactive deployments
Preview – petrinaut-docs — be747d16 Deployed Oct 7, 2026 by vercel[bot]
Preview – petrinaut — be747d16 Deployed Oct 7, 2026 by vercel[bot]
Preview – hash — b25edb6c Deployed Oct 7, 2026 by vercel[bot]
Preview – hashdotdesign-tokens — 0d56c273 Deployed Oct 7, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

1 participant