devduck 0.2.0__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of devduck might be problematic. Click here for more details.
- devduck/__init__.py +273 -99
- devduck/_version.py +2 -2
- devduck/tools/create_subagent.py +659 -0
- devduck/tools/store_in_kb.py +187 -0
- devduck/tools/tcp.py +0 -3
- devduck/tools/use_github.py +438 -0
- devduck/tools/websocket.py +1 -1
- {devduck-0.2.0.dist-info → devduck-0.3.0.dist-info}/METADATA +17 -8
- devduck-0.3.0.dist-info/RECORD +18 -0
- devduck/install.sh +0 -42
- devduck-0.2.0.dist-info/RECORD +0 -16
- {devduck-0.2.0.dist-info → devduck-0.3.0.dist-info}/WHEEL +0 -0
- {devduck-0.2.0.dist-info → devduck-0.3.0.dist-info}/entry_points.txt +0 -0
- {devduck-0.2.0.dist-info → devduck-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {devduck-0.2.0.dist-info → devduck-0.3.0.dist-info}/top_level.txt +0 -0
devduck/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ import platform
|
|
|
10
10
|
import socket
|
|
11
11
|
import logging
|
|
12
12
|
import tempfile
|
|
13
|
+
from datetime import datetime
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
from datetime import datetime
|
|
15
16
|
from typing import Dict, Any
|
|
@@ -51,19 +52,18 @@ logger.info("DevDuck logging system initialized")
|
|
|
51
52
|
|
|
52
53
|
# 🔧 Self-healing dependency installer
|
|
53
54
|
def ensure_deps():
|
|
54
|
-
"""Install dependencies at runtime if missing"""
|
|
55
|
+
"""Install core dependencies at runtime if missing"""
|
|
55
56
|
import importlib.metadata
|
|
56
57
|
|
|
57
|
-
deps
|
|
58
|
+
# Only ensure core deps - everything else is optional
|
|
59
|
+
core_deps = [
|
|
58
60
|
"strands-agents",
|
|
59
|
-
"
|
|
60
|
-
"strands-agents[openai]",
|
|
61
|
-
"strands-agents[anthropic]",
|
|
61
|
+
"prompt_toolkit",
|
|
62
62
|
"strands-agents-tools",
|
|
63
63
|
]
|
|
64
64
|
|
|
65
65
|
# Check each package individually using importlib.metadata
|
|
66
|
-
for dep in
|
|
66
|
+
for dep in core_deps:
|
|
67
67
|
pkg_name = dep.split("[")[0] # Get base package name (strip extras)
|
|
68
68
|
try:
|
|
69
69
|
# Check if package is installed using metadata (checks PyPI package name)
|
|
@@ -606,7 +606,16 @@ def append_to_shell_history(query, response):
|
|
|
606
606
|
|
|
607
607
|
# 🦆 The devduck agent
|
|
608
608
|
class DevDuck:
|
|
609
|
-
def __init__(
|
|
609
|
+
def __init__(
|
|
610
|
+
self,
|
|
611
|
+
auto_start_servers=True,
|
|
612
|
+
tcp_port=9999,
|
|
613
|
+
ws_port=8080,
|
|
614
|
+
mcp_port=8000,
|
|
615
|
+
enable_tcp=True,
|
|
616
|
+
enable_ws=True,
|
|
617
|
+
enable_mcp=True,
|
|
618
|
+
):
|
|
610
619
|
"""Initialize the minimalist adaptive agent"""
|
|
611
620
|
logger.info("Initializing DevDuck agent...")
|
|
612
621
|
try:
|
|
@@ -622,27 +631,101 @@ class DevDuck:
|
|
|
622
631
|
|
|
623
632
|
# Import after ensuring deps
|
|
624
633
|
from strands import Agent, tool
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
634
|
+
|
|
635
|
+
# Core tools (always available)
|
|
636
|
+
core_tools = []
|
|
637
|
+
|
|
638
|
+
# Try importing optional tools gracefully
|
|
639
|
+
try:
|
|
640
|
+
from strands.models.ollama import OllamaModel
|
|
641
|
+
except ImportError:
|
|
642
|
+
logger.warning(
|
|
643
|
+
"strands-agents[ollama] not installed - Ollama model unavailable"
|
|
644
|
+
)
|
|
645
|
+
OllamaModel = None
|
|
646
|
+
|
|
647
|
+
try:
|
|
648
|
+
from strands_tools.utils.models.model import create_model
|
|
649
|
+
except ImportError:
|
|
650
|
+
logger.warning(
|
|
651
|
+
"strands-agents-tools not installed - create_model unavailable"
|
|
652
|
+
)
|
|
653
|
+
create_model = None
|
|
654
|
+
|
|
655
|
+
try:
|
|
656
|
+
from .tools import (
|
|
657
|
+
tcp,
|
|
658
|
+
websocket,
|
|
659
|
+
mcp_server,
|
|
660
|
+
install_tools,
|
|
661
|
+
use_github,
|
|
662
|
+
create_subagent,
|
|
663
|
+
store_in_kb,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
core_tools.extend(
|
|
667
|
+
[
|
|
668
|
+
tcp,
|
|
669
|
+
websocket,
|
|
670
|
+
mcp_server,
|
|
671
|
+
install_tools,
|
|
672
|
+
use_github,
|
|
673
|
+
create_subagent,
|
|
674
|
+
store_in_kb,
|
|
675
|
+
]
|
|
676
|
+
)
|
|
677
|
+
except ImportError as e:
|
|
678
|
+
logger.warning(f"devduck.tools import failed: {e}")
|
|
679
|
+
|
|
680
|
+
try:
|
|
681
|
+
from strands_fun_tools import (
|
|
682
|
+
listen,
|
|
683
|
+
cursor,
|
|
684
|
+
clipboard,
|
|
685
|
+
screen_reader,
|
|
686
|
+
yolo_vision,
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
core_tools.extend(
|
|
690
|
+
[listen, cursor, clipboard, screen_reader, yolo_vision]
|
|
691
|
+
)
|
|
692
|
+
except ImportError:
|
|
693
|
+
logger.info(
|
|
694
|
+
"strands-fun-tools not installed - vision/audio tools unavailable (install with: pip install devduck[all])"
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
try:
|
|
698
|
+
from strands_tools import (
|
|
699
|
+
shell,
|
|
700
|
+
editor,
|
|
701
|
+
calculator,
|
|
702
|
+
python_repl,
|
|
703
|
+
image_reader,
|
|
704
|
+
use_agent,
|
|
705
|
+
load_tool,
|
|
706
|
+
environment,
|
|
707
|
+
mcp_client,
|
|
708
|
+
retrieve,
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
core_tools.extend(
|
|
712
|
+
[
|
|
713
|
+
shell,
|
|
714
|
+
editor,
|
|
715
|
+
calculator,
|
|
716
|
+
python_repl,
|
|
717
|
+
image_reader,
|
|
718
|
+
use_agent,
|
|
719
|
+
load_tool,
|
|
720
|
+
environment,
|
|
721
|
+
mcp_client,
|
|
722
|
+
retrieve,
|
|
723
|
+
]
|
|
724
|
+
)
|
|
725
|
+
except ImportError:
|
|
726
|
+
logger.info(
|
|
727
|
+
"strands-agents-tools not installed - core tools unavailable (install with: pip install devduck[all])"
|
|
728
|
+
)
|
|
646
729
|
|
|
647
730
|
# Wrap system_prompt_tool with @tool decorator
|
|
648
731
|
@tool
|
|
@@ -665,39 +748,21 @@ class DevDuck:
|
|
|
665
748
|
"""View and manage DevDuck logs."""
|
|
666
749
|
return view_logs_tool(action, lines, pattern)
|
|
667
750
|
|
|
668
|
-
#
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
python_repl,
|
|
674
|
-
image_reader,
|
|
675
|
-
use_agent,
|
|
676
|
-
load_tool,
|
|
677
|
-
environment,
|
|
678
|
-
system_prompt,
|
|
679
|
-
view_logs,
|
|
680
|
-
tcp,
|
|
681
|
-
websocket,
|
|
682
|
-
mcp_server,
|
|
683
|
-
install_tools,
|
|
684
|
-
mcp_client,
|
|
685
|
-
listen,
|
|
686
|
-
cursor,
|
|
687
|
-
clipboard,
|
|
688
|
-
screen_reader,
|
|
689
|
-
yolo_vision,
|
|
690
|
-
]
|
|
751
|
+
# Add built-in tools to the toolset
|
|
752
|
+
core_tools.extend([system_prompt, view_logs])
|
|
753
|
+
|
|
754
|
+
# Assign tools
|
|
755
|
+
self.tools = core_tools
|
|
691
756
|
|
|
692
757
|
logger.info(f"Initialized {len(self.tools)} tools")
|
|
693
758
|
|
|
694
759
|
# Check if MODEL_PROVIDER env variable is set
|
|
695
760
|
model_provider = os.getenv("MODEL_PROVIDER")
|
|
696
761
|
|
|
697
|
-
if model_provider:
|
|
762
|
+
if model_provider and create_model:
|
|
698
763
|
# Use create_model utility for any provider (bedrock, anthropic, etc.)
|
|
699
764
|
self.agent_model = create_model(provider=model_provider)
|
|
700
|
-
|
|
765
|
+
elif OllamaModel:
|
|
701
766
|
# Fallback to default Ollama behavior
|
|
702
767
|
self.agent_model = OllamaModel(
|
|
703
768
|
host=self.ollama_host,
|
|
@@ -705,6 +770,10 @@ class DevDuck:
|
|
|
705
770
|
temperature=1,
|
|
706
771
|
keep_alive="5m",
|
|
707
772
|
)
|
|
773
|
+
else:
|
|
774
|
+
raise ImportError(
|
|
775
|
+
"No model provider available. Install with: pip install devduck[all]"
|
|
776
|
+
)
|
|
708
777
|
|
|
709
778
|
# Create agent with self-healing
|
|
710
779
|
self.agent = Agent(
|
|
@@ -714,54 +783,59 @@ class DevDuck:
|
|
|
714
783
|
load_tools_from_directory=True,
|
|
715
784
|
)
|
|
716
785
|
|
|
717
|
-
# 🚀 AUTO-START SERVERS: TCP
|
|
786
|
+
# 🚀 AUTO-START SERVERS: TCP, WebSocket, MCP HTTP
|
|
718
787
|
if auto_start_servers:
|
|
719
788
|
logger.info("Auto-starting servers...")
|
|
720
789
|
print("🦆 Auto-starting servers...")
|
|
721
790
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
791
|
+
if enable_tcp:
|
|
792
|
+
try:
|
|
793
|
+
# Start TCP server on configurable port
|
|
794
|
+
tcp_result = self.agent.tool.tcp(
|
|
795
|
+
action="start_server", port=tcp_port
|
|
796
|
+
)
|
|
797
|
+
if tcp_result.get("status") == "success":
|
|
798
|
+
logger.info(f"✓ TCP server started on port {tcp_port}")
|
|
799
|
+
print(f"🦆 ✓ TCP server: localhost:{tcp_port}")
|
|
800
|
+
else:
|
|
801
|
+
logger.warning(f"TCP server start issue: {tcp_result}")
|
|
802
|
+
except Exception as e:
|
|
803
|
+
logger.error(f"Failed to start TCP server: {e}")
|
|
804
|
+
print(f"🦆 ⚠ TCP server failed: {e}")
|
|
733
805
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
806
|
+
if enable_ws:
|
|
807
|
+
try:
|
|
808
|
+
# Start WebSocket server on configurable port
|
|
809
|
+
ws_result = self.agent.tool.websocket(
|
|
810
|
+
action="start_server", port=ws_port
|
|
811
|
+
)
|
|
812
|
+
if ws_result.get("status") == "success":
|
|
813
|
+
logger.info(f"✓ WebSocket server started on port {ws_port}")
|
|
814
|
+
print(f"🦆 ✓ WebSocket server: localhost:{ws_port}")
|
|
815
|
+
else:
|
|
816
|
+
logger.warning(f"WebSocket server start issue: {ws_result}")
|
|
817
|
+
except Exception as e:
|
|
818
|
+
logger.error(f"Failed to start WebSocket server: {e}")
|
|
819
|
+
print(f"🦆 ⚠ WebSocket server failed: {e}")
|
|
747
820
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
821
|
+
if enable_mcp:
|
|
822
|
+
try:
|
|
823
|
+
# Start MCP server with HTTP transport on configurable port
|
|
824
|
+
mcp_result = self.agent.tool.mcp_server(
|
|
825
|
+
action="start",
|
|
826
|
+
transport="http",
|
|
827
|
+
port=mcp_port,
|
|
828
|
+
expose_agent=True,
|
|
829
|
+
agent=self.agent,
|
|
830
|
+
)
|
|
831
|
+
if mcp_result.get("status") == "success":
|
|
832
|
+
logger.info(f"✓ MCP HTTP server started on port {mcp_port}")
|
|
833
|
+
print(f"🦆 ✓ MCP server: http://localhost:{mcp_port}/mcp")
|
|
834
|
+
else:
|
|
835
|
+
logger.warning(f"MCP server start issue: {mcp_result}")
|
|
836
|
+
except Exception as e:
|
|
837
|
+
logger.error(f"Failed to start MCP server: {e}")
|
|
838
|
+
print(f"🦆 ⚠ MCP server failed: {e}")
|
|
765
839
|
|
|
766
840
|
# Start file watcher for auto hot-reload
|
|
767
841
|
self._start_file_watcher()
|
|
@@ -847,6 +921,12 @@ You have full access to your own source code for self-awareness and self-modific
|
|
|
847
921
|
- Connect from Claude Desktop, other agents, or custom clients
|
|
848
922
|
- Full bidirectional communication
|
|
849
923
|
|
|
924
|
+
## Knowledge Base Integration:
|
|
925
|
+
- **Automatic RAG** - Set STRANDS_KNOWLEDGE_BASE_ID to enable automatic retrieval/storage
|
|
926
|
+
- Before each query: Retrieves relevant context from knowledge base
|
|
927
|
+
- After each response: Stores conversation for future reference
|
|
928
|
+
- Seamless memory across sessions without manual tool calls
|
|
929
|
+
|
|
850
930
|
## Tool Creation Patterns:
|
|
851
931
|
|
|
852
932
|
### **1. @tool Decorator:**
|
|
@@ -996,7 +1076,7 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
|
|
|
996
1076
|
self.agent = None
|
|
997
1077
|
|
|
998
1078
|
def __call__(self, query):
|
|
999
|
-
"""Make the agent callable"""
|
|
1079
|
+
"""Make the agent callable with automatic knowledge base integration"""
|
|
1000
1080
|
if not self.agent:
|
|
1001
1081
|
logger.warning("Agent unavailable - attempted to call with query")
|
|
1002
1082
|
return "🦆 Agent unavailable - try: devduck.restart()"
|
|
@@ -1006,8 +1086,37 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
|
|
|
1006
1086
|
# Mark agent as executing to prevent hot-reload interruption
|
|
1007
1087
|
self._agent_executing = True
|
|
1008
1088
|
|
|
1089
|
+
# 📚 Knowledge Base Retrieval (BEFORE agent runs)
|
|
1090
|
+
knowledge_base_id = os.getenv("STRANDS_KNOWLEDGE_BASE_ID")
|
|
1091
|
+
if knowledge_base_id and hasattr(self.agent, "tool"):
|
|
1092
|
+
try:
|
|
1093
|
+
if "retrieve" in self.agent.tool_names:
|
|
1094
|
+
logger.info(f"Retrieving context from KB: {knowledge_base_id}")
|
|
1095
|
+
self.agent.tool.retrieve(
|
|
1096
|
+
text=query, knowledgeBaseId=knowledge_base_id
|
|
1097
|
+
)
|
|
1098
|
+
except Exception as e:
|
|
1099
|
+
logger.warning(f"KB retrieval failed: {e}")
|
|
1100
|
+
|
|
1101
|
+
# Run the agent
|
|
1009
1102
|
result = self.agent(query)
|
|
1010
1103
|
|
|
1104
|
+
# 💾 Knowledge Base Storage (AFTER agent runs)
|
|
1105
|
+
if knowledge_base_id and hasattr(self.agent, "tool"):
|
|
1106
|
+
try:
|
|
1107
|
+
if "store_in_kb" in self.agent.tool_names:
|
|
1108
|
+
|
|
1109
|
+
conversation_content = f"Input: {query}, Result: {result!s}"
|
|
1110
|
+
conversation_title = f"DevDuck: {datetime.now().strftime('%Y-%m-%d')} | {query[:500]}"
|
|
1111
|
+
self.agent.tool.store_in_kb(
|
|
1112
|
+
content=conversation_content,
|
|
1113
|
+
title=conversation_title,
|
|
1114
|
+
knowledge_base_id=knowledge_base_id,
|
|
1115
|
+
)
|
|
1116
|
+
logger.info(f"Stored conversation in KB: {knowledge_base_id}")
|
|
1117
|
+
except Exception as e:
|
|
1118
|
+
logger.warning(f"KB storage failed: {e}")
|
|
1119
|
+
|
|
1011
1120
|
# Agent finished - check if reload was pending
|
|
1012
1121
|
self._agent_executing = False
|
|
1013
1122
|
logger.info("Agent call completed successfully")
|
|
@@ -1157,7 +1266,24 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
|
|
|
1157
1266
|
|
|
1158
1267
|
|
|
1159
1268
|
# 🦆 Auto-initialize when imported
|
|
1160
|
-
|
|
1269
|
+
# Check environment variables to control server configuration
|
|
1270
|
+
_auto_start = os.getenv("DEVDUCK_AUTO_START_SERVERS", "true").lower() == "true"
|
|
1271
|
+
_tcp_port = int(os.getenv("DEVDUCK_TCP_PORT", "9999"))
|
|
1272
|
+
_ws_port = int(os.getenv("DEVDUCK_WS_PORT", "8080"))
|
|
1273
|
+
_mcp_port = int(os.getenv("DEVDUCK_MCP_PORT", "8000"))
|
|
1274
|
+
_enable_tcp = os.getenv("DEVDUCK_ENABLE_TCP", "true").lower() == "true"
|
|
1275
|
+
_enable_ws = os.getenv("DEVDUCK_ENABLE_WS", "true").lower() == "true"
|
|
1276
|
+
_enable_mcp = os.getenv("DEVDUCK_ENABLE_MCP", "true").lower() == "true"
|
|
1277
|
+
|
|
1278
|
+
devduck = DevDuck(
|
|
1279
|
+
auto_start_servers=_auto_start,
|
|
1280
|
+
tcp_port=_tcp_port,
|
|
1281
|
+
ws_port=_ws_port,
|
|
1282
|
+
mcp_port=_mcp_port,
|
|
1283
|
+
enable_tcp=_enable_tcp,
|
|
1284
|
+
enable_ws=_enable_ws,
|
|
1285
|
+
enable_mcp=_enable_mcp,
|
|
1286
|
+
)
|
|
1161
1287
|
|
|
1162
1288
|
|
|
1163
1289
|
# 🚀 Convenience functions
|
|
@@ -1426,9 +1552,57 @@ You have full access to your own source code for self-awareness and self-modific
|
|
|
1426
1552
|
|
|
1427
1553
|
def cli():
|
|
1428
1554
|
"""CLI entry point for pip-installed devduck command"""
|
|
1555
|
+
import argparse
|
|
1556
|
+
|
|
1557
|
+
parser = argparse.ArgumentParser(
|
|
1558
|
+
description="🦆 DevDuck - Extreme minimalist self-adapting agent",
|
|
1559
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
1560
|
+
epilog="""
|
|
1561
|
+
Examples:
|
|
1562
|
+
devduck # Start interactive mode
|
|
1563
|
+
devduck "your query here" # One-shot query
|
|
1564
|
+
devduck --tcp-port 9000 # Custom TCP port
|
|
1565
|
+
devduck --no-tcp --no-ws # Disable TCP and WebSocket
|
|
1566
|
+
devduck --mcp-port 3000 # Custom MCP port
|
|
1567
|
+
""",
|
|
1568
|
+
)
|
|
1569
|
+
|
|
1570
|
+
# Query argument
|
|
1571
|
+
parser.add_argument("query", nargs="*", help="Query to send to the agent")
|
|
1572
|
+
|
|
1573
|
+
# Server configuration
|
|
1574
|
+
parser.add_argument(
|
|
1575
|
+
"--tcp-port", type=int, default=9999, help="TCP server port (default: 9999)"
|
|
1576
|
+
)
|
|
1577
|
+
parser.add_argument(
|
|
1578
|
+
"--ws-port",
|
|
1579
|
+
type=int,
|
|
1580
|
+
default=8080,
|
|
1581
|
+
help="WebSocket server port (default: 8080)",
|
|
1582
|
+
)
|
|
1583
|
+
parser.add_argument(
|
|
1584
|
+
"--mcp-port",
|
|
1585
|
+
type=int,
|
|
1586
|
+
default=8000,
|
|
1587
|
+
help="MCP HTTP server port (default: 8000)",
|
|
1588
|
+
)
|
|
1589
|
+
|
|
1590
|
+
# Server enable/disable flags
|
|
1591
|
+
parser.add_argument("--no-tcp", action="store_true", help="Disable TCP server")
|
|
1592
|
+
parser.add_argument("--no-ws", action="store_true", help="Disable WebSocket server")
|
|
1593
|
+
parser.add_argument("--no-mcp", action="store_true", help="Disable MCP server")
|
|
1594
|
+
parser.add_argument(
|
|
1595
|
+
"--no-servers",
|
|
1596
|
+
action="store_true",
|
|
1597
|
+
help="Disable all servers (no TCP, WebSocket, or MCP)",
|
|
1598
|
+
)
|
|
1599
|
+
|
|
1600
|
+
args = parser.parse_args()
|
|
1601
|
+
|
|
1429
1602
|
logger.info("CLI mode started")
|
|
1430
|
-
|
|
1431
|
-
|
|
1603
|
+
|
|
1604
|
+
if args.query:
|
|
1605
|
+
query = " ".join(args.query)
|
|
1432
1606
|
logger.info(f"CLI query: {query}")
|
|
1433
1607
|
result = ask(query)
|
|
1434
1608
|
print(result)
|
devduck/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.3.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|