pythonclaw 0.2.0__tar.gz → 0.2.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.
Files changed (122) hide show
  1. {pythonclaw-0.2.0/pythonclaw.egg-info → pythonclaw-0.2.1}/PKG-INFO +5 -2
  2. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/README.md +4 -1
  3. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pyproject.toml +1 -1
  4. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/__init__.py +1 -1
  5. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/onboard.py +48 -0
  6. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/web/static/index.html +84 -0
  7. {pythonclaw-0.2.0 → pythonclaw-0.2.1/pythonclaw.egg-info}/PKG-INFO +5 -2
  8. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/LICENSE +0 -0
  9. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/__main__.py +0 -0
  10. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/channels/discord_bot.py +0 -0
  11. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/channels/telegram_bot.py +0 -0
  12. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/config.py +0 -0
  13. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/__init__.py +0 -0
  14. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/agent.py +0 -0
  15. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/compaction.py +0 -0
  16. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/knowledge/rag.py +0 -0
  17. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/llm/anthropic_client.py +0 -0
  18. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/llm/base.py +0 -0
  19. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/llm/gemini_client.py +0 -0
  20. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/llm/openai_compatible.py +0 -0
  21. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/llm/response.py +0 -0
  22. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/memory/manager.py +0 -0
  23. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/memory/storage.py +0 -0
  24. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/persistent_agent.py +0 -0
  25. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/__init__.py +0 -0
  26. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/chunker.py +0 -0
  27. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/dense.py +0 -0
  28. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/fusion.py +0 -0
  29. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/reranker.py +0 -0
  30. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/retriever.py +0 -0
  31. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/retrieval/sparse.py +0 -0
  32. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/session_store.py +0 -0
  33. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/skill_loader.py +0 -0
  34. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/skillhub.py +0 -0
  35. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/tools.py +0 -0
  36. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/core/utils.py +0 -0
  37. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/daemon.py +0 -0
  38. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/init.py +0 -0
  39. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/main.py +0 -0
  40. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/scheduler/cron.py +0 -0
  41. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/scheduler/heartbeat.py +0 -0
  42. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/server.py +0 -0
  43. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/session_manager.py +0 -0
  44. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/persona/demo_persona.md +0 -0
  45. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/communication/CATEGORY.md +0 -0
  46. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/communication/email/SKILL.md +0 -0
  47. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/communication/email/__pycache__/send_email.cpython-311.pyc +0 -0
  48. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/communication/email/send_email.py +0 -0
  49. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/CATEGORY.md +0 -0
  50. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/csv_analyzer/SKILL.md +0 -0
  51. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/csv_analyzer/__pycache__/analyze.cpython-311.pyc +0 -0
  52. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/csv_analyzer/analyze.py +0 -0
  53. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/finance/SKILL.md +0 -0
  54. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/finance/__pycache__/fetch_quote.cpython-311.pyc +0 -0
  55. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/finance/fetch_quote.py +0 -0
  56. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/news/SKILL.md +0 -0
  57. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/news/__pycache__/search_news.cpython-311.pyc +0 -0
  58. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/news/search_news.py +0 -0
  59. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/pdf_reader/SKILL.md +0 -0
  60. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/pdf_reader/__pycache__/read_pdf.cpython-311.pyc +0 -0
  61. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/pdf_reader/read_pdf.py +0 -0
  62. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/scraper/SKILL.md +0 -0
  63. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/scraper/__pycache__/scrape.cpython-311.pyc +0 -0
  64. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/scraper/scrape.py +0 -0
  65. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/weather/SKILL.md +0 -0
  66. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/weather/__pycache__/weather.cpython-311.pyc +0 -0
  67. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/weather/weather.py +0 -0
  68. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/youtube/SKILL.md +0 -0
  69. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/youtube/__pycache__/youtube_info.cpython-311.pyc +0 -0
  70. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/data/youtube/youtube_info.py +0 -0
  71. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/CATEGORY.md +0 -0
  72. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/code_runner/SKILL.md +0 -0
  73. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/code_runner/__pycache__/run_code.cpython-311.pyc +0 -0
  74. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/code_runner/run_code.py +0 -0
  75. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/github/SKILL.md +0 -0
  76. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/github/__pycache__/gh.cpython-311.pyc +0 -0
  77. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/github/gh.py +0 -0
  78. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/http_request/SKILL.md +0 -0
  79. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/http_request/__pycache__/request.cpython-311.pyc +0 -0
  80. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/dev/http_request/request.py +0 -0
  81. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/google/CATEGORY.md +0 -0
  82. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/google/workspace/SKILL.md +0 -0
  83. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/google/workspace/check_setup.sh +0 -0
  84. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/meta/CATEGORY.md +0 -0
  85. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/meta/skill_creator/SKILL.md +0 -0
  86. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/CATEGORY.md +0 -0
  87. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/change_persona/SKILL.md +0 -0
  88. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/change_setting/SKILL.md +0 -0
  89. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/change_setting/__pycache__/update_config.cpython-311.pyc +0 -0
  90. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/change_setting/update_config.py +0 -0
  91. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/change_soul/SKILL.md +0 -0
  92. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/onboarding/SKILL.md +0 -0
  93. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/onboarding/__pycache__/write_identity.cpython-311.pyc +0 -0
  94. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/onboarding/write_identity.py +0 -0
  95. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/random/SKILL.md +0 -0
  96. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/random/__pycache__/random_util.cpython-311.pyc +0 -0
  97. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/random/random_util.py +0 -0
  98. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/time/SKILL.md +0 -0
  99. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/time/__pycache__/time_util.cpython-311.pyc +0 -0
  100. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/system/time/time_util.py +0 -0
  101. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/text/CATEGORY.md +0 -0
  102. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/text/translator/SKILL.md +0 -0
  103. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/text/translator/__pycache__/translate.cpython-311.pyc +0 -0
  104. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/text/translator/translate.py +0 -0
  105. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/web/CATEGORY.md +0 -0
  106. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/skills/web/tavily/SKILL.md +0 -0
  107. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/templates/soul/SOUL.md +0 -0
  108. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/web/__init__.py +0 -0
  109. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/web/app.py +0 -0
  110. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/web/static/favicon.png +0 -0
  111. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw/web/static/logo.png +0 -0
  112. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw.egg-info/SOURCES.txt +0 -0
  113. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw.egg-info/dependency_links.txt +0 -0
  114. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw.egg-info/entry_points.txt +0 -0
  115. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw.egg-info/requires.txt +0 -0
  116. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/pythonclaw.egg-info/top_level.txt +0 -0
  117. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/setup.cfg +0 -0
  118. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/tests/test_compaction.py +0 -0
  119. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/tests/test_persistence.py +0 -0
  120. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/tests/test_rag_hybrid.py +0 -0
  121. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/tests/test_skills.py +0 -0
  122. {pythonclaw-0.2.0 → pythonclaw-0.2.1}/tests/test_soul.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonclaw
