Skip to content

fix: improve reasoning, streaming, and agent generation behavior - #4271

Merged
SpicyMarinara merged 5 commits into
stagingfrom
fix/reasoning-summary-smooth-streaming
Jul 29, 2026
Merged

fix: improve reasoning, streaming, and agent generation behavior#4271
SpicyMarinara merged 5 commits into
stagingfrom
fix/reasoning-summary-smooth-streaming

Conversation

@SpicyMarinara

@SpicyMarinara SpicyMarinara commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Why

Several generation paths were producing degraded or misleading behavior:

  • OpenAI Responses reasoning tokens were consumed without consistently requesting or surfacing a readable reasoning summary.
  • Provider-sized stream bursts made the visible response feel chunky instead of following the configured typewriter speed.
  • Legacy Expression Engine tool settings forced the JSON tracker into a separate tool-capable request.
  • Regeneration leaked the response being replaced back into the prompt through automatic summaries and recalled memory ([Issue]: Regenerated messages leak into summary and memory context #4270).
  • NoodleHome retained a stale hook dependency warning.

What changed

  • Always request an automatic OpenAI reasoning summary unless reasoning is explicitly disabled, and collect supported streaming summary events without duplicating text.
  • Drive the visible stream from one grapheme-aware, user-selected characters-per-second clock with a short initial buffer and reduced-motion support.
  • Retire set_expression for Expression Engine, including compatibility normalization for older installed package manifests and saved settings, so it can batch with compatible JSON tracker agents.
  • Exclude structured summary entries that cover a message being regenerated and recompile the prompt-time summary from the remaining entries.
  • Bound memory recall before the regenerated message timestamp so chunks containing the discarded response cannot re-enter the prompt.
  • Add focused regressions for legacy Expression settings, regeneration summary/memory isolation, reasoning summaries, streaming cadence, and tracker batching.
  • Add the missing localizeUi hook dependency and refresh a stale Roleplay source assertion.

The downloadable Expression Engine 1.0.2 package/catalog update is in Pasta-Devs/Marinara-Agents#127.

User impact

Reasoning summaries become available when the provider emits them, streamed text reveals smoothly at the configured rate, and Expression Engine no longer pays for a redundant tool round-trip. Regenerating a message no longer supplies its discarded response to the model as settled summary or memory context.

When one structured summary entry covers many messages including the regenerated one, that entire opaque entry is omitted for the regeneration request. This conservatively loses some summary context for one request rather than leaking the response being replaced; stored summary data is not mutated.

Validation

  • pnpm check
  • pnpm regression:providers
  • pnpm regression:expression-tools
  • pnpm regression:regeneration-context
  • pnpm regression:roleplay
  • git diff --check

Manual verification

  • Manually verify GPT-5.6 reasoning summary appears in the brain panel with streaming enabled.
  • Manually verify streaming speeds 1, 30, 99, and 100 produce the expected smooth/instant reveal behavior.
  • Restart Marinara Engine and manually verify legacy Expression Engine settings batch with World State.
  • Manually verify Music DJ remains a separate tool-capable request.
  • Manually reproduce [Issue]: Regenerated messages leak into summary and memory context #4270 and confirm the regenerated assistant message is absent from Chat Summary and Memories prompt blocks.

Closes #4270

Summary by CodeRabbit

  • New Features
    • Streaming text animations now use consistent pacing with reduced-motion support and grapheme-safe reveals.
    • Regeneration-aware context improves both memory recall and roleplay summaries by excluding regenerated content.
    • Retired built-in agent tools are automatically filtered from enabled/default tool settings.
  • Bug Fixes
    • Improved resilience for OpenAI streamed reasoning summaries.
    • Fixed notification “mark as read” reactivity to localization updates.
  • Tests
    • Added/updated regression coverage for streaming pacing, regeneration context handling, retired expression tools, and OpenAI provider compatibility.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR unifies streaming typewriter pacing, adds grapheme-safe reveals, filters regenerated messages from summaries and memories, normalizes retired built-in tools, improves OpenAI reasoning-summary streaming, updates a notification effect dependency, and adds regression scripts.

Changes

Unified streaming typewriter

Layer / File(s) Summary
Streaming policy and grapheme slicing
packages/client/src/lib/generation-stream-policy.ts
Replaces roleplay-specific reveal-rate helpers with streaming-speed mapping, frame budgeting, and grapheme-safe character slicing.
Unified typewriter execution
packages/client/src/hooks/use-generate.ts
Adds shared prebuffering, reduced-motion pacing, remainder accumulation, and unified typewriter state.
Streaming regression coverage
scripts/regressions/roleplay-streaming.regression.ts
Updates cadence, prebuffer, reduced-motion, grapheme, and ambient-render assertions.

Regeneration context filtering

Layer / File(s) Summary
Regenerated summary exclusion
packages/server/src/routes/generate/generate-route-utils.ts
Filters summary entries covering excluded message IDs before recompiling roleplay summaries.
Timestamp-bounded memory recall
packages/server/src/services/memory-recall.ts, packages/server/src/services/generation/memory-recall-context.ts
Adds excludeFromMessageAt through the recall API and filters memory chunks by timestamp.
Regeneration route wiring
packages/server/src/routes/generate/generate.routes.ts
Passes the regenerated message timestamp and ID through summary and memory-recall paths.
Regeneration regression coverage
scripts/regressions/regeneration-context.regression.ts, package.json
Validates filtered summaries, memories, injected context, and exposes the regression command.

Built-in agent tool normalization

Layer / File(s) Summary
Retired tool normalization
packages/shared/src/types/agent.ts, packages/server/src/routes/generate/retry-agents-route.ts
Filters retired tools during settings merging, default replacement, and retry-agent tool handling.
Expression tool retirement regression
scripts/regressions/expression-tool-retirement.regression.ts, package.json
Verifies legacy Expression settings and defaults no longer restore retired tools.

OpenAI reasoning-summary streaming

Layer / File(s) Summary
Overlap-aware reasoning emission
packages/server/src/services/llm/providers/openai.provider.ts
Accumulates reasoning-summary deltas and emits missing text across both Responses streaming paths.
Provider compatibility regression
scripts/regressions/provider-compat.regression.ts
Updates mocked events and assertions for reconstructed reasoning summaries.

Supporting updates

Layer / File(s) Summary
Notification effect dependency
packages/client/src/components/noodle/NoodleHome.tsx
Adds localizeUi to the notification-read effect dependencies.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant GenerateRoutes
  participant SummaryResolver
  participant MemoryRecall
  Client->>GenerateRoutes: regenerate assistant message
  GenerateRoutes->>SummaryResolver: exclude regenerated message ID
  GenerateRoutes->>MemoryRecall: apply regenerateContextCutoff
  MemoryRecall-->>GenerateRoutes: filtered memory context
  GenerateRoutes-->>Client: generation prompt without regenerated content
Loading

Possibly related PRs

Suggested labels: refactor

Suggested reviewers: thetopham, xelvanis

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes target reasoning summaries, streaming cadence, Expression tool batching, and NoodleHome, which are unrelated to #4270. Split the unrelated reasoning/streaming/Expression/NoodleHome work into separate PRs or link additional issues so this PR stays focused on #4270.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main themes of the PR, though it is broader than the regeneration fix alone.
Description check ✅ Passed The description covers the required sections and key details; only non-critical template sections like docs/release impact and UI evidence are sparse.
Linked Issues check ✅ Passed The regeneration changes exclude the replaced message from summaries and memory recall, satisfying #4270's prompt-context isolation requirement.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/reasoning-summary-smooth-streaming

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

Comment @coderabbitai help to get the list of available commands.

@SpicyMarinara
SpicyMarinara marked this pull request as ready for review July 29, 2026 19:42
@SpicyMarinara

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/client/src/hooks/use-generate.ts`:
- Around line 1491-1492: The typewriter frame calculation currently caps output
to a fixed per-frame allowance, reducing the configured rate at lower frame
rates. Update the logic around typewriterRemainder and the derived n to
calculate the frame cap from elapsedMs while preserving maxCharsThisFrame and
pendingText limits, then add a regression test simulating 30 FPS to verify the
configured characters-per-second rate remains stable.

In `@packages/server/src/routes/generate/generate-route-utils.ts`:
- Around line 640-645: Update the summary filtering flow around
normalizeChatSummaryEntries so a synthesized legacy entry from summary is
discarded when summaryEntries is absent or invalid during regeneration, rather
than retained without message-ID provenance. Preserve valid explicitly provided
entries and compile only the entries whose covered IDs are not excluded. Add a
regression case covering input with summary only and no summaryEntries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3c48037b-0903-4ccf-b359-4f41c1d75b96

📥 Commits

Reviewing files that changed from the base of the PR and between f294482 and 2bf0123.

📒 Files selected for processing (15)
  • package.json
  • packages/client/src/components/noodle/NoodleHome.tsx
  • packages/client/src/hooks/use-generate.ts
  • packages/client/src/lib/generation-stream-policy.ts
  • packages/server/src/routes/generate.routes.ts
  • packages/server/src/routes/generate/generate-route-utils.ts
  • packages/server/src/routes/generate/retry-agents-route.ts
  • packages/server/src/services/generation/memory-recall-context.ts
  • packages/server/src/services/llm/providers/openai.provider.ts
  • packages/server/src/services/memory-recall.ts
  • packages/shared/src/types/agent.ts
  • scripts/regressions/expression-tool-retirement.regression.ts
  • scripts/regressions/provider-compat.regression.ts
  • scripts/regressions/regeneration-context.regression.ts
  • scripts/regressions/roleplay-streaming.regression.ts

Comment thread packages/client/src/hooks/use-generate.ts Outdated
Comment thread packages/server/src/routes/generate/generate-route-utils.ts Outdated

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/server/src/routes/generate/generate-route-utils.ts (1)

640-648: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude unprovenanced entries during regeneration.

normalizeChatSummaryEntries preserves explicit entries that have neither messageIds nor hiddenMessageIds. Those entries produce an empty coveredMessageIds array and are retained, so their content can still contain the discarded response. During regeneration, conservatively drop entries without provenance and add a regression case covering a mixed set of provenanced and unprovenanced entries.

Proposed fix
  const retainedEntries = entries.filter((entry) => {
    const coveredMessageIds = [...(entry.messageIds ?? []), ...(entry.hiddenMessageIds ?? [])];
-   return !coveredMessageIds.some((messageId) => excludedMessageIds.has(messageId));
+   return (
+     coveredMessageIds.length > 0 &&
+     !coveredMessageIds.some((messageId) => excludedMessageIds.has(messageId))
+   );
  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/server/src/routes/generate/generate-route-utils.ts` around lines 640
- 648, Update the retainedEntries filtering in the regeneration logic to exclude
any summary entry lacking both messageIds and hiddenMessageIds, while preserving
the existing excludedMessageIds checks for provenanced entries. Add a regression
case covering mixed provenanced and unprovenanced entries and verify the
unprovenanced entry is discarded.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/server/src/routes/generate/generate-route-utils.ts`:
- Around line 640-648: Update the retainedEntries filtering in the regeneration
logic to exclude any summary entry lacking both messageIds and hiddenMessageIds,
while preserving the existing excludedMessageIds checks for provenanced entries.
Add a regression case covering mixed provenanced and unprovenanced entries and
verify the unprovenanced entry is discarded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: eb2e01d9-c29f-4ccb-b251-7dbfef13f159

📥 Commits

Reviewing files that changed from the base of the PR and between 2bf0123 and d0234ec.

📒 Files selected for processing (5)
  • packages/client/src/hooks/use-generate.ts
  • packages/client/src/lib/generation-stream-policy.ts
  • packages/server/src/routes/generate/generate-route-utils.ts
  • scripts/regressions/regeneration-context.regression.ts
  • scripts/regressions/roleplay-streaming.regression.ts

@SpicyMarinara
SpicyMarinara merged commit 2ab662b into staging Jul 29, 2026
17 checks passed
@SpicyMarinara
SpicyMarinara deleted the fix/reasoning-summary-smooth-streaming branch July 29, 2026 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant