Skip to content

feat(chat): display sub-agent model information in message info dialog#332

Merged
larryro merged 15 commits into
mainfrom
feat/324-display-subagent-model-info
Feb 1, 2026
Merged

feat(chat): display sub-agent model information in message info dialog#332
larryro merged 15 commits into
mainfrom
feat/324-display-subagent-model-info

Conversation

@larryro
Copy link
Copy Markdown
Collaborator

@larryro larryro commented Feb 1, 2026

Summary

  • Display all model calls (routing + sub-agents) in the message info dialog
  • Track sub-agent model/provider/tokens through the completion handler pipeline
  • Add context window viewer showing token distribution as markdown
  • Add count operation to customer and product read tools

Closes #324

Test plan

  • Send a message that triggers sub-agent calls (CRM, Web, etc.)
  • Open message info dialog and verify sub-agent section shows
  • Verify each sub-agent displays: agent type, model, provider, token usage
  • Click context window link to view token distribution details
  • Test customer/product read tools with count operation

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added context window display with collapsible formatting in message info dialog
    • Added sub-agent call details showing agent name, model, provider, and token breakdown
    • Added context statistics display (token count, message count, approvals)
    • Added count operations for customers and products with pagination support
  • Improvements

    • Enhanced message metadata tracking with model and provider information for sub-agents
    • Improved formatting and organization of agent response information

✏️ Tip: You can customize this high-level summary in your review settings.

- Add model and provider fields to subAgentUsage schema and validators
- Update extractToolCallsFromSteps to capture model info from sub-agent results
- Pass model and provider from sub-agent tools to parent response
- Add SubAgentUsage interface and expose in useMessageMetadata hook
- Add sub-agent calls section to MessageInfoDialog with model, provider, and tokens
- Add translation key for sub-agent calls section

Refs #324
… handler

The ChatCompleteResult interface and mutation validator were missing
model and provider fields in subAgentUsage, causing the data to be
stripped when passing to saveMessageMetadata.

Refs #324
The subAgentUsage data was being extracted in generateAgentResponse but
not being passed through onAgentComplete to saveMessageMetadata. Added:
- toolCalls and subAgentUsage fields to AgentResponseResult interface
- subAgentUsage parameter to the saveMessageMetadata call
- Pass toolCalls and subAgentUsage from generateAgentResponse to onAgentComplete
…gents

Non-streaming mode (used by sub-agents) was not capturing the response
object from generateText, causing it to fall back to the configured
model name instead of the actual model returned by the API.
Don't fall back to config model when response.modelId is unavailable.
This ensures we only display the actual model returned by the API.
…ools

Add 'count' operation that allows agents to get total counts for
customers and products. Implements pagination-based counting with a
limit of 3 requests (1500 items max) to prevent excessive resource
usage on large datasets. Products support optional status/minStock
filters for count.
- Display full AI context with collapsible <details> sections
- Show system prompt, history, and current request separately
- Refactor context formatting from XML to collapsible HTML
- Add agent instructions to context window display
- Prevent AI from mimicking internal tool result formats
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 1, 2026

📝 Walkthrough

Walkthrough

This PR extends the message info dialog and related metadata infrastructure to display comprehensive model call information. It adds UI components to render context windows as expandable Markdown and displays sub-agent usage details (agent type, model, provider, tokens). The backend is refactored to collect and propagate model/provider metadata through sub-agent tool responses and to construct a structured context window with system instructions in collapsible HTML sections. Message metadata types are extended to include subAgentUsage, contextWindow, and contextStats. Agent instructions are wired into response generation, and context formatting is rewritten from XML-style tags to HTML

Details collapsible sections. Product and customer read tools gain "count" operations with pagination support.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (1)
services/platform/convex/agent_tools/products/product_read_tool.ts (1)

41-46: ⚠️ Potential issue | 🟡 Minor

Update the fields description to mention count as well.
The fields help text still says “Ignored for 'list'.” With the new count op, it should say list/count.

📝 Suggested fix
-      "For 'get_by_id' only: Fields to return. Default: ['_id','name','description','price','currency','status','category','imageUrl','stock']. Ignored for 'list'.",
+      "For 'get_by_id' only: Fields to return. Default: ['_id','name','description','price','currency','status','category','imageUrl','stock']. Ignored for 'list' and 'count'.",
🤖 Fix all issues with AI agents
In `@services/platform/app/features/chat/components/message-info-dialog.tsx`:
- Around line 119-129: The token-usage block only renders when
metadata.totalTokens or metadata.contextWindow is present, so cases with only
metadata.inputTokens or metadata.outputTokens are skipped; update the gating
condition around the Field rendering (the JSX that currently checks
(metadata.totalTokens !== undefined || metadata.contextWindow)) to also consider
metadata.inputTokens and metadata.outputTokens (and any other token fields used)
so the Field and its children (including ContextWindowToken and any input/output
token displays) render whenever any token-related metadata exists; adjust the
condition and keep references to metadata, Field, and ContextWindowToken intact.
- Around line 57-67: The Markdown rendering in message-info-dialog.tsx uses
rehypeRaw to render untrusted HTML (contextWindow) and must be sanitized to
prevent XSS: import rehypeSanitize and add it to the Markdown rehypePlugins so
raw HTML is parsed then sanitized (rehypeRaw before rehypeSanitize), configuring
rehypeSanitize to allow <details> and <summary> (or extend the default schema)
so the existing disclosure UI still works; update the Markdown invocation in the
component that renders {contextWindow} to include rehypeSanitize and adjust
imports accordingly.