3
- Version: 0.2.0
3
+ Version: 0.2.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
@@ -76,7 +76,10 @@ Dynamic: license-file
76
76
  <a href="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml">
77
77
  <img src="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml/badge.svg" alt="CI">
78
78
  </a>
79
- <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" alt="Python 3.10+">
79
+ <a href="https://pypi.org/project/pythonclaw/">
80
+ <img src="https://img.shields.io/pypi/v/pythonclaw?color=blue" alt="PyPI">
81
+ </a>
82
+ <img src="https://img.shields.io/pypi/pyversions/pythonclaw" alt="Python">
80
83
  <a href="LICENSE">
81
84
  <img src="https://img.shields.io/github/license/ericwang915/PythonClaw" alt="MIT License">
82
85
  </a>
@@ -13,7 +13,10 @@
13
13
  <a href="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml">
14
14
  <img src="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml/badge.svg" alt="CI">
15
15
  </a>
16
- <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" alt="Python 3.10+">
16
+ <a href="https://pypi.org/project/pythonclaw/">
17
+ <img src="https://img.shields.io/pypi/v/pythonclaw?color=blue" alt="PyPI">
18
+ </a>
19
+ <img src="https://img.shields.io/pypi/pyversions/pythonclaw" alt="Python">
17
20
  <a href="LICENSE">
