Skip to content

fix(ai): show chat references as readable text in conversation titles - #9919

Closed
dfliess wants to merge 3 commits into
rilldata:mainfrom
dfliess:dfliess/chat-title-references
Closed

dfliess wants to merge 3 commits into
rilldata:mainfrom
dfliess:dfliess/chat-title-references

Conversation

@dfliess

@dfliess dfliess commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

A conversation's title is its first prompt truncated to 50 bytes. When the prompt starts with an @ or / reference, the title shows the reference's markup, cut in the middle:

  • <chat-reference>type="metricsView" metricsView=...
  • <chat-reference>type="skill" skill="monthly-cl...

That's what the chat sidebar header, its history menu and the full-page conversation list show, since the three render conversation.title as plain text.

This fixes it in promptToTitle, so the title is still stored as plain text and the UI doesn't change:

  • Each <chat-reference> is replaced with readable text before truncating: the display name of the referenced metrics view, measure, dimension or canvas when the session can access it (with the same security check as GetMetricsView), falling back to its name; /name for skills; the dates of a time range in its time zone; and a canvas component's title, then its display name, then its canvas's display name. References of unknown types are dropped.
  • Since everyone can read a component and access is decided by its canvas (as in ResolveCanvas), a component's title is only used when it belongs to the referenced canvas and the session can access that canvas.
  • The truncation no longer splits a multi-byte rune. title[:47] could leave a dangling lead byte, and protobuf refuses to marshal a string field with invalid UTF-8, so the conversation couldn't be returned by the API.
  • chatReferenceAttrs is extracted from referencedSkills, so both parse references the same way.

The text is close to the chips the UI renders, but not identical: for charts, the UI builds an English title from the chart's fields, while the conversation title uses the component's title, which is usually in the project's language. Existing conversations keep their current titles.

Tested with TestRouterAgentTitle (one case per reference type, plus truncation), and locally with a project whose conversations start with a metrics view and a skill reference.


Developed in collaboration with Claude Code

dfliess and others added 3 commits October 7, 2026 10:37
The conversation title is the first prompt truncated to 50 bytes, taken
as-is. Prompts carry each @ or / reference as markup, e.g.
<chat-reference>type="metricsView" metricsView="orders"</chat-reference>,
which is longer than the title, so a conversation that starts with a
reference gets a title like `<chat-reference>type="metricsView" metricsView=...`
in the chat sidebar, its history menu and the full-page conversation list.

Replace each reference with readable text before truncating: the display
name of the referenced metrics view, measure, dimension or canvas when the
session can access it (falling back to its name), `/name` for skills, the
dates of a time range in its time zone, and the name for the other types.
References of unknown types are dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
promptToTitle cut the title at byte 47 with title[:47], which can land
inside a multi-byte rune. The dangling lead byte followed by "..." is
invalid UTF-8, and protobuf refuses to marshal it ("string field contains
invalid UTF-8"), so the conversation can't be returned by the API. Titles
in languages with accents hit this, and the display names that now
replace chat references make it more likely.

Add truncateUTF8, which backs off to the previous rune boundary, and use
it for the title.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Components defined in a canvas are named after their position, e.g.
sales--component-1-0, which says nothing in a conversation title. Show a
component reference by the component's title, then its display name,
then the display name of its canvas, and only then its name.

Everyone can read a component, and access to it is decided by the canvas
that shows it, as in ResolveCanvas. So the component's title is only used
when it belongs to the referenced canvas and the session can access that
canvas.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dfliess
dfliess force-pushed the dfliess/chat-title-references branch from 542539f to d14c123 Compare October 7, 2026 08:49
@nishantmonu51 nishantmonu51 added Type:Bug Something isn't working Size:M Medium change: 100-499 lines Area:AI AI assistant, chat and agents labels Oct 10, 2026
@nishantmonu51
nishantmonu51 requested review from nishantmonu51 and a lite review from Copilot October 21, 2026 04:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Preserve time-zone attributes and enforce the required ReadObjects permission before exposing resource names.

1 open issue
What changed in this PR

Updates AI conversation titles to show readable chat-reference labels and safely truncate UTF-8 text.

Changes:

  • Resolves resource, skill, time-range, and component references.
  • Centralizes reference attribute parsing.
  • Adds UTF-8-safe truncation and title tests.
File Description
runtime/​ai/​truncate.go Adds UTF-8-safe truncation.
runtime/​ai/​skill_references.go Centralizes chat-reference parsing.
runtime/​ai/​router_agent.go Generates readable reference-based titles.
runtime/​ai/​router_agent_test.go Tests title formatting and security behavior.

Review effort: Lite

Comment on lines +321 to +328
func (t *RouterAgent) accessibleResource(ctx context.Context, kind, name string) *runtimev1.Resource {
session := GetSession(ctx)

ctrl, err := t.Runtime.Controller(ctx, session.InstanceID())
if err != nil {
return nil
}
r, err := ctrl.Get(ctx, &runtimev1.ResourceName{Kind: kind, Name: name}, false)

@AdityaHegde AdityaHegde left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is a one time replacement of reference => displayName, so these can go stale. While this can be replaced at runtime in Rill UI, mcp usage wont have a good path for this. But router agent is only called from Rill UI so I think an alternative can also work.

How about we cut at the end of a reference and replace the reference in Rill UI, we already have a lot of code for this there.
Edit: Actually the whole mention system is only present in Rill UI, so I think the approach of replacing during runtime is better.

@AdityaHegde

Copy link
Copy Markdown
Collaborator

@dfliess I have already kicked off the changes in #10047 . You can follow that and lemme know if you see any gap.

@AdityaHegde

Copy link
Copy Markdown
Collaborator

I have merged 10047. Will be deployed in next major release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area:AI AI assistant, chat and agents Size:M Medium change: 100-499 lines Type:Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants