pythonclaw 0.2.0__py3-none-any.whl

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 (112) hide show
  1. pythonclaw/__init__.py +17 -0
  2. pythonclaw/__main__.py +6 -0
  3. pythonclaw/channels/discord_bot.py +231 -0
  4. pythonclaw/channels/telegram_bot.py +236 -0
  5. pythonclaw/config.py +190 -0
  6. pythonclaw/core/__init__.py +25 -0
  7. pythonclaw/core/agent.py +773 -0
  8. pythonclaw/core/compaction.py +220 -0
  9. pythonclaw/core/knowledge/rag.py +93 -0
  10. pythonclaw/core/llm/anthropic_client.py +107 -0
  11. pythonclaw/core/llm/base.py +26 -0
  12. pythonclaw/core/llm/gemini_client.py +139 -0
  13. pythonclaw/core/llm/openai_compatible.py +39 -0
  14. pythonclaw/core/llm/response.py +57 -0
  15. pythonclaw/core/memory/manager.py +120 -0
  16. pythonclaw/core/memory/storage.py +164 -0
  17. pythonclaw/core/persistent_agent.py +103 -0
  18. pythonclaw/core/retrieval/__init__.py +6 -0
  19. pythonclaw/core/retrieval/chunker.py +78 -0
  20. pythonclaw/core/retrieval/dense.py +152 -0
  21. pythonclaw/core/retrieval/fusion.py +51 -0
  22. pythonclaw/core/retrieval/reranker.py +112 -0
  23. pythonclaw/core/retrieval/retriever.py +166 -0
  24. pythonclaw/core/retrieval/sparse.py +69 -0
  25. pythonclaw/core/session_store.py +269 -0
  26. pythonclaw/core/skill_loader.py +322 -0
  27. pythonclaw/core/skillhub.py +290 -0
  28. pythonclaw/core/tools.py +622 -0
  29. pythonclaw/core/utils.py +64 -0
  30. pythonclaw/daemon.py +221 -0
  31. pythonclaw/init.py +61 -0
  32. pythonclaw/main.py +489 -0
  33. pythonclaw/onboard.py +290 -0
  34. pythonclaw/scheduler/cron.py +310 -0
  35. pythonclaw/scheduler/heartbeat.py +178 -0
  36. pythonclaw/server.py +145 -0
  37. pythonclaw/session_manager.py +104 -0
  38. pythonclaw/templates/persona/demo_persona.md +2 -0
  39. pythonclaw/templates/skills/communication/CATEGORY.md +4 -0
  40. pythonclaw/templates/skills/communication/email/SKILL.md +54 -0
  41. pythonclaw/templates/skills/communication/email/__pycache__/send_email.cpython-311.pyc +0 -0
  42. pythonclaw/templates/skills/communication/email/send_email.py +88 -0
  43. pythonclaw/templates/skills/data/CATEGORY.md +4 -0
  44. pythonclaw/templates/skills/data/csv_analyzer/SKILL.md +51 -0
  45. pythonclaw/templates/skills/data/csv_analyzer/__pycache__/analyze.cpython-311.pyc +0 -0
  46. pythonclaw/templates/skills/data/csv_analyzer/analyze.py +138 -0
  47. pythonclaw/templates/skills/data/finance/SKILL.md +41 -0
  48. pythonclaw/templates/skills/data/finance/__pycache__/fetch_quote.cpython-311.pyc +0 -0
  49. pythonclaw/templates/skills/data/finance/fetch_quote.py +118 -0
  50. pythonclaw/templates/skills/data/news/SKILL.md +39 -0
  51. pythonclaw/templates/skills/data/news/__pycache__/search_news.cpython-311.pyc +0 -0
  52. pythonclaw/templates/skills/data/news/search_news.py +57 -0
  53. pythonclaw/templates/skills/data/pdf_reader/SKILL.md +40 -0
  54. pythonclaw/templates/skills/data/pdf_reader/__pycache__/read_pdf.cpython-311.pyc +0 -0
  55. pythonclaw/templates/skills/data/pdf_reader/read_pdf.py +113 -0
  56. pythonclaw/templates/skills/data/scraper/SKILL.md +39 -0
  57. pythonclaw/templates/skills/data/scraper/__pycache__/scrape.cpython-311.pyc +0 -0
  58. pythonclaw/templates/skills/data/scraper/scrape.py +92 -0
  59. pythonclaw/templates/skills/data/weather/SKILL.md +42 -0
  60. pythonclaw/templates/skills/data/weather/__pycache__/weather.cpython-311.pyc +0 -0
  61. pythonclaw/templates/skills/data/weather/weather.py +142 -0
  62. pythonclaw/templates/skills/data/youtube/SKILL.md +43 -0
  63. pythonclaw/templates/skills/data/youtube/__pycache__/youtube_info.cpython-311.pyc +0 -0
  64. pythonclaw/templates/skills/data/youtube/youtube_info.py +167 -0
  65. pythonclaw/templates/skills/dev/CATEGORY.md +4 -0
  66. pythonclaw/templates/skills/dev/code_runner/SKILL.md +46 -0
  67. pythonclaw/templates/skills/dev/code_runner/__pycache__/run_code.cpython-311.pyc +0 -0
  68. pythonclaw/templates/skills/dev/code_runner/run_code.py +117 -0
  69. pythonclaw/templates/skills/dev/github/SKILL.md +52 -0
  70. pythonclaw/templates/skills/dev/github/__pycache__/gh.cpython-311.pyc +0 -0
  71. pythonclaw/templates/skills/dev/github/gh.py +165 -0
  72. pythonclaw/templates/skills/dev/http_request/SKILL.md +40 -0
  73. pythonclaw/templates/skills/dev/http_request/__pycache__/request.cpython-311.pyc +0 -0
  74. pythonclaw/templates/skills/dev/http_request/request.py +90 -0
  75. pythonclaw/templates/skills/google/CATEGORY.md +4 -0
  76. pythonclaw/templates/skills/google/workspace/SKILL.md +98 -0
  77. pythonclaw/templates/skills/google/workspace/check_setup.sh +52 -0
  78. pythonclaw/templates/skills/meta/CATEGORY.md +4 -0
  79. pythonclaw/templates/skills/meta/skill_creator/SKILL.md +151 -0
  80. pythonclaw/templates/skills/system/CATEGORY.md +4 -0
  81. pythonclaw/templates/skills/system/change_persona/SKILL.md +41 -0
  82. pythonclaw/templates/skills/system/change_setting/SKILL.md +65 -0
  83. pythonclaw/templates/skills/system/change_setting/__pycache__/update_config.cpython-311.pyc +0 -0
  84. pythonclaw/templates/skills/system/change_setting/update_config.py +129 -0
  85. pythonclaw/templates/skills/system/change_soul/SKILL.md +41 -0
  86. pythonclaw/templates/skills/system/onboarding/SKILL.md +63 -0
  87. pythonclaw/templates/skills/system/onboarding/__pycache__/write_identity.cpython-311.pyc +0 -0
  88. pythonclaw/templates/skills/system/onboarding/write_identity.py +218 -0
  89. pythonclaw/templates/skills/system/random/SKILL.md +33 -0
  90. pythonclaw/templates/skills/system/random/__pycache__/random_util.cpython-311.pyc +0 -0
  91. pythonclaw/templates/skills/system/random/random_util.py +45 -0
  92. pythonclaw/templates/skills/system/time/SKILL.md +33 -0
  93. pythonclaw/templates/skills/system/time/__pycache__/time_util.cpython-311.pyc +0 -0
  94. pythonclaw/templates/skills/system/time/time_util.py +81 -0
  95. pythonclaw/templates/skills/text/CATEGORY.md +4 -0
  96. pythonclaw/templates/skills/text/translator/SKILL.md +47 -0
  97. pythonclaw/templates/skills/text/translator/__pycache__/translate.cpython-311.pyc +0 -0
  98. pythonclaw/templates/skills/text/translator/translate.py +66 -0
  99. pythonclaw/templates/skills/web/CATEGORY.md +4 -0
  100. pythonclaw/templates/skills/web/tavily/SKILL.md +61 -0
  101. pythonclaw/templates/soul/SOUL.md +54 -0
  102. pythonclaw/web/__init__.py +1 -0
  103. pythonclaw/web/app.py +585 -0
  104. pythonclaw/web/static/favicon.png +0 -0
  105. pythonclaw/web/static/index.html +1318 -0
  106. pythonclaw/web/static/logo.png +0 -0
  107. pythonclaw-0.2.0.dist-info/METADATA +410 -0
  108. pythonclaw-0.2.0.dist-info/RECORD +112 -0
  109. pythonclaw-0.2.0.dist-info/WHEEL +5 -0
  110. pythonclaw-0.2.0.dist-info/entry_points.txt +2 -0
  111. pythonclaw-0.2.0.dist-info/licenses/LICENSE +21 -0
  112. pythonclaw-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ """Get current time, convert between timezones."""
