Skip to content

Conversation

@pjain1
Copy link
Member

@pjain1 pjain1 commented Dec 18, 2025

Adds supports for sharing and forking shared conversations. Once a conversation is shared, anyone knowing the conversation id can access till the shared message. User can then start a new conversation from it which copies over the shared messages to new conversation.

Now after forking new user might not have same access as previous in which case they might get access errors on continuing conversation, we let LLM know about this by injecting this info in the system prompt for shared conversations. On testing I have seen replies like this from LLM

It looks like I don't have permission to access the detailed profit trends over time by label in this environment. This may be due to a change in access permissions or a conversation transfer (fork). If you have access, you can try re-running this analysis, or let me know if you'd like to explore a different dataset or angle!

Unhandled case - However, there is an edge case around chart message. Existing charts does MV agg API calls which will fail if the new user does not have access to the underlying mv. So charts will just show spinner.

New APIs

  • ShareConversation, optionally accepts shared_until_message_id, returns nothing: Only owners (or rill dev) may call. Validates the provided message exists in the caller’s view. Persists shared_until_message_id as the last router result at or before the requested message; if omitted, uses the latest router result.

  • ForkConversation, accepts nothing and returns new conversation_id: Clones the conversation; owners get all messages, non-owners only get messages up to the shared boundary.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

@pjain1 pjain1 marked this pull request as draft December 18, 2025 11:56
@pjain1 pjain1 changed the title share conversation support share/fork conversation support Dec 18, 2025
@pjain1 pjain1 changed the title share/fork conversation support [PLAT-333] share/fork conversation support Dec 18, 2025
@pjain1 pjain1 marked this pull request as ready for review December 20, 2025 15:10
runtime/ai/ai.go Outdated
Comment on lines 209 to 249
// Load the session in the catalog
session, err := catalog.FindAISession(ctx, opts.SessionID)
if err != nil {
return "", fmt.Errorf("failed to find session %q: %w", opts.SessionID, err)
}

// Check access: for now, only allow users to access their own sessions or shared sessions with trimmed messages.
// Checking !SkipChecks to ensure access for superusers and for Rill Developer (where auth is disabled and SkipChecks is true).
if opts.Claims.UserID != session.OwnerID && !opts.Claims.SkipChecks && session.SharedUntilMessageID == "" {
return "", fmt.Errorf("access denied to session %q", session.ID)
}

retrieveUntilMessageID := session.SharedUntilMessageID
if session.OwnerID == opts.Claims.UserID || opts.Claims.SkipChecks {
// If the user owns the session or skipCheck enabled, they can see all messages.
retrieveUntilMessageID = ""
}

var messages []*Message
ms, err := catalog.FindAIMessages(ctx, opts.SessionID)
if err != nil {
return "", fmt.Errorf("failed to find messages for session %q: %w", opts.SessionID, err)
}
for _, m := range ms {
messages = append(messages, &Message{
ID: m.ID,
ParentID: m.ParentID,
SessionID: m.SessionID,
Time: m.CreatedOn,
Index: m.Index,
Role: Role(m.Role),
Type: MessageType(m.Type),
Tool: m.Tool,
ContentType: MessageContentType(m.ContentType),
Content: m.Content,
})
// only load messages up to and including that retrieveUntilMessageID; messages are ordered by "Index" ascending.
if m.ID == retrieveUntilMessageID {
break
}
}
Copy link
Contributor

@begelundmuller begelundmuller Dec 22, 2025

Choose a reason for hiding this comment

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

Isn't this the same logic as in r.Session()? Can it use r.Session(...).Messages() instead to get the messages?

Or what do you think about making it a on Session, like s.ai.Session(...).Fork(newOwner)?

Copy link
Member Author

@pjain1 pjain1 Dec 27, 2025

Choose a reason for hiding this comment

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

Creating a Session does a lot more than what is needed here, like setting up the logger, creating activity client etc. and may add more things in future. Thus it seems unnecessary, mainly we want messages with some access checks so not much logic there anyways.

Copy link
Contributor

Choose a reason for hiding this comment

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

Session() is actually meant to be the single entrypoint for accessing a session, to make sure we parse DB messages and enforce access checks uniformly. So it would be nice to avoid the duplication.

The logger/activity clients are cheap, so no need to worry about those. And if we need to add other non-cheap logic in the future, we can do it in a lazy-loading way to make sure Session remains useful as the single entrypoint for all use cases.

Copy link
Member Author

@pjain1 pjain1 Dec 30, 2025

Choose a reason for hiding this comment

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

Changed to load session and use messages from it. Again forking from existing session will require double copying of messages one from session message to drivers.AIMessage for inserting into catalog and also to ai.Message for loading the Session. Just avoiding unnecessary work but otherwise Fork method on a Session can be supported.

Copy link
Contributor

@begelundmuller begelundmuller left a comment

Choose a reason for hiding this comment

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

@pjain1 I also responded with some suggestions on the unresolved comments above :)

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.

3 participants