18
21
  <img src="https://img.shields.io/github/license/ericwang915/PythonClaw" alt="MIT License">
19
22
  </a>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pythonclaw"
7
- version = "0.2.0"
7
+ version = "0.2.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"}
@@ -6,7 +6,7 @@ from .core.llm.base import LLMProvider
6
6
  from .core.llm.openai_compatible import OpenAICompatibleProvider
7
7
  from .init import init
8
8
 
9
- __version__ = "0.2.0"
9
+ __version__ = "0.2.1"
10
10
  __all__ = [
11
11
  "Agent",
12
12
  "LLMProvider",
@@ -214,6 +214,54 @@ def _optional_keys(cfg: dict) -> None:
214
214
  print(" → SkillHub key set")
215
215
 
216
216
  print()
217
+ _channel_keys(cfg)
218
+
219
+
220
+ def _channel_keys(cfg: dict) -> None:
221
+ print(_c(" Channels (press Enter to skip):", _DIM))
222
+ print()
223
+
224
+ channels = cfg.setdefault("channels", {})
225
+
226
+ # Telegram
227
+ tg = channels.setdefault("telegram", {"token": "", "allowedUsers": []})
228
+ tg_existing = tg.get("token", "")
229
+ if tg_existing:
230
+ masked = tg_existing[:6] + "****" + tg_existing[-4:] if len(tg_existing) > 10 else "****"
231
+ print(f" Telegram Bot Token (current: {masked}, press Enter to keep)")
232
+ token = input(" Telegram Bot Token: ").strip()
233
+ if token:
234
+ tg["token"] = token
235
+ print(" → Telegram token set")
236
+ elif tg_existing:
237
+ print(" → Keeping existing Telegram token")
238
+
239
+ allowed = input(" Telegram Allowed User IDs (comma-separated, or Enter to allow all): ").strip()
240
+ if allowed:
241
+ tg["allowedUsers"] = [uid.strip() for uid in allowed.split(",") if uid.strip()]
242
+ print(f" → {len(tg['allowedUsers'])} user(s) whitelisted")
243
+
244
+ print()
245
+
246
+ # Discord
247
+ dc = channels.setdefault("discord", {"token": "", "allowedUsers": [], "allowedChannels": []})
248
+ dc_existing = dc.get("token", "")
249
+ if dc_existing:
250
+ masked = dc_existing[:6] + "****" + dc_existing[-4:] if len(dc_existing) > 10 else "****"
251
+ print(f" Discord Bot Token (current: {masked}, press Enter to keep)")
252
+ dc_token = input(" Discord Bot Token: ").strip()
253
+ if dc_token:
254
+ dc["token"] = dc_token
255
+ print(" → Discord token set")
256
+ elif dc_existing:
257
+ print(" → Keeping existing Discord token")
258
+
259
+ dc_channels = input(" Discord Allowed Channel IDs (comma-separated, or Enter to allow all): ").strip()
260
+ if dc_channels:
261
+ dc["allowedChannels"] = [ch.strip() for ch in dc_channels.split(",") if ch.strip()]
262
+ print(f" → {len(dc['allowedChannels'])} channel(s) whitelisted")
263
+
264
+ print()
217
265
 
218
266
 
219
267
  def _validate_key(cfg: dict, provider: dict) -> None:
@@ -266,6 +266,18 @@
266
266
  </div>
267
267
  </div>
268
268
 
269
+ <!-- Memory -->
270
+ <div class="section-card mb-6">
271
+ <h3 class="text-[.8125rem] font-semibold text-white mb-3 flex items-center gap-2">
272
+ <svg class="w-4 h-4 text-cyan-400" fill="none" stroke="currentColor" stroke-width="1.75" viewBox="0 0 24 24"><path d="M12 2a10 10 0 100 20 10 10 0 000-20z"/><path d="M12 6v6l4 2"/></svg>
273
+ Memory
274
+ <span id="memory-badge" class="text-[.625rem] text-gray-500 font-normal ml-1">0 entries</span>
275
+ </h3>
276
+ <div id="memory-content" class="max-h-[260px] overflow-y-auto chat-scroll">
277
+ <span class="text-[.75rem] text-gray-600 italic">No memories stored yet.</span>
278
+ </div>
279
+ </div>
280
+
269
281
  <!-- Tools & Quick Actions Row -->
270
282
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
271
283
  <!-- Tools List -->
@@ -479,6 +491,29 @@
479
491
  </div>
480
492
  </div>
481
493
 
494
+ <!-- Channels -->
495
+ <div class="cfg-section">
496
+ <h3 class="cfg-title">Channels</h3>
497
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4">
498
+ <div class="sm:col-span-2">
499
+ <label class="block text-xs text-gray-500 mb-1.5">Telegram Bot Token</label>
500
+ <input id="cfg-tg-token" type="password" class="input-field">
501
+ </div>
502
+ <div>
503
+ <label class="block text-xs text-gray-500 mb-1.5">Telegram Allowed Users</label>
504
+ <input id="cfg-tg-users" type="text" placeholder="Comma-separated user IDs (blank = allow all)" class="input-field">
505
+ </div>
506
+ <div class="sm:col-span-2 mt-2">
507
+ <label class="block text-xs text-gray-500 mb-1.5">Discord Bot Token</label>
508
+ <input id="cfg-dc-token" type="password" class="input-field">
509
+ </div>
510
+ <div>
511
+ <label class="block text-xs text-gray-500 mb-1.5">Discord Allowed Channels</label>
512
+ <input id="cfg-dc-channels" type="text" placeholder="Comma-separated channel IDs (blank = allow all)" class="input-field">
513
+ </div>
514
+ </div>
515
+ </div>
516
+
482
517
  <!-- Web Dashboard -->
483
518
  <div class="cfg-section">
484
519
  <h3 class="cfg-title">Web Dashboard</h3>
@@ -653,6 +688,29 @@ async function refreshDashboard() {
653
688
  `).join('');
654
689
  }
655
690
  } catch (e) { console.error('Identity fetch:', e); }
691
+
692
+ try {
693
+ const res3 = await fetch('/api/memories');
694
+ const mem = await res3.json();
695
+ const container = document.getElementById('memory-content');
696
+ const badge = document.getElementById('memory-badge');
697
+ const entries = mem.memories || {};
698
+ const keys = Object.keys(entries);
699
+ badge.textContent = keys.length + ' entries';
700
+
701
+ if (keys.length === 0) {
702
+ container.innerHTML = '<span class="text-[.75rem] text-gray-600 italic">No memories stored yet. Chat with the agent to build memory.</span>';
703
+ } else {
704
+ container.innerHTML = '<div class="space-y-2">' + keys.map(k => {
705
+ const val = escapeHtml(String(entries[k]));
706
+ const preview = val.length > 200 ? val.substring(0, 200) + '...' : val;
707
+ return `<div class="px-3 py-2 rounded-lg bg-surface-800/50 border border-surface-700/30">
708
+ <div class="text-[.6875rem] text-cyan-400 font-medium mb-1">${escapeHtml(k)}</div>
709
+ <div class="text-[.75rem] text-gray-400 leading-relaxed whitespace-pre-wrap">${preview}</div>
710
+ </div>`;
711
+ }).join('') + '</div>';
712
+ }
713
+ } catch (e) { console.error('Memories fetch:', e); }
656
714
  }
657
715
 
658
716
  // ── Identity Editor ──────────────────────────────────────────────────────────
@@ -1008,6 +1066,19 @@ async function loadConfig() {
1008
1066
  ghTokenField.placeholder = secretsSet['skills.github.token']
1009
1067
  ? '(token is set — leave blank to keep)' : 'ghp_xxxxxxxxxx';
1010
1068
 
1069
+ const channels = _rawConfig.channels || {};
1070
+ const tgCfg = channels.telegram || {};
1071
+ const tgTokenField = document.getElementById('cfg-tg-token');
1072
+ tgTokenField.value = '';
1073
+ tgTokenField.placeholder = secretsSet['channels.telegram.token'] ? '(token is set — leave blank to keep)' : 'Enter Telegram bot token';
1074
+ document.getElementById('cfg-tg-users').value = (tgCfg.allowedUsers || []).join(', ');
1075
+
1076
+ const dcCfg = channels.discord || {};
1077
+ const dcTokenField = document.getElementById('cfg-dc-token');
1078
+ dcTokenField.value = '';
1079
+ dcTokenField.placeholder = secretsSet['channels.discord.token'] ? '(token is set — leave blank to keep)' : 'Enter Discord bot token';
1080
+ document.getElementById('cfg-dc-channels').value = (dcCfg.allowedChannels || []).join(', ');
1081
+
1011
1082
  const web = _rawConfig.web || {};
1012
1083
  document.getElementById('cfg-web-host').value = web.host || '0.0.0.0';
1013
1084
  document.getElementById('cfg-web-port').value = web.port || 7788;
@@ -1090,6 +1161,19 @@ async function saveConfig() {
1090
1161
  const ghToken = document.getElementById('cfg-github-token').value.trim();
1091
1162
  if (ghToken) cfg.skills.github.token = ghToken;
1092
1163
 
1164
+ if (!cfg.channels) cfg.channels = {};
1165
+ if (!cfg.channels.telegram) cfg.channels.telegram = {};
1166
+ const tgToken = document.getElementById('cfg-tg-token').value.trim();
1167
+ if (tgToken) cfg.channels.telegram.token = tgToken;
1168
+ const tgUsers = document.getElementById('cfg-tg-users').value.trim();
1169
+ cfg.channels.telegram.allowedUsers = tgUsers ? tgUsers.split(',').map(s => s.trim()).filter(Boolean) : [];
1170
+
1171
+ if (!cfg.channels.discord) cfg.channels.discord = {};
1172
+ const dcToken = document.getElementById('cfg-dc-token').value.trim();
1173
+ if (dcToken) cfg.channels.discord.token = dcToken;
1174
+ const dcChannels = document.getElementById('cfg-dc-channels').value.trim();
1175
+ cfg.channels.discord.allowedChannels = dcChannels ? dcChannels.split(',').map(s => s.trim()).filter(Boolean) : [];
1176
+
1093
1177
  if (!cfg.web) cfg.web = {};
1094
1178
  cfg.web.host = document.getElementById('cfg-web-host').value.trim() || '0.0.0.0';
1095
1179
  cfg.web.port = parseInt(document.getElementById('cfg-web-port').value) || 7788;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonclaw
3
- Version: 0.2.0
3
+ Version: 0.2.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
@@ -76,7 +76,10 @@ Dynamic: license-file
76
76
  <a href="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml">
77
77
  <img src="https://github.com/ericwang915/PythonClaw/actions/workflows/ci.yml/badge.svg" alt="CI">
78
78
  </a>
79
- <img src="https://img.shields.io/badge/python-3.10+-blue?logo=python&logoColor=white" alt="Python 3.10+">
79
+ <a href="https://pypi.org/project/pythonclaw/">
80
+ <img src="https://img.shields.io/pypi/v/pythonclaw?color=blue" alt="PyPI">
81
+ </a>
82
+ <img src="https://img.shields.io/pypi/pyversions/pythonclaw" alt="Python">
80
83
  <a href="LICENSE">
81
84
  <img src="https://img.shields.io/github/license/ericwang915/PythonClaw" alt="MIT License">
82
85
  </a>
File without changes
File without changes