In `@services/platform/convex/agent_tools/customers/helpers/count_customers.ts`:
- Around line 32-33: Add a short explanatory comment next to the existing
`@ts-ignore` above the queryFn assignment to document why TS2589 is suppressed:
mention that Convex's API can produce excessively deep type instantiations
causing false-positive TS2589 errors, reference the Convex issue or internal
ticket/PR (e.g., "see Convex issue #... or internal RFC") and note this is a
recurring pattern so maintainers know the suppression is intentional for
internal.customers.internal_queries.query_customers.queryCustomersInternal; keep
it concise (one or two sentences) and include a TODO to remove the `@ts-ignore`
if/when the Convex types are fixed.

In `@services/platform/convex/lib/agent_response/generate_response.ts`:
- Around line 602-608: The selection of sub-agent data using directResult ??
outputDirect ?? outputValue can pick an empty or irrelevant object (e.g., {}
without model/usage). Update the logic in generate_response.ts to choose the
first candidate that actually contains sub-agent fields (e.g., has `model` or
`usage`) rather than just non-nullish: inspect `directResult`, then
`outputDirect`, then `outputValue` and pick the first where a predicate (e.g.,
hasSubAgentFields(obj) => obj && (obj.model || obj.usage)) returns true; if none
match, fall back to the original nullish coalescing. Apply this to how
`subAgentData` is derived so that `toolUsage` is taken from a validated
sub-agent object.

In `@services/platform/convex/lib/context_management/message_formatter.ts`:
- Around line 20-31: The wrapInDetails function inserts untrusted summary and
content directly into HTML; escape both inputs to prevent HTML structure
breakage and XSS. Update wrapInDetails to HTML-entity-escape summary and content
(at least &, <, >, ", and ') before interpolation, e.g. call a shared utility
like escapeHtml(summary) and escapeHtml(content) inside wrapInDetails while
keeping the existing open handling (openAttr and template). Ensure the escape
helper is used here so all callers get sanitized output.
- Around line 37-40: The summarize function can throw when JSON.stringify
encounters circular refs, BigInt, or other non-serializable values; update
summarize(output, max) to safely stringify inside a try-catch: attempt
JSON.stringify for non-strings, on failure fallback to a safe representation
(e.g. convert BigInt to string, use util.inspect or String(output), or return a
placeholder like '[unserializable]') and then truncate to max as before; mirror
the error-handling pattern used by estimateJsonTokens to ensure summarize never
throws and always returns a string.

In `@services/platform/lib/shared/schemas/pagination.ts`:
- Around line 3-7: Add a brief JSDoc comment above the id property in the
cursorPaginationOptsSchema to explain its purpose (e.g., request correlation or
deduplication) so future maintainers know when to provide it; locate the
z.object definition named cursorPaginationOptsSchema and document the id field
(z.number().optional()) with a one-line comment describing its semantics and
intended use.

Comment thread services/platform/app/features/chat/components/message-info-dialog.tsx Outdated
Comment thread services/platform/convex/agent_tools/customers/helpers/count_customers.ts Outdated
Comment thread services/platform/convex/lib/agent_response/generate_response.ts
Comment thread services/platform/lib/shared/schemas/pagination.ts
…icking

Add retry mechanism when LLM returns empty text responses, which handles
thinking models that may consume all tokens for reasoning. Both streaming
and non-streaming modes now rebuild context and retry without tools.

Also change tool result format from markdown quotes to log-style format
and strengthen agent instructions to prevent AI from outputting internal
formats like [Tool Result], JSON structures, or fake tool calls.
Use rehype-sanitize with a custom schema that allows details and summary
tags while sanitizing potentially dangerous HTML content.
Include inputTokens, outputTokens, reasoningTokens, and cachedInputTokens
in the condition to ensure token usage section renders when any token
field is present.
Add explanation that TS2589 errors occur due to known Convex limitation
with deeply nested internal query types.
Prefer the variant that actually contains model or usage data rather
than just non-nullish values, preventing edge cases with empty objects.
Escape summary and content parameters to prevent HTML structure breakage
and provide defense-in-depth against XSS.
…alues

Add safeStringify helper that handles circular references, BigInt, and
other non-serializable values that would cause JSON.stringify to throw.
Document that the id field is used for request correlation to help
future maintainers understand its purpose.
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.

Display all model call information in message info dialog

1 participant