Skip to content

workspace,studio: offer the person's likely next message in an empty box - #191

Open
mutewinter wants to merge 3 commits into
mainfrom
prompt-suggestions
Open

mutewinter wants to merge 3 commits into
mainfrom
prompt-suggestions

Conversation

@mutewinter

@mutewinter mutewinter commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

After a chat's turn ends, the empty reply box can now show one suggested next message, in gray where "Talk to Instrument" usually is, with a small Tab key after it. Tab, or a click on the key, puts it in as your own words, ready to send or change. Typing anything hides it, and it never sends by itself.

How it's made

  • When a chat settles (its agent and every task are done), the app asks the model the last reply ran on what you'd most likely send next.
  • The ask is the last reply's own request again (same messages, tools and cache session) with one instruction added after it, so the provider's cache covers the conversation and the call only adds the instruction and a one-line answer. It's the same trick the context-rollover summary already uses.
  • The suggestion lives in memory on this computer and reaches the window through a new chats.live.nextMessage stream. Sending a message or a new turn starting takes it away.
  • Each ask shows in Settings › Activity as "Suggested reply".

When it doesn't suggest

Code skips the ask entirely when:

  • you stopped the turn yourself;
  • a card is waiting on you (permission, sign-in, a question);
  • the last reply failed;
  • something in the chat is still running (it only runs once the chat settles).

The model answers NONE, and code shows nothing, when:

  • the agent's last message asked you something, even in passing;
  • something failed;
  • you just said thanks or goodbye;
  • it would mean guessing at someone else's private life.

Code also drops an answer that's empty, longer than 120 characters, or talks about the suggestion instead of being one. In Studio it's shown only in the chat's own box, and not while you're replying to a specific message, dictating, or have something attached.

The instruction

It's NEXT_MESSAGE_INSTRUCTION in packages/workspace/src/lib/chat/next-message.ts. It started from a replay over 41 real chats, then was loosened to suggest on most turns, since a wrong suggestion costs nothing when you have to take it.

Evals (evals/cases/next-message.ts, 2 trials each)

Offers one after a finished answer Offers none after "thanks" Input tokens served from cache
Workers AI glm-5.3-flash 2/2 1/2 0 to 16k of about 20k
Claude Haiku 5.5 (Claude account) 1/2 2/2 about 24k of 29.7k

Answers were 5 to 25 output tokens. Examples: "What about a lightweight rain shell option instead of a jacket?", "Which shoes do you pack when yours don't have any waterproof ones?". GLM once invented "What's on my calendar tomorrow?" after a thank-you.

Not done yet

  • Not checked in the running app. The gray line's alignment with the box's first line is only tested in jsdom.
  • Not tried on ChatGPT or OpenRouter models.
  • No back-off when suggestions keep being ignored, and no setting to turn it off.

Summary by CodeRabbit

  • New Features
    • Chats can display an AI-generated suggested reply in the message composer when it’s empty and no reply is selected.
    • Accept a suggestion with Tab or its on-screen control. The suggestion is hidden while you type and can reappear after you clear the composer.
    • Suggestions are unavailable when attachments are present, a reply is selected, or the chat is actively working.

Once a chat settles, the app asks the model its last reply ran on what
the person would most likely send next, and the chat's empty box shows
it in gray where the placeholder goes, with a Tab key after it. Tab, or a
click on the key, puts it in as the person's words to send or change;
typing anything puts it away, and a new message or turn takes it back.

The ask is the last reply's own request again, its messages, tools and
cache session, with one instruction after it, so the provider's cache
serves the conversation and the call adds the instruction and a line.
It is not asked when the person stopped the turn, a card or question
waits on them, or the reply failed, and the model answers NONE after a
question, a failure, or a thank-you. The suggestion is kept in memory on
this computer and reaches the window through `chats.live.nextMessage`;
the request is logged as "Suggested reply".

Rejected: the decision model | not everyone has it; the chat's own model always answers
Rejected: a separate prompt over a text rendering of the chat | none of it is cached, and it is not the voice the chat has
Rejected: two or three chips under the reply | one gray line in the box is quieter, and a press never sends it
Rejected: staying quiet after greetings and when the next step is unclear | a suggestion the person has to take costs nothing when wrong
Commits-to: a suggestion is never sent without the person taking it and sending it
Commits-to: the ask reuses the last reply's request byte for byte up to its instruction
Tested: evals/cases/next-message.ts, 2 trials each: Workers AI glm-5.3-flash offers one after a finished answer 2/2, none after thanks 1/2 (once invented "What's on my calendar tomorrow?"); Claude Haiku 5.5 via the Claude account 1/2 and 2/2, 24,185 of about 29,700 input tokens read from the cache, 5 to 25 output tokens
Tested: the instruction's rules replayed over 41 real chats on Haiku 5.5 before it moved into the request
Not-tested: seen in the running app; the overlay's alignment with the box's first line is checked only in jsdom
Not-tested: ChatGPT and OpenRouter models, and backing off after suggestions left untaken
Nothing outside next-message.ts reads it, which fails check:unused.
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Explain Change →

Note

CodeRabbit ASCII loading animation

Currently processing new changes in this PR. This may take a few minutes, please wait...

Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7139a39f-4fe7-474b-ba85-df43a3e256ee
Commits

