Skip to content

Improve chat tools and metadata#896

Merged
DanielButler1 merged 5 commits into
mainfrom
fix/chat-tag-import-normalization
Jul 4, 2026
Merged

Improve chat tools and metadata#896
DanielButler1 merged 5 commits into
mainfrom
fix/chat-tag-import-normalization

Conversation

@DanielButler1

@DanielButler1 DanielButler1 commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • adds chat shortcuts, the shortcut reference dialog, prompt queue controls, and composer tool configuration improvements
  • restores and extends chat tags and bulk chat editing while preserving thread dates for rename/tag/pin-only edits
  • improves response metadata with API stream timing, more precise generation duration formatting, hover timestamps, and safer streaming metadata merging

Validation

  • pnpm --filter @ai-stats/web exec tsc --noEmit --pretty false
  • pnpm --filter @ai-stats/gateway-api typecheck
  • pnpm --filter @ai-stats/gateway-api exec eslint src/pipeline/after/stream.ts
  • pnpm --filter @ai-stats/web test -- chat-playground-core.test.ts
  • pnpm --filter @ai-stats/web exec eslint src/components/(chat)/ChatShortcutReference.tsx src/components/(chat)/ChatMessageFooters.tsx src/components/(chat)/ChatConversationMessages.tsx src/components/(chat)/ChatPlayground.tsx src/components/(chat)/ChatConversationComposer.tsx src/components/(chat)/ChatSidebar.tsx src/components/(chat)/ChatTagsDialog.tsx src/components/(chat)/playground/chat-playground-core.ts src/components/(chat)/playground/use-grouped-chat-threads.ts src/components/ai-elements/reasoning.tsx src/lib/config/featureLabels.ts src/lib/indexeddb/chats.ts (warnings only)

Created with Codex

Summary by CodeRabbit

  • New Features

    • Added keyboard shortcut help for chat, plus a shortcuts reference in settings.
    • Enabled queued prompt submission while a message is sending.
    • Expanded composer server tool configuration (including new fusion/sub-agent options) and added richer tool settings UI.
    • Introduced an API target selector and more consistent base-URL handling across chat requests.
    • Improved assistant/server stream timing metadata shown in the UI.
  • Bug Fixes

    • Normalized and sanitized saved chat tags/threads on load and save to prevent malformed/duplicate data.
    • Tag filtering and “visible threads” handling in the chat playground now use normalized tag data.
    • Missing tag colors now fall back to a default.
  • Tests

    • Added Jest coverage for chat tag/thread normalization and tool-definition building.

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@DanielButler1, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: aa09f857-a964-40ee-a912-753a2014774b

📥 Commits

Reviewing files that changed from the base of the PR and between a899c82 and e80c730.

