Skip to content

feat(channels): add xiaoyi channel support#875

Open
ystyle wants to merge 1 commit intosipeed:refactor/channel-systemfrom
ystyle:feat/xiaoyi-channel-refactor
Open

feat(channels): add xiaoyi channel support#875
ystyle wants to merge 1 commit intosipeed:refactor/channel-systemfrom
ystyle:feat/xiaoyi-channel-refactor

Conversation

@ystyle
Copy link

@ystyle ystyle commented Feb 27, 2026

Summary

  • Add XiaoYiChannel in pkg/channels/xiaoyi/ subpackage following new channel architecture
  • Implement A2A (Agent-to-Agent) protocol using xiaoyi-agent-sdk
  • Use BaseChannel with factory registration pattern
  • Add XiaoYiConfig to config.go
  • Add documentation with link to Huawei official setup guide

Files Changed

  • pkg/channels/xiaoyi/init.go - Factory registration
  • pkg/channels/xiaoyi/xiaoyi.go - Channel implementation
  • pkg/config/config.go - Add XiaoYiConfig
  • pkg/channels/manager.go - Register xiaoyi in initChannels
  • cmd/picoclaw/internal/gateway/helpers.go - Blank import
  • docs/channels/xiaoyi/ - Documentation (zh/en)
  • README.md / README.zh.md - Update channel list
  • go.mod / go.sum - Add SDK dependency

Configuration

{
  "channels": {
    "xiaoyi": {
      "enabled": true,
      "ak": "your-access-key",
      "sk": "your-secret-key",
      "agent_id": "your-agent-id"
    }
  }
}

Related

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are there changes to the Dockerfile regarding the channel modifications?

Copy link
Author

Choose a reason for hiding this comment

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

Already resolved, it was a mistaken submission

@ystyle ystyle force-pushed the feat/xiaoyi-channel-refactor branch from b974a00 to ae50335 Compare February 27, 2026 14:42
@ystyle
Copy link
Author

ystyle commented Feb 27, 2026

Hi @alexhoshina, thank you for the review!

  1. Dockerfile changes: I've removed them in the latest commit (ae50335). The Dockerfile modifications were for local testing and should not be part of this PR.

  2. HandleMessage signature: I checked the `refactor/channel-system` branch, the `HandleMessage` function signature in `BaseChannel` is:

```go
func (c *BaseChannel) HandleMessage(
ctx context.Context,
peer bus.Peer,
messageID, senderID, chatID, content string,
media []string,
metadata map[string]string,
senderOpts ...bus.SenderInfo,
)
```

My implementation follows the same pattern as the `telegram` channel. I've also tested it locally - sending a message to XiaoYi and getting a response works correctly. Could you please double-check? Thanks!

README.md Outdated
## 💬 Chat Apps

Talk to your picoclaw through Telegram, Discord, WhatsApp, DingTalk, LINE, or WeCom
Talk to your picoclaw through Telegram, Discord, DingTalk, LINE, WeCom, or XiaoYi
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why was WhatsApp deleted?

return nil
}

chatID := fmt.Sprintf("%s:%s", sessionID, taskID)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Potential impact on sessionID parsing needs to be analyzed, introducing new considerations: whether it will affect the parsing of sessionID

return fmt.Errorf("xiaoyi reply: %w", channels.ErrTemporary)
}

if err := c.client.SendStatus(ctx, taskID, sessionID, "Completed", "completed"); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Will the completed status published here conflict with long message fragmentation?

@alexhoshina
Copy link
Collaborator

Also, regarding the SDK you are using, perhaps it should also use a license compatible with Pico.

@alexhoshina
Copy link
Collaborator

Hi @alexhoshina, thank you for the review!

  1. Dockerfile changes: I've removed them in the latest commit (ae50335). The Dockerfile modifications were for local testing and should not be part of this PR.
  2. HandleMessage signature: I checked the refactor/channel-system branch, the HandleMessage function signature in BaseChannel is:

go func (c *BaseChannel) HandleMessage( ctx context.Context, peer bus.Peer, messageID, senderID, chatID, content string, media []string, metadata map[string]string, senderOpts ...bus.SenderInfo, )

My implementation follows the same pattern as the telegram channel. I've also tested it locally - sending a message to XiaoYi and getting a response works correctly. Could you please double-check? Thanks!

You are correct, I was referring to the old function signature, my apologies.

@ystyle
Copy link
Author

ystyle commented Feb 27, 2026

@alexhoshina Thanks for the feedback!

  1. WhatsApp deleted? - No, WhatsApp is not deleted. The latest commit (ae50335) only adds xiaoyi channel. Could you please check the latest version? The changed files are:

    • README.md, README.zh.md
    • cmd/picoclaw/internal/gateway/helpers.go (only adds xiaoyi import)
    • docs/channels/xiaoyi/ (new)
    • go.mod, go.sum
    • pkg/channels/manager.go
    • pkg/channels/xiaoyi/ (new)
    • pkg/config/config.go
  2. sessionID parsing with : - The chatID format is sessionID:taskID only for outbound messages. The sessionID itself doesn't contain :, so parsing should be safe.

  3. completed status vs long message fragmentation - Good point! The SendStatus("completed") is called after ReplyStream. If message fragmentation happens, the status might be sent too early. I should move the status call to ensure it's sent after all fragments. Let me check how other channels handle this.

@ystyle
Copy link
Author

ystyle commented Feb 27, 2026

@alexhoshina Good point about message fragmentation!

Currently, XiaoYi channel doesn't implement MessageLengthProvider (no MaxMessageLength set), so the Manager won't split messages. The SDK handles the message internally.

