mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-04-14 23:19:55 +00:00
feat(channels/feishu): add domain config for Lark global support
Add 'domain' field to FeishuConfig (Literal['feishu', 'lark'], default 'feishu'). Pass domain to lark.Client.builder() and lark.ws.Client to support Lark global (open.larksuite.com) in addition to Feishu China (open.feishu.cn). Existing configs default to 'feishu' for backward compatibility. Also add documentation for domain field in README.md and add tests for domain config.
This commit is contained in:
parent
a70928cc5c
commit
ee946d96ca
@ -563,7 +563,8 @@ Uses **WebSocket** long connection — no public IP required.
|
||||
"reactEmoji": "OnIt",
|
||||
"doneEmoji": "DONE",
|
||||
"toolHintPrefix": "🔧",
|
||||
"streaming": true
|
||||
"streaming": true,
|
||||
"domain": "feishu"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -576,6 +577,7 @@ Uses **WebSocket** long connection — no public IP required.
|
||||
> `reactEmoji`: Emoji for "processing" status (default: `OnIt`). See [available emojis](https://open.larkoffice.com/document/server-docs/im-v1/message-reaction/emojis-introduce).
|
||||
> `doneEmoji`: Optional emoji for "completed" status (e.g., `DONE`, `OK`, `HEART`). When set, bot adds this reaction after removing `reactEmoji`.
|
||||
> `toolHintPrefix`: Prefix for inline tool hints in streaming cards (default: `🔧`).
|
||||
> `domain`: `"feishu"` (default) for China (open.feishu.cn), `"lark"` for international Lark (open.larksuite.com).
|
||||
|
||||
**3. Run**
|
||||
|
||||
|
||||
@ -22,6 +22,8 @@ from nanobot.channels.base import BaseChannel
|
||||
from nanobot.config.paths import get_media_dir
|
||||
from nanobot.config.schema import Base
|
||||
|
||||
from lark_oapi.core.const import FEISHU_DOMAIN, LARK_DOMAIN
|
||||
|
||||
FEISHU_AVAILABLE = importlib.util.find_spec("lark_oapi") is not None
|
||||
|
||||
# Message type display mapping
|
||||
@ -255,6 +257,7 @@ class FeishuConfig(Base):
|
||||
group_policy: Literal["open", "mention"] = "mention"
|
||||
reply_to_message: bool = False # If True, bot replies quote the user's original message
|
||||
streaming: bool = True
|
||||
domain: Literal["feishu", "lark"] = "feishu" # Set to "lark" for international Lark
|
||||
|
||||
|
||||
_STREAM_ELEMENT_ID = "streaming_md"
|
||||
@ -328,10 +331,12 @@ class FeishuChannel(BaseChannel):
|
||||
self._loop = asyncio.get_running_loop()
|
||||
|
||||
# Create Lark client for sending messages
|
||||
domain = LARK_DOMAIN if self.config.domain == "lark" else FEISHU_DOMAIN
|
||||
self._client = (
|
||||
lark.Client.builder()
|
||||
.app_id(self.config.app_id)
|
||||
.app_secret(self.config.app_secret)
|
||||
.domain(domain)
|
||||
.log_level(lark.LogLevel.INFO)
|
||||
.build()
|
||||
)
|
||||
@ -359,6 +364,7 @@ class FeishuChannel(BaseChannel):
|
||||
self._ws_client = lark.ws.Client(
|
||||
self.config.app_id,
|
||||
self.config.app_secret,
|
||||
domain=domain,
|
||||
event_handler=event_handler,
|
||||
log_level=lark.LogLevel.INFO,
|
||||
)
|
||||
|
||||
48
tests/channels/test_feishu_domain.py
Normal file
48
tests/channels/test_feishu_domain.py
Normal file
@ -0,0 +1,48 @@
|
||||
"""Tests for Feishu/Lark domain configuration."""
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from nanobot.bus.queue import MessageBus
|
||||
from nanobot.channels.feishu import FeishuChannel, FeishuConfig
|
||||
|
||||
|
||||
def _make_channel(domain: str = "feishu") -> FeishuChannel:
|
||||
config = FeishuConfig(
|
||||
enabled=True,
|
||||
app_id="cli_test",
|
||||
app_secret="secret",
|
||||
allow_from=["*"],
|
||||
domain=domain,
|
||||
)
|
||||
ch = FeishuChannel(config, MessageBus())
|
||||
ch._client = MagicMock()
|
||||
ch._loop = None
|
||||
return ch
|
||||
|
||||
|
||||
class TestFeishuConfigDomain:
|
||||
def test_domain_default_is_feishu(self):
|
||||
config = FeishuConfig()
|
||||
assert config.domain == "feishu"
|
||||
|
||||
def test_domain_accepts_lark(self):
|
||||
config = FeishuConfig(domain="lark")
|
||||
assert config.domain == "lark"
|
||||
|
||||
def test_domain_accepts_feishu(self):
|
||||
config = FeishuConfig(domain="feishu")
|
||||
assert config.domain == "feishu"
|
||||
|
||||
def test_default_config_includes_domain(self):
|
||||
default_cfg = FeishuChannel.default_config()
|
||||
assert "domain" in default_cfg
|
||||
assert default_cfg["domain"] == "feishu"
|
||||
|
||||
def test_channel_persists_domain_from_config(self):
|
||||
ch = _make_channel(domain="lark")
|
||||
assert ch.config.domain == "lark"
|
||||
|
||||
def test_channel_persists_feishu_domain_from_config(self):
|
||||
ch = _make_channel(domain="feishu")
|
||||
assert ch.config.domain == "feishu"
|
||||
Loading…
x
Reference in New Issue
Block a user