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.
Files changed (61) hide show
  1. x_agent_kit-0.2.0/PKG-INFO +20 -0
  2. x_agent_kit-0.2.0/README.md +629 -0
  3. x_agent_kit-0.2.0/pyproject.toml +31 -0
  4. x_agent_kit-0.2.0/setup.cfg +4 -0
  5. x_agent_kit-0.2.0/tests/test_agent.py +85 -0
  6. x_agent_kit-0.2.0/tests/test_approval_queue.py +44 -0
  7. x_agent_kit-0.2.0/tests/test_brain_claude.py +98 -0
  8. x_agent_kit-0.2.0/tests/test_brain_gemini.py +43 -0
  9. x_agent_kit-0.2.0/tests/test_brain_openai.py +39 -0
  10. x_agent_kit-0.2.0/tests/test_builtin_tools.py +93 -0
  11. x_agent_kit-0.2.0/tests/test_channels.py +49 -0
  12. x_agent_kit-0.2.0/tests/test_config.py +79 -0
  13. x_agent_kit-0.2.0/tests/test_conversation.py +38 -0
  14. x_agent_kit-0.2.0/tests/test_feishu_cards.py +57 -0
  15. x_agent_kit-0.2.0/tests/test_feishu_message_handler.py +44 -0
  16. x_agent_kit-0.2.0/tests/test_feishu_plan_handler.py +54 -0
  17. x_agent_kit-0.2.0/tests/test_i18n.py +76 -0
  18. x_agent_kit-0.2.0/tests/test_integration.py +36 -0
  19. x_agent_kit-0.2.0/tests/test_memory.py +102 -0
  20. x_agent_kit-0.2.0/tests/test_models.py +38 -0
  21. x_agent_kit-0.2.0/tests/test_plan.py +136 -0
  22. x_agent_kit-0.2.0/tests/test_plan_cards.py +85 -0
  23. x_agent_kit-0.2.0/tests/test_plan_tools.py +100 -0
  24. x_agent_kit-0.2.0/tests/test_progress.py +89 -0
  25. x_agent_kit-0.2.0/tests/test_scheduler.py +26 -0
  26. x_agent_kit-0.2.0/tests/test_skills.py +37 -0
  27. x_agent_kit-0.2.0/tests/test_tools.py +130 -0
  28. x_agent_kit-0.2.0/x_agent_kit/__init__.py +4 -0
  29. x_agent_kit-0.2.0/x_agent_kit/agent.py +243 -0
  30. x_agent_kit-0.2.0/x_agent_kit/approval_queue.py +60 -0
  31. x_agent_kit-0.2.0/x_agent_kit/brain/__init__.py +0 -0
  32. x_agent_kit-0.2.0/x_agent_kit/brain/base.py +6 -0
  33. x_agent_kit-0.2.0/x_agent_kit/brain/claude.py +264 -0
  34. x_agent_kit-0.2.0/x_agent_kit/brain/gemini.py +56 -0
  35. x_agent_kit-0.2.0/x_agent_kit/brain/openai_brain.py +38 -0
  36. x_agent_kit-0.2.0/x_agent_kit/channels/__init__.py +0 -0
  37. x_agent_kit-0.2.0/x_agent_kit/channels/base.py +16 -0
  38. x_agent_kit-0.2.0/x_agent_kit/channels/cli_channel.py +45 -0
  39. x_agent_kit-0.2.0/x_agent_kit/channels/feishu.py +418 -0
  40. x_agent_kit-0.2.0/x_agent_kit/channels/feishu_cards.py +373 -0
  41. x_agent_kit-0.2.0/x_agent_kit/config.py +101 -0
  42. x_agent_kit-0.2.0/x_agent_kit/conversation.py +23 -0
  43. x_agent_kit-0.2.0/x_agent_kit/i18n/__init__.py +47 -0
  44. x_agent_kit-0.2.0/x_agent_kit/i18n/en.json +53 -0
  45. x_agent_kit-0.2.0/x_agent_kit/i18n/zh_CN.json +53 -0
  46. x_agent_kit-0.2.0/x_agent_kit/memory.py +168 -0
  47. x_agent_kit-0.2.0/x_agent_kit/models.py +20 -0
  48. x_agent_kit-0.2.0/x_agent_kit/plan.py +185 -0
  49. x_agent_kit-0.2.0/x_agent_kit/progress.py +45 -0
  50. x_agent_kit-0.2.0/x_agent_kit/scheduler.py +26 -0
  51. x_agent_kit-0.2.0/x_agent_kit/skills/__init__.py +0 -0
  52. x_agent_kit-0.2.0/x_agent_kit/skills/loader.py +51 -0
  53. x_agent_kit-0.2.0/x_agent_kit/tools/__init__.py +1 -0
  54. x_agent_kit-0.2.0/x_agent_kit/tools/base.py +55 -0
  55. x_agent_kit-0.2.0/x_agent_kit/tools/builtin.py +285 -0
  56. x_agent_kit-0.2.0/x_agent_kit/tools/registry.py +34 -0
  57. x_agent_kit-0.2.0/x_agent_kit.egg-info/PKG-INFO +20 -0
  58. x_agent_kit-0.2.0/x_agent_kit.egg-info/SOURCES.txt +59 -0
  59. x_agent_kit-0.2.0/x_agent_kit.egg-info/dependency_links.txt +1 -0
  60. x_agent_kit-0.2.0/x_agent_kit.egg-info/requires.txt +20 -0
  61. 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"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+