versionhq 1.1.7.5__tar.gz → 1.1.7.7__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 (72) hide show
  1. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.gitignore +2 -0
  2. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/PKG-INFO +9 -7
  3. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/README.md +2 -3
  4. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/pyproject.toml +8 -6
  5. versionhq-1.1.7.7/requirements-dev.txt +9 -0
  6. versionhq-1.1.7.7/requirements.txt +220 -0
  7. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/__init__.py +1 -1
  8. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/agent/model.py +5 -5
  9. versionhq-1.1.7.7/src/versionhq/storage/task_output_storage.py +141 -0
  10. versionhq-1.1.7.7/src/versionhq/task/log_handler.py +59 -0
  11. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/task/model.py +49 -31
  12. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/team/model.py +28 -67
  13. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq.egg-info/PKG-INFO +9 -7
  14. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq.egg-info/SOURCES.txt +4 -0
  15. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq.egg-info/requires.txt +3 -3
  16. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/task/task_test.py +26 -5
  17. versionhq-1.1.7.7/tests/team/__init__.py +0 -0
  18. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/team/team_test.py +9 -104
  19. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/uv.lock +19 -24
  20. versionhq-1.1.7.5/requirements.txt +0 -20
  21. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.github/workflows/publish.yml +0 -0
  22. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.github/workflows/publish_testpypi.yml +0 -0
  23. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.github/workflows/run_tests.yml +0 -0
  24. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.github/workflows/security_check.yml +0 -0
  25. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.pre-commit-config.yaml +0 -0
  26. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/.python-version +0 -0
  27. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/LICENSE +0 -0
  28. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/SECURITY.md +0 -0
  29. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/db/preprocess.py +0 -0
  30. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/runtime.txt +0 -0
  31. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/setup.cfg +0 -0
  32. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/__init__.py +0 -0
  33. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/cache_handler.py +0 -0
  34. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/i18n.py +0 -0
  35. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/logger.py +0 -0
  36. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/process_config.py +0 -0
  37. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/rpm_controller.py +0 -0
  38. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/_utils/usage_metrics.py +0 -0
  39. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/agent/TEMPLATES/Backstory.py +0 -0
  40. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/agent/TEMPLATES/__init__.py +0 -0
  41. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/agent/__init__.py +0 -0
  42. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/agent/parser.py +0 -0
  43. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/cli/__init__.py +0 -0
  44. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/__init__.py +0 -0
  45. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/customer/__init__.py +0 -0
  46. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/customer/model.py +0 -0
  47. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/product/__init__.py +0 -0
  48. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/product/model.py +0 -0
  49. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/workflow/__init__.py +0 -0
  50. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/clients/workflow/model.py +0 -0
  51. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/llm/__init__.py +0 -0
  52. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/llm/llm_vars.py +0 -0
  53. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/llm/model.py +0 -0
  54. {versionhq-1.1.7.5/src/versionhq/team → versionhq-1.1.7.7/src/versionhq/storage}/__init__.py +0 -0
  55. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/task/__init__.py +0 -0
  56. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/task/formatter.py +0 -0
  57. {versionhq-1.1.7.5/src/versionhq/tool → versionhq-1.1.7.7/src/versionhq/team}/__init__.py +0 -0
  58. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/team/team_planner.py +0 -0
  59. {versionhq-1.1.7.5/tests → versionhq-1.1.7.7/src/versionhq/tool}/__init__.py +0 -0
  60. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/tool/decorator.py +0 -0
  61. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/tool/model.py +0 -0
  62. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq/tool/tool_handler.py +0 -0
  63. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq.egg-info/dependency_links.txt +0 -0
  64. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/src/versionhq.egg-info/top_level.txt +0 -0
  65. {versionhq-1.1.7.5/tests/agent → versionhq-1.1.7.7/tests}/__init__.py +0 -0
  66. {versionhq-1.1.7.5/tests/cli → versionhq-1.1.7.7/tests/agent}/__init__.py +0 -0
  67. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/agent/agent_test.py +0 -0
  68. {versionhq-1.1.7.5/tests/task → versionhq-1.1.7.7/tests/cli}/__init__.py +0 -0
  69. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/clients/workflow_test.py +0 -0
  70. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/conftest.py +0 -0
  71. {versionhq-1.1.7.5/tests/team → versionhq-1.1.7.7/tests/task}/__init__.py +0 -0
  72. {versionhq-1.1.7.5 → versionhq-1.1.7.7}/tests/team/Prompts/Demo_test.py +0 -0
