Skip to content

πŸ› fix: fixed the group topic copy not right#11730

Merged
ONLY-yours merged 1 commit intonextfrom
feat/groupTopicCopy
Jan 23, 2026
Merged

πŸ› fix: fixed the group topic copy not right#11730
ONLY-yours merged 1 commit intonextfrom
feat/groupTopicCopy

Conversation

@ONLY-yours
Copy link
Copy Markdown
Member

@ONLY-yours ONLY-yours commented Jan 23, 2026

πŸ’» Change Type

fix: LOBE-3016

  • ✨ feat
  • πŸ› fix
  • ♻️ refactor
  • πŸ’„ style
  • πŸ‘· build
  • ⚑️ perf
  • βœ… test
  • πŸ“ docs
  • πŸ”¨ chore

πŸ”— Related Issue

πŸ”€ Description of Change

πŸ§ͺ How to Test

  • Tested locally
  • Added/updated tests
  • No tests needed

πŸ“Έ Screenshots / Videos

Before After
... ...

πŸ“ Additional Information

Summary by Sourcery

Ensure topic duplication correctly preserves message relationships and associated tool/plugin metadata.

Bug Fixes:

  • Fix topic duplication so duplicated messages reference the correct new parent message IDs instead of original ones.
  • Fix topic duplication so tool IDs in assistant messages and corresponding message plugin toolCallIds are remapped consistently.

Tests:

  • Add coverage for duplicating topics with parent-child message chains to verify correct parentId remapping.
  • Add coverage for duplicating topics with tool-using messages to verify tool ID and message plugin toolCallId remapping.

@vercel
Copy link
Copy Markdown

vercel bot commented Jan 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
lobehub Building Building Preview, Comment Jan 23, 2026 8:39am

Request Review

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 23, 2026
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Jan 23, 2026

Reviewer's Guide

Enhances topic duplication logic so that duplicated messages preserve correct parent-child relationships and tool/plugin associations, and adds tests to validate these behaviors.

Sequence diagram for topic duplication with messages and plugins

sequenceDiagram
  participant TopicModel
  participant DB as DatabaseTx
  participant Messages
  participant MessagePlugins
  participant IdGen as IdGenerator

  TopicModel->>DB: beginTransaction
  TopicModel->>DB: select messages where topicId,userId orderBy createdAt
  DB-->>TopicModel: originalMessages

  TopicModel->>TopicModel: build messageIds from originalMessages
  TopicModel->>DB: select messagePlugins where id in messageIds
  DB-->>TopicModel: originalPlugins

  TopicModel->>TopicModel: build idMap oldMessageId->newMessageId
  loop build toolIdMap
    TopicModel->>IdGen: generate tool id for each tool in message.tools
    IdGen-->>TopicModel: newToolId
    TopicModel->>TopicModel: store toolIdMap oldToolId->newToolId
  end

  loop for each message in originalMessages (in order)
    TopicModel->>TopicModel: newId = idMap[message.id]
    TopicModel->>TopicModel: newParentId = idMap[message.parentId]
    TopicModel->>TopicModel: remap tools using toolIdMap
    TopicModel->>DB: insert into messages (newId,newParentId,topicId,tools,clientId=null)
    DB-->>TopicModel: insertedMessage

    TopicModel->>TopicModel: plugin = find originalPlugins by plugin.id == message.id
    alt plugin exists
      TopicModel->>TopicModel: newToolCallId = toolIdMap[plugin.toolCallId]
      TopicModel->>DB: insert into messagePlugins (id=newId,toolCallId=newToolCallId,clientId=null)
      DB-->>TopicModel: insertedPlugin
    end
  end

  TopicModel->>DB: commitTransaction
Loading

ER diagram for topics, messages, and messagePlugins duplication relationships