Reviewing files that changed from the base of the PR and between 39b7110 and 0106485.

Files selected for processing: 5
  • apps/studio/src/client/components/task/chat.tsx
  • packages/workspace/src/lib/chat/next-message.ts
  • packages/workspace/src/lib/prepare-model-messages.test.ts
  • packages/workspace/src/lib/prepare-model-messages.ts
  • packages/workspace/src/lib/tool-result-clearing.ts
Walkthrough

The change generates suggestions for the next user message after eligible chat settlements. It exposes suggestions through a live chat route and offers them in the composer when the draft is empty and eligible. It also adds evaluation cases and tests for suggestion parsing and editor behavior.

Changes: Next-message suggestions

Layer / File(s) Summary
Generate and validate suggestions
packages/workspace/src/lib/chat/next-message.ts, packages/workspace/src/lib/chat/attach.ts, packages/workspace/src/lib/chat/next-message.test.ts, packages/workspace/src/lib/activity/schema.ts, apps/studio/src/client/components/settings/activity-section.tsx, packages/workspace/evals/cases/*
Chat attachment starts suggestion generation for eligible settlements. The generator prepares model input, parses the response, records usage, and publishes valid suggestions. Evaluation cases and unit tests cover generation and parsing.
Expose suggestions through the live chat route
packages/workspace/src/rpc/publisher.ts, packages/workspace/src/rpc/routes/chats.ts
The new publisher event identifies a chat with an updated suggestion. The live route returns the current suggestion or null and rereads after matching events or chat message changes.
Offer and accept suggestions in the composer
apps/studio/src/client/components/task/chat.tsx, apps/studio/src/client/components/prompt-input.tsx, apps/studio/src/client/components/prompt-editor.tsx, apps/studio/src/client/components/prompt-editor-suggestion.test.tsx
The chat passes suggestions to eligible prompt inputs. The editor displays an offer when the document is empty and dictation is inactive, and accepts it through Tab or a button. Tests cover display, acceptance, and visibility updates.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ChatSettlement
  participant SuggestionGenerator
  participant AIGateway
  participant LiveChatRoute
  participant ChatConversation
  participant PromptEditor
  ChatSettlement->>SuggestionGenerator: start generation for an eligible settlement
  SuggestionGenerator->>AIGateway: request a next-message suggestion
  AIGateway-->>SuggestionGenerator: return answer and usage
  SuggestionGenerator->>LiveChatRoute: publish chat.nextMessage when valid
  LiveChatRoute-->>ChatConversation: stream the current suggestion
  ChatConversation->>PromptEditor: pass suggestion to an eligible prompt input
  PromptEditor-->>ChatConversation: insert suggestion on Tab or button click
Loading

Possibly related PRs

Merge Risk: Moderate · previous review 39b71

Suggestion generation can change which chat history the next turn uses, and outdated suggestions can appear in the composer. Fix those behaviors and remove the conversation-derived log before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names two of the main changes: a suggested next message (workspace and Studio) and its display in an empty input box. It is a real, specific summary of the feature. It does not name the Tab-…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title names two of the main changes: a suggested next message (workspace and Studio) and its display in an empty input box. It is a real, specific summary of the feature. It does not name the Tab-to-accept behavior, the Activity log entry, or the in-memory storage, which is acceptable because a title need not cover every detail.

Full details: Docstring Coverage

Explanation

Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 9 functions across 13 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c6d60040-59f2-4452-83b7-4cf64d64d460
Commits

Reviewing files that changed from the base of the PR and between 55b42fb and 39b7110.

Files selected for processing: 13
  • apps/studio/src/client/components/prompt-editor-suggestion.test.tsx
  • apps/studio/src/client/components/prompt-editor.tsx
  • apps/studio/src/client/components/prompt-input.tsx
  • apps/studio/src/client/components/settings/activity-section.tsx
  • apps/studio/src/client/components/task/chat.tsx
  • packages/workspace/evals/cases/index.ts
  • packages/workspace/evals/cases/next-message.ts
  • packages/workspace/src/lib/activity/schema.ts
  • packages/workspace/src/lib/chat/attach.ts
  • packages/workspace/src/lib/chat/next-message.test.ts
  • packages/workspace/src/lib/chat/next-message.ts
  • packages/workspace/src/rpc/publisher.ts
  • packages/workspace/src/rpc/routes/chats.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@coderabbitai coderabbitai 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.

  • Fix comments: Fix CodeRabbit comments on this PR

The next-message ask prepares its request read-only: where the request
would first record a model change, a rollover or a tool-result clearing,
`prepareModelMessages` refuses and no suggestion is made, so the side
call never reshapes the history the person's next turn is sent with. A
request about to be reshaped is one the cache no longer serves anyway.

Each chat's latest settle is kept, and an ask a later settle overtook
publishes nothing. Studio hides the suggestion while a sent message is
still on its way to the records, and a debug line printing the model's
answer is gone.

Rejected: rebuilding `empty` when the editor view is built | the view is built once at mount, from the same default value the state starts from
Rejected: guarding the baseline rewrite too | it is due only after a rollover, refused first, or for a baseline older than the build that just wrote the reply
Commits-to: a side call built from a turn's request records nothing in the chat
Review: CodeRabbit on #191
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant