Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Reply ordering, remote image URLs, and mention parsing currently produce incorrect behavior.
Review effort: Balanced
Findings: 3
Open (4)
What changed in this PR
Adds a KOOK adapter using Kook.Net, integrating message handling, sending, channel operations, configuration, and CLI startup.
Changes:
- Adds KOOK message parsing, rendering, sending, replies, images, and recall.
- Adds guild/direct-channel identification and member lookup.
- Registers the adapter in configuration, CLI, solution, and documentation.
| File | Description |
|---|---|
src/HuaJiBot.NET/Config/Config.cs |
Adds KOOK service and token configuration. |
src/HuaJiBot.NET.CLI/HuaJiBot.NET.CLI.csproj |
References the adapter and config output settings. |
src/HuaJiBot.NET.CLI/App.cs |
Creates and starts the KOOK adapter. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookTextSegment.cs |
Models outbound KMarkdown text. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookOutboundSegment.cs |
Defines the outbound segment base type. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookOutboundBuilder.cs |
Builds text, image, and reply segments. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookMessageRenderer.cs |
Renders received messages as readable text. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookImageSegment.cs |
Models outbound images. |
src/HuaJiBot.NET.Adapter.Kook/Messaging/KookCommandReader.cs |
Converts KOOK messages into command entities. |
src/HuaJiBot.NET.Adapter.Kook/KookAdapter.cs |
Implements lifecycle, events, messaging, and channel operations. |
src/HuaJiBot.NET.Adapter.Kook/HuaJiBot.NET.Adapter.Kook.csproj |
Defines the adapter project and Kook.Net dependency. |
src/HuaJiBot.NET.Adapter.Kook/Channels/KookChannelKind.cs |
Distinguishes guild and direct channels. |
src/HuaJiBot.NET.Adapter.Kook/Channels/KookChannelId.cs |
Parses structured KOOK channel identifiers. |
README.md |
Documents the KOOK adapter. |
HuaJiBot.NET.slnx |
Adds the adapter to the solution. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| var userMentionTags = message | ||
| .Tags.Where(x => x.Type is TagType.UserMention) | ||
| .OrderBy(x => x.Index) | ||
| .ToArray(); |
There was a problem hiding this comment.
Kook.Net 0.11.1 does not populate tags for direct gateway messages or Card messages
This isn't accurate. See:
SocketUserMessage always parses tags for text and KMarkdown messages, whether they come from an ITextChannel or an IDMChannel. Card and attachment messages do not need parsing tags.
| case ReplyMessage { MessageId: var msgId } | ||
| when Guid.TryParse(msgId, out var quotedId): | ||
| quote = new MessageReference(quotedId); | ||
| break; |
There was a problem hiding this comment.
On this point, we should first confirm: can a Reply appear in the middle of a message, meaning that only part of the text is a reply while the rest is not? As far as I understand, it can't. So the presence of a Reply simply means the whole message is a reply.
Please confirm.
| /// </summary> | ||
| internal static class KookOutboundBuilder | ||
| { | ||
| public static IReadOnlyList<KookOutboundSegment> Build(IEnumerable<SendingMessageBase> messages) |
There was a problem hiding this comment.
Related unit tests are added.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
We have noted your PR and appreciate your contribution. In my view, the primary issue right now is that our KOOK server is not yet being utilized extensively; its main function currently serves as a platform for voice chat among a subset of members—a use case that neither requires nor supports cross-platform content synchronization via a bot. Before merging this PR, I believe our priority should be to actively build up the server's usage and establish it as a primary communication channel. We welcome more developers to get involved in the operation and maintenance of the relevant code repositories, and I would like to thank you on behalf of NBTCA. |


I noticed that PR #10 was closed.
First off, thanks to @LazuliKao for taking a shot at bringing Kook.Net into HuaJiBot.NET. Since that PR was left unmaintained, I'm going to try implementing this adapter myself as the Kook.Net developer.
Summary
Adds a
HuaJiBot.NET.Adapter.Kookadapter that connects KOOK through Kook.Net. It follows the existing adapter contract (BotServiceBase/IAdapterService/ event senders) and reuses Kook.Net's strongly-typed SDK, so it carries no protocol DTOs of its own.What's implemented
Receiving
OnGroupMessageReceived, with the channelChannelIdcarried asGroupId.OnPrivateMessageReceived, with the DM channelChatCodecarried asGroupId.Sending
SendRichMessageAsyncsendsRichContent.Markdownas raw KMarkdown, so bold, links, mentions and emoji render natively.Message parsing / rendering
Parsing and rendering are kept apart because they serve different consumers:
KookCommandReaderturns a message into structured reader entities for the command system. Mentions keep their user ID, and images are carried as their URL so a command can take one as aUriargument.KookMessageRendererturns a message into human-readable text forTextMessage. Plain text and KMarkdown go throughResolve(), card messages are laid out as aCard -> Module -> Elementtree, and media is listed with its basic info.Channel management
KookChannelIdmodels a channel as an explicitKind(guildulongvs directGuidchatCode) instead of leaving callers to infer it from which parse succeeded. Callersswitchon the kind and throw on anything unrecognized.Questions for maintainers
Both are framework-level and left to core rather than worked around in the adapter.
Note
Question 1: Typed image reader entity.
Received images are currently carried as
ReaderText(url), so there's no way to tell an image apart from a URL the user typed. A distinctReaderImageentity (plus aCommandReader.Image(out url)) inCommonCommandReaderwould fix this, additive and transparent to other adapters. Worth adding?Note
Question 2: Direct-message commands.
CommandServiceonly subscribes toOnGroupMessageReceivedandProcessCommandonly takesGroupMessageEventArgs, so DM commands don't reach the command system on any adapter. Having it also handleOnPrivateMessageReceived/PrivateMessageEventArgswould enable them everywhere at once. (PrivateMessageEventArgs.Replyis an empty stub, related to the same gap.)If you have any suggestions for changes, please don't hesitate to raise them!