agno-lark 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno_lark-0.1.0/LICENSE +21 -0
- agno_lark-0.1.0/PKG-INFO +251 -0
- agno_lark-0.1.0/README.md +204 -0
- agno_lark-0.1.0/pyproject.toml +82 -0
- agno_lark-0.1.0/pyproject.toml.orig +66 -0
- agno_lark-0.1.0/src/agno_lark/__init__.py +28 -0
- agno_lark-0.1.0/src/agno_lark/app.py +56 -0
- agno_lark-0.1.0/src/agno_lark/bridge.py +517 -0
- agno_lark-0.1.0/src/agno_lark/cards.py +57 -0
- agno_lark-0.1.0/src/agno_lark/cli.py +51 -0
- agno_lark-0.1.0/src/agno_lark/config.py +89 -0
- agno_lark-0.1.0/src/agno_lark/interface.py +103 -0
- agno_lark-0.1.0/src/agno_lark/media.py +25 -0
- agno_lark-0.1.0/src/agno_lark/py.typed +0 -0
- agno_lark-0.1.0/src/agno_lark/session.py +36 -0
- agno_lark-0.1.0/src/agno_lark/state.py +167 -0
- agno_lark-0.1.0/src/agno_lark/target.py +35 -0
agno_lark-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 agno-lark contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
agno_lark-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: agno-lark
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight Python bridge between Lark/Feishu and Agno AgentOS.
|
|
5
|
+
Keywords: agno,agentos,lark,feishu,im,websocket
|
|
6
|
+
Author: _白开水_
|
|
7
|
+
Author-email: _白开水_ <pkk518@gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 agno-lark contributors
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
Classifier: Development Status :: 3 - Alpha
|
|
30
|
+
Classifier: Intended Audience :: Developers
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
35
|
+
Classifier: Topic :: Communications :: Chat
|
|
36
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
37
|
+
Requires-Dist: agno[os]>=3.1,<4
|
|
38
|
+
Requires-Dist: aiosqlite>=0.20,<1
|
|
39
|
+
Requires-Dist: httpx[socks]>=0.28,<1
|
|
40
|
+
Requires-Dist: lark-channel-sdk>=1.4,<2
|
|
41
|
+
Requires-Dist: pydantic-settings>=2.6,<3
|
|
42
|
+
Requires-Python: >=3.12, <4
|
|
43
|
+
Project-URL: Homepage, https://github.com/pangkk18/agno-lark
|
|
44
|
+
Project-URL: Repository, https://github.com/pangkk18/agno-lark
|
|
45
|
+
Project-URL: Issues, https://github.com/pangkk18/agno-lark/issues
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# agno-lark
|
|
49
|
+
|
|
50
|
+
A lightweight Python bridge between Lark/Feishu IM and Agno AgentOS.
|
|
51
|
+
|
|
52
|
+
`agno-lark` (import package: `agno_lark`) runs as an independent bridge process. It uses the official `lark-channel-sdk` WebSocket channel to receive Lark/Feishu messages, forwards them to an AgentOS agent, team, or workflow, and stores deduplication, session generations, and run records in SQLite.
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
U[Lark/Feishu user] --> C[FeishuChannel\nWebSocket]
|
|
57
|
+
C --> B[agno-lark\nLarkInterface]
|
|
58
|
+
B --> S[(SQLite\ndedup / sessions / runs)]
|
|
59
|
+
B --> A[AgentOS\nagent / team / workflow]
|
|
60
|
+
A --> B
|
|
61
|
+
B --> C
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The Chinese documentation is available in [`READM_ZH.md`](READM_ZH.md).
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
- Persistent Lark/Feishu WebSocket connection; HTTP webhook mode is not required.
|
|
69
|
+
- Direct messages and group messages that mention the bot.
|
|
70
|
+
- Text replies, image resources, and file resources converted to Agno media objects.
|
|
71
|
+
- Remote AgentOS targets for `agent`, `team`, and `workflow`.
|
|
72
|
+
- User, chat, and thread session isolation with `/new` generation resets.
|
|
73
|
+
- Configurable group context:
|
|
74
|
+
- `user` (default): each member who mentions the bot gets an independent context.
|
|
75
|
+
- `shared`: members share one context for the same chat and thread.
|
|
76
|
+
- SQLite message deduplication, run records, TTL cleanup, WAL, and busy-timeout handling.
|
|
77
|
+
- Streaming Feishu cards with status, run ID, elapsed time, and cancellation actions.
|
|
78
|
+
- `/new`, `/status`, `/cancel [run_id]`, and `/help` commands.
|
|
79
|
+
- User and chat allowlists, reconnect handling, error handling, and structured logging.
|
|
80
|
+
|
|
81
|
+
The first release does not process audio, video, or voice messages and does not implement HITL resume approval. Long-running tasks use foreground SSE streaming.
|
|
82
|
+
|
|
83
|
+
## Requirements and installation
|
|
84
|
+
|
|
85
|
+
Python 3.12 or newer (and lower than 4.0) is required. [uv](https://docs.astral.sh/uv/) is recommended:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv sync
|
|
89
|
+
cp .env.example .env
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
After the first PyPI release, install the published package in an existing project with either:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv add agno-lark
|
|
96
|
+
# or
|
|
97
|
+
python -m pip install agno-lark
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The distribution name uses a hyphen (`agno-lark`), while Python imports use an underscore:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from agno_lark import LarkInterface, build_remote_target, load_settings
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The package also installs the `agno-lark` command. After installation, run the bridge with:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
agno-lark --help
|
|
110
|
+
agno-lark
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Create the Lark/Feishu application
|
|
114
|
+
|
|
115
|
+
Create an enterprise application in the Lark or Feishu Open Platform and enable bot capabilities. Record the App ID (`cli_...`) and App Secret. Select the long connection (WebSocket) mode in event subscriptions and subscribe to message events. Grant the permissions required to receive and send messages, read image/file resources, and send card messages. Publish the application and add the bot to the target chats.
|
|
116
|
+
|
|
117
|
+
The official Channel SDK handles the WebSocket connection, event normalization, resource downloads, deduplication, and card callbacks. This project does not require a separate webhook endpoint.
|
|
118
|
+
|
|
119
|
+
## Configuration
|
|
120
|
+
|
|
121
|
+
Copy `.env.example` and fill in the values below. The `FEISHU_*` prefix is retained for compatibility with existing Lark/Feishu application configuration; the distribution and import names are `agno-lark` and `agno_lark`.
|
|
122
|
+
|
|
123
|
+
```dotenv
|
|
124
|
+
FEISHU_APP_ID=cli_xxx
|
|
125
|
+
FEISHU_APP_SECRET=xxx
|
|
126
|
+
|
|
127
|
+
AGENTOS_URL=http://127.0.0.1:7777
|
|
128
|
+
AGENTOS_TOKEN=xxx
|
|
129
|
+
AGENTOS_TARGET_TYPE=agent
|
|
130
|
+
AGENTOS_TARGET_ID=assistant
|
|
131
|
+
# Legacy alias for an agent target:
|
|
132
|
+
# AGENTOS_AGENT_ID=assistant
|
|
133
|
+
|
|
134
|
+
FEISHU_STATE_DB=.data/agno-feishu.sqlite3
|
|
135
|
+
FEISHU_ALLOWED_USER_IDS=
|
|
136
|
+
FEISHU_ALLOWED_CHAT_IDS=
|
|
137
|
+
# user (default: one context per member) or shared (one context per chat/thread)
|
|
138
|
+
FEISHU_GROUP_SESSION_MODE=user
|
|
139
|
+
|
|
140
|
+
BRIDGE_HOST=127.0.0.1
|
|
141
|
+
BRIDGE_PORT=7788
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Allowlist values are comma-separated. If both allowlists are empty, access is open; production deployments should configure at least one allowlist. `AGENTOS_TOKEN` may be empty for a public AgentOS, but a Bearer token is recommended for production.
|
|
145
|
+
|
|
146
|
+
`FEISHU_GROUP_SESSION_MODE` affects group chats only. In `user` mode, the scope includes `sender.open_id`; in `shared` mode, the scope includes the chat and thread but not the sender. Direct messages are always isolated by their direct-message chat. The default SQLite filename remains `.data/agno-feishu.sqlite3` so existing state data can be reused.
|
|
147
|
+
|
|
148
|
+
## Quick start with a remote AgentOS
|
|
149
|
+
|
|
150
|
+
Start AgentOS at `AGENTOS_URL`, then run the bridge:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uv run agno-lark
|
|
154
|
+
uv run agno-lark --host 0.0.0.0 --port 7788
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The bridge creates a `RemoteAgent`, `RemoteTeam`, or `RemoteWorkflow` from `AGENTOS_TARGET_TYPE` and mounts the Lark/Feishu interface into the local AgentOS gateway. The status endpoint is `GET /feishu/status`; this path is retained for compatibility with existing deployments.
|
|
158
|
+
|
|
159
|
+
## Embed in an existing AgentOS application
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from agno.os import AgentOS
|
|
163
|
+
from agno_lark import LarkInterface, build_remote_target, load_settings
|
|
164
|
+
|
|
165
|
+
settings = load_settings()
|
|
166
|
+
target = build_remote_target(settings)
|
|
167
|
+
lark = LarkInterface(target=target, settings=settings)
|
|
168
|
+
|
|
169
|
+
agent_os = AgentOS(
|
|
170
|
+
agents=[target] if settings.target_type == "agent" else None,
|
|
171
|
+
teams=[target] if settings.target_type == "team" else None,
|
|
172
|
+
workflows=[target] if settings.target_type == "workflow" else None,
|
|
173
|
+
interfaces=[lark],
|
|
174
|
+
)
|
|
175
|
+
app = agent_os.get_app()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`LarkInterface.get_router()` returns a FastAPI `APIRouter` with a managed lifespan. Startup opens the SQLite store and connects `FeishuChannel`; shutdown disconnects the channel and closes the store. Only the asynchronous AgentOS execution path is supported. `FeishuInterface` remains exported as a compatibility alias.
|
|
179
|
+
|
|
180
|
+
## Messages, sessions, and commands
|
|
181
|
+
|
|
182
|
+
- Direct messages are handled immediately; group messages must mention the bot.
|
|
183
|
+
- `user_id` is taken from `sender.open_id`.
|
|
184
|
+
- In the default `user` group mode, a scope can look like `feishu:agent:assistant:chat_oc_xxx:thread_omt_xxx:user:ou_xxx:v3`.
|
|
185
|
+
- In `shared` group mode, the same chat/thread uses a scope such as `feishu:agent:assistant:chat_oc_xxx:thread_omt_xxx:v3` for every member, while each AgentOS run still receives the sender's `user_id`.
|
|
186
|
+
- `/new` increments the generation for the current user scope or shared chat/thread scope.
|
|
187
|
+
|
|
188
|
+
| Command | Behavior |
|
|
189
|
+
| --- | --- |
|
|
190
|
+
| `/new` | Increment the current scope generation and start a fresh session. |
|
|
191
|
+
| `/status` | Show active and recent runs for the current scope. |
|
|
192
|
+
| `/cancel` | Cancel the most recent active run for the current scope. |
|
|
193
|
+
| `/cancel <run_id>` | Request cancellation of a specific run. |
|
|
194
|
+
| `/help` | Show the command help card. |
|
|
195
|
+
|
|
196
|
+
Cancellation first records `cancel_requested` and then calls the scoped AgentOS cancel endpoint. The final state comes from the SSE terminal event. Card actions re-check the operator and chat allowlists before starting status or cancellation work.
|
|
197
|
+
|
|
198
|
+
## State database and troubleshooting
|
|
199
|
+
|
|
200
|
+
The default database `.data/agno-feishu.sqlite3` uses WAL and a busy timeout. It contains `schema_version`, `dedup_messages`, `session_scopes`, and `runs`. Message deduplication defaults to 24 hours and run records are retained for 7 days.
|
|
201
|
+
|
|
202
|
+
If no messages arrive, check application publication, WebSocket subscriptions, bot membership, and allowlists. For 401/403 responses, check the AgentOS token, target ID, and AgentOS authorization. For resource failures, check Lark/Feishu resource-read permissions. Logs do not include the App Secret, AgentOS token, raw file contents, or complete user messages.
|
|
203
|
+
|
|
204
|
+
If your shell exports a SOCKS proxy and the local environment does not have `socksio`, set `NO_PROXY=127.0.0.1,localhost` (and the AgentOS hostname) when testing a local AgentOS. If outbound AgentOS requests must use a SOCKS proxy, install the HTTPX SOCKS extra in the deployment environment with `uv pip install "httpx[socks]>=0.28,<1"`.
|
|
205
|
+
|
|
206
|
+
## Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
uv sync
|
|
210
|
+
uv run pytest
|
|
211
|
+
uv run ruff check .
|
|
212
|
+
uv run mypy src
|
|
213
|
+
uv build
|
|
214
|
+
uv run agno-lark --help
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Tests use fake Channel and Agno targets plus `httpx` mocks; they do not contact Lark/Feishu or AgentOS. See [`examples/agent_os_remote.py`](examples/agent_os_remote.py) for the remote integration example.
|
|
218
|
+
|
|
219
|
+
## Release and publish
|
|
220
|
+
|
|
221
|
+
The package will be published to [PyPI](https://pypi.org/project/agno-lark/) as `agno-lark`. Every release version must be unique. Update `version` in `pyproject.toml`, then run the local checks and build:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
uv lock
|
|
225
|
+
uv sync --locked
|
|
226
|
+
uv run pytest
|
|
227
|
+
uv run ruff check .
|
|
228
|
+
uv run mypy src
|
|
229
|
+
uv build
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
For a first release or a manual release, create a PyPI API token and publish without putting the token in the repository or shell history:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
export UV_PUBLISH_TOKEN='pypi-...'
|
|
236
|
+
uv publish
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
To verify a release on TestPyPI first, use a TestPyPI token and the TestPyPI upload endpoint:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
export UV_PUBLISH_TOKEN='pypi-...'
|
|
243
|
+
uv publish --publish-url https://test.pypi.org/legacy/
|
|
244
|
+
uv pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ agno-lark
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This repository also includes a GitHub Actions workflow for PyPI Trusted Publishing. Configure the GitHub repository as a trusted publisher for the `agno-lark` project on PyPI, then push a tag such as `v0.1.0`; the workflow builds and publishes without a long-lived PyPI token.
|
|
248
|
+
|
|
249
|
+
## License
|
|
250
|
+
|
|
251
|
+
This project is released under the MIT License. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# agno-lark
|
|
2
|
+
|
|
3
|
+
A lightweight Python bridge between Lark/Feishu IM and Agno AgentOS.
|
|
4
|
+
|
|
5
|
+
`agno-lark` (import package: `agno_lark`) runs as an independent bridge process. It uses the official `lark-channel-sdk` WebSocket channel to receive Lark/Feishu messages, forwards them to an AgentOS agent, team, or workflow, and stores deduplication, session generations, and run records in SQLite.
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart LR
|
|
9
|
+
U[Lark/Feishu user] --> C[FeishuChannel\nWebSocket]
|
|
10
|
+
C --> B[agno-lark\nLarkInterface]
|
|
11
|
+
B --> S[(SQLite\ndedup / sessions / runs)]
|
|
12
|
+
B --> A[AgentOS\nagent / team / workflow]
|
|
13
|
+
A --> B
|
|
14
|
+
B --> C
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The Chinese documentation is available in [`READM_ZH.md`](READM_ZH.md).
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- Persistent Lark/Feishu WebSocket connection; HTTP webhook mode is not required.
|
|
22
|
+
- Direct messages and group messages that mention the bot.
|
|
23
|
+
- Text replies, image resources, and file resources converted to Agno media objects.
|
|
24
|
+
- Remote AgentOS targets for `agent`, `team`, and `workflow`.
|
|
25
|
+
- User, chat, and thread session isolation with `/new` generation resets.
|
|
26
|
+
- Configurable group context:
|
|
27
|
+
- `user` (default): each member who mentions the bot gets an independent context.
|
|
28
|
+
- `shared`: members share one context for the same chat and thread.
|
|
29
|
+
- SQLite message deduplication, run records, TTL cleanup, WAL, and busy-timeout handling.
|
|
30
|
+
- Streaming Feishu cards with status, run ID, elapsed time, and cancellation actions.
|
|
31
|
+
- `/new`, `/status`, `/cancel [run_id]`, and `/help` commands.
|
|
32
|
+
- User and chat allowlists, reconnect handling, error handling, and structured logging.
|
|
33
|
+
|
|
34
|
+
The first release does not process audio, video, or voice messages and does not implement HITL resume approval. Long-running tasks use foreground SSE streaming.
|
|
35
|
+
|
|
36
|
+
## Requirements and installation
|
|
37
|
+
|
|
38
|
+
Python 3.12 or newer (and lower than 4.0) is required. [uv](https://docs.astral.sh/uv/) is recommended:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv sync
|
|
42
|
+
cp .env.example .env
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
After the first PyPI release, install the published package in an existing project with either:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv add agno-lark
|
|
49
|
+
# or
|
|
50
|
+
python -m pip install agno-lark
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The distribution name uses a hyphen (`agno-lark`), while Python imports use an underscore:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from agno_lark import LarkInterface, build_remote_target, load_settings
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The package also installs the `agno-lark` command. After installation, run the bridge with:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
agno-lark --help
|
|
63
|
+
agno-lark
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Create the Lark/Feishu application
|
|
67
|
+
|
|
68
|
+
Create an enterprise application in the Lark or Feishu Open Platform and enable bot capabilities. Record the App ID (`cli_...`) and App Secret. Select the long connection (WebSocket) mode in event subscriptions and subscribe to message events. Grant the permissions required to receive and send messages, read image/file resources, and send card messages. Publish the application and add the bot to the target chats.
|
|
69
|
+
|
|
70
|
+
The official Channel SDK handles the WebSocket connection, event normalization, resource downloads, deduplication, and card callbacks. This project does not require a separate webhook endpoint.
|
|
71
|
+
|
|
72
|
+
## Configuration
|
|
73
|
+
|
|
74
|
+
Copy `.env.example` and fill in the values below. The `FEISHU_*` prefix is retained for compatibility with existing Lark/Feishu application configuration; the distribution and import names are `agno-lark` and `agno_lark`.
|
|
75
|
+
|
|
76
|
+
```dotenv
|
|
77
|
+
FEISHU_APP_ID=cli_xxx
|
|
78
|
+
FEISHU_APP_SECRET=xxx
|
|
79
|
+
|
|
80
|
+
AGENTOS_URL=http://127.0.0.1:7777
|
|
81
|
+
AGENTOS_TOKEN=xxx
|
|
82
|
+
AGENTOS_TARGET_TYPE=agent
|
|
83
|
+
AGENTOS_TARGET_ID=assistant
|
|
84
|
+
# Legacy alias for an agent target:
|
|
85
|
+
# AGENTOS_AGENT_ID=assistant
|
|
86
|
+
|
|
87
|
+
FEISHU_STATE_DB=.data/agno-feishu.sqlite3
|
|
88
|
+
FEISHU_ALLOWED_USER_IDS=
|
|
89
|
+
FEISHU_ALLOWED_CHAT_IDS=
|
|
90
|
+
# user (default: one context per member) or shared (one context per chat/thread)
|
|
91
|
+
FEISHU_GROUP_SESSION_MODE=user
|
|
92
|
+
|
|
93
|
+
BRIDGE_HOST=127.0.0.1
|
|
94
|
+
BRIDGE_PORT=7788
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Allowlist values are comma-separated. If both allowlists are empty, access is open; production deployments should configure at least one allowlist. `AGENTOS_TOKEN` may be empty for a public AgentOS, but a Bearer token is recommended for production.
|
|
98
|
+
|
|
99
|
+
`FEISHU_GROUP_SESSION_MODE` affects group chats only. In `user` mode, the scope includes `sender.open_id`; in `shared` mode, the scope includes the chat and thread but not the sender. Direct messages are always isolated by their direct-message chat. The default SQLite filename remains `.data/agno-feishu.sqlite3` so existing state data can be reused.
|
|
100
|
+
|
|
101
|
+
## Quick start with a remote AgentOS
|
|
102
|
+
|
|
103
|
+
Start AgentOS at `AGENTOS_URL`, then run the bridge:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv run agno-lark
|
|
107
|
+
uv run agno-lark --host 0.0.0.0 --port 7788
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The bridge creates a `RemoteAgent`, `RemoteTeam`, or `RemoteWorkflow` from `AGENTOS_TARGET_TYPE` and mounts the Lark/Feishu interface into the local AgentOS gateway. The status endpoint is `GET /feishu/status`; this path is retained for compatibility with existing deployments.
|
|
111
|
+
|
|
112
|
+
## Embed in an existing AgentOS application
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from agno.os import AgentOS
|
|
116
|
+
from agno_lark import LarkInterface, build_remote_target, load_settings
|
|
117
|
+
|
|
118
|
+
settings = load_settings()
|
|
119
|
+
target = build_remote_target(settings)
|
|
120
|
+
lark = LarkInterface(target=target, settings=settings)
|
|
121
|
+
|
|
122
|
+
agent_os = AgentOS(
|
|
123
|
+
agents=[target] if settings.target_type == "agent" else None,
|
|
124
|
+
teams=[target] if settings.target_type == "team" else None,
|
|
125
|
+
workflows=[target] if settings.target_type == "workflow" else None,
|
|
126
|
+
interfaces=[lark],
|
|
127
|
+
)
|
|
128
|
+
app = agent_os.get_app()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`LarkInterface.get_router()` returns a FastAPI `APIRouter` with a managed lifespan. Startup opens the SQLite store and connects `FeishuChannel`; shutdown disconnects the channel and closes the store. Only the asynchronous AgentOS execution path is supported. `FeishuInterface` remains exported as a compatibility alias.
|
|
132
|
+
|
|
133
|
+
## Messages, sessions, and commands
|
|
134
|
+
|
|
135
|
+
- Direct messages are handled immediately; group messages must mention the bot.
|
|
136
|
+
- `user_id` is taken from `sender.open_id`.
|
|
137
|
+
- In the default `user` group mode, a scope can look like `feishu:agent:assistant:chat_oc_xxx:thread_omt_xxx:user:ou_xxx:v3`.
|
|
138
|
+
- In `shared` group mode, the same chat/thread uses a scope such as `feishu:agent:assistant:chat_oc_xxx:thread_omt_xxx:v3` for every member, while each AgentOS run still receives the sender's `user_id`.
|
|
139
|
+
- `/new` increments the generation for the current user scope or shared chat/thread scope.
|
|
140
|
+
|
|
141
|
+
| Command | Behavior |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `/new` | Increment the current scope generation and start a fresh session. |
|
|
144
|
+
| `/status` | Show active and recent runs for the current scope. |
|
|
145
|
+
| `/cancel` | Cancel the most recent active run for the current scope. |
|
|
146
|
+
| `/cancel <run_id>` | Request cancellation of a specific run. |
|
|
147
|
+
| `/help` | Show the command help card. |
|
|
148
|
+
|
|
149
|
+
Cancellation first records `cancel_requested` and then calls the scoped AgentOS cancel endpoint. The final state comes from the SSE terminal event. Card actions re-check the operator and chat allowlists before starting status or cancellation work.
|
|
150
|
+
|
|
151
|
+
## State database and troubleshooting
|
|
152
|
+
|
|
153
|
+
The default database `.data/agno-feishu.sqlite3` uses WAL and a busy timeout. It contains `schema_version`, `dedup_messages`, `session_scopes`, and `runs`. Message deduplication defaults to 24 hours and run records are retained for 7 days.
|
|
154
|
+
|
|
155
|
+
If no messages arrive, check application publication, WebSocket subscriptions, bot membership, and allowlists. For 401/403 responses, check the AgentOS token, target ID, and AgentOS authorization. For resource failures, check Lark/Feishu resource-read permissions. Logs do not include the App Secret, AgentOS token, raw file contents, or complete user messages.
|
|
156
|
+
|
|
157
|
+
If your shell exports a SOCKS proxy and the local environment does not have `socksio`, set `NO_PROXY=127.0.0.1,localhost` (and the AgentOS hostname) when testing a local AgentOS. If outbound AgentOS requests must use a SOCKS proxy, install the HTTPX SOCKS extra in the deployment environment with `uv pip install "httpx[socks]>=0.28,<1"`.
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv sync
|
|
163
|
+
uv run pytest
|
|
164
|
+
uv run ruff check .
|
|
165
|
+
uv run mypy src
|
|
166
|
+
uv build
|
|
167
|
+
uv run agno-lark --help
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Tests use fake Channel and Agno targets plus `httpx` mocks; they do not contact Lark/Feishu or AgentOS. See [`examples/agent_os_remote.py`](examples/agent_os_remote.py) for the remote integration example.
|
|
171
|
+
|
|
172
|
+
## Release and publish
|
|
173
|
+
|
|
174
|
+
The package will be published to [PyPI](https://pypi.org/project/agno-lark/) as `agno-lark`. Every release version must be unique. Update `version` in `pyproject.toml`, then run the local checks and build:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
uv lock
|
|
178
|
+
uv sync --locked
|
|
179
|
+
uv run pytest
|
|
180
|
+
uv run ruff check .
|
|
181
|
+
uv run mypy src
|
|
182
|
+
uv build
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
For a first release or a manual release, create a PyPI API token and publish without putting the token in the repository or shell history:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
export UV_PUBLISH_TOKEN='pypi-...'
|
|
189
|
+
uv publish
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
To verify a release on TestPyPI first, use a TestPyPI token and the TestPyPI upload endpoint:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
export UV_PUBLISH_TOKEN='pypi-...'
|
|
196
|
+
uv publish --publish-url https://test.pypi.org/legacy/
|
|
197
|
+
uv pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ agno-lark
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This repository also includes a GitHub Actions workflow for PyPI Trusted Publishing. Configure the GitHub repository as a trusted publisher for the `agno-lark` project on PyPI, then push a tag such as `v0.1.0`; the workflow builds and publishes without a long-lived PyPI token.
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
This project is released under the MIT License. See [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agno-lark"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A lightweight Python bridge between Lark/Feishu and Agno AgentOS."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
keywords = [
|
|
7
|
+
"agno",
|
|
8
|
+
"agentos",
|
|
9
|
+
"lark",
|
|
10
|
+
"feishu",
|
|
11
|
+
"im",
|
|
12
|
+
"websocket",
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Communications :: Chat",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
requires-python = ">=3.12,<4"
|
|
25
|
+
dependencies = [
|
|
26
|
+
"agno[os]>=3.1,<4",
|
|
27
|
+
"aiosqlite>=0.20,<1",
|
|
28
|
+
"httpx[socks]>=0.28,<1",
|
|
29
|
+
"lark-channel-sdk>=1.4,<2",
|
|
30
|
+
"pydantic-settings>=2.6,<3",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[[project.authors]]
|
|
34
|
+
name = "_白开水_"
|
|
35
|
+
email = "pkk518@gmail.com"
|
|
36
|
+
|
|
37
|
+
[project.license]
|
|
38
|
+
file = "LICENSE"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
agno-lark = "agno_lark.cli:main"
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
Homepage = "https://github.com/pangkk18/agno-lark"
|
|
45
|
+
Repository = "https://github.com/pangkk18/agno-lark"
|
|
46
|
+
Issues = "https://github.com/pangkk18/agno-lark/issues"
|
|
47
|
+
|
|
48
|
+
[build-system]
|
|
49
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
50
|
+
build-backend = "uv_build"
|
|
51
|
+
|
|
52
|
+
[dependency-groups]
|
|
53
|
+
dev = [
|
|
54
|
+
"mypy>=1.15,<2",
|
|
55
|
+
"pytest>=8.3,<9",
|
|
56
|
+
"pytest-asyncio>=0.25,<1",
|
|
57
|
+
"respx>=0.22,<1",
|
|
58
|
+
"ruff>=0.9,<1",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[tool.pytest.ini_options]
|
|
62
|
+
addopts = "-q"
|
|
63
|
+
asyncio_mode = "auto"
|
|
64
|
+
testpaths = ["tests"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff]
|
|
67
|
+
line-length = 100
|
|
68
|
+
target-version = "py312"
|
|
69
|
+
|
|
70
|
+
[tool.ruff.lint]
|
|
71
|
+
select = [
|
|
72
|
+
"E",
|
|
73
|
+
"F",
|
|
74
|
+
"I",
|
|
75
|
+
"UP",
|
|
76
|
+
"B",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[tool.mypy]
|
|
80
|
+
python_version = "3.12"
|
|
81
|
+
strict = true
|
|
82
|
+
files = ["src"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "agno-lark"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A lightweight Python bridge between Lark/Feishu and Agno AgentOS."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "_白开水_", email = "pkk518@gmail.com" }
|
|
8
|
+
]
|
|
9
|
+
license = { file = "LICENSE" }
|
|
10
|
+
keywords = ["agno", "agentos", "lark", "feishu", "im", "websocket"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"Operating System :: OS Independent",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Communications :: Chat",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
]
|
|
21
|
+
requires-python = ">=3.12,<4"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"agno[os]>=3.1,<4",
|
|
24
|
+
"aiosqlite>=0.20,<1",
|
|
25
|
+
"httpx[socks]>=0.28,<1",
|
|
26
|
+
"lark-channel-sdk>=1.4,<2",
|
|
27
|
+
"pydantic-settings>=2.6,<3",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
32
|
+
build-backend = "uv_build"
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
agno-lark = "agno_lark.cli:main"
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/pangkk18/agno-lark"
|
|
39
|
+
Repository = "https://github.com/pangkk18/agno-lark"
|
|
40
|
+
Issues = "https://github.com/pangkk18/agno-lark/issues"
|
|
41
|
+
|
|
42
|
+
[dependency-groups]
|
|
43
|
+
dev = [
|
|
44
|
+
"mypy>=1.15,<2",
|
|
45
|
+
"pytest>=8.3,<9",
|
|
46
|
+
"pytest-asyncio>=0.25,<1",
|
|
47
|
+
"respx>=0.22,<1",
|
|
48
|
+
"ruff>=0.9,<1",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
addopts = "-q"
|
|
53
|
+
asyncio_mode = "auto"
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
line-length = 100
|
|
58
|
+
target-version = "py312"
|
|
59
|
+
|
|
60
|
+
[tool.ruff.lint]
|
|
61
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
62
|
+
|
|
63
|
+
[tool.mypy]
|
|
64
|
+
python_version = "3.12"
|
|
65
|
+
strict = true
|
|
66
|
+
files = ["src"]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Lark/Feishu bridge for Agno AgentOS."""
|
|
2
|
+
|
|
3
|
+
from .app import create_app
|
|
4
|
+
from .bridge import FeishuBridge, LarkBridge
|
|
5
|
+
from .config import FeishuSettings, LarkSettings, load_settings
|
|
6
|
+
from .interface import FeishuInterface, LarkInterface
|
|
7
|
+
from .session import make_scope_key, make_session_id
|
|
8
|
+
from .state import RunRecord, SqliteStateStore
|
|
9
|
+
from .target import TargetDescriptor, build_remote_target
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"LarkInterface",
|
|
13
|
+
"FeishuInterface",
|
|
14
|
+
"LarkBridge",
|
|
15
|
+
"FeishuBridge",
|
|
16
|
+
"LarkSettings",
|
|
17
|
+
"FeishuSettings",
|
|
18
|
+
"RunRecord",
|
|
19
|
+
"SqliteStateStore",
|
|
20
|
+
"TargetDescriptor",
|
|
21
|
+
"build_remote_target",
|
|
22
|
+
"create_app",
|
|
23
|
+
"load_settings",
|
|
24
|
+
"make_scope_key",
|
|
25
|
+
"make_session_id",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
__version__ = "0.1.0"
|