erDiagram
  Topic {
    string id
  }

  Message {
    string id
    string topicId
    string userId
    string parentId
    json   tools
    datetime createdAt
  }

  MessagePlugin {
    string id
    string toolCallId
    string clientId
  }

  Topic ||--o{ Message : has_messages
  Message ||--o{ Message : parent_child
  Message ||--o{ MessagePlugin : has_plugins

  Tool {
    string id
  }

  Message }o--o{ Tool : embedded_tools
  MessagePlugin }o--|| Tool : tool_call_references
Loading

Class diagram for TopicModel duplication logic changes

classDiagram
  class TopicModel {
    +string userId
    +duplicateTopicWithMessagesAndPlugins(tx, topicId)
  }

  class Message {
    +string id
    +string topicId
    +string userId
    +string parentId
    +json tools
    +datetime createdAt
  }

  class MessagePlugin {
    +string id
    +string toolCallId
    +string clientId
  }

  class IdGenerator {
    +string generateMessagesId()
  }

  class Tool {
    +string id
  }

  TopicModel --> Message : duplicates
  TopicModel --> MessagePlugin : duplicates
  TopicModel --> IdGenerator : uses

  Message "1" --> "0..*" Message : parent_child
  Message "1" --> "0..*" MessagePlugin : has_plugins

  Message "1" --> "0..*" Tool : tools_array
  MessagePlugin "1" --> "0..1" Tool : toolCallId_refers_to
Loading

File-Level Changes

Change Details Files
Ensure duplicated topic messages preserve parent-child relationships and tool/plugin linkage when cloning a topic.
  • Order original topic messages by createdAt before duplication to ensure deterministic processing order.
  • Preload all original messages and related messagePlugins for the topic and build mappings from old to new message IDs and tool IDs.
  • Duplicate messages sequentially, rewriting parentId to point at the corresponding new message ID and regenerating message IDs and clientId.
  • Rewrite tools arrays on assistant messages using the tool ID mapping and generate new tool IDs with a toolu_ prefix.
  • Copy associated messagePlugins rows for each duplicated message, updating id, clientId, and toolCallId to use the new message and tool IDs.
packages/database/src/models/topic.ts
Add regression tests that verify correct duplication of message hierarchies and tool/plugin metadata.
  • Add a test that creates a chain of messages with parentId relationships and asserts the duplicated messages preserve the structure with new IDs.
  • Add a test that creates an assistant message with tools plus a corresponding tool message and messagePlugins row, then asserts duplicated messages have new tool IDs and correctly wired messagePlugins.toolCallId.
  • Assert counts and basic properties on duplicated messages to confirm duplication completeness.
packages/database/src/models/__tests__/topics/topic.create.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@dosubot dosubot bot added the πŸ› Bug label Jan 23, 2026
@gru-agent
Copy link
Copy Markdown
Contributor

gru-agent bot commented Jan 23, 2026

TestGru Assignment

Summary

Link CommitId Status Reason
Detail c32519b 🚫 Skipped No files need to be tested {"packages/database/src/models/tests/topics/topic.create.test.ts":"File path does not match include patterns.","packages/database/src/models/topic.ts":"Can not find valuable test target.\nTopicModel: Out of scope - The TopicModel class is primarily a data access layer (repository/service) that interacts extensively with the database, manages transactions, and coordinates multi-table operations. Its methods involve significant integration logic, external dependencies, and process corr…"}

History Assignment

Tip

You can @gru-agent and leave your feedback. TestGru will make adjustments based on your input

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The use of any[] and as any for tools makes the new logic harder to reason about and risks silent breakage if the shape changes; consider introducing a proper Tool type/interface and using that throughout the duplication flow.
  • In the duplication loop you do originalPlugins.find((p) => p.id === message.id) on each iteration; for better clarity and performance, build a Map from messagePlugins.id to plugin once up front and do O(1) lookups in the loop.
  • Tool IDs are regenerated via toolIdMap using toolu_${idGenerator('messages')}, which couples tool IDs to the messages ID generator and introduces an extra prefix; it may be cleaner to either reuse the original tool IDs where safe or introduce a dedicated tool ID generator/strategy for more predictable identifiers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The use of `any[]` and `as any` for `tools` makes the new logic harder to reason about and risks silent breakage if the shape changes; consider introducing a proper `Tool` type/interface and using that throughout the duplication flow.
- In the duplication loop you do `originalPlugins.find((p) => p.id === message.id)` on each iteration; for better clarity and performance, build a `Map` from `messagePlugins.id` to plugin once up front and do O(1) lookups in the loop.
- Tool IDs are regenerated via `toolIdMap` using `toolu_${idGenerator('messages')}`, which couples tool IDs to the messages ID generator and introduces an extra prefix; it may be cleaner to either reuse the original tool IDs where safe or introduce a dedicated tool ID generator/strategy for more predictable identifiers.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

πŸ’‘ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c32519bf96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with πŸ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 509 to +513
const originalMessages = await tx
.select()
.from(messages)
.where(and(eq(messages.topicId, topicId), eq(messages.userId, this.userId)));

// copy messages
const duplicatedMessages = await Promise.all(
originalMessages.map(async (message) => {
const result = (await tx
.insert(messages)
.values({
...message,
clientId: null,
id: idGenerator('messages'),
topicId: duplicatedTopic.id,
})
.returning()) as DBMessageItem[];

return result[0];
}),
);
.where(and(eq(messages.topicId, topicId), eq(messages.userId, this.userId)))
.orderBy(messages.createdAt);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ensure parent messages are inserted before children

The new duplication path remaps parentId to new IDs, which means inserts must respect parent-child order to satisfy the messages.parentId FK. Ordering only by createdAt doesn’t guarantee parents come first when timestamps are equal or out-of-order (common in imported/backfilled topics), so a child can be inserted before its parent and the transaction will fail with an FK violation. Consider ordering by the parent chain (topological sort) or inserting with parentId null then updating after all rows exist.

Useful? React with πŸ‘Β / πŸ‘Ž.

]);
});

const { topic: duplicatedTopic, messages: duplicatedMessages } = await topicModel.duplicate(
});
});