@@ -1,4 +1,5 @@
1
1
  knowledge/
2
+ memory/
2
3
 
3
4
  composio.py
4
5
  memo.txt
@@ -8,6 +9,7 @@ build/
8
9
  .pypirc
9
10
  uploads/
10
11
  sample_dataset/
12
+ chroma.sqlite3
11
13
  *egg-info/
12
14
 
13
15
  __pycache__/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: versionhq
3
- Version: 1.1.7.5
3
+ Version: 1.1.7.7
4
4
  Summary: LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -32,6 +32,9 @@ Keywords: orchestration framework,orchestration,ai agent,multi-agent system,RAG,
32
32
  Classifier: Programming Language :: Python
33
33
  Classifier: License :: OSI Approved :: MIT License
34
34
  Classifier: Operating System :: OS Independent
35
+ Classifier: Development Status :: 3 - Alpha
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: Topic :: Software Development :: Build Tools
35
38
  Requires-Python: >=3.12
36
39
  Description-Content-Type: text/markdown
37
40
  License-File: LICENSE
@@ -43,12 +46,12 @@ Requires-Dist: typing
43
46
  Requires-Dist: json-repair>=0.31.0
44
47
  Requires-Dist: litellm>=1.55.8
45
48
  Requires-Dist: openai>=1.57.0
46
- Requires-Dist: composio-openai>=0.6.0
47
- Requires-Dist: pre-commit>=4.0.1
48
- Requires-Dist: gunicorn>=23.0.0
49
+ Requires-Dist: composio-openai>=0.6.9
49
50
  Requires-Dist: composio>=0.1.0
50
51
  Requires-Dist: setuptools>=75.6.0
51
52
  Requires-Dist: wheel>=0.45.1
53
+ Requires-Dist: python-dotenv>=1.0.0
54
+ Requires-Dist: appdirs>=1.4.4
52
55
 
53
56
  # Overview
54
57
 
@@ -56,7 +59,7 @@ Requires-Dist: wheel>=0.45.1
56
59
  [![Publisher](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml/badge.svg)](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
57
60
  ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.5-blue)
