pythonclaw 0.5.0__tar.gz → 0.6.1__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.
- {pythonclaw-0.5.0/pythonclaw.egg-info → pythonclaw-0.6.1}/PKG-INFO +9 -9
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/README.md +8 -8
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pyproject.toml +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/channels/discord_bot.py +65 -11
- pythonclaw-0.6.1/pythonclaw/channels/telegram_bot.py +559 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/channels/whatsapp_bot.py +60 -8
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/agent.py +347 -114
- pythonclaw-0.6.1/pythonclaw/core/llm/anthropic_client.py +297 -0
- pythonclaw-0.6.1/pythonclaw/core/llm/base.py +55 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/llm/gemini_client.py +53 -1
- pythonclaw-0.6.1/pythonclaw/core/llm/openai_compatible.py +109 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/memory/manager.py +75 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/memory/storage.py +83 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/persistent_agent.py +27 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/session_store.py +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/skill_loader.py +13 -13
- pythonclaw-0.6.1/pythonclaw/core/skillhub.py +309 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/tools.py +37 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/main.py +15 -10
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/onboard.py +14 -14
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/communication/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/communication/slack/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/google/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/image_gen/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/spotify/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/tts/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/meta/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/notion/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/obsidian/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/trello/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/model_usage/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/session_logs/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/text/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/web/CATEGORY.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/web/summarize/SKILL.md +1 -1
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/web/app.py +134 -29
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/web/static/index.html +276 -107
- {pythonclaw-0.5.0 → pythonclaw-0.6.1/pythonclaw.egg-info}/PKG-INFO +9 -9
- pythonclaw-0.5.0/pythonclaw/channels/telegram_bot.py +0 -291
- pythonclaw-0.5.0/pythonclaw/core/llm/anthropic_client.py +0 -107
- pythonclaw-0.5.0/pythonclaw/core/llm/base.py +0 -26
- pythonclaw-0.5.0/pythonclaw/core/llm/openai_compatible.py +0 -39
- pythonclaw-0.5.0/pythonclaw/core/skillhub.py +0 -319
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/LICENSE +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/MANIFEST.in +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/__init__.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/__main__.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/config.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/__init__.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/compaction.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/knowledge/rag.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/llm/response.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/__init__.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/chunker.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/dense.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/fusion.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/reranker.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/retriever.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/retrieval/sparse.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/core/utils.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/daemon.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/init.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/scheduler/cron.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/scheduler/heartbeat.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/server.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/session_manager.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/persona/demo_persona.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/communication/email/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/communication/email/send_email.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/communication/slack/slack_api.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/csv_analyzer/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/csv_analyzer/analyze.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/finance/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/finance/fetch_quote.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/news/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/news/search_news.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/pdf_reader/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/pdf_reader/read_pdf.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/scraper/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/scraper/scrape.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/weather/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/weather/weather.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/youtube/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/data/youtube/youtube_info.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/code_runner/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/code_runner/run_code.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/github/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/github/gh.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/http_request/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/dev/http_request/request.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/google/workspace/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/google/workspace/check_setup.sh +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/image_gen/generate.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/spotify/spotify_ctl.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/media/tts/speak.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/meta/skill_creator/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/notion/notion_api.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/obsidian/obsidian_vault.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/productivity/trello/trello_api.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/change_persona/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/change_setting/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/change_setting/update_config.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/change_soul/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/model_usage/usage_stats.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/onboarding/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/onboarding/write_identity.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/random/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/random/random_util.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/session_logs/search_sessions.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/time/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/system/time/time_util.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/text/translator/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/text/translator/translate.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/web/summarize/summarize_url.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/skills/web/tavily/SKILL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/soul/SOUL.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/templates/tools/TOOLS.md +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/web/__init__.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/web/static/favicon.png +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw/web/static/logo.png +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw.egg-info/SOURCES.txt +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw.egg-info/dependency_links.txt +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw.egg-info/entry_points.txt +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw.egg-info/requires.txt +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/pythonclaw.egg-info/top_level.txt +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/setup.cfg +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/tests/test_compaction.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/tests/test_persistence.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/tests/test_rag_hybrid.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/tests/test_skills.py +0 -0
- {pythonclaw-0.5.0 → pythonclaw-0.6.1}/tests/test_soul.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonclaw
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support.
|
|
5
5
|
Author-email: Eric Wang <wangchen2007915@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -78,7 +78,7 @@ Dynamic: license-file
|
|
|
78
78
|
| | Feature | Details |
|
|
79
79
|
|---|---------|---------|
|
|
80
80
|
| 🧠 | **Provider-agnostic** | DeepSeek, Grok, Claude, Gemini, Kimi, GLM — or any OpenAI-compatible API |
|
|
81
|
-
| 🛠️ | **Three-tier skills** | Progressive loading: metadata → instructions → resources. Community marketplace via [
|
|
81
|
+
| 🛠️ | **Three-tier skills** | Progressive loading: metadata → instructions → resources. Community marketplace via [ClawHub](https://clawhub.com) (13K+ free skills) |
|
|
82
82
|
| 💾 | **Persistent memory** | Markdown-based long-term memory with daily logs and semantic recall |
|
|
83
83
|
| 🔍 | **Hybrid RAG** | BM25 + dense embeddings + RRF fusion + LLM re-ranking |
|
|
84
84
|
| 🌐 | **Web dashboard** | Browser UI for chat, config, skill catalog, identity editing, and marketplace |
|
|
@@ -133,7 +133,7 @@ pythonclaw onboard
|
|
|
133
133
|
| `pythonclaw stop` | Stop the running daemon |
|
|
134
134
|
| `pythonclaw status` | Show daemon status (PID, uptime, port) |
|
|
135
135
|
| `pythonclaw chat` | Interactive CLI chat (foreground REPL) |
|
|
136
|
-
| `pythonclaw skill search <query>` | Search skills on [
|
|
136
|
+
| `pythonclaw skill search <query>` | Search skills on [ClawHub](https://clawhub.com) |
|
|
137
137
|
| `pythonclaw skill browse` | Browse top-rated skills |
|
|
138
138
|
| `pythonclaw skill install <id>` | Install a community skill |
|
|
139
139
|
| `pythonclaw skill info <id>` | View skill details |
|
|
@@ -191,7 +191,7 @@ $ pythonclaw start
|
|
|
191
191
|
│ LLM Provider Abstraction Layer │
|
|
192
192
|
│ DeepSeek │ Grok │ Claude │ Gemini │ Kimi │ GLM │
|
|
193
193
|
├──────────────────────────────────────────────────────────────┤
|
|
194
|
-
│
|
|
194
|
+
│ ClawHub Marketplace (clawhub.com) │
|
|
195
195
|
└──────────────────────────────────────────────────────────────┘
|
|
196
196
|
```
|
|
197
197
|
|
|
@@ -204,7 +204,7 @@ Start with `pythonclaw start` and open **http://localhost:7788**.
|
|
|
204
204
|
- **Dashboard** — agent status, soul/persona preview, tool list
|
|
205
205
|
- **Chat** — real-time chat with voice input (Deepgram)
|
|
206
206
|
- **Skill Catalog** — browse installed skills by category
|
|
207
|
-
- **Marketplace** — search and install skills from [
|
|
207
|
+
- **Marketplace** — search and install skills from [ClawHub](https://clawhub.com)
|
|
208
208
|
- **Configuration** — edit LLM provider, API keys, and settings in-browser
|
|
209
209
|
|
|
210
210
|
---
|
|
@@ -272,9 +272,9 @@ description: Execute Python code safely in an isolated subprocess.
|
|
|
272
272
|
Run `python {skill_path}/run_code.py "expression"`
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
-
###
|
|
275
|
+
### ClawHub Marketplace
|
|
276
276
|
|
|
277
|
-
Browse and install
|
|
277
|
+
Browse and install 13,000+ community skills from [ClawHub](https://clawhub.com) — free, no API key required:
|
|
278
278
|
|
|
279
279
|
```bash
|
|
280
280
|
pythonclaw skill search "database backup"
|
|
@@ -351,7 +351,7 @@ PythonClaw/
|
|
|
351
351
|
│ │ ├── agent.py # Core reasoning loop
|
|
352
352
|
│ │ ├── tools.py # Tool schemas and execution
|
|
353
353
|
│ │ ├── skill_loader.py # Three-tier skill system
|
|
354
|
-
│ │ ├── skillhub.py #
|
|
354
|
+
│ │ ├── skillhub.py # ClawHub marketplace client
|
|
355
355
|
│ │ ├── persistent_agent.py
|
|
356
356
|
│ │ ├── compaction.py # Context compaction
|
|
357
357
|
│ │ ├── llm/ # Provider adapters
|
|
@@ -397,7 +397,7 @@ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
397
397
|
| CLI | `openclaw start/stop` | `pythonclaw start/stop/status` |
|
|
398
398
|
| Dashboard | Web UI | Web UI (localhost:7788) |
|
|
399
399
|
| Memory | Markdown | Markdown (long-term + daily) |
|
|
400
|
-
| Skills | Plugin system | Three-tier +
|
|
400
|
+
| Skills | Plugin system | Three-tier + ClawHub marketplace |
|
|
401
401
|
| Channels | Discord, Telegram, WhatsApp | CLI, Web, Telegram, Discord, WhatsApp |
|
|
402
402
|
| Voice | — | Deepgram STT |
|
|
403
403
|
| LLM Providers | OpenAI, Anthropic, Gemini | DeepSeek, Grok, Claude, Gemini, Kimi, GLM |
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
| | Feature | Details |
|
|
37
37
|
|---|---------|---------|
|
|
38
38
|
| 🧠 | **Provider-agnostic** | DeepSeek, Grok, Claude, Gemini, Kimi, GLM — or any OpenAI-compatible API |
|
|
39
|
-
| 🛠️ | **Three-tier skills** | Progressive loading: metadata → instructions → resources. Community marketplace via [
|
|
39
|
+
| 🛠️ | **Three-tier skills** | Progressive loading: metadata → instructions → resources. Community marketplace via [ClawHub](https://clawhub.com) (13K+ free skills) |
|
|
40
40
|
| 💾 | **Persistent memory** | Markdown-based long-term memory with daily logs and semantic recall |
|
|
41
41
|
| 🔍 | **Hybrid RAG** | BM25 + dense embeddings + RRF fusion + LLM re-ranking |
|
|
42
42
|
| 🌐 | **Web dashboard** | Browser UI for chat, config, skill catalog, identity editing, and marketplace |
|
|
@@ -91,7 +91,7 @@ pythonclaw onboard
|
|
|
91
91
|
| `pythonclaw stop` | Stop the running daemon |
|
|
92
92
|
| `pythonclaw status` | Show daemon status (PID, uptime, port) |
|
|
93
93
|
| `pythonclaw chat` | Interactive CLI chat (foreground REPL) |
|
|
94
|
-
| `pythonclaw skill search <query>` | Search skills on [
|
|
94
|
+
| `pythonclaw skill search <query>` | Search skills on [ClawHub](https://clawhub.com) |
|
|
95
95
|
| `pythonclaw skill browse` | Browse top-rated skills |
|
|
96
96
|
| `pythonclaw skill install <id>` | Install a community skill |
|
|
97
97
|
| `pythonclaw skill info <id>` | View skill details |
|
|
@@ -149,7 +149,7 @@ $ pythonclaw start
|
|
|
149
149
|
│ LLM Provider Abstraction Layer │
|
|
150
150
|
│ DeepSeek │ Grok │ Claude │ Gemini │ Kimi │ GLM │
|
|
151
151
|
├──────────────────────────────────────────────────────────────┤
|
|
152
|
-
│
|
|
152
|
+
│ ClawHub Marketplace (clawhub.com) │
|
|
153
153
|
└──────────────────────────────────────────────────────────────┘
|
|
154
154
|
```
|
|
155
155
|
|
|
@@ -162,7 +162,7 @@ Start with `pythonclaw start` and open **http://localhost:7788**.
|
|
|
162
162
|
- **Dashboard** — agent status, soul/persona preview, tool list
|
|
163
163
|
- **Chat** — real-time chat with voice input (Deepgram)
|
|
164
164
|
- **Skill Catalog** — browse installed skills by category
|
|
165
|
-
- **Marketplace** — search and install skills from [
|
|
165
|
+
- **Marketplace** — search and install skills from [ClawHub](https://clawhub.com)
|
|
166
166
|
- **Configuration** — edit LLM provider, API keys, and settings in-browser
|
|
167
167
|
|
|
168
168
|
---
|
|
@@ -230,9 +230,9 @@ description: Execute Python code safely in an isolated subprocess.
|
|
|
230
230
|
Run `python {skill_path}/run_code.py "expression"`
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
-
###
|
|
233
|
+
### ClawHub Marketplace
|
|
234
234
|
|
|
235
|
-
Browse and install
|
|
235
|
+
Browse and install 13,000+ community skills from [ClawHub](https://clawhub.com) — free, no API key required:
|
|
236
236
|
|
|
237
237
|
```bash
|
|
238
238
|
pythonclaw skill search "database backup"
|
|
@@ -309,7 +309,7 @@ PythonClaw/
|
|
|
309
309
|
│ │ ├── agent.py # Core reasoning loop
|
|
310
310
|
│ │ ├── tools.py # Tool schemas and execution
|
|
311
311
|
│ │ ├── skill_loader.py # Three-tier skill system
|
|
312
|
-
│ │ ├── skillhub.py #
|
|
312
|
+
│ │ ├── skillhub.py # ClawHub marketplace client
|
|
313
313
|
│ │ ├── persistent_agent.py
|
|
314
314
|
│ │ ├── compaction.py # Context compaction
|
|
315
315
|
│ │ ├── llm/ # Provider adapters
|
|
@@ -355,7 +355,7 @@ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
355
355
|
| CLI | `openclaw start/stop` | `pythonclaw start/stop/status` |
|
|
356
356
|
| Dashboard | Web UI | Web UI (localhost:7788) |
|
|
357
357
|
| Memory | Markdown | Markdown (long-term + daily) |
|
|
358
|
-
| Skills | Plugin system | Three-tier +
|
|
358
|
+
| Skills | Plugin system | Three-tier + ClawHub marketplace |
|
|
359
359
|
| Channels | Discord, Telegram, WhatsApp | CLI, Web, Telegram, Discord, WhatsApp |
|
|
360
360
|
| Voice | — | Deepgram STT |
|
|
361
361
|
| LLM Providers | OpenAI, Anthropic, Gemini | DeepSeek, Grok, Claude, Gemini, Kimi, GLM |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pythonclaw"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.1"
|
|
8
8
|
description = "OpenClaw reimagined in pure Python — autonomous AI agent with memory, RAG, skills, web dashboard, and multi-channel support."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Discord channel for PythonClaw.
|
|
3
3
|
|
|
4
|
-
Session IDs: "discord:{user_id}" (DMs) or "discord:{channel_id}" (guilds)
|
|
4
|
+
Session IDs: "discord:dm:{user_id}" (DMs) or "discord:{channel_id}" (guilds)
|
|
5
5
|
|
|
6
6
|
Commands
|
|
7
7
|
--------
|
|
@@ -9,21 +9,29 @@ Commands
|
|
|
9
9
|
!status — show session info
|
|
10
10
|
!compact [hint] — compact conversation history
|
|
11
11
|
<text> — forwarded to Agent.chat(), reply sent back
|
|
12
|
+
<image> — image attachments sent to LLM for analysis
|
|
12
13
|
|
|
13
14
|
The bot responds to:
|
|
14
15
|
- Direct messages (always)
|
|
15
|
-
- Channel mentions (@bot message) in guilds
|
|
16
|
-
-
|
|
16
|
+
- Channel mentions (@bot message) in guilds (when requireMention=true)
|
|
17
|
+
- All messages in whitelisted channels (when requireMention=false)
|
|
17
18
|
|
|
18
19
|
Access control
|
|
19
20
|
--------------
|
|
20
21
|
Set DISCORD_ALLOWED_USERS to a comma-separated list of Discord user IDs.
|
|
21
22
|
Set DISCORD_ALLOWED_CHANNELS to restrict which guild channels the bot listens in.
|
|
22
23
|
Leave empty to allow all.
|
|
24
|
+
|
|
25
|
+
Group behaviour
|
|
26
|
+
---------------
|
|
27
|
+
Set ``channels.discord.requireMention`` to ``true`` to require @bot mention
|
|
28
|
+
in guild channels. Default is ``false`` (respond when mentioned OR in
|
|
29
|
+
whitelisted channels).
|
|
23
30
|
"""
|
|
24
31
|
|
|
25
32
|
from __future__ import annotations
|
|
26
33
|
|
|
34
|
+
import base64
|
|
27
35
|
import logging
|
|
28
36
|
from typing import TYPE_CHECKING
|
|
29
37
|
|
|
@@ -52,11 +60,13 @@ class DiscordBot:
|
|
|
52
60
|
token: str,
|
|
53
61
|
allowed_users: list[int] | None = None,
|
|
54
62
|
allowed_channels: list[int] | None = None,
|
|
63
|
+
require_mention: bool = False,
|
|
55
64
|
) -> None:
|
|
56
65
|
self._sm = session_manager
|
|
57
66
|
self._token = token
|
|
58
67
|
self._allowed_users: set[int] = set(allowed_users) if allowed_users else set()
|
|
59
68
|
self._allowed_channels: set[int] = set(allowed_channels) if allowed_channels else set()
|
|
69
|
+
self._require_mention = require_mention
|
|
60
70
|
|
|
61
71
|
intents = discord.Intents.default()
|
|
62
72
|
intents.message_content = True
|
|
@@ -113,20 +123,27 @@ class DiscordBot:
|
|
|
113
123
|
is_dm = isinstance(message.channel, discord.DMChannel)
|
|
114
124
|
is_mentioned = client.user in message.mentions if not is_dm else False
|
|
115
125
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
if not is_dm:
|
|
127
|
+
if self._require_mention and not is_mentioned:
|
|
128
|
+
return
|
|
129
|
+
if not self._require_mention and not is_mentioned:
|
|
130
|
+
if not self._is_allowed_channel(message.channel.id):
|
|
131
|
+
return
|
|
119
132
|
|
|
120
133
|
if not self._is_allowed_user(message.author.id):
|
|
121
134
|
await message.reply("Sorry, you are not authorised to use this bot.")
|
|
122
135
|
return
|
|
123
136
|
|
|
124
137
|
content = message.content.strip()
|
|
125
|
-
# Remove bot mention from the beginning
|
|
126
138
|
if is_mentioned and client.user:
|
|
127
139
|
content = content.replace(f"<@{client.user.id}>", "").strip()
|
|
128
140
|
|
|
129
|
-
|
|
141
|
+
has_image = any(
|
|
142
|
+
a.content_type and a.content_type.startswith("image/")
|
|
143
|
+
for a in message.attachments
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if not content and not has_image:
|
|
130
147
|
return
|
|
131
148
|
|
|
132
149
|
# Command dispatch
|
|
@@ -141,7 +158,35 @@ class DiscordBot:
|
|
|
141
158
|
await self._cmd_compact(message, is_dm, hint)
|
|
142
159
|
return
|
|
143
160
|
|
|
144
|
-
|
|
161
|
+
chat_input = content or ""
|
|
162
|
+
if has_image:
|
|
163
|
+
chat_input = await self._build_image_input(
|
|
164
|
+
message, content or "What's in this image?"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
await self._handle_chat(message, chat_input, is_dm)
|
|
168
|
+
|
|
169
|
+
# ── Image handling ────────────────────────────────────────────────────────
|
|
170
|
+
|
|
171
|
+
@staticmethod
|
|
172
|
+
async def _build_image_input(message: discord.Message, caption: str) -> list:
|
|
173
|
+
"""Download image attachments and build multimodal content array."""
|
|
174
|
+
parts: list[dict] = [{"type": "text", "text": caption}]
|
|
175
|
+
for att in message.attachments:
|
|
176
|
+
if att.content_type and att.content_type.startswith("image/"):
|
|
177
|
+
try:
|
|
178
|
+
data = await att.read()
|
|
179
|
+
b64 = base64.b64encode(data).decode()
|
|
180
|
+
media_type = att.content_type.split(";")[0]
|
|
181
|
+
parts.append({
|
|
182
|
+
"type": "image_url",
|
|
183
|
+
"image_url": {
|
|
184
|
+
"url": f"data:{media_type};base64,{b64}",
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
except Exception:
|
|
188
|
+
logger.warning("[Discord] Failed to download attachment %s", att.filename)
|
|
189
|
+
return parts
|
|
145
190
|
|
|
146
191
|
# ── Command implementations ───────────────────────────────────────────────
|
|
147
192
|
|
|
@@ -180,12 +225,17 @@ class DiscordBot:
|
|
|
180
225
|
for chunk in self._split_message(result or "(no result)"):
|
|
181
226
|
await message.reply(chunk)
|
|
182
227
|
|
|
183
|
-
async def _handle_chat(
|
|
228
|
+
async def _handle_chat(
|
|
229
|
+
self,
|
|
230
|
+
message: discord.Message,
|
|
231
|
+
content: str | list,
|
|
232
|
+
is_dm: bool,
|
|
233
|
+
) -> None:
|
|
184
234
|
sid = self._session_id(message.author.id if is_dm else message.channel.id, is_dm)
|
|
185
235
|
agent = self._sm.get_or_create(sid)
|
|
186
236
|
|
|
187
237
|
if self._sm.is_locked(sid):
|
|
188
|
-
await message.reply("Processing previous message
|
|
238
|
+
await message.reply("Processing previous message\u2026")
|
|
189
239
|
|
|
190
240
|
async with message.channel.typing():
|
|
191
241
|
try:
|
|
@@ -226,11 +276,15 @@ def create_bot(session_manager: "SessionManager") -> "DiscordBot":
|
|
|
226
276
|
allowed_channels = config.get_int_list(
|
|
227
277
|
"channels", "discord", "allowedChannels", env="DISCORD_ALLOWED_CHANNELS",
|
|
228
278
|
)
|
|
279
|
+
require_mention = config.get_bool(
|
|
280
|
+
"channels", "discord", "requireMention", default=False,
|
|
281
|
+
)
|
|
229
282
|
return DiscordBot(
|
|
230
283
|
session_manager=session_manager,
|
|
231
284
|
token=token,
|
|
232
285
|
allowed_users=allowed_users or None,
|
|
233
286
|
allowed_channels=allowed_channels or None,
|
|
287
|
+
require_mention=require_mention,
|
|
234
288
|
)
|
|
235
289
|
|
|
236
290
|
|