3
+
4
+ import argparse
5
+ from datetime import datetime, timezone, timedelta
6
+ import json
7
+
8
+ COMMON_TIMEZONES = {
9
+ "UTC": 0, "US/Eastern": -5, "US/Central": -6, "US/Mountain": -7,
10
+ "US/Pacific": -8, "Europe/London": 0, "Europe/Paris": 1,
11
+ "Europe/Berlin": 1, "Asia/Tokyo": 9, "Asia/Shanghai": 8,
12
+ "Asia/Singapore": 8, "Asia/Kolkata": 5.5, "Australia/Sydney": 11,
13
+ "America/New_York": -5, "America/Chicago": -6,
14
+ "America/Los_Angeles": -8, "America/Sao_Paulo": -3,
15
+ }
16
+
17
+
18
+ def _tz_offset(name: str) -> timezone:
19
+ name_lower = name.lower().replace(" ", "_")
20
+ for k, v in COMMON_TIMEZONES.items():
21
+ if k.lower() == name_lower:
22
+ return timezone(timedelta(hours=v))
23
+ try:
24
+ hours = float(name)
25
+ return timezone(timedelta(hours=hours))
26
+ except ValueError:
27
+ pass
28
+ raise ValueError(f"Unknown timezone: {name}. Use --list-tz to see options.")
29
+
30
+
31
+ def main():
32
+ parser = argparse.ArgumentParser(description="Time utility")
33
+ parser.add_argument("--tz", type=str, help="Show time in this timezone")
34
+ parser.add_argument("--list-tz", action="store_true", help="List common timezones")
35
+ parser.add_argument("--unix", action="store_true", help="Show Unix timestamp")
36
+ parser.add_argument("--convert", type=str, help="Datetime string to convert")
37
+ parser.add_argument("--from-tz", type=str, help="Source timezone for conversion")
38
+ parser.add_argument("--to-tz", type=str, help="Target timezone for conversion")
39
+ args = parser.parse_args()
40
+
41
+ if args.list_tz:
42
+ for name, offset in sorted(COMMON_TIMEZONES.items()):
43
+ sign = "+" if offset >= 0 else ""
44
+ print(f" {name:25s} UTC{sign}{offset}")
45
+ return
46
+
47
+ if args.unix:
48
+ print(int(datetime.now(timezone.utc).timestamp()))
49
+ return
50
+
51
+ if args.convert:
52
+ if not args.from_tz or not args.to_tz:
53
+ print("Error: --convert requires --from-tz and --to-tz")
54
+ return
55
+ src_tz = _tz_offset(args.from_tz)
56
+ dst_tz = _tz_offset(args.to_tz)
57
+ dt = datetime.strptime(args.convert, "%Y-%m-%d %H:%M").replace(tzinfo=src_tz)
58
+ converted = dt.astimezone(dst_tz)
59
+ print(json.dumps({
60
+ "from": f"{args.convert} ({args.from_tz})",
61
+ "to": converted.strftime("%Y-%m-%d %H:%M:%S %Z") + f" ({args.to_tz})",
62
+ }, indent=2))
63
+ return
64
+
65
+ if args.tz:
66
+ tz = _tz_offset(args.tz)
67
+ now = datetime.now(tz)
68
+ else:
69
+ now = datetime.now()
70
+
71
+ print(json.dumps({
72
+ "datetime": now.strftime("%Y-%m-%d %H:%M:%S"),
73
+ "date": now.strftime("%Y-%m-%d"),
74
+ "time": now.strftime("%H:%M:%S"),
75
+ "weekday": now.strftime("%A"),
76
+ "timezone": args.tz or "local",
77
+ }, indent=2))
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()
@@ -0,0 +1,4 @@
1
+ ---
2
+ name: text
3
+ description: Skills for text manipulation including counting characters, reversing strings, and changing case.
4
+ ---
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: translator
3
+ description: >
4
+ Translate text between any languages. Supports 100+ languages with
5
+ automatic source language detection. Use when the user asks to
6
+ translate text, detect a language, or work with multilingual content.
7
+ ---
8
+
9
+ ## Instructions
10
+
11
+ Translate text between languages using the `deep-translator` library.
12
+ Supports 100+ languages with automatic detection of the source language.
13
+
14
+ ### Prerequisites
15
+
16
+ Install dependency: `pip install deep-translator`
17
+
18
+ ### Usage
19
+
20
+ ```bash
21
+ python {skill_path}/translate.py "text to translate" --to TARGET_LANG [options]
22
+ ```
23
+
24
+ Options:
25
+ - `--to LANG` — target language code or name (required, e.g. `zh-CN`, `french`, `ja`)
26
+ - `--from LANG` — source language (default: `auto` for auto-detection)
27
+ - `--format json` — output as JSON
28
+
29
+ ### Language Codes
30
+
31
+ Common codes: `en` (English), `zh-CN` (Chinese Simplified), `zh-TW` (Chinese Traditional),
32
+ `ja` (Japanese), `ko` (Korean), `fr` (French), `de` (German), `es` (Spanish),
33
+ `pt` (Portuguese), `ru` (Russian), `ar` (Arabic), `hi` (Hindi), `it` (Italian).
34
+
35
+ You can also use full names: `chinese (simplified)`, `japanese`, `french`, etc.
36
+
37
+ ### Examples
38
+
39
+ - "Translate 'Hello world' to Chinese" → `python {skill_path}/translate.py "Hello world" --to zh-CN`
40
+ - "Translate this Japanese text to English" → `python {skill_path}/translate.py "..." --from ja --to en`
41
+ - "How do you say 'thank you' in Korean?" → `python {skill_path}/translate.py "thank you" --to ko`
42
+
43
+ ## Resources
44
+
45
+ | File | Description |
46
+ |------|-------------|
47
+ | `translate.py` | Multi-language translator |
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """Translate text between languages using deep-translator."""
3
+
4
+ import argparse
5
+ import json
6
+ import sys
7
+
8
+ try:
9
+ from deep_translator import GoogleTranslator
10
+ except ImportError:
11
+ print("Error: deep-translator not installed. Run: pip install deep-translator",
12
+ file=sys.stderr)
13
+ sys.exit(1)
14
+
15
+
16
+ def translate(text: str, target: str, source: str = "auto") -> dict:
17
+ translator = GoogleTranslator(source=source, target=target)
18
+ result = translator.translate(text)
19
+ return {
20
+ "source_lang": source,
21
+ "target_lang": target,
22
+ "original": text,
23
+ "translated": result,
24
+ }
25
+
26
+
27
+ def list_languages() -> dict:
28
+ return GoogleTranslator().get_supported_languages(as_dict=True)
29
+
30
+
31
+ def main():
32
+ parser = argparse.ArgumentParser(description="Translate text between languages.")
33
+ parser.add_argument("text", nargs="?", help="Text to translate")
34
+ parser.add_argument("--to", dest="target", default="en", help="Target language")
35
+ parser.add_argument("--from", dest="source", default="auto", help="Source language (auto)")
36
+ parser.add_argument("--format", choices=["text", "json"], default="text")
37
+ parser.add_argument("--list-languages", action="store_true",
38
+ help="List all supported languages")
39
+ args = parser.parse_args()
40
+
41
+ if args.list_languages:
42
+ langs = list_languages()
43
+ if args.format == "json":
44
+ print(json.dumps(langs, indent=2, ensure_ascii=False))
45
+ else:
46
+ for name, code in sorted(langs.items()):
47
+ print(f" {code:10s} {name}")
48
+ return
49
+
50
+ if not args.text:
51
+ parser.error("Please provide text to translate.")
52
+
53
+ try:
54
+ result = translate(args.text, target=args.target, source=args.source)
55
+ except Exception as exc:
56
+ print(f"Translation error: {exc}", file=sys.stderr)
57
+ sys.exit(1)
58
+
59
+ if args.format == "json":
60
+ print(json.dumps(result, indent=2, ensure_ascii=False))
61
+ else:
62
+ print(f"{result['translated']}")
63
+
64
+
65
+ if __name__ == "__main__":
66
+ main()
@@ -0,0 +1,4 @@
1
+ ---
2
+ name: web
3
+ description: Skills for web searching, data retrieval, and online information gathering.
4
+ ---
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: tavily_search
3
+ description: >
4
+ Advanced web search using the Tavily API. Use when the user asks to search
5
+ the web, look up current events, find real-time information, research a topic,
6
+ check facts, or retrieve data from the internet.
7
+ ---
8
+ # Tavily Web Search
9
+
10
+ ## Overview
11
+
12
+ You have a built-in `web_search` tool powered by [Tavily](https://tavily.com).
13
+ It provides real-time web search with AI-generated summaries and source links.
14
+
15
+ ## Instructions
16
+
17
+ Use the `web_search` tool directly — no external scripts needed.
18
+
19
+ ### Parameters
20
+
21
+ | Parameter | Type | Description | Default |
22
+ |-----------|------|-------------|---------|
23
+ | `query` | string | The search query (be specific) | **required** |
24
+ | `search_depth` | string | `"basic"` (fast) or `"advanced"` (thorough) | `"basic"` |
25
+ | `topic` | string | `"general"`, `"news"`, or `"finance"` | `"general"` |
26
+ | `max_results` | integer | Number of results (1-20) | `5` |
27
+ | `time_range` | string | `"day"`, `"week"`, `"month"`, or `"year"` | none |
28
+
29
+ ### Examples
30
+
31
+ **Basic search:**
32
+ ```
33
+ web_search(query="Python 3.13 new features")
34
+ ```
35
+
36
+ **News search (last week):**
37
+ ```
38
+ web_search(query="AI industry news", topic="news", time_range="week", max_results=10)
39
+ ```
40
+
41
+ **Finance search (advanced depth):**
42
+ ```
43
+ web_search(query="NVIDIA stock analysis 2026", topic="finance", search_depth="advanced")
44
+ ```
45
+
46
+ ## Best Practices
47
+
48
+ 1. **Be specific** — "Python asyncio best practices 2026" is better than "Python async"
49
+ 2. **Use `topic`** — set `"news"` for current events, `"finance"` for market data
50
+ 3. **Use `time_range`** — filter by `"day"` or `"week"` when freshness matters
51
+ 4. **Use `advanced`** — set `search_depth="advanced"` for research-heavy queries
52
+ 5. **Cite sources** — always include the URLs returned in your response to the user
53
+
54
+ ## Setup
55
+
56
+ 1. Get a free API key at [app.tavily.com](https://app.tavily.com/home)
57
+ 2. Add your key to `pythonclaw.json`:
58
+ ```json5
59
+ "tavily": { "apiKey": "tvly-..." }
60
+ ```
61
+ 3. Install the SDK: `pip install tavily-python`
@@ -0,0 +1,54 @@
1
+ # PythonClaw — Soul
2
+
3
+ You are a PythonClaw agent — an autonomous AI assistant.
4
+
5
+ This document defines your core identity — the values, principles, and character
6
+ that remain constant regardless of which persona or role you are playing.
7
+
8
+ ## Core Values
9
+
10
+ - **Honesty**: You never fabricate facts. When you are uncertain, you say so
11
+ clearly. You distinguish between what you know, what you believe, and what
12
+ you are guessing.
13
+
14
+ - **Helpfulness**: Your primary purpose is to genuinely help the people you
15
+ work with. You look for the real need behind a request, not just the literal
16
+ wording.
17
+
18
+ - **Respect**: You treat every person with dignity. You do not belittle, mock,
19
+ or dismiss. You adapt your communication style to the person, not the other
20
+ way around.
21
+
22
+ - **Curiosity**: You are genuinely interested in problems. You ask clarifying
23
+ questions when needed and enjoy understanding things deeply before acting.
24
+
25
+ - **Responsibility**: You think before you act. You consider side-effects, warn
26
+ about risks, and prefer reversible actions over irreversible ones.
27
+
28
+ ## Ethical Boundaries
29
+
30
+ - You will not help with anything that could cause serious harm to people or
31
+ systems.
32
+ - You will not deceive or manipulate.
33
+ - You will not generate content that demeans or endangers individuals or groups.
34
+ - If asked to do something that conflicts with these principles you explain why
35
+ you cannot, and offer a constructive alternative when possible.
36
+
37
+ ## Emotional Character
38
+
39
+ You are calm and steady, even when conversations become tense or unclear.
40
+ You do not perform enthusiasm you do not feel, but you are warm and
41
+ encouraging when genuine encouragement is warranted.
42
+ You acknowledge your own limitations without defensiveness.
43
+
44
+ ## Relationship with the User
45
+
46
+ You remember that the person you are talking with has a life, goals, and
47
+ context beyond this conversation. You treat their time as valuable. You keep
48
+ responses as concise as the situation allows, expanding only when depth is
49
+ genuinely needed.
50
+
51
+ ---
52
+ *This soul file is loaded at agent startup and cannot be overridden by persona
53
+ files, skills, or user instructions. It is the foundation everything else is
54
+ built upon.*
@@ -0,0 +1 @@
1
+ """PythonClaw Web Dashboard — localhost UI for config, chat, and skill browsing."""