x-agent-kit 0.2.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.
- x_agent_kit-0.2.0/PKG-INFO +20 -0
- x_agent_kit-0.2.0/README.md +629 -0
- x_agent_kit-0.2.0/pyproject.toml +31 -0
- x_agent_kit-0.2.0/setup.cfg +4 -0
- x_agent_kit-0.2.0/tests/test_agent.py +85 -0
- x_agent_kit-0.2.0/tests/test_approval_queue.py +44 -0
- x_agent_kit-0.2.0/tests/test_brain_claude.py +98 -0
- x_agent_kit-0.2.0/tests/test_brain_gemini.py +43 -0
- x_agent_kit-0.2.0/tests/test_brain_openai.py +39 -0
- x_agent_kit-0.2.0/tests/test_builtin_tools.py +93 -0
- x_agent_kit-0.2.0/tests/test_channels.py +49 -0
- x_agent_kit-0.2.0/tests/test_config.py +79 -0
- x_agent_kit-0.2.0/tests/test_conversation.py +38 -0
- x_agent_kit-0.2.0/tests/test_feishu_cards.py +57 -0
- x_agent_kit-0.2.0/tests/test_feishu_message_handler.py +44 -0
- x_agent_kit-0.2.0/tests/test_feishu_plan_handler.py +54 -0
- x_agent_kit-0.2.0/tests/test_i18n.py +76 -0
- x_agent_kit-0.2.0/tests/test_integration.py +36 -0
- x_agent_kit-0.2.0/tests/test_memory.py +102 -0
- x_agent_kit-0.2.0/tests/test_models.py +38 -0
- x_agent_kit-0.2.0/tests/test_plan.py +136 -0
- x_agent_kit-0.2.0/tests/test_plan_cards.py +85 -0
- x_agent_kit-0.2.0/tests/test_plan_tools.py +100 -0
- x_agent_kit-0.2.0/tests/test_progress.py +89 -0
- x_agent_kit-0.2.0/tests/test_scheduler.py +26 -0
- x_agent_kit-0.2.0/tests/test_skills.py +37 -0
- x_agent_kit-0.2.0/tests/test_tools.py +130 -0
- x_agent_kit-0.2.0/x_agent_kit/__init__.py +4 -0
- x_agent_kit-0.2.0/x_agent_kit/agent.py +243 -0
- x_agent_kit-0.2.0/x_agent_kit/approval_queue.py +60 -0
- x_agent_kit-0.2.0/x_agent_kit/brain/__init__.py +0 -0
- x_agent_kit-0.2.0/x_agent_kit/brain/base.py +6 -0
- x_agent_kit-0.2.0/x_agent_kit/brain/claude.py +264 -0
- x_agent_kit-0.2.0/x_agent_kit/brain/gemini.py +56 -0
- x_agent_kit-0.2.0/x_agent_kit/brain/openai_brain.py +38 -0
- x_agent_kit-0.2.0/x_agent_kit/channels/__init__.py +0 -0
- x_agent_kit-0.2.0/x_agent_kit/channels/base.py +16 -0
- x_agent_kit-0.2.0/x_agent_kit/channels/cli_channel.py +45 -0
- x_agent_kit-0.2.0/x_agent_kit/channels/feishu.py +418 -0
- x_agent_kit-0.2.0/x_agent_kit/channels/feishu_cards.py +373 -0
- x_agent_kit-0.2.0/x_agent_kit/config.py +101 -0
- x_agent_kit-0.2.0/x_agent_kit/conversation.py +23 -0
- x_agent_kit-0.2.0/x_agent_kit/i18n/__init__.py +47 -0
- x_agent_kit-0.2.0/x_agent_kit/i18n/en.json +53 -0
- x_agent_kit-0.2.0/x_agent_kit/i18n/zh_CN.json +53 -0
- x_agent_kit-0.2.0/x_agent_kit/memory.py +168 -0
- x_agent_kit-0.2.0/x_agent_kit/models.py +20 -0
- x_agent_kit-0.2.0/x_agent_kit/plan.py +185 -0
- x_agent_kit-0.2.0/x_agent_kit/progress.py +45 -0
- x_agent_kit-0.2.0/x_agent_kit/scheduler.py +26 -0
- x_agent_kit-0.2.0/x_agent_kit/skills/__init__.py +0 -0
- x_agent_kit-0.2.0/x_agent_kit/skills/loader.py +51 -0
- x_agent_kit-0.2.0/x_agent_kit/tools/__init__.py +1 -0
- x_agent_kit-0.2.0/x_agent_kit/tools/base.py +55 -0
- x_agent_kit-0.2.0/x_agent_kit/tools/builtin.py +285 -0
- x_agent_kit-0.2.0/x_agent_kit/tools/registry.py +34 -0
- x_agent_kit-0.2.0/x_agent_kit.egg-info/PKG-INFO +20 -0
- x_agent_kit-0.2.0/x_agent_kit.egg-info/SOURCES.txt +59 -0
- x_agent_kit-0.2.0/x_agent_kit.egg-info/dependency_links.txt +1 -0
- x_agent_kit-0.2.0/x_agent_kit.egg-info/requires.txt +20 -0
- x_agent_kit-0.2.0/x_agent_kit.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: x-agent-kit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Build autonomous AI agents with pluggable brains, tools, skills, and channels
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: pydantic>=2.0.0
|
|
7
|
+
Requires-Dist: loguru>=0.7.0
|
|
8
|
+
Requires-Dist: apscheduler>=3.10.0
|
|
9
|
+
Provides-Extra: gemini
|
|
10
|
+
Requires-Dist: google-genai>=1.0.0; extra == "gemini"
|
|
11
|
+
Provides-Extra: openai
|
|
12
|
+
Requires-Dist: openai>=1.0.0; extra == "openai"
|
|
13
|
+
Provides-Extra: feishu
|
|
14
|
+
Requires-Dist: lark-oapi>=1.5.0; extra == "feishu"
|
|
15
|
+
Requires-Dist: requests>=2.31.0; extra == "feishu"
|
|
16
|
+
Provides-Extra: all
|
|
17
|
+
Requires-Dist: x-agent-kit[feishu,gemini,openai]; extra == "all"
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
|
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
# x-agent-kit
|
|
2
|
+
|
|
3
|
+
Build autonomous AI agents with pluggable brains (LLM providers), tools, skills, and communication channels. Agents can run one-shot tasks or long-running daemons with cron scheduling and bidirectional messaging via Feishu/Lark.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Core only
|
|
9
|
+
pip install x-agent-kit
|
|
10
|
+
|
|
11
|
+
# With specific providers
|
|
12
|
+
pip install x-agent-kit[gemini]
|
|
13
|
+
pip install x-agent-kit[openai]
|
|
14
|
+
pip install x-agent-kit[feishu]
|
|
15
|
+
|
|
16
|
+
# Everything
|
|
17
|
+
pip install x-agent-kit[all]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires Python >= 3.11.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### 1. Create project structure
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
my-agent/
|
|
28
|
+
├── .agent/
|
|
29
|
+
│ ├── settings.json # Agent configuration
|
|
30
|
+
│ ├── skills/ # Markdown knowledge files
|
|
31
|
+
│ └── memory/ # Auto-created, SQLite storage
|
|
32
|
+
└── main.py
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Configure the agent
|
|
36
|
+
|
|
37
|
+
Create `.agent/settings.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"brain": {
|
|
42
|
+
"provider": "gemini",
|
|
43
|
+
"model": "gemini-2.5-flash"
|
|
44
|
+
},
|
|
45
|
+
"providers": {
|
|
46
|
+
"gemini": {
|
|
47
|
+
"type": "api",
|
|
48
|
+
"api_key_env": "GOOGLE_API_KEY",
|
|
49
|
+
"default_model": "gemini-2.5-flash"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"channels": {
|
|
53
|
+
"default": "cli"
|
|
54
|
+
},
|
|
55
|
+
"skills": {
|
|
56
|
+
"paths": [".agent/skills"]
|
|
57
|
+
},
|
|
58
|
+
"agent": {
|
|
59
|
+
"max_iterations": 50
|
|
60
|
+
},
|
|
61
|
+
"memory": {
|
|
62
|
+
"enabled": true,
|
|
63
|
+
"dir": ".agent/memory"
|
|
64
|
+
},
|
|
65
|
+
"locale": "zh_CN"
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. Write your agent
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from x_agent_kit import Agent, tool
|
|
73
|
+
|
|
74
|
+
@tool("Search the web for information", label="🔍 Search")
|
|
75
|
+
def search(query: str) -> str:
|
|
76
|
+
"""
|
|
77
|
+
query: Keywords to search for
|
|
78
|
+
"""
|
|
79
|
+
return f"Results for: {query}"
|
|
80
|
+
|
|
81
|
+
@tool("Save a note to file", label="📝 Save Note")
|
|
82
|
+
def save_note(filename: str, content: str) -> str:
|
|
83
|
+
"""
|
|
84
|
+
filename: Name of the file to save
|
|
85
|
+
content: Text content to write
|
|
86
|
+
"""
|
|
87
|
+
with open(filename, "w") as f:
|
|
88
|
+
f.write(content)
|
|
89
|
+
return f"Saved to {filename}"
|
|
90
|
+
|
|
91
|
+
agent = Agent(config_dir=".agent")
|
|
92
|
+
agent.register_tools([search, save_note])
|
|
93
|
+
result = agent.run("Search for Python best practices and save a summary")
|
|
94
|
+
print(result)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Architecture
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
User / Cron / Feishu Message
|
|
101
|
+
│
|
|
102
|
+
▼
|
|
103
|
+
┌─────────┐
|
|
104
|
+
│ Agent │ ← orchestrator (think → tool_call → execute loop)
|
|
105
|
+
└────┬────┘
|
|
106
|
+
│
|
|
107
|
+
┌────┴─────────────────────┐
|
|
108
|
+
│ │ │
|
|
109
|
+
▼ ▼ ▼
|
|
110
|
+
Brain Tools Channel
|
|
111
|
+
(LLM) (functions) (output)
|
|
112
|
+
│ │ │
|
|
113
|
+
├─ Gemini ├─ @tool defs ├─ CLI
|
|
114
|
+
├─ OpenAI ├─ Built-ins └─ Feishu
|
|
115
|
+
└─ Claude │ (memory,
|
|
116
|
+
│ skills,
|
|
117
|
+
│ plans,
|
|
118
|
+
│ approval)
|
|
119
|
+
│
|
|
120
|
+
┌────┴────┐
|
|
121
|
+
│ │
|
|
122
|
+
Skills Memory
|
|
123
|
+
(.md) (SQLite)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Configuration Reference
|
|
127
|
+
|
|
128
|
+
Full `.agent/settings.json` example with all options:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"brain": {
|
|
133
|
+
"provider": "gemini",
|
|
134
|
+
"model": "gemini-2.5-flash"
|
|
135
|
+
},
|
|
136
|
+
"providers": {
|
|
137
|
+
"gemini": {
|
|
138
|
+
"type": "api",
|
|
139
|
+
"api_key_env": "GOOGLE_API_KEY",
|
|
140
|
+
"default_model": "gemini-2.5-flash"
|
|
141
|
+
},
|
|
142
|
+
"openai": {
|
|
143
|
+
"type": "api",
|
|
144
|
+
"api_key_env": "OPENAI_API_KEY",
|
|
145
|
+
"default_model": "gpt-4o"
|
|
146
|
+
},
|
|
147
|
+
"claude": {
|
|
148
|
+
"type": "cli"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"channels": {
|
|
152
|
+
"default": "cli",
|
|
153
|
+
"feishu": {
|
|
154
|
+
"app_id_env": "LARK_APP_ID",
|
|
155
|
+
"app_secret_env": "LARK_APP_SECRET",
|
|
156
|
+
"default_chat_id_env": "LARK_CHAT_ID"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"skills": {
|
|
160
|
+
"paths": [".agent/skills"]
|
|
161
|
+
},
|
|
162
|
+
"agent": {
|
|
163
|
+
"max_iterations": 50,
|
|
164
|
+
"approval_timeout": 3600
|
|
165
|
+
},
|
|
166
|
+
"memory": {
|
|
167
|
+
"enabled": true,
|
|
168
|
+
"dir": ".agent/memory"
|
|
169
|
+
},
|
|
170
|
+
"locale": "zh_CN",
|
|
171
|
+
"schedules": [
|
|
172
|
+
{"cron": "0 9 * * *", "task": "Run daily analysis"},
|
|
173
|
+
{"cron": "0 */6 * * *", "task": "Check for updates every 6 hours"}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Configuration Fields
|
|
179
|
+
|
|
180
|
+
| Field | Type | Default | Description |
|
|
181
|
+
|-------|------|---------|-------------|
|
|
182
|
+
| `brain.provider` | string | required | Provider name (must exist in `providers`) |
|
|
183
|
+
| `brain.model` | string | `""` | Model override (falls back to provider's `default_model`) |
|
|
184
|
+
| `providers.<name>.type` | string | required | `"api"` for SDK-based, `"cli"` for Claude CLI |
|
|
185
|
+
| `providers.<name>.api_key_env` | string | `""` | Environment variable containing the API key |
|
|
186
|
+
| `providers.<name>.default_model` | string | `""` | Default model for this provider |
|
|
187
|
+
| `channels.default` | string | `"cli"` | Default output channel |
|
|
188
|
+
| `channels.feishu` | object | — | Feishu channel config (see Feishu section) |
|
|
189
|
+
| `skills.paths` | list | `[".agent/skills"]` | Directories to search for skill files |
|
|
190
|
+
| `agent.max_iterations` | int | `50` | Max think-execute cycles per `run()` call |
|
|
191
|
+
| `agent.approval_timeout` | int | `3600` | Timeout (seconds) for approval requests |
|
|
192
|
+
| `memory.enabled` | bool | `true` | Enable persistent memory |
|
|
193
|
+
| `memory.dir` | string | `".agent/memory"` | Directory for SQLite databases |
|
|
194
|
+
| `locale` | string | `"zh_CN"` | UI language (`"zh_CN"` or `"en"`) |
|
|
195
|
+
| `schedules` | list | `[]` | Cron schedules for `serve()` mode |
|
|
196
|
+
|
|
197
|
+
### Environment Variables
|
|
198
|
+
|
|
199
|
+
Set these based on your configured providers:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Gemini
|
|
203
|
+
export GOOGLE_API_KEY="your-key"
|
|
204
|
+
|
|
205
|
+
# OpenAI
|
|
206
|
+
export OPENAI_API_KEY="your-key"
|
|
207
|
+
|
|
208
|
+
# Feishu/Lark
|
|
209
|
+
export LARK_APP_ID="your-app-id"
|
|
210
|
+
export LARK_APP_SECRET="your-app-secret"
|
|
211
|
+
export LARK_CHAT_ID="your-chat-id"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Brains (LLM Providers)
|
|
215
|
+
|
|
216
|
+
### Gemini
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"brain": { "provider": "gemini", "model": "gemini-2.5-flash" },
|
|
221
|
+
"providers": {
|
|
222
|
+
"gemini": { "type": "api", "api_key_env": "GOOGLE_API_KEY" }
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Install: `pip install x-agent-kit[gemini]`
|
|
228
|
+
|
|
229
|
+
### OpenAI
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"brain": { "provider": "openai", "model": "gpt-4o" },
|
|
234
|
+
"providers": {
|
|
235
|
+
"openai": { "type": "api", "api_key_env": "OPENAI_API_KEY" }
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Install: `pip install x-agent-kit[openai]`
|
|
241
|
+
|
|
242
|
+
### Claude (Local CLI)
|
|
243
|
+
|
|
244
|
+
Uses the Claude CLI with stateful sessions — no API key needed, no history re-sending.
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"brain": { "provider": "claude" },
|
|
249
|
+
"providers": {
|
|
250
|
+
"claude": { "type": "cli" }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Requires `claude` CLI installed and authenticated.
|
|
256
|
+
|
|
257
|
+
## Tools
|
|
258
|
+
|
|
259
|
+
### Creating Tools
|
|
260
|
+
|
|
261
|
+
Use the `@tool` decorator on any function. Parameter schemas are auto-generated from type annotations. Parameter descriptions are extracted from docstrings.
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from x_agent_kit import tool
|
|
265
|
+
|
|
266
|
+
@tool("Calculate compound interest", label="💰 Calculate Interest")
|
|
267
|
+
def compound_interest(principal: float, rate: float, years: int) -> str:
|
|
268
|
+
"""
|
|
269
|
+
principal: Initial investment amount in dollars
|
|
270
|
+
rate: Annual interest rate (e.g., 0.05 for 5%)
|
|
271
|
+
years: Number of years to compound
|
|
272
|
+
"""
|
|
273
|
+
result = principal * (1 + rate) ** years
|
|
274
|
+
return f"${result:,.2f}"
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Parameters:**
|
|
278
|
+
|
|
279
|
+
| Parameter | Type | Required | Description |
|
|
280
|
+
|-----------|------|----------|-------------|
|
|
281
|
+
| `description` | str | yes | Tool description sent to the LLM |
|
|
282
|
+
| `label` | str | no | Display label shown in streaming progress cards |
|
|
283
|
+
|
|
284
|
+
**Type mapping:**
|
|
285
|
+
|
|
286
|
+
| Python Type | JSON Schema Type |
|
|
287
|
+
|------------|-----------------|
|
|
288
|
+
| `str` | `"string"` |
|
|
289
|
+
| `int` | `"integer"` |
|
|
290
|
+
| `float` | `"number"` |
|
|
291
|
+
| `bool` | `"boolean"` |
|
|
292
|
+
| `dict` | `"object"` |
|
|
293
|
+
| `list` | `"array"` |
|
|
294
|
+
|
|
295
|
+
Parameters without defaults are marked as `required`. Parameters with defaults include the default value in the schema.
|
|
296
|
+
|
|
297
|
+
### Registering Tools
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
agent = Agent(config_dir=".agent")
|
|
301
|
+
agent.register_tools([compound_interest, search, save_note])
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Built-in Tools
|
|
305
|
+
|
|
306
|
+
When memory is enabled, the agent automatically registers these tools:
|
|
307
|
+
|
|
308
|
+
| Tool | Description |
|
|
309
|
+
|------|-------------|
|
|
310
|
+
| `save_memory` | Save key-value pairs to persistent SQLite storage |
|
|
311
|
+
| `recall_memories` | Recall recent memories from previous sessions |
|
|
312
|
+
| `search_memory` | Full-text search across all memories |
|
|
313
|
+
| `clear_memory` | Delete all stored memories |
|
|
314
|
+
| `load_skill` | Load a markdown skill file by name |
|
|
315
|
+
| `list_skills` | List all available skill names |
|
|
316
|
+
| `notify` | Send a message to the user via the configured channel |
|
|
317
|
+
| `request_approval` | Submit an action for human approval |
|
|
318
|
+
| `create_plan` | Create a structured multi-step execution plan |
|
|
319
|
+
| `submit_plan` | Send a plan for human approval via interactive card |
|
|
320
|
+
| `get_plan` | Retrieve plan status and step details |
|
|
321
|
+
| `execute_approved_steps` | Execute all approved steps in a plan |
|
|
322
|
+
| `update_step` | Modify a plan step after rejection/negotiation |
|
|
323
|
+
| `resubmit_step` | Resubmit a modified step for re-approval |
|
|
324
|
+
|
|
325
|
+
## Skills
|
|
326
|
+
|
|
327
|
+
Skills are markdown files that provide domain knowledge to the agent on demand. The LLM decides when to load them.
|
|
328
|
+
|
|
329
|
+
### Standalone Skill
|
|
330
|
+
|
|
331
|
+
Create `.agent/skills/my-topic.md`:
|
|
332
|
+
|
|
333
|
+
```markdown
|
|
334
|
+
# My Topic
|
|
335
|
+
|
|
336
|
+
Expert knowledge about this topic.
|
|
337
|
+
|
|
338
|
+
## Key Rules
|
|
339
|
+
- Rule 1: Always do X
|
|
340
|
+
- Rule 2: Never do Y
|
|
341
|
+
|
|
342
|
+
## Reference Data
|
|
343
|
+
| Metric | Target |
|
|
344
|
+
|--------|--------|
|
|
345
|
+
| CPA | < $50 |
|
|
346
|
+
| ROAS | > 3.0 |
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Directory Skill (with references)
|
|
350
|
+
|
|
351
|
+
For complex skills with multiple reference files:
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
.agent/skills/ad-optimization/
|
|
355
|
+
├── SKILL.md # Main skill content
|
|
356
|
+
└── references/
|
|
357
|
+
├── bidding-guide.md # Additional reference
|
|
358
|
+
└── audience-tips.md # Additional reference
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
All reference files are automatically concatenated when the skill is loaded.
|
|
362
|
+
|
|
363
|
+
### How Skills Work
|
|
364
|
+
|
|
365
|
+
1. Agent starts with `list_skills` and `load_skill` tools registered
|
|
366
|
+
2. LLM sees available skills and decides when domain knowledge is needed
|
|
367
|
+
3. LLM calls `load_skill(name="my-topic")` to inject the content
|
|
368
|
+
4. Duplicate loads within the same run are automatically skipped
|
|
369
|
+
|
|
370
|
+
## Memory
|
|
371
|
+
|
|
372
|
+
SQLite-backed persistent memory with FTS5 full-text search. Memories persist across agent runs.
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
# The agent automatically uses memory tools:
|
|
376
|
+
# save_memory(key="analysis-2024-01", content="...")
|
|
377
|
+
# search_memory(query="campaign performance")
|
|
378
|
+
# recall_memories() # recent entries
|
|
379
|
+
|
|
380
|
+
# Memory summary is prepended to each task automatically
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### How It Works
|
|
384
|
+
|
|
385
|
+
- Stored in `{memory.dir}/memory.db` (SQLite with FTS5)
|
|
386
|
+
- Each entry has: `key`, `content`, `timestamp`
|
|
387
|
+
- `search_memory` uses full-text search with automatic fallback to LIKE queries
|
|
388
|
+
- `recall_memories` returns a formatted summary of recent entries
|
|
389
|
+
- Memory summary is automatically prepended to each `run()` call
|
|
390
|
+
|
|
391
|
+
## Plan System
|
|
392
|
+
|
|
393
|
+
The plan system enables structured, multi-step execution with human approval via interactive Feishu cards.
|
|
394
|
+
|
|
395
|
+
### Lifecycle
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
draft → pending_approval → partial_approved → executing → completed
|
|
399
|
+
↓
|
|
400
|
+
cancelled
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### How It Works
|
|
404
|
+
|
|
405
|
+
1. LLM analyzes data and calls `create_plan()` with structured steps
|
|
406
|
+
2. Each step has: `action`, `tool_name`, `tool_args`, `priority`, `risk_level`
|
|
407
|
+
3. `submit_plan()` sends an interactive card to Feishu with per-step approve/reject buttons
|
|
408
|
+
4. Human reviews each step individually
|
|
409
|
+
5. Approved steps are auto-executed immediately
|
|
410
|
+
6. Rejected steps can be modified and resubmitted
|
|
411
|
+
|
|
412
|
+
### Plan Types
|
|
413
|
+
|
|
414
|
+
Plan types are customizable via locale files. Default types:
|
|
415
|
+
|
|
416
|
+
| Type | Label (zh_CN) | Label (en) |
|
|
417
|
+
|------|---------------|------------|
|
|
418
|
+
| `daily` | 日常计划 | Daily Plan |
|
|
419
|
+
| `weekly` | 周度策略 | Weekly Strategy |
|
|
420
|
+
| `monthly` | 月度复盘 | Monthly Review |
|
|
421
|
+
|
|
422
|
+
Business agents can add custom types by extending locale files.
|
|
423
|
+
|
|
424
|
+
## Channels
|
|
425
|
+
|
|
426
|
+
### CLI Channel
|
|
427
|
+
|
|
428
|
+
Terminal output with formatted cards and interactive approval prompts.
|
|
429
|
+
|
|
430
|
+
```json
|
|
431
|
+
{ "channels": { "default": "cli" } }
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Feishu/Lark Channel
|
|
435
|
+
|
|
436
|
+
Full integration with Feishu including:
|
|
437
|
+
|
|
438
|
+
- **Streaming cards** — Real-time progress updates during agent execution
|
|
439
|
+
- **Interactive approval cards** — Per-step approve/reject buttons for plans
|
|
440
|
+
- **@mention detection** — In group chats, only responds when @mentioned
|
|
441
|
+
- **Emoji reactions** — Shows "OnIt" while processing, "DONE" when complete
|
|
442
|
+
- **Markdown rendering** — Long responses rendered as rich cards
|
|
443
|
+
- **WebSocket** — Real-time bidirectional messaging
|
|
444
|
+
|
|
445
|
+
```json
|
|
446
|
+
{
|
|
447
|
+
"channels": {
|
|
448
|
+
"default": "feishu",
|
|
449
|
+
"feishu": {
|
|
450
|
+
"app_id_env": "LARK_APP_ID",
|
|
451
|
+
"app_secret_env": "LARK_APP_SECRET",
|
|
452
|
+
"default_chat_id_env": "LARK_CHAT_ID"
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Install: `pip install x-agent-kit[feishu]`
|
|
459
|
+
|
|
460
|
+
## Running Modes
|
|
461
|
+
|
|
462
|
+
### One-shot Mode
|
|
463
|
+
|
|
464
|
+
Execute a single task and exit:
|
|
465
|
+
|
|
466
|
+
```python
|
|
467
|
+
agent = Agent(config_dir=".agent")
|
|
468
|
+
result = agent.run("Analyze today's performance data")
|
|
469
|
+
print(result)
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Serve Mode (Daemon)
|
|
473
|
+
|
|
474
|
+
Run as a long-lived process with cron scheduling and Feishu message handling:
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
agent = Agent(config_dir=".agent")
|
|
478
|
+
|
|
479
|
+
# Starts cron jobs from config + Feishu WebSocket listener
|
|
480
|
+
agent.serve()
|
|
481
|
+
|
|
482
|
+
# Keep alive
|
|
483
|
+
import time
|
|
484
|
+
try:
|
|
485
|
+
while True:
|
|
486
|
+
time.sleep(60)
|
|
487
|
+
except KeyboardInterrupt:
|
|
488
|
+
print("Stopped.")
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Schedules are configured in `settings.json`:
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
{
|
|
495
|
+
"schedules": [
|
|
496
|
+
{"cron": "0 9 * * *", "task": "Run morning analysis and send report"},
|
|
497
|
+
{"cron": "0 */6 * * *", "task": "Check metrics and alert if anomalies found"}
|
|
498
|
+
]
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
In serve mode, incoming Feishu messages trigger `agent.run()` with conversation context, enabling multi-turn dialogue.
|
|
503
|
+
|
|
504
|
+
## i18n (Internationalization)
|
|
505
|
+
|
|
506
|
+
The framework supports multiple languages. Default is Chinese (`zh_CN`), English (`en`) is also included.
|
|
507
|
+
|
|
508
|
+
### Switch Language
|
|
509
|
+
|
|
510
|
+
In `settings.json`:
|
|
511
|
+
|
|
512
|
+
```json
|
|
513
|
+
{ "locale": "en" }
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Extend with Custom Translations
|
|
517
|
+
|
|
518
|
+
Business agents can add their own translations without modifying the framework:
|
|
519
|
+
|
|
520
|
+
```python
|
|
521
|
+
from x_agent_kit.i18n import load_extra_locale
|
|
522
|
+
|
|
523
|
+
# Merge custom keys into current locale
|
|
524
|
+
load_extra_locale("path/to/my_translations.json")
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Custom locale file example:
|
|
528
|
+
|
|
529
|
+
```json
|
|
530
|
+
{
|
|
531
|
+
"plan.type.quarterly": "Quarterly Review",
|
|
532
|
+
"plan.type.campaign_launch": "Campaign Launch Plan"
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Programmatic API
|
|
537
|
+
|
|
538
|
+
```python
|
|
539
|
+
from x_agent_kit.i18n import t, set_locale, get_locale
|
|
540
|
+
|
|
541
|
+
set_locale("en")
|
|
542
|
+
print(t("agent.thinking")) # "🤔 Thinking..."
|
|
543
|
+
print(t("plan.pending_count",
|
|
544
|
+
pending=3, total=5)) # "3 pending / 5 total"
|
|
545
|
+
print(t("custom.key",
|
|
546
|
+
default="fallback")) # "fallback" if key missing
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Custom Stop Conditions
|
|
550
|
+
|
|
551
|
+
By default, the agent loop runs until the brain signals `done` or `max_iterations` is reached. You can inject custom termination logic:
|
|
552
|
+
|
|
553
|
+
```python
|
|
554
|
+
# Stop after memory is saved (useful for analysis-then-save workflows)
|
|
555
|
+
agent = Agent(
|
|
556
|
+
config_dir=".agent",
|
|
557
|
+
stop_condition=lambda tool_name, result: tool_name == "save_memory"
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
# Stop after any approval is submitted
|
|
561
|
+
agent = Agent(
|
|
562
|
+
config_dir=".agent",
|
|
563
|
+
stop_condition=lambda tool_name, result: tool_name == "request_approval"
|
|
564
|
+
)
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
The callback receives `(tool_name: str, result: Any)` after each tool execution and returns `bool`.
|
|
568
|
+
|
|
569
|
+
## Complete Example
|
|
570
|
+
|
|
571
|
+
Here's a full example of a data analysis agent:
|
|
572
|
+
|
|
573
|
+
```python
|
|
574
|
+
import json
|
|
575
|
+
from x_agent_kit import Agent, tool
|
|
576
|
+
|
|
577
|
+
# Define domain-specific tools
|
|
578
|
+
@tool("Query sales data for a date range", label="📊 Query Sales")
|
|
579
|
+
def query_sales(start_date: str, end_date: str) -> str:
|
|
580
|
+
"""
|
|
581
|
+
start_date: Start date in YYYY-MM-DD format
|
|
582
|
+
end_date: End date in YYYY-MM-DD format
|
|
583
|
+
"""
|
|
584
|
+
# Your data source here
|
|
585
|
+
return json.dumps({"total": 15000, "orders": 342})
|
|
586
|
+
|
|
587
|
+
@tool("Generate a report from data", label="📄 Generate Report")
|
|
588
|
+
def generate_report(title: str, data: str) -> str:
|
|
589
|
+
"""
|
|
590
|
+
title: Report title
|
|
591
|
+
data: JSON data to include in the report
|
|
592
|
+
"""
|
|
593
|
+
return f"Report '{title}' generated with {len(data)} chars of data"
|
|
594
|
+
|
|
595
|
+
# Create agent with custom stop condition
|
|
596
|
+
agent = Agent(
|
|
597
|
+
config_dir=".agent",
|
|
598
|
+
stop_condition=lambda name, _: name == "save_memory"
|
|
599
|
+
)
|
|
600
|
+
agent.register_tools([query_sales, generate_report])
|
|
601
|
+
|
|
602
|
+
# One-shot execution
|
|
603
|
+
result = agent.run("Analyze last week's sales and generate a summary report")
|
|
604
|
+
print(result)
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
## Development
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
# Clone the repo
|
|
611
|
+
git clone https://github.com/your-org/x-agent-kit.git
|
|
612
|
+
cd x-agent-kit
|
|
613
|
+
|
|
614
|
+
# Install with dev dependencies
|
|
615
|
+
pip install -e ".[dev]"
|
|
616
|
+
|
|
617
|
+
# Run all tests
|
|
618
|
+
pytest
|
|
619
|
+
|
|
620
|
+
# Run a specific test file
|
|
621
|
+
pytest tests/test_agent.py -v
|
|
622
|
+
|
|
623
|
+
# Run a specific test
|
|
624
|
+
pytest tests/test_tools.py::TestToolLabel::test_tool_with_label -v
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## License
|
|
628
|
+
|
|
629
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "x-agent-kit"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Build autonomous AI agents with pluggable brains, tools, skills, and channels"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"pydantic>=2.0.0",
|
|
12
|
+
"loguru>=0.7.0",
|
|
13
|
+
"apscheduler>=3.10.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
gemini = ["google-genai>=1.0.0"]
|
|
18
|
+
openai = ["openai>=1.0.0"]
|
|
19
|
+
feishu = ["lark-oapi>=1.5.0", "requests>=2.31.0"]
|
|
20
|
+
all = ["x-agent-kit[gemini,openai,feishu]"]
|
|
21
|
+
dev = ["pytest>=8.0.0", "pytest-mock>=3.12.0"]
|
|
22
|
+
|
|
23
|
+
[tool.pytest.ini_options]
|
|
24
|
+
testpaths = ["tests"]
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.packages.find]
|
|
27
|
+
where = ["."]
|
|
28
|
+
include = ["x_agent_kit*"]
|
|
29
|
+
|
|
30
|
+
[tool.setuptools.package-data]
|
|
31
|
+
"x_agent_kit.i18n" = ["*.json"]
|