However, if we need to support MaxMessageLength in the future, the SendStatus("completed") call would need to be moved - perhaps to a callback or we could implement a separate interface for post-send actions.

For now, the implementation works correctly without fragmentation. Should I:

  1. Add a comment explaining this limitation?
  2. Or remove SendStatus("completed") and let the SDK handle the final state?

What do you suggest?

@alexhoshina
Copy link
Collaborator

@alexhoshina Thanks for the feedback!

  1. WhatsApp deleted? - No, WhatsApp is not deleted. The latest commit (ae50335) only adds xiaoyi channel. Could you please check the latest version? The changed files are:

    • README.md, README.zh.md
    • cmd/picoclaw/internal/gateway/helpers.go (only adds xiaoyi import)
    • docs/channels/xiaoyi/ (new)
    • go.mod, go.sum
    • pkg/channels/manager.go
    • pkg/channels/xiaoyi/ (new)
    • pkg/config/config.go
  2. sessionID parsing with : - The chatID format is sessionID:taskID only for outbound messages. The sessionID itself doesn't contain :, so parsing should be safe.

  3. completed status vs long message fragmentation - Good point! The SendStatus("completed") is called after ReplyStream. If message fragmentation happens, the status might be sent too early. I should move the status call to ensure it's sent after all fragments. Let me check how other channels handle this.

WhatsApp has been removed in RADEME, you can check the line numbers I've marked, but it's just a minor issue

@yinwm
Copy link
Collaborator

yinwm commented Feb 27, 2026

  • sessionID parsing with : - The chatID format is sessionID:taskID only for outbound messages. The sessionID itself doesn't contain :, so parsing should be safe.

Is xiaoyi need this chatID format?

- Add XiaoYiChannel in pkg/channels/xiaoyi/ subpackage
- Implement A2A protocol using xiaoyi-agent-sdk
- Use ReplyStream + SendStatus for long-task pattern
- Add XiaoYiConfig to config.go
- Register xiaoyi in manager.go initChannels
- Add blank import in gateway helpers
- Add documentation in docs/channels/xiaoyi/
- Update README.md and README.zh.md channel lists
@ystyle ystyle force-pushed the feat/xiaoyi-channel-refactor branch from ae50335 to 693db82 Compare February 27, 2026 16:12
@ystyle
Copy link
Author

ystyle commented Feb 27, 2026

@alexhoshina Sorry for the confusion! You were right about WhatsApp.

I found the issue - when I added XiaoYi to the README.md description line, I accidentally replaced "WhatsApp" instead of appending "XiaoYi".

This has been fixed in the latest commit (693db82):

  • Before: Talk to your picoclaw through Telegram, Discord, DingTalk, LINE, or WeCom (missing WhatsApp)
  • After: Talk to your picoclaw through Telegram, Discord, WhatsApp, DingTalk, LINE, WeCom, or XiaoYi

Thank you for catching this! 🙏

@ystyle
Copy link
Author

ystyle commented Feb 27, 2026

@yinwm Yes, the sessionID:taskID format is needed for XiaoYi channel because:

  1. Inbound: SDK's OnMessage callback provides both sessionID and taskID
  2. Outbound: When Agent replies, we need to call client.ReplyStream(taskID, sessionID, content) - so we need to extract both from chatID

The chatID passed through the message bus needs to carry both pieces of information, hence the sessionID:taskID format.

Alternative approaches:

  • Store taskID in metadata and only use sessionID as chatID
  • Use a custom struct instead of string

But the current : separator approach is simple and consistent with how other channels encode multiple IDs. Do you have a better suggestion?

Copy link

@nikolasdehor nikolasdehor left a comment

Choose a reason for hiding this comment

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

Well-structured channel implementation that follows existing patterns. The author has been responsive to feedback. Additional observations: (1) SDK license: As alexhoshina noted, the xiaoyi-agent-sdk dependency needs a compatible license (picoclaw uses Apache-2.0). The SDK repo should have an explicit license file before this PR merges. (2) chatID separator robustness: The sessionID:taskID format parsed with SplitN(msg.ChatID, ":", 2) works only if sessionID never contains ':'. Consider using a different separator or storing taskID in metadata. (3) Context usage: c.HandleMessage(c.ctx, ...) uses the channel-level context rather than the per-message ctx. If the channel is stopped mid-processing, this could cancel in-flight messages prematurely. (4) Error wrapping: In Send, the error is wrapped as channels.ErrTemporary regardless of the actual error type. Some errors (invalid session) may be permanent. Good work overall — pending license resolution.

@alexhoshina
Copy link
Collaborator

Well-structured channel implementation that follows existing patterns. The author has been responsive to feedback. Additional observations: (1) SDK license: As alexhoshina noted, the xiaoyi-agent-sdk dependency needs a compatible license (picoclaw uses Apache-2.0). The SDK repo should have an explicit license file before this PR merges. (2) chatID separator robustness: The sessionID:taskID format parsed with SplitN(msg.ChatID, ":", 2) works only if sessionID never contains ':'. Consider using a different separator or storing taskID in metadata. (3) Context usage: c.HandleMessage(c.ctx, ...) uses the channel-level context rather than the per-message ctx. If the channel is stopped mid-processing, this could cancel in-flight messages prematurely. (4) Error wrapping: In Send, the error is wrapped as channels.ErrTemporary regardless of the actual error type. Some errors (invalid session) may be permanent. Good work overall — pending license resolution.

Note that pico uses the MIT license

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.

4 participants