58
61
  ![python ver](https://img.shields.io/badge/Python-3.12/3.13-purple)
59
- ![pyenv ver](https://img.shields.io/badge/pyenv-2.4.23-orange)
62
+ ![pyenv ver](https://img.shields.io/badge/pyenv-2.5.0-orange)
60
63
 
61
64
 
62
65
  An LLM orchestration frameworks for multi-agent systems with RAG to autopilot outbound workflows.
@@ -276,8 +279,7 @@ src/
276
279
  ```
277
280
  uv venv
278
281
  source .venv/bin/activate
279
-
280
- uv pip install -r requirements.txt -v
282
+ uv pip sync
281
283
  ```
282
284
 
283
285
  * In case of AssertionError/module mismatch, run Python version control using `.pyenv`
@@ -4,7 +4,7 @@
4
4
  [![Publisher](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml/badge.svg)](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
5
5
  ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.5-blue)
6
6
  ![python ver](https://img.shields.io/badge/Python-3.12/3.13-purple)
7
- ![pyenv ver](https://img.shields.io/badge/pyenv-2.4.23-orange)
7
+ ![pyenv ver](https://img.shields.io/badge/pyenv-2.5.0-orange)
8
8
 
9
9
 
10
10
  An LLM orchestration frameworks for multi-agent systems with RAG to autopilot outbound workflows.
@@ -224,8 +224,7 @@ src/
224
224
  ```
225
225
  uv venv
226
226
  source .venv/bin/activate
227
-
228
- uv pip install -r requirements.txt -v
227
+ uv pip sync
229
228
  ```
230
229
 
231
230
  * In case of AssertionError/module mismatch, run Python version control using `.pyenv`
@@ -15,7 +15,7 @@ exclude = ["test*", "__pycache__"]
15
15
 
16
16
  [project]
17
17
  name = "versionhq"
18
- version = "1.1.7.5"
18
+ version = "1.1.7.7"
19
19
  authors = [{ name = "Kuriko Iwai", email = "kuriko@versi0n.io" }]
20
20
  description = "LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows"
21
21
  readme = "README.md"
@@ -31,17 +31,20 @@ dependencies = [
31
31
  "json-repair>=0.31.0",
32
32
  "litellm>=1.55.8",
33
33
  "openai>=1.57.0",
34
- "composio-openai>=0.6.0",
35
- "pre-commit>=4.0.1",
36
- "gunicorn>=23.0.0",
34
+ "composio-openai>=0.6.9",
37
35
  "composio>=0.1.0",
38
36
  "setuptools>=75.6.0",
39
37
  "wheel>=0.45.1",
38
+ "python-dotenv>=1.0.0",
39
+ "appdirs>=1.4.4",
40
40
  ]
41
41
  classifiers = [
42
42
  "Programming Language :: Python",
43
43
  "License :: OSI Approved :: MIT License",
44
44
  "Operating System :: OS Independent",
45
+ "Development Status :: 3 - Alpha",
46
+ "Intended Audience :: Developers",
47
+ "Topic :: Software Development :: Build Tools",
45
48
  ]
46
49
 
47
50
  [project.urls]
@@ -52,10 +55,9 @@ Issues = "https://github.com/versionHQ/multi-agent-system/issues"
52
55
  [tool.uv]
53
56
  dev-dependencies = [
54
57
  "mypy>=1.10.0",
55
- "pre-commit>=3.6.0",
58
+ "pre-commit>=4.0.1",
56
59
  "pytest>=8.0.0",
57
60
  "pytest-vcr>=1.0.2",
58
- "python-dotenv>=1.0.0",
59
61
  "black",
60
62
  "bandit",
61
63
  "twine",
@@ -0,0 +1,9 @@
1
+ mypy>=1.10.0
2
+ pre-commit>=4.0.1
3
+ pytest>=8.0.0
4
+ pytest-vcr>=1.0.2
5
+ python-dotenv>=1.0.0
6
+ black
7
+ bandit
8
+ twine
9
+ pytest>=8.3.4
@@ -0,0 +1,220 @@
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv pip compile pyproject.toml -o requirements.txt
3
+ aiohappyeyeballs==2.4.4
4
+ # via aiohttp
5
+ aiohttp==3.11.11
6
+ # via
7
+ # composio-core
8
+ # litellm
9
+ aiosignal==1.3.2
10
+ # via aiohttp
11
+ annotated-types==0.7.0
12
+ # via pydantic
13
+ anyio==4.7.0
14
+ # via
15
+ # httpx
16
+ # openai
17
+ # starlette
18
+ appdirs==1.4.4
19
+ # via versionhq (pyproject.toml)
20
+ attrs==24.3.0
21
+ # via
22
+ # aiohttp
23
+ # jsonschema
24
+ # referencing
25
+ bcrypt==4.2.1
26
+ # via paramiko
27
+ certifi==2024.12.14
28
+ # via
29
+ # httpcore
30
+ # httpx
31
+ # requests
32
+ # sentry-sdk
33
+ cffi==1.17.1
34
+ # via
35
+ # cryptography
36
+ # pynacl
37
+ charset-normalizer==3.4.1
38
+ # via requests
39
+ click==8.1.8
40
+ # via
41
+ # composio-core
42
+ # litellm
43
+ # uvicorn
44
+ composio==0.1.0
45
+ # via versionhq (pyproject.toml)
46
+ composio-core==0.6.9
47
+ # via composio-openai
48
+ composio-openai==0.6.9
49
+ # via versionhq (pyproject.toml)
50
+ cryptography==44.0.0
51
+ # via paramiko
52
+ distro==1.9.0
53
+ # via openai
54
+ fastapi==0.115.6
55
+ # via composio-core
56
+ filelock==3.16.1
57
+ # via huggingface-hub
58
+ frozenlist==1.5.0
59
+ # via
60
+ # aiohttp
61
+ # aiosignal
62
+ fsspec==2024.12.0
63
+ # via huggingface-hub
64
+ h11==0.14.0
65
+ # via
66
+ # httpcore
67
+ # uvicorn
68
+ httpcore==1.0.7
69
+ # via httpx
70
+ httpx==0.27.2
71
+ # via
72
+ # litellm
73
+ # openai
74
+ huggingface-hub==0.27.0
75
+ # via tokenizers
76
+ idna==3.10
77
+ # via
78
+ # anyio
79
+ # httpx
80
+ # requests
81
+ # yarl
82
+ importlib-metadata==8.5.0
83
+ # via
84
+ # composio-core
85
+ # litellm
86
+ inflection==0.5.1
87
+ # via composio-core
88
+ jinja2==3.1.5
89
+ # via litellm
90
+ jiter==0.8.2
91
+ # via openai
92
+ json-repair==0.35.0
93
+ # via versionhq (pyproject.toml)
94
+ jsonref==1.1.0
95
+ # via composio-core
96
+ jsonschema==4.23.0
97
+ # via
98
+ # composio-core
99
+ # litellm
100
+ jsonschema-specifications==2024.10.1
101
+ # via jsonschema
102
+ litellm==1.56.5
103
+ # via versionhq (pyproject.toml)
104
+ markdown-it-py==3.0.0
105
+ # via rich
106
+ markupsafe==3.0.2
107
+ # via
108
+ # jinja2
109
+ # werkzeug
110
+ mdurl==0.1.2
111
+ # via markdown-it-py
112
+ multidict==6.1.0
113
+ # via
114
+ # aiohttp
115
+ # yarl
116
+ openai==1.58.1
117
+ # via
118
+ # versionhq (pyproject.toml)
119
+ # composio-openai
120
+ # litellm
121
+ packaging==24.2
122
+ # via huggingface-hub
123
+ paramiko==3.5.0
124
+ # via composio-core
125
+ propcache==0.2.1
126
+ # via
127
+ # aiohttp
128
+ # yarl
129
+ pycparser==2.22
130
+ # via cffi
131
+ pydantic==2.10.4
132
+ # via
133
+ # versionhq (pyproject.toml)
134
+ # composio-core
135
+ # fastapi
136
+ # litellm
137
+ # openai
138
+ pydantic-core==2.27.2
139
+ # via pydantic
140
+ pygments==2.18.0
141
+ # via rich
142
+ pynacl==1.5.0
143
+ # via paramiko
144
+ pyperclip==1.9.0
145
+ # via composio-core
146
+ pysher==1.0.8
147
+ # via composio-core
148
+ python-dotenv==1.0.1
149
+ # via
150
+ # versionhq (pyproject.toml)
151
+ # litellm
152
+ pyyaml==6.0.2
153
+ # via huggingface-hub
154
+ referencing==0.35.1
155
+ # via
156
+ # jsonschema
157
+ # jsonschema-specifications
158
+ regex==2024.11.6
159
+ # via
160
+ # versionhq (pyproject.toml)
161
+ # tiktoken
162
+ requests==2.32.3
163
+ # via
164
+ # versionhq (pyproject.toml)
165
+ # composio-core
166
+ # huggingface-hub
167
+ # pysher
168
+ # tiktoken
169
+ rich==13.9.4
170
+ # via composio-core
171
+ rpds-py==0.22.3
172
+ # via
173
+ # jsonschema
174
+ # referencing
175
+ semver==3.0.2
176
+ # via composio-core
177
+ sentry-sdk==2.19.2
178
+ # via composio-core
179
+ setuptools==75.6.0
180
+ # via versionhq (pyproject.toml)
181
+ sniffio==1.3.1
182
+ # via
183
+ # anyio
184
+ # httpx
185
+ # openai
186
+ starlette==0.41.3
187
+ # via fastapi
188
+ tiktoken==0.8.0
189
+ # via litellm
190
+ tokenizers==0.21.0
191
+ # via litellm
192
+ tqdm==4.67.1
193
+ # via
194
+ # huggingface-hub
195
+ # openai
196
+ typing==3.10.0.0
197
+ # via versionhq (pyproject.toml)
198
+ typing-extensions==4.12.2
199
+ # via
200
+ # fastapi
201
+ # huggingface-hub
202
+ # openai
203
+ # pydantic
204
+ # pydantic-core
205
+ urllib3==2.3.0
206
+ # via
207
+ # requests
208
+ # sentry-sdk
209
+ uvicorn==0.34.0
210
+ # via composio-core
211
+ websocket-client==1.8.0
212
+ # via pysher
213
+ werkzeug==3.1.3
214
+ # via versionhq (pyproject.toml)
215
+ wheel==0.45.1
216
+ # via versionhq (pyproject.toml)
217
+ yarl==1.18.3
218
+ # via aiohttp
219
+ zipp==3.21.0
220
+ # via importlib-metadata
@@ -17,7 +17,7 @@ from versionhq.team.model import Team, TeamOutput
17
17
  from versionhq.tool.model import Tool
18
18
 
19
19
 
20
- __version__ = "1.1.7.5"
20
+ __version__ = "1.1.7.7"
21
21
  __all__ = [
22
22
  "Agent",
23
23
  "Customer",
@@ -85,7 +85,7 @@ class Agent(ABC, BaseModel):
85
85
  """
86
86
 
87
87
  __hash__ = object.__hash__
88
- _logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=False))
88
+ _logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=True))
89
89
  _rpm_controller: Optional[RPMController] = PrivateAttr(default=None)
90
90
  _request_within_rpm_limit: Any = PrivateAttr(default=None)
91
91
  _token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess)
@@ -327,7 +327,7 @@ class Agent(ABC, BaseModel):
327
327
  messages = []
328
328
  messages.append({"role": "user", "content": prompts}) #! REFINEME
329
329
  messages.append({"role": "assistant", "content": self.backstory})
330
- print("Messages sent to the model:", messages)
330
+ self._logger.log(level="info", message=f"Messages sent to the model: {messages}", color="blue")
331
331
 
332
332
  callbacks = kwargs.get("callbacks", None)
333
333
 
@@ -338,7 +338,7 @@ class Agent(ABC, BaseModel):
338
338
  callbacks=callbacks,
339
339
  )
340
340
  task_execution_counter += 1
341
- print("Agent's #1 res: ", response)
341
+ self._logger.log(level="info", message=f"Agent's first response: {response}", color="blue")
342
342
 
343
343
  if (response is None or response == "") and task_execution_counter < self.max_retry_limit:
344
344
  while task_execution_counter <= self.max_retry_limit:
@@ -349,10 +349,10 @@ class Agent(ABC, BaseModel):
349
349
  callbacks=callbacks,
350
350
  )
351
351
  task_execution_counter += 1
352
- print(f"Agent's #{task_execution_counter} res: ", response)
352
+ self._logger.log(level="info", message=f"Agent's next response: {response}", color="blue")
353
353
 
354
354
  elif response is None or response == "":
355
- print("Received None or empty response from LLM call.")
355
+ self._logger.log(level="error", message="Received None or empty response from the model", color="red")
356
356
  raise ValueError("Invalid response from LLM call - None or empty.")
357
357
 
358
358
  return {"output": response.output if hasattr(response, "output") else response}
@@ -0,0 +1,141 @@
1
+ import appdirs
2
+ import os
3
+ import json
4
+ import sqlite3
5
+ import datetime
6
+ from typing import Any, Dict, List, Optional
7
+ from dotenv import load_dotenv
8
+ from pathlib import Path
9
+
10
+ from versionhq._utils.logger import Logger
11
+
12
+ load_dotenv(override=True)
13
+
14
+
15
+ def fetch_db_storage_path():
16
+ project_directory_name = os.environ.get("STORAGE_DIR", Path.cwd().name)
17
+ app_author = "versionhq"
18
+ data_dir = Path(appdirs.user_data_dir(project_directory_name, app_author))
19
+ data_dir.mkdir(parents=True, exist_ok=True)
20
+ return data_dir
21
+
22
+ storage_path = fetch_db_storage_path()
23
+ default_db_name = "task_outputs"
24
+
25
+
26
+ class TaskOutputSQLiteStorage:
27
+ """
28
+ An SQLite storage class to handle storing task outputs.
29
+ """
30
+
31
+ def __init__(self, db_path: str = f"{storage_path}/{default_db_name}.db") -> None:
32
+ self.db_path = db_path
33
+ self._logger = Logger(verbose=True)
34
+ self._initialize_db()
35
+
36
+
37
+ def _initialize_db(self):
38
+ """
39
+ Initializes the SQLite database and creates LTM table.
40
+ """
41
+
42
+ try:
43
+ with sqlite3.connect(self.db_path) as conn:
44
+ cursor = conn.cursor()
45
+ cursor.execute(
46
+ """
47
+ CREATE TABLE IF NOT EXISTS task_outputs (
48
+ task_id TEXT PRIMARY KEY,
49
+ output JSON,
50
+ task_index INTEGER,
51
+ inputs JSON,
52
+ was_replayed BOOLEAN,
53
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
54
+ )
55
+ """
56
+ )
57
+ conn.commit()
58
+
59
+ except sqlite3.Error as e:
60
+ self._logger.log(level="error", message=f"DATABASE INITIALIZATION ERROR: {e}", color="red")
61
+
62
+
63
+ def add(self, task, output: Dict[str, Any], task_index: int, was_replayed: bool = False, inputs: Dict[str, Any] = {}):
64
+ try:
65
+ with sqlite3.connect(self.db_path) as conn:
66
+ cursor = conn.cursor()
67
+ cursor.execute(
68
+ """INSERT OR REPLACE INTO task_outputs
69
+ (task_id, output, task_index, inputs, was_replayed, timestamp)
70
+ VALUES (?, ?, ?, ?, ?, ?)
71
+ """,
72
+ (str(task.id), json.dumps(output), task_index, json.dumps(inputs), was_replayed, datetime.datetime.now())
73
+ )
74
+ conn.commit()
75
+
76
+ except sqlite3.Error as e:
77
+ self._logger.log(level="error", message=f"SAVING TASK OUTPUTS ERROR: {e}", color="red")
78
+
79
+
80
+ def update(self, task_index: int, **kwargs):
81
+ try:
82
+ with sqlite3.connect(self.db_path) as conn:
83
+ cursor = conn.cursor()
84
+
85
+ fields, values = [], []
86
+ for k, v in kwargs.items():
87
+ fields.append(f"{k} = ?")
88
+ values.append(json.dumps(v) if isinstance(v, dict) else v)
89
+
90
+ query = f"UPDATE latest_kickoff_task_outputs SET {', '.join(fields)} WHERE task_index = ?" # nosec
91
+ values.append(task_index)
92
+ cursor.execute(query, tuple(values))
93
+ conn.commit()
94
+
95
+ if cursor.rowcount == 0:
96
+ self._logger.log(
97
+ level="info", message=f"No row found with task_index {task_index}. No update performed.", color="yellow",
98
+ )
99
+
100
+ except sqlite3.Error as e:
101
+ self._logger.log(level="error", message=f"UPDATE TASK OUTPUTS ERROR: {e}", color="red")
102
+
103
+
104
+ def load(self) -> Optional[List[Dict[str, Any]]]:
105
+ try:
106
+ with sqlite3.connect(self.db_path) as conn:
107
+ cursor = conn.cursor()
108
+ cursor.execute("""
109
+ SELECT *
110
+ FROM task_outputs
111
+ ORDER BY task_index
112
+ """)
113
+
114
+ rows = cursor.fetchall()
115
+ results = []
116
+ for row in rows:
117
+ result = {
118
+ "task_id": row[0],
119
+ "output": json.loads(row[1]),
120
+ "task_index": row[2],
121
+ "inputs": json.loads(row[3]),
122
+ "was_replayed": row[4],
123
+ "timestamp": row[5],
124
+ }
125
+ results.append(result)
126
+ return results
127
+
128
+ except sqlite3.Error as e:
129
+ self._logger.log(level="error", message=f"LOADING TASK OUTPUTS ERROR: {e}", color="red")
130
+ return None
131
+
132
+
133
+ def delete_all(self):
134
+ try:
135
+ with sqlite3.connect(self.db_path) as conn:
136
+ cursor = conn.cursor()
137
+ cursor.execute("DELETE FROM task_outputs")
138
+ conn.commit()
139
+
140
+ except sqlite3.Error as e:
141
+ self._logger.log(level="error", message=f"ERROR: Failed to delete all: {e}", color="red")
@@ -0,0 +1,59 @@
1
+ from datetime import datetime
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+ from versionhq.storage.task_output_storage import TaskOutputSQLiteStorage
7
+
8
+
9
+ class ExecutionLog(BaseModel):
10
+ task_id: str
11
+ output: Dict[str, Any]
12
+ timestamp: datetime = Field(default_factory=datetime.now)
13
+ task_index: int
14
+ inputs: Dict[str, Any] = Field(default_factory=dict)
15
+ was_replayed: bool = False
16
+
17
+ def __getitem__(self, key: str) -> Any:
18
+ return getattr(self, key)
19
+
20
+
21
+
22
+ class TaskOutputStorageHandler:
23
+
24
+ def __init__(self):
25
+ self.storage = TaskOutputSQLiteStorage()
26
+
27
+
28
+ def update(self, task, task_index: int, was_replayed: bool = False, inputs: Dict[str, Any] = {}) -> None:
29
+ """
30
+ task: task instance
31
+ """
32
+ saved_outputs = self.load()
33
+ if saved_outputs is None:
34
+ raise ValueError("Logs cannot be None")
35
+
36
+ self.add(task, task_index, was_replayed, inputs)
37
+
38
+
39
+ def add(self, task, task_index: int, was_replayed: bool = False, inputs: Dict[str, Any] = {}) -> None:
40
+ from versionhq.task.model import Task
41
+
42
+ output_to_store = dict()
43
+
44
+ if isinstance(task, Task):
45
+ output_to_store = dict(
46
+ description=str(task.description),
47
+ raw=str(task.output.raw),
48
+ responsible_agent=str(task.processed_by_agents),
49
+ )
50
+
51
+ self.storage.add(task=task, output=output_to_store, task_index=task_index, was_replayed=was_replayed, inputs=inputs)
52
+
53
+
54
+ def reset(self) -> None:
55
+ self.storage.delete_all()
56
+
57
+
58
+ def load(self) -> Optional[List[Dict[str, Any]]]:
59
+ return self.storage.load()