⛔ Files ignored due to path filters (1)
  • .entire/logs/entire.log is excluded by !**/*.log
📒 Files selected for processing (4)
  • .entire/.gitignore
  • apps/api/src/pipeline/after/stream.ts
  • apps/web/src/components/(chat)/ChatConversation.tsx
  • apps/web/src/components/(chat)/ChatPlayground.tsx
📝 Walkthrough

Walkthrough

This PR normalizes chat tag/thread data, expands chat playground API-target and server-tool handling, adds queued prompts and bulk thread actions, updates message metadata rendering, and forwards custom base URLs through chat proxy routes while attaching timing metadata to terminal stream frames.

Changes

Chat data normalization and tool config

Layer / File(s) Summary
IndexedDB normalization
apps/web/src/lib/indexeddb/chats.ts, apps/web/src/lib/indexeddb/chats.test.ts
Chat threads and tags are sanitized before storage and after reads, and the normalization behavior is covered by tests.
Server tool definitions
apps/web/src/components/(chat)/playground/chat-playground-core.ts, apps/web/src/components/(chat)/playground/chat-playground-core.test.ts
Chat playground core filters supported server tools, adds API-target storage, and builds tool definitions for datetime, web search, web fetch, image generation, fusion, advisor, and subagent settings, with tests covering the mappings.
Thread grouping and shared labels
apps/web/src/components/(chat)/playground/use-grouped-chat-threads.ts, apps/web/src/lib/config/featureLabels.ts, apps/web/src/components/(chat)/chatConversationHelpers.ts, apps/web/src/components/(chat)/ChatMessageMarkers.tsx, apps/web/src/components/ai-elements/reasoning.tsx
Thread activity grouping uses message timestamps, the web search feature label changes, and reasoning-effort and reasoning-display helpers add support for the max value.

Chat playground shell and multi-thread actions

Layer / File(s) Summary
Playground state and selection flow
apps/web/src/components/(chat)/ChatPlayground.tsx
ChatPlayground normalizes tags, infers and stores API targets, resolves request base URLs, updates assistant variants, tracks bulk thread selection, and wires shortcut help plus bulk dialogs into the shell.
Header, sidebar, and dialogs
apps/web/src/components/(chat)/ChatHeader.tsx, apps/web/src/components/(chat)/ChatSidebar.tsx, apps/web/src/components/(chat)/ChatTagsDialog.tsx, apps/web/src/components/(chat)/ChatDeleteDialog.tsx, apps/web/src/components/(chat)/ChatShortcutReference.tsx
ChatHeader adds API-target controls and shortcuts settings, ChatSidebar adds edit mode and tag visibility controls, and delete/tags dialogs support plural and multi-thread copy.

Conversation flow and composer controls

Layer / File(s) Summary
Queued prompts and submission
apps/web/src/components/(chat)/ChatConversation.tsx
Conversation state now queues prompts, drains them per thread, supports editing and reordering queued items, and derives prompt history from prior user messages.
Composer tool settings
apps/web/src/components/(chat)/ChatConversationComposer.tsx
Composer controls are expanded for server-tool configuration, timezone and model pickers, slash-menu routing, accent styling, and queued-prompt UI actions.
Message metadata rendering
apps/web/src/components/(chat)/ChatConversationMessages.tsx, apps/web/src/components/(chat)/ChatMessageFooters.tsx
Message footers now render sent-at labels and display-ready generation durations, and message rows use the updated timestamp and token helpers.

Gateway proxy and stream timing

Layer / File(s) Summary
Gateway base URL resolution
apps/web/src/app/api/chat/_shared/gatewayProxy.ts, apps/web/src/app/api/chat/audio/route.ts, apps/web/src/app/api/chat/embeddings/route.ts, apps/web/src/app/api/chat/image/route.ts, apps/web/src/app/api/chat/moderation/route.ts, apps/web/src/app/api/chat/text/route.ts, apps/web/src/app/api/chat/video/route.ts
The gateway proxy envelope, proxy helpers, and chat routes accept base URL overrides and resolve public, configured, or localhost gateway targets.
Stream timing metadata
apps/api/src/pipeline/after/stream.ts
Terminal stream frames derive output-token counts from multiple usage shapes and attach generation, latency, and throughput metadata while removing finish reasons from frame metadata.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChatPlayground
  participant ChatHeader
  participant ChatSidebar
  participant ChatDeleteDialog
  participant ChatTagsDialog

  ChatPlayground->>ChatPlayground: infer apiTarget / resolve baseUrl
  ChatPlayground->>ChatHeader: pass apiTarget and onApiTargetChange
  ChatPlayground->>ChatSidebar: pass bulk action callbacks
  ChatSidebar->>ChatPlayground: request delete/edit selected threads
  ChatPlayground->>ChatDeleteDialog: open with count
  ChatPlayground->>ChatTagsDialog: open with threads selection
Loading
sequenceDiagram
  participant ChatConversation
  participant ChatConversationComposer
  participant onSend

  ChatConversation->>ChatConversationComposer: pass queuedPrompts and callbacks
  ChatConversationComposer->>ChatConversation: submit prompt or queue edit/reorder
  ChatConversation->>ChatConversation: drain queued prompt for active thread
  ChatConversation->>onSend: sendPrompt(payload)
Loading
sequenceDiagram
  participant ChatRoute
  participant gatewayProxy as gatewayProxy.ts
  participant Gateway

  ChatRoute->>gatewayProxy: proxyGatewayPost/Get(baseUrl)
  gatewayProxy->>gatewayProxy: resolveGatewayBaseUrl(requestedBaseUrl)
  gatewayProxy->>Gateway: proxy request to selected upstream
  Gateway-->>gatewayProxy: response / stream
  gatewayProxy-->>ChatRoute: proxied result
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is broadly aligned with the changeset, covering chat tools and metadata improvements, though it is somewhat generic.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/chat-tag-import-normalization

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.

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

🧹 Nitpick comments (1)
apps/web/src/lib/indexeddb/chats.ts (1)

131-158: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Solid sanitization logic; consider validating color format.

The trim/dedup/default-color logic matches the documented test contract exactly. One optional improvement: color is only checked for non-emptiness, not for a valid CSS color shape (e.g., hex). Malformed imported values (e.g., "javascript:x", overly long strings) would pass through unchanged and could produce visually broken tag swatches downstream.

♻️ Optional: constrain color to a hex pattern
+const HEX_COLOR_PATTERN = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
+
 export function normalizeChatTags(value: unknown): ChatTag[] {
     ...
-        const color =
-            typeof candidate.color === "string" && candidate.color.trim()
-                ? candidate.color.trim()
-                : DEFAULT_CHAT_TAG_COLOR;
+        const trimmedColor =
+            typeof candidate.color === "string" ? candidate.color.trim() : "";
+        const color = HEX_COLOR_PATTERN.test(trimmedColor)
+            ? trimmedColor
+            : DEFAULT_CHAT_TAG_COLOR;
🤖 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 `@apps/web/src/lib/indexeddb/chats.ts` around lines 131 - 158,
normalizeChatTags currently accepts any non-empty string for ChatTag.color, so
malformed imported values can slip through. Update normalizeChatTags in chats.ts
to validate the color field more strictly before constructing each ChatTag,
using the existing DEFAULT_CHAT_TAG_COLOR fallback when the value does not match
the intended CSS/hex format. Keep the current id/name trimming and dedup
behavior intact while tightening the color handling inside the normalizeChatTags
loop.
🤖 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.

Nitpick comments:
In `@apps/web/src/lib/indexeddb/chats.ts`:
- Around line 131-158: normalizeChatTags currently accepts any non-empty string
for ChatTag.color, so malformed imported values can slip through. Update
normalizeChatTags in chats.ts to validate the color field more strictly before
constructing each ChatTag, using the existing DEFAULT_CHAT_TAG_COLOR fallback
when the value does not match the intended CSS/hex format. Keep the current
id/name trimming and dedup behavior intact while tightening the color handling
inside the normalizeChatTags loop.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 27aaa2a8-f704-492b-a4bd-3917ae948075

📥 Commits

Reviewing files that changed from the base of the PR and between adb5db0 and 8510037.

📒 Files selected for processing (3)
  • apps/web/src/components/(chat)/ChatPlayground.tsx
  • apps/web/src/lib/indexeddb/chats.test.ts
  • apps/web/src/lib/indexeddb/chats.ts

@DanielButler1 DanielButler1 changed the title Normalize imported chat tags Improve chat tools and metadata Jul 4, 2026

@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

Caution

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

⚠️ Outside diff range comments (4)
apps/web/src/app/api/chat/_shared/gatewayProxy.ts (1)

32-36: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail-open fallback makes the missing-config branch unreachable

resolveGatewayBaseUrl() always returns either the requested URL, configuredGatewayBaseUrl, or PUBLIC_GATEWAY_BASE_URL, so proxyGatewayPost()/proxyGatewayGet() can no longer hit buildGatewayMissingConfigResponse(). If misconfigured deployments should still fail closed, restore the null path; otherwise remove the dead guard and document the fallback.

🤖 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 `@apps/web/src/app/api/chat/_shared/gatewayProxy.ts` around lines 32 - 36,
`resolveGatewayBaseUrl()` in `gatewayProxy.ts` currently falls back to
`PUBLIC_GATEWAY_BASE_URL`, which makes the missing-config branch in
`proxyGatewayPost()` and `proxyGatewayGet()` unreachable. Decide whether
misconfigured deployments should fail closed or fail open: if fail closed,
restore a null/absent path so `buildGatewayMissingConfigResponse()` can still be
returned; if fail open, remove the dead guard and update the gateway base URL
logic/documentation to reflect the fallback.
apps/web/src/app/api/chat/video/route.ts (1)

86-119: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Forward baseUrl through video GET proxying
apps/web/src/app/api/chat/video/route.ts: both GET branches drop the override, so a video job created against a custom gateway can’t be listed or polled from this route. Pass baseUrl into proxyGatewayGet here too.

🤖 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 `@apps/web/src/app/api/chat/video/route.ts` around lines 86 - 119, The GET
handler in video/route.ts is dropping the custom gateway override when proxying
both the list and poll branches. Update the GET logic to forward baseUrl into
proxyGatewayGet alongside the existing path from resolveVideoListPath and
resolveVideoPollPath, so requests created against a custom gateway continue to
resolve correctly.
apps/web/src/app/api/chat/audio/route.ts (1)

50-82: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Thread baseUrl through music polling apps/web/src/app/api/chat/audio/route.ts:50-82 Polling here ignores the gateway override used by POST, so music jobs created on a custom/dev gateway will be polled against the default backend and can miss or 404. Pass baseUrl in the poll URL and forward it to proxyGatewayGet.

🤖 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 `@apps/web/src/app/api/chat/audio/route.ts` around lines 50 - 82, The music
polling GET handler currently ignores the gateway override used by POST, so
polling can hit the wrong backend. Update the GET path in audio route’s GET
handler to read the same baseUrl query param and thread it into both the polling
URL built by resolveMusicPollPath and the proxyGatewayGet call. Keep the
existing resourceId/action validation in place, but ensure the resolved poll
request uses the caller-provided baseUrl when present.
apps/web/src/components/(chat)/playground/chat-playground-core.ts (1)

467-507: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clamp advisor temperature too buildAdvisorDefinition forwards advisor.temperature unchanged, while the sibling subagent path clamps it to [0, 2]. Normalizing here avoids inconsistent tool payloads and rejected requests.

🤖 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 `@apps/web/src/components/`(chat)/playground/chat-playground-core.ts around
lines 467 - 507, The buildAdvisorDefinition helper currently forwards
advisor.temperature without normalization, unlike the sibling subagent path.
Update buildAdvisorDefinition to clamp the temperature value to the accepted [0,
2] range before assigning it to parameters.temperature, and keep the existing
checks in place for advisor, advisor.temperature, and the
withParameters("ai-stats:advisor", ...) call so the advisor payload stays
consistent.
🧹 Nitpick comments (4)
apps/web/src/components/(chat)/ChatConversationComposer.tsx (1)

517-532: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate helper — extract getReadableTextColor to a shared module.

This function is identical to getReadableTextColor in apps/web/src/components/(chat)/ChatConversationMessages.tsx (lines 517-532). Extract it into a shared, named export and import it in both files to avoid divergence.

As per coding guidelines: "Prefer named exports for shared utilities in TypeScript".

🤖 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 `@apps/web/src/components/`(chat)/ChatConversationComposer.tsx around lines 517
- 532, The `getReadableTextColor` helper in `ChatConversationComposer` is
duplicated in `ChatConversationMessages`, so extract it into a shared utility
module as a named export and update both components to import and use that
shared function. Keep the implementation in one place only, and remove the local
duplicate so the `getReadableTextColor` behavior stays consistent across both
chat components.

Source: Coding guidelines

apps/web/src/app/api/chat/_shared/gatewayProxy.ts (1)

223-249: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Security-sensitive allow-list logic lacks dedicated tests.

resolveGatewayBaseUrl/isDevelopmentLocalGatewayBaseUrl gate which upstream host a client-supplied baseUrl can reach (SSRF-relevant). Given the PR's stated validation only covers chats.test.ts, this new allow-list has no unit coverage for the match/no-match/dev-local branches.

🤖 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 `@apps/web/src/app/api/chat/_shared/gatewayProxy.ts` around lines 223 - 249,
Add dedicated unit tests for the allow-list logic in
isDevelopmentLocalGatewayBaseUrl and resolveGatewayBaseUrl, since these
functions control which client-supplied baseUrl is accepted. Cover the exact
match branch, the configuredGatewayBaseUrl and PUBLIC_GATEWAY_BASE_URL fallback
behavior, and the development-local acceptance/rejection branches for
localhost/127.0.0.1, protocol, port, and pathname. Place the tests near the
gatewayProxy coverage so the new SSRF-sensitive rules are exercised
independently of chats.test.ts.
apps/web/src/lib/indexeddb/chats.ts (1)

50-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared reasoningEffort union to avoid triple duplication.

The literal union "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" is now repeated verbatim in ChatAdvisorServerToolConfig, ChatSubagentServerToolConfig, and ChatModelSettings. Any future addition/removal of an effort level requires updating three places in lockstep, which is easy to miss.

♻️ Suggested consolidation
+export type ChatReasoningEffort =
+	| "none"
+	| "minimal"
+	| "low"
+	| "medium"
+	| "high"
+	| "xhigh"
+	| "max";
+
 export type ChatAdvisorServerToolConfig = {
     ...
-    reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
+    reasoningEffort?: ChatReasoningEffort;
 };

 export type ChatSubagentServerToolConfig = {
     ...
-    reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
+    reasoningEffort?: ChatReasoningEffort;
 };

Also applies to: 61-68, 136-136

🤖 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 `@apps/web/src/lib/indexeddb/chats.ts` around lines 50 - 59, The repeated
reasoningEffort literal union in ChatAdvisorServerToolConfig,
ChatSubagentServerToolConfig, and ChatModelSettings should be consolidated into
a shared type alias or exported union so updates happen in one place. Define a
single reusable symbol near the existing chat settings types in chats.ts, then
replace each inline union with that shared type while preserving the same
allowed values.
apps/web/src/components/(chat)/playground/chat-playground-core.ts (1)

19-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Verify SUPPORTED_CHAT_SERVER_TOOLS stays in sync with ChatServerToolType.

This set is manually kept parallel to ChatServerToolType defined in apps/web/src/lib/indexeddb/chats.ts. They currently match, but nothing enforces that at compile time — adding a new tool literal to the type without updating this set would silently disable the tool for normalizeServerTools filtering, rather than raising a type/lint error.

♻️ Suggested compile-time guard
-const SUPPORTED_CHAT_SERVER_TOOLS = new Set<ChatServerToolType>([
-	"gateway:datetime",
-	...
-]);
+const SUPPORTED_CHAT_SERVER_TOOLS_LIST = [
+	"gateway:datetime",
+	"ai-stats:web_search",
+	"ai-stats:web_fetch",
+	"ai-stats:advisor",
+	"ai-stats:image_generation",
+	"ai-stats:fusion",
+	"ai-stats:subagent",
+] as const satisfies readonly ChatServerToolType[];
+// TS will error if a ChatServerToolType member is missing above (via exhaustiveness check elsewhere) or extra
+const SUPPORTED_CHAT_SERVER_TOOLS = new Set<ChatServerToolType>(
+	SUPPORTED_CHAT_SERVER_TOOLS_LIST,
+);
🤖 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 `@apps/web/src/components/`(chat)/playground/chat-playground-core.ts around
lines 19 - 41, `SUPPORTED_CHAT_SERVER_TOOLS` is manually duplicating
`ChatServerToolType`, so new tool literals can be added to the type in
`chats.ts` without being accepted by `normalizeServerTools`. Add a compile-time
guard in `chat-playground-core.ts` that ties `SUPPORTED_CHAT_SERVER_TOOLS` to
`ChatServerToolType` (for example via a type-level exhaustiveness check or
mapped assertion) so any mismatch fails TypeScript compilation. Keep the guard
near `SUPPORTED_CHAT_SERVER_TOOLS` and `normalizeServerTools` so the sync
requirement is enforced automatically.
🤖 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 `@apps/api/src/pipeline/after/stream.ts`:
- Around line 297-318: The terminal message_stop frame is dropping timing
because timingUsage falls back to null instead of preserving the last computed
usage. Update the stream timing logic in the after/stream flow so the
message_stop path uses latestStreamUsageRaw when next.usage,
next.response.usage, and next.message.usage are absent, while keeping the
existing matchedTimingFrame and attachStreamTimingMeta behavior intact.

In `@apps/web/src/components/`(chat)/ChatConversation.tsx:
- Around line 477-511: The queue-drain lock in ChatConversation’s useEffect can
stay stuck if sendPrompt/onSend rejects a prompt before isSending changes, which
prevents later queued prompts from draining. Update the send path around
sendPrompt(nextPrompt) so the lock is cleared when the send is not accepted, or
have sendPrompt return an explicit acceptance result and only remove the
prompt/set queue state when accepted. Use queueDrainInFlightRef, sendPrompt, and
the queuedPrompts/activeThreadId effect as the main touchpoints.

---

Outside diff comments:
In `@apps/web/src/app/api/chat/_shared/gatewayProxy.ts`:
- Around line 32-36: `resolveGatewayBaseUrl()` in `gatewayProxy.ts` currently
falls back to `PUBLIC_GATEWAY_BASE_URL`, which makes the missing-config branch
in `proxyGatewayPost()` and `proxyGatewayGet()` unreachable. Decide whether
misconfigured deployments should fail closed or fail open: if fail closed,
restore a null/absent path so `buildGatewayMissingConfigResponse()` can still be
returned; if fail open, remove the dead guard and update the gateway base URL
logic/documentation to reflect the fallback.

In `@apps/web/src/app/api/chat/audio/route.ts`:
- Around line 50-82: The music polling GET handler currently ignores the gateway
override used by POST, so polling can hit the wrong backend. Update the GET path
in audio route’s GET handler to read the same baseUrl query param and thread it
into both the polling URL built by resolveMusicPollPath and the proxyGatewayGet
call. Keep the existing resourceId/action validation in place, but ensure the
resolved poll request uses the caller-provided baseUrl when present.

In `@apps/web/src/app/api/chat/video/route.ts`:
- Around line 86-119: The GET handler in video/route.ts is dropping the custom
gateway override when proxying both the list and poll branches. Update the GET
logic to forward baseUrl into proxyGatewayGet alongside the existing path from
resolveVideoListPath and resolveVideoPollPath, so requests created against a
custom gateway continue to resolve correctly.

In `@apps/web/src/components/`(chat)/playground/chat-playground-core.ts:
- Around line 467-507: The buildAdvisorDefinition helper currently forwards
advisor.temperature without normalization, unlike the sibling subagent path.
Update buildAdvisorDefinition to clamp the temperature value to the accepted [0,
2] range before assigning it to parameters.temperature, and keep the existing
checks in place for advisor, advisor.temperature, and the
withParameters("ai-stats:advisor", ...) call so the advisor payload stays
consistent.

---

Nitpick comments:
In `@apps/web/src/app/api/chat/_shared/gatewayProxy.ts`:
- Around line 223-249: Add dedicated unit tests for the allow-list logic in
isDevelopmentLocalGatewayBaseUrl and resolveGatewayBaseUrl, since these
functions control which client-supplied baseUrl is accepted. Cover the exact
match branch, the configuredGatewayBaseUrl and PUBLIC_GATEWAY_BASE_URL fallback
behavior, and the development-local acceptance/rejection branches for
localhost/127.0.0.1, protocol, port, and pathname. Place the tests near the
gatewayProxy coverage so the new SSRF-sensitive rules are exercised
independently of chats.test.ts.

In `@apps/web/src/components/`(chat)/ChatConversationComposer.tsx:
- Around line 517-532: The `getReadableTextColor` helper in
`ChatConversationComposer` is duplicated in `ChatConversationMessages`, so
extract it into a shared utility module as a named export and update both
components to import and use that shared function. Keep the implementation in
one place only, and remove the local duplicate so the `getReadableTextColor`
behavior stays consistent across both chat components.

In `@apps/web/src/components/`(chat)/playground/chat-playground-core.ts:
- Around line 19-41: `SUPPORTED_CHAT_SERVER_TOOLS` is manually duplicating
`ChatServerToolType`, so new tool literals can be added to the type in
`chats.ts` without being accepted by `normalizeServerTools`. Add a compile-time
guard in `chat-playground-core.ts` that ties `SUPPORTED_CHAT_SERVER_TOOLS` to
`ChatServerToolType` (for example via a type-level exhaustiveness check or
mapped assertion) so any mismatch fails TypeScript compilation. Keep the guard
near `SUPPORTED_CHAT_SERVER_TOOLS` and `normalizeServerTools` so the sync
requirement is enforced automatically.

In `@apps/web/src/lib/indexeddb/chats.ts`:
- Around line 50-59: The repeated reasoningEffort literal union in
ChatAdvisorServerToolConfig, ChatSubagentServerToolConfig, and ChatModelSettings
should be consolidated into a shared type alias or exported union so updates
happen in one place. Define a single reusable symbol near the existing chat
settings types in chats.ts, then replace each inline union with that shared type
while preserving the same allowed values.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bd08e5b4-623e-44ed-8f53-12b3d4da4aaa

📥 Commits

Reviewing files that changed from the base of the PR and between 8510037 and a899c82.

📒 Files selected for processing (26)
  • apps/api/src/pipeline/after/stream.ts
  • apps/web/src/app/api/chat/_shared/gatewayProxy.ts
  • apps/web/src/app/api/chat/audio/route.ts
  • apps/web/src/app/api/chat/embeddings/route.ts
  • apps/web/src/app/api/chat/image/route.ts
  • apps/web/src/app/api/chat/moderation/route.ts
  • apps/web/src/app/api/chat/text/route.ts
  • apps/web/src/app/api/chat/video/route.ts
  • apps/web/src/components/(chat)/ChatConversation.tsx
  • apps/web/src/components/(chat)/ChatConversationComposer.tsx
  • apps/web/src/components/(chat)/ChatConversationMessages.tsx
  • apps/web/src/components/(chat)/ChatDeleteDialog.tsx
  • apps/web/src/components/(chat)/ChatHeader.tsx
  • apps/web/src/components/(chat)/ChatMessageFooters.tsx
  • apps/web/src/components/(chat)/ChatMessageMarkers.tsx
  • apps/web/src/components/(chat)/ChatPlayground.tsx
  • apps/web/src/components/(chat)/ChatShortcutReference.tsx
  • apps/web/src/components/(chat)/ChatSidebar.tsx
  • apps/web/src/components/(chat)/ChatTagsDialog.tsx
  • apps/web/src/components/(chat)/chatConversationHelpers.ts
  • apps/web/src/components/(chat)/playground/chat-playground-core.test.ts
  • apps/web/src/components/(chat)/playground/chat-playground-core.ts
  • apps/web/src/components/(chat)/playground/use-grouped-chat-threads.ts
  • apps/web/src/components/ai-elements/reasoning.tsx
  • apps/web/src/lib/config/featureLabels.ts
  • apps/web/src/lib/indexeddb/chats.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/lib/config/featureLabels.ts

Comment thread apps/api/src/pipeline/after/stream.ts
Comment thread apps/web/src/components/(chat)/ChatConversation.tsx
@DanielButler1 DanielButler1 merged commit ef84286 into main Jul 4, 2026
33 checks passed
@DanielButler1 DanielButler1 deleted the fix/chat-tag-import-normalization branch July 4, 2026 10:27
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