const { topic: duplicatedTopic, messages: duplicatedMessages } = await topicModel.duplicate(
@codecov
Copy link
Copy Markdown

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 98.30508% with 1 line in your changes missing coverage. Please review.
βœ… Project coverage is 74.15%. Comparing base (2b620df) to head (c32519b).
⚠️ Report is 29 commits behind head on next.

Additional details and impacted files
@@            Coverage Diff             @@
##             next   #11730      +/-   ##
==========================================
+ Coverage   74.14%   74.15%   +0.01%     
==========================================
  Files        1191     1191              
  Lines       94844    94887      +43     
  Branches    12933    12948      +15     
==========================================
+ Hits        70324    70366      +42     
- Misses      24430    24431       +1     
  Partials       90       90              
Flag Coverage Ξ”
app 67.17% <ΓΈ> (ΓΈ)
database 91.48% <98.30%> (+0.03%) ⬆️
packages/agent-runtime 90.20% <ΓΈ> (ΓΈ)
packages/context-engine 85.36% <ΓΈ> (ΓΈ)
packages/conversation-flow 92.28% <ΓΈ> (ΓΈ)
packages/file-loaders 87.04% <ΓΈ> (ΓΈ)
packages/memory-user-memory 69.68% <ΓΈ> (ΓΈ)
packages/model-bank 100.00% <ΓΈ> (ΓΈ)
packages/model-runtime 86.72% <ΓΈ> (ΓΈ)
packages/prompts 79.33% <ΓΈ> (ΓΈ)
packages/python-interpreter 92.90% <ΓΈ> (ΓΈ)
packages/ssrf-safe-fetch 0.00% <ΓΈ> (ΓΈ)
packages/utils 93.22% <ΓΈ> (ΓΈ)
packages/web-crawler 95.62% <ΓΈ> (ΓΈ)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Ξ”
Store 67.96% <ΓΈ> (ΓΈ)
Services 50.58% <ΓΈ> (ΓΈ)
Server 67.71% <ΓΈ> (ΓΈ)
Libs 40.36% <ΓΈ> (ΓΈ)
Utils 93.60% <ΓΈ> (ΓΈ)
πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • πŸ“¦ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ONLY-yours ONLY-yours merged commit 282c1fb into next Jan 23, 2026
54 of 56 checks passed
@ONLY-yours ONLY-yours deleted the feat/groupTopicCopy branch January 23, 2026 09:12
@lobehubbot
Copy link
Copy Markdown
Member

lobehubbot commented Jan 23, 2026

❀️ Great PR @ONLY-yours ❀️

The growth of the project is inseparable from user feedback and contributions. Thank you for your contribution! If you are interested in the lobehub developer community, please join our discord and then DM @arvinxx or @canisminor1990. They will invite you to our private developer channel. We are talking about lobe-chat development and sharing AI newsletters from around the world.


This comment was translated by Claude.

Original Content

❀️ Great PR @ONLY-yours ❀️

The growth of project is inseparable from user feedback and contribution, thanks for your contribution! If you are interesting with the lobehub developer community, please join our discord and then dm @arvinxx or @canisminor1990. They will invite you to our private developer channel. We are talking about the lobe-chat development or sharing ai newsletter around the world.

JamieStivala pushed a commit to jaworldwideorg/OneJA-Bot that referenced this pull request Jan 23, 2026
### [Version&nbsp;1.153.1](v1.153.0...v1.153.1)
<sup>Released on **2026-01-23**</sup>

#### πŸ› Bug Fixes

- **misc**: Add advace config back in agent/group profiles, fixed the group topic copy not right.

#### πŸ’„ Styles

- **misc**: Move plugin store button outside scroll container.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Add advace config back in agent/group profiles, closes [lobehub#11727](https://github.com/jaworldwideorg/OneJA-Bot/issues/11727) ([403175f](403175f))
* **misc**: Fixed the group topic copy not right, closes [lobehub#11730](https://github.com/jaworldwideorg/OneJA-Bot/issues/11730) ([282c1fb](282c1fb))

#### Styles

* **misc**: Move plugin store button outside scroll container, closes [lobehub#11728](https://github.com/jaworldwideorg/OneJA-Bot/issues/11728) ([c484d1a](c484d1a))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
lobehubbot pushed a commit that referenced this pull request Jan 23, 2026
## [Version&nbsp;2.0.0-next.348](v2.0.0-next.347...v2.0.0-next.348)
<sup>Released on **2026-01-23**</sup>

#### πŸ› Bug Fixes

- **copilot**: History popover not refreshing when agentId changes.
- **misc**: Fixed the agent group builder tools excaution edge case crash, fixed the group topic copy not right.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **copilot**: History popover not refreshing when agentId changes, closes [#11731](#11731) ([64f39e7](64f39e7))
* **misc**: Fixed the agent group builder tools excaution edge case crash, closes [#11735](#11735) ([5de4742](5de4742))
* **misc**: Fixed the group topic copy not right, closes [#11730](#11730) ([282c1fb](282c1fb))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
@lobehubbot
Copy link
Copy Markdown
Member

πŸŽ‰ This PR is included in version 2.0.0-next.348 πŸŽ‰

The release is available on:

Your semantic-release bot πŸ“¦πŸš€

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

Labels

πŸ› Bug released on @next size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants