fastclaw-ai 1.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.
Files changed (40) hide show
  1. fastclaw_ai-1.1.0/PKG-INFO +114 -0
  2. fastclaw_ai-1.1.0/fastclaw/README.md +80 -0
  3. fastclaw_ai-1.1.0/fastclaw/__init__.py +32 -0
  4. fastclaw_ai-1.1.0/fastclaw/__main__.py +18 -0
  5. fastclaw_ai-1.1.0/fastclaw/cli.py +231 -0
  6. fastclaw_ai-1.1.0/fastclaw/core/__init__.py +43 -0
  7. fastclaw_ai-1.1.0/fastclaw/core/app.py +778 -0
  8. fastclaw_ai-1.1.0/fastclaw/core/config.py +86 -0
  9. fastclaw_ai-1.1.0/fastclaw/core/paths.py +21 -0
  10. fastclaw_ai-1.1.0/fastclaw/core/prompts.py +110 -0
  11. fastclaw_ai-1.1.0/fastclaw/gateway/__init__.py +10 -0
  12. fastclaw_ai-1.1.0/fastclaw/gateway/channels/__init__.py +17 -0
  13. fastclaw_ai-1.1.0/fastclaw/gateway/channels/base.py +53 -0
  14. fastclaw_ai-1.1.0/fastclaw/gateway/channels/client.py +166 -0
  15. fastclaw_ai-1.1.0/fastclaw/gateway/channels/feishu.py +431 -0
  16. fastclaw_ai-1.1.0/fastclaw/gateway/channels/handlers.py +312 -0
  17. fastclaw_ai-1.1.0/fastclaw/gateway/channels/imessage.py +151 -0
  18. fastclaw_ai-1.1.0/fastclaw/gateway/channels/telegram.py +183 -0
  19. fastclaw_ai-1.1.0/fastclaw/gateway/cron_scheduler.py +264 -0
  20. fastclaw_ai-1.1.0/fastclaw/gateway/event_bus.py +93 -0
  21. fastclaw_ai-1.1.0/fastclaw/gateway/router.py +1084 -0
  22. fastclaw_ai-1.1.0/fastclaw/gateway/server.py +178 -0
  23. fastclaw_ai-1.1.0/fastclaw/main.py +406 -0
  24. fastclaw_ai-1.1.0/fastclaw/webui/index.html +1236 -0
  25. fastclaw_ai-1.1.0/fastclaw/webui/static/css/element-plus-theme.css +1 -0
  26. fastclaw_ai-1.1.0/fastclaw/webui/static/css/element-plus.css +1 -0
  27. fastclaw_ai-1.1.0/fastclaw/webui/static/js/element-plus-icons.min.js +3 -0
  28. fastclaw_ai-1.1.0/fastclaw/webui/static/js/element-plus-zh-cn.min.js +2 -0
  29. fastclaw_ai-1.1.0/fastclaw/webui/static/js/element-plus.full.min.js +72 -0
  30. fastclaw_ai-1.1.0/fastclaw/webui/static/js/marked.min.js +69 -0
  31. fastclaw_ai-1.1.0/fastclaw/webui/static/js/vue3.prod.js +11 -0
  32. fastclaw_ai-1.1.0/fastclaw/webui/test.html +23 -0
  33. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/PKG-INFO +114 -0
  34. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/SOURCES.txt +38 -0
  35. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/dependency_links.txt +1 -0
  36. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/entry_points.txt +2 -0
  37. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/requires.txt +13 -0
  38. fastclaw_ai-1.1.0/fastclaw_ai.egg-info/top_level.txt +1 -0
  39. fastclaw_ai-1.1.0/pyproject.toml +69 -0
  40. fastclaw_ai-1.1.0/setup.cfg +4 -0
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastclaw-ai
3
+ Version: 1.1.0
4
+ Summary: FastClaw - AI Agent Framework with multi-channel support
5
+ Author: kandada
6
+ License: GPL-3.0
7
+ Project-URL: Homepage, https://github.com/kandada/fastclaw
8
+ Project-URL: Repository, https://github.com/kandada/fastclaw.git
9
+ Project-URL: Issues, https://github.com/kandada/fastclaw/issues
10
+ Project-URL: Documentation, https://github.com/kandada/fastclaw#readme
11
+ Keywords: ai,agent,llm,chatbot,fastmind
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: fastmind>=0.1.9
23
+ Requires-Dist: openai>=1.0.0
24
+ Requires-Dist: websockets>=10.0
25
+ Requires-Dist: fastapi>=0.100.0
26
+ Requires-Dist: uvicorn[standard]>=0.35.0
27
+ Requires-Dist: httpx>=0.23.0
28
+ Requires-Dist: anyio>=4.5
29
+ Requires-Dist: croniter>=6.2.0
30
+ Requires-Dist: lark-oapi>=1.0.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
33
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
34
+
35
+ # FastClaw
36
+
37
+ a python-based light but strong lobster
38
+
39
+ ## Design Philosophy
40
+
41
+ FastClaw is built on the core concept of **event-driven agent orchestration**. Key design principles:
42
+
43
+ - **Graph-based Agent**: Uses a directed graph to orchestrate agent behavior, supporting conditional branching between nodes (e.g., tool execution, response generation)
44
+ - **Event Streaming**: Real-time streaming output of LLM responses for better user experience
45
+ - **Tool System**: Extensible tool framework supporting Shell commands, skills, and custom integrations
46
+ - **Session Management**: Persistent conversation history with multi-session support
47
+ - **Cron Scheduling**: Built-in cron-style task scheduling for automated workflows
48
+
49
+ ## Quick Start
50
+
51
+ ### Installation
52
+
53
+ ```bash
54
+ git clone https://github.com/kandada/fastclaw.git
55
+ cd fastclaw
56
+ pip install -r requirements.txt
57
+ ```
58
+
59
+ ### Start Server
60
+
61
+ ```bash
62
+ python main.py start
63
+ # or want it remaining in background:
64
+ nohup python main.py start > fastclaw.log 2>&1 &
65
+ ```
66
+
67
+ ### Agent Configuration
68
+ ```bash
69
+ vim workspace/data/agents/main_agent/metadata.json
70
+ # Edit the file to configure your LLM provider and API key
71
+ # Currently supports OpenAI gateway models (DeepSeek, OpenAI, etc.), recommended: deepseek-chat
72
+ # Default agent is main_agent. To switch, modify workspace/data/settings.json
73
+ ```
74
+
75
+ Access at http://localhost:8765
76
+ You can also select agents and enter API keys in the Settings page.
77
+ API key must be provided for the agent to work properly.
78
+
79
+ ### CLI Usage
80
+
81
+ ```bash
82
+ # Interactive chat
83
+ python main.py chat
84
+
85
+ # New session
86
+ python main.py chat --new
87
+
88
+ # Check status
89
+ python main.py status
90
+ ```
91
+
92
+ ## Features
93
+
94
+ - 🤖 **LLM-powered** - Built on [FastMind](https://github.com/kandada/fastmind) framework with streaming support
95
+ - 🔧 **Tool Calling** - Execute Shell commands, skills, and more
96
+ - ⏰ **Cron Jobs** - Schedule tasks with cron expressions
97
+ - 💬 **Multi-channel** - Feishu, iMessage integrations
98
+ - 🎨 **Extensible** - Easy to add custom skills and agents
99
+
100
+ ## License
101
+
102
+ GPL-3.0
103
+
104
+ ## Acknowledgments
105
+
106
+ Inspired by [OpenClaw](https://github.com/openclaw/openclaw). Special thanks to the open source community.
107
+
108
+ ---
109
+
110
+ FastClaw is powerful, but its use depends entirely on the user - all responsibility lies with the user yourself.
111
+
112
+ ---
113
+
114
+ Author:[xiefujin](https://github.com/kandada) email: 490021684@qq.com,welcome to contact me.
@@ -0,0 +1,80 @@
1
+ # FastClaw
2
+
3
+ a python-based light but strong lobster
4
+
5
+ ## Design Philosophy
6
+
7
+ FastClaw is built on the core concept of **event-driven agent orchestration**. Key design principles:
8
+
9
+ - **Graph-based Agent**: Uses a directed graph to orchestrate agent behavior, supporting conditional branching between nodes (e.g., tool execution, response generation)
10
+ - **Event Streaming**: Real-time streaming output of LLM responses for better user experience
11
+ - **Tool System**: Extensible tool framework supporting Shell commands, skills, and custom integrations
12
+ - **Session Management**: Persistent conversation history with multi-session support
13
+ - **Cron Scheduling**: Built-in cron-style task scheduling for automated workflows
14
+
15
+ ## Quick Start
16
+
17
+ ### Installation
18
+
19
+ ```bash
20
+ git clone https://github.com/kandada/fastclaw.git
21
+ cd fastclaw
22
+ pip install -r requirements.txt
23
+ ```
24
+
25
+ ### Start Server
26
+
27
+ ```bash
28
+ python main.py start
29
+ # or want it remaining in background:
30
+ nohup python main.py start > fastclaw.log 2>&1 &
31
+ ```
32
+
33
+ ### Agent Configuration
34
+ ```bash
35
+ vim workspace/data/agents/main_agent/metadata.json
36
+ # Edit the file to configure your LLM provider and API key
37
+ # Currently supports OpenAI gateway models (DeepSeek, OpenAI, etc.), recommended: deepseek-chat
38
+ # Default agent is main_agent. To switch, modify workspace/data/settings.json
39
+ ```
40
+
41
+ Access at http://localhost:8765
42
+ You can also select agents and enter API keys in the Settings page.
43
+ API key must be provided for the agent to work properly.
44
+
45
+ ### CLI Usage
46
+
47
+ ```bash
48
+ # Interactive chat
49
+ python main.py chat
50
+
51
+ # New session
52
+ python main.py chat --new
53
+
54
+ # Check status
55
+ python main.py status
56
+ ```
57
+
58
+ ## Features
59
+
60
+ - 🤖 **LLM-powered** - Built on [FastMind](https://github.com/kandada/fastmind) framework with streaming support
61
+ - 🔧 **Tool Calling** - Execute Shell commands, skills, and more
62
+ - ⏰ **Cron Jobs** - Schedule tasks with cron expressions
63
+ - 💬 **Multi-channel** - Feishu, iMessage integrations
64
+ - 🎨 **Extensible** - Easy to add custom skills and agents
65
+
66
+ ## License
67
+
68
+ GPL-3.0
69
+
70
+ ## Acknowledgments
71
+
72
+ Inspired by [OpenClaw](https://github.com/openclaw/openclaw). Special thanks to the open source community.
73
+
74
+ ---
75
+
76
+ FastClaw is powerful, but its use depends entirely on the user - all responsibility lies with the user yourself.
77
+
78
+ ---
79
+
80
+ Author:[xiefujin](https://github.com/kandada) email: 490021684@qq.com,welcome to contact me.
@@ -0,0 +1,32 @@
1
+ """
2
+ FastClaw - AI Agent Framework
3
+
4
+ 支持三种运行方式:
5
+ 1. 直接运行: cd fastclaw && python main.py
6
+ 2. 模块运行: python -m fastclaw
7
+ 3. pip 安装后: fastclaw start
8
+ """
9
+
10
+ __version__ = "1.1.0"
11
+
12
+ import os
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ # ===== 路径处理 =====
17
+
18
+ _PKG_DIR = Path(__file__).resolve().parent
19
+ _PROJECT_ROOT = _PKG_DIR.parent
20
+
21
+ # 设置默认 FASTCLAW_WORKSPACE 环境变量
22
+ # 优先级:已设置的环境变量 > 项目根目录的 workspace/ > ~/.fastclaw/workspace
23
+ _default_workspace = _PROJECT_ROOT / "workspace"
24
+ if os.environ.get("FASTCLAW_WORKSPACE") is None:
25
+ if _default_workspace.exists() and _default_workspace.is_dir():
26
+ os.environ["FASTCLAW_WORKSPACE"] = str(_default_workspace)
27
+ else:
28
+ os.environ["FASTCLAW_WORKSPACE"] = str(Path.home() / ".fastclaw" / "workspace")
29
+
30
+ # 确保项目根目录在 sys.path(用于直接运行模式)
31
+ if str(_PROJECT_ROOT) not in sys.path:
32
+ sys.path.insert(0, str(_PROJECT_ROOT))
@@ -0,0 +1,18 @@
1
+ """
2
+ 支持 python -m fastclaw 运行
3
+ """
4
+
5
+ import sys
6
+ import asyncio
7
+ from pathlib import Path
8
+
9
+ _PKG_DIR = Path(__file__).resolve().parent
10
+ _PROJECT_ROOT = _PKG_DIR.parent
11
+
12
+ if str(_PROJECT_ROOT) not in sys.path:
13
+ sys.path.insert(0, str(_PROJECT_ROOT))
14
+
15
+ from fastclaw.main import main as fastclaw_main
16
+
17
+ if __name__ == "__main__":
18
+ asyncio.run(fastclaw_main())
@@ -0,0 +1,231 @@
1
+ # cli.py
2
+ """FastClaw 命令行界面"""
3
+
4
+ import asyncio
5
+ import sys
6
+ import logging
7
+ import uuid
8
+ from pathlib import Path
9
+
10
+ try:
11
+ from termcolor import colored
12
+ except ImportError:
13
+
14
+ def colored(text, color=None):
15
+ return text
16
+
17
+
18
+ from fastmind import Event
19
+
20
+ if __package__ in (None, ""):
21
+ from core.app import start
22
+ from gateway.channels.handlers import (
23
+ handle_channel_command,
24
+ load_sessions,
25
+ save_sessions,
26
+ get_last_session,
27
+ )
28
+ else:
29
+ from .core.app import start
30
+ from .gateway.channels.handlers import (
31
+ handle_channel_command,
32
+ load_sessions,
33
+ save_sessions,
34
+ get_last_session,
35
+ )
36
+
37
+ logging.disable(logging.WARNING)
38
+
39
+
40
+ def create_cli_session():
41
+ """创建 CLI 会话并保存到 sessions.json"""
42
+ sessions = load_sessions()
43
+ new_session_id = f"cli_{uuid.uuid4().hex[:8]}"
44
+ sessions[new_session_id] = {
45
+ "session_id": new_session_id,
46
+ "agent_id": "main_agent",
47
+ "created_at": str(uuid.uuid4()),
48
+ "last_active_time": int(__import__("time").time()),
49
+ }
50
+ save_sessions(sessions)
51
+ return new_session_id
52
+
53
+
54
+ async def chat(new_session=False, session_id=None):
55
+ """交互式对话"""
56
+ api = await start()
57
+ if session_id:
58
+ pass
59
+ elif new_session:
60
+ session_id = create_cli_session()
61
+ else:
62
+ last_session = get_last_session("cli")
63
+ if last_session:
64
+ session_id = last_session
65
+ else:
66
+ session_id = create_cli_session()
67
+
68
+ print("=" * 50)
69
+ print("FastClaw CLI (输入 'quit' 退出)")
70
+ print("支持命令: /new, /clear, /session <id>, /session_list")
71
+ print("=" * 50)
72
+
73
+ async def consume_stream():
74
+ """消费流式输出事件"""
75
+ buffer = ""
76
+ thinking_buffer = ""
77
+ thinking_shown = False
78
+ try:
79
+ async for event in api.stream_events(session_id):
80
+ if event.type == "stream.thinking":
81
+ delta = event.payload.get("delta", "")
82
+ delta_clean = delta.replace("\n", " ").replace("\r", " ")
83
+ if not thinking_shown:
84
+ thinking_shown = True
85
+ thinking_buffer = ""
86
+ print(f"{colored('[思考中...] ', 'cyan')}", end="", flush=True)
87
+ thinking_buffer += delta_clean
88
+ display_text = thinking_buffer[:200]
89
+ print(
90
+ f"\r{colored('[思考中...] ', 'cyan')}{display_text}",
91
+ end="",
92
+ flush=True,
93
+ )
94
+ elif event.type == "stream.chunk":
95
+ if thinking_shown:
96
+ print("\r" + " " * 80, end="", flush=True)
97
+ print("\r", end="", flush=True)
98
+ thinking_shown = False
99
+ thinking_buffer = ""
100
+ delta = event.payload.get("delta", "")
101
+ buffer += delta
102
+ try:
103
+ print(delta, end="", flush=True)
104
+ except (UnicodeEncodeError, UnicodeDecodeError):
105
+ safe_delta = delta.encode("utf-8", errors="replace").decode(
106
+ "utf-8", errors="replace"
107
+ )
108
+ print(safe_delta, end="", flush=True)
109
+ elif event.type == "stream.fragment":
110
+ if thinking_shown:
111
+ print("\r" + " " * 80, end="", flush=True)
112
+ print("\r", end="", flush=True)
113
+ thinking_shown = False
114
+ thinking_buffer = ""
115
+ tool_calls = event.payload.get("tool_calls", [])
116
+ if tool_calls:
117
+ seen = set()
118
+ unique_names = []
119
+ for tc in tool_calls:
120
+ name = tc.get("function", {}).get("name", "unknown")
121
+ if name not in seen:
122
+ seen.add(name)
123
+ unique_names.append(name)
124
+ print(f"[执行工具: {', '.join(unique_names)}]")
125
+ content = event.payload.get("content", "")
126
+ if content:
127
+ pass
128
+ elif event.type == "stream.end":
129
+ if thinking_shown:
130
+ print("\r" + " " * 80, end="", flush=True)
131
+ print("\r", end="", flush=True)
132
+ thinking_shown = False
133
+ thinking_buffer = ""
134
+ print()
135
+ return buffer
136
+ elif event.type == "stream.error":
137
+ if thinking_shown:
138
+ print("\r" + " " * 80, end="", flush=True)
139
+ print("\r", end="", flush=True)
140
+ thinking_shown = False
141
+ thinking_buffer = ""
142
+ print(f"\n[错误: {event.payload.get('error', '未知错误')}]")
143
+ return None
144
+ except asyncio.CancelledError:
145
+ return buffer
146
+ except Exception as e:
147
+ print(f"\n[异常: {e}]")
148
+ return buffer
149
+
150
+ async def handle_cli_command(
151
+ text: str, current_session_id: str
152
+ ) -> tuple[bool, str]:
153
+ """处理 CLI 命令,返回 (是否已处理, 是否需要更新session_id, 新的session_id)"""
154
+ text = text.strip()
155
+ new_session_id = current_session_id
156
+
157
+ if text == "/new":
158
+ new_session_id = create_cli_session()
159
+ print(f"\n已创建新会话: {new_session_id}")
160
+ return True, new_session_id
161
+
162
+ elif text == "/clear":
163
+ from fastclaw.core.config import get_sessions_dir
164
+
165
+ session_dir = get_sessions_dir() / current_session_id
166
+ messages_file = session_dir / "messages.jsonl"
167
+ if messages_file.exists():
168
+ messages_file.unlink()
169
+ print(f"\n已清空当前会话 {current_session_id} 的聊天记录")
170
+ return True, current_session_id
171
+
172
+ elif text.startswith("/session "):
173
+ parts = text.split(" ", 1)
174
+ if len(parts) == 2:
175
+ target_id = parts[1].strip()
176
+ sessions = load_sessions()
177
+ if target_id in sessions:
178
+ print(f"\n已切换到会话: {target_id}")
179
+ new_session_id = target_id
180
+ else:
181
+ print(f"\n未找到会话: {target_id}")
182
+ return True, current_session_id
183
+
184
+ elif text == "/session_list":
185
+ sessions = load_sessions()
186
+ if sessions:
187
+ print("\n当前所有会话:")
188
+ for sid, info in sessions.items():
189
+ marker = " <-- 当前" if sid == current_session_id else ""
190
+ agent = info.get("agent_id", "unknown")
191
+ print(f" - {sid} (agent: {agent}){marker}")
192
+ else:
193
+ print("\n当前没有会话")
194
+ return True, current_session_id
195
+
196
+ return False, current_session_id
197
+
198
+ while True:
199
+ try:
200
+ user_input = input(f"\n你 ({session_id}): ").strip()
201
+ if not user_input:
202
+ continue
203
+ if user_input.lower() == "quit":
204
+ break
205
+
206
+ is_command, new_session_id = await handle_cli_command(
207
+ user_input, session_id
208
+ )
209
+ session_id = new_session_id
210
+ if is_command:
211
+ continue
212
+
213
+ event = Event("user.message", {"text": user_input}, session_id)
214
+ await api.push_event(session_id, event)
215
+
216
+ await consume_stream()
217
+
218
+ except KeyboardInterrupt:
219
+ print("\n\n退出...")
220
+ break
221
+ except EOFError:
222
+ print("\n\n退出...")
223
+ break
224
+ except Exception as e:
225
+ print(f"\n错误: {e}")
226
+
227
+ await api.stop()
228
+
229
+
230
+ if __name__ == "__main__":
231
+ asyncio.run(chat())
@@ -0,0 +1,43 @@
1
+ """FastClaw 核心引擎"""
2
+
3
+ import sys
4
+
5
+ _IS_PACKAGE_MODE = __package__ and __package__.startswith("fastclaw.")
6
+
7
+ if _IS_PACKAGE_MODE:
8
+ from .app import (
9
+ app,
10
+ start,
11
+ SKILLS,
12
+ load_skills,
13
+ load_agent_config,
14
+ load_settings,
15
+ calculate_tokens,
16
+ count_messages_tokens,
17
+ )
18
+ from .prompts import format_system_prompt, SYSTEM_PROMPT
19
+ else:
20
+ from core.app import (
21
+ app,
22
+ start,
23
+ SKILLS,
24
+ load_skills,
25
+ load_agent_config,
26
+ load_settings,
27
+ calculate_tokens,
28
+ count_messages_tokens,
29
+ )
30
+ from core.prompts import format_system_prompt, SYSTEM_PROMPT
31
+
32
+ __all__ = [
33
+ "app",
34
+ "start",
35
+ "SKILLS",
36
+ "load_skills",
37
+ "load_agent_config",
38
+ "load_settings",
39
+ "calculate_tokens",
40
+ "count_messages_tokens",
41
+ "format_system_prompt",
42
+ "SYSTEM_PROMPT",
43
+ ]