versionhq 1.1.7.9__tar.gz → 1.1.8__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.
- {versionhq-1.1.7.9 → versionhq-1.1.8}/PKG-INFO +1 -1
- {versionhq-1.1.7.9 → versionhq-1.1.8}/pyproject.toml +1 -1
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/__init__.py +1 -1
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/storage/task_output_storage.py +19 -22
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/task/model.py +5 -9
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/team/model.py +3 -4
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq.egg-info/PKG-INFO +1 -1
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/task/task_test.py +7 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/team/team_test.py +42 -26
- {versionhq-1.1.7.9 → versionhq-1.1.8}/uv.lock +1 -1
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.github/workflows/publish.yml +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.github/workflows/publish_testpypi.yml +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.github/workflows/run_tests.yml +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.github/workflows/security_check.yml +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.gitignore +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.pre-commit-config.yaml +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/.python-version +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/LICENSE +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/README.md +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/SECURITY.md +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/db/preprocess.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/requirements-dev.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/requirements.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/runtime.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/setup.cfg +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/cache_handler.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/i18n.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/logger.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/process_config.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/rpm_controller.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/_utils/usage_metrics.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/agent/TEMPLATES/Backstory.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/agent/TEMPLATES/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/agent/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/agent/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/agent/parser.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/cli/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/customer/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/customer/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/product/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/product/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/workflow/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/clients/workflow/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/llm/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/llm/llm_vars.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/llm/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/storage/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/task/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/task/formatter.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/task/log_handler.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/team/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/team/team_planner.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/tool/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/tool/decorator.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/tool/model.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq/tool/tool_handler.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq.egg-info/SOURCES.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq.egg-info/dependency_links.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq.egg-info/requires.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/src/versionhq.egg-info/top_level.txt +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/agent/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/agent/agent_test.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/cli/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/clients/workflow_test.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/conftest.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/task/__init__.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/team/Prompts/Demo_test.py +0 -0
- {versionhq-1.1.7.9 → versionhq-1.1.8}/tests/team/__init__.py +0 -0
@@ -15,7 +15,7 @@ exclude = ["test*", "__pycache__"]
|
|
15
15
|
|
16
16
|
[project]
|
17
17
|
name = "versionhq"
|
18
|
-
version = "1.1.
|
18
|
+
version = "1.1.8"
|
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"
|
@@ -11,11 +11,9 @@ from versionhq._utils.logger import Logger
|
|
11
11
|
|
12
12
|
load_dotenv(override=True)
|
13
13
|
|
14
|
-
|
15
14
|
def fetch_db_storage_path():
|
16
|
-
|
17
|
-
|
18
|
-
data_dir = Path(appdirs.user_data_dir(project_directory_name, app_author))
|
15
|
+
directory_name = Path.cwd().name
|
16
|
+
data_dir = Path(appdirs.user_data_dir(appname=directory_name, appauthor="Version IO Sdn Bhd.", version=None, roaming=False))
|
19
17
|
data_dir.mkdir(parents=True, exist_ok=True)
|
20
18
|
return data_dir
|
21
19
|
|
@@ -39,25 +37,25 @@ class TaskOutputSQLiteStorage:
|
|
39
37
|
Initializes the SQLite database and creates LTM table.
|
40
38
|
"""
|
41
39
|
|
42
|
-
try:
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
)
|
40
|
+
# try:
|
41
|
+
with sqlite3.connect(self.db_path) as conn:
|
42
|
+
cursor = conn.cursor()
|
43
|
+
cursor.execute(
|
55
44
|
"""
|
45
|
+
CREATE TABLE IF NOT EXISTS task_outputs (
|
46
|
+
task_id TEXT PRIMARY KEY,
|
47
|
+
output JSON,
|
48
|
+
task_index INTEGER,
|
49
|
+
inputs JSON,
|
50
|
+
was_replayed BOOLEAN,
|
51
|
+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
56
52
|
)
|
57
|
-
|
53
|
+
"""
|
54
|
+
)
|
55
|
+
conn.commit()
|
58
56
|
|
59
|
-
except sqlite3.Error as e:
|
60
|
-
|
57
|
+
# except sqlite3.Error as e:
|
58
|
+
# self._logger.log(level="error", message=f"DATABASE INITIALIZATION ERROR: {e}", color="red")
|
61
59
|
|
62
60
|
|
63
61
|
def add(self, task, output: Dict[str, Any], task_index: int, was_replayed: bool = False, inputs: Dict[str, Any] = {}):
|
@@ -81,13 +79,12 @@ class TaskOutputSQLiteStorage:
|
|
81
79
|
try:
|
82
80
|
with sqlite3.connect(self.db_path) as conn:
|
83
81
|
cursor = conn.cursor()
|
84
|
-
|
85
82
|
fields, values = [], []
|
86
83
|
for k, v in kwargs.items():
|
87
84
|
fields.append(f"{k} = ?")
|
88
85
|
values.append(json.dumps(v) if isinstance(v, dict) else v)
|
89
86
|
|
90
|
-
query = f"UPDATE latest_kickoff_task_outputs SET {', '.join(fields)} WHERE task_index = ?"
|
87
|
+
query = f"UPDATE latest_kickoff_task_outputs SET {', '.join(fields)} WHERE task_index = ?"
|
91
88
|
values.append(task_index)
|
92
89
|
cursor.execute(query, tuple(values))
|
93
90
|
conn.commit()
|
@@ -206,10 +206,10 @@ Your outputs MUST adhere to the following format and should NOT include any irre
|
|
206
206
|
@property
|
207
207
|
def summary(self) -> str:
|
208
208
|
return f"""
|
209
|
-
Task: {self.id}
|
210
|
-
"
|
211
|
-
"
|
212
|
-
"
|
209
|
+
Task ID: {str(self.id)}
|
210
|
+
"Description": {self.description}
|
211
|
+
"Prompt": {self.output_prompt}
|
212
|
+
"Tools": {", ".join([tool_called.tool.name for tool_called in self.tools_called])}
|
213
213
|
"""
|
214
214
|
|
215
215
|
|
@@ -382,11 +382,7 @@ Your outputs MUST adhere to the following format and should NOT include any irre
|
|
382
382
|
"""
|
383
383
|
|
384
384
|
future: Future[TaskOutput] = Future()
|
385
|
-
threading.Thread(
|
386
|
-
daemon=True,
|
387
|
-
target=self._execute_task_async,
|
388
|
-
args=(agent, context, tools, future),
|
389
|
-
).start()
|
385
|
+
threading.Thread(daemon=True, target=self._execute_task_async, args=(agent, context, tools, future)).start()
|
390
386
|
return future
|
391
387
|
|
392
388
|
|
@@ -123,7 +123,7 @@ class Team(BaseModel):
|
|
123
123
|
__hash__ = object.__hash__
|
124
124
|
_execution_span: Any = PrivateAttr()
|
125
125
|
_logger: Logger = PrivateAttr()
|
126
|
-
|
126
|
+
_inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
|
127
127
|
|
128
128
|
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
|
129
129
|
name: Optional[str] = Field(default=None)
|
@@ -382,14 +382,13 @@ class Team(BaseModel):
|
|
382
382
|
futures.append((task, future, task_index))
|
383
383
|
else:
|
384
384
|
context = create_raw_outputs(tasks=[task,], task_outputs=([last_sync_output,] if last_sync_output else [] ))
|
385
|
-
task_output = task.execute_sync(agent=responsible_agent, context=context, tools=responsible_agent.tools
|
386
|
-
)
|
385
|
+
task_output = task.execute_sync(agent=responsible_agent, context=context, tools=responsible_agent.tools)
|
387
386
|
if responsible_agent is self.manager_agent:
|
388
387
|
lead_task_output = task_output
|
389
388
|
|
390
389
|
task_outputs.append(task_output)
|
391
390
|
# self._process_task_result(task, task_output)
|
392
|
-
task._store_execution_log(task_index, was_replayed)
|
391
|
+
task._store_execution_log(task_index, was_replayed, self._inputs)
|
393
392
|
|
394
393
|
|
395
394
|
if futures:
|
@@ -277,4 +277,11 @@ def test_conditional_task():
|
|
277
277
|
assert conditional_res.task_id is conditional_task.id
|
278
278
|
|
279
279
|
|
280
|
+
def test_store_task_log():
|
281
|
+
task = Task(
|
282
|
+
description="Analyze the client's business model.",
|
283
|
+
output_field_list=[ResponseField(title="task_1", type=str, required=True),],
|
284
|
+
)
|
285
|
+
assert task._task_output_handler.load() is not None
|
286
|
+
|
280
287
|
# tools, token usage
|
@@ -127,28 +127,17 @@ def test_form_team_without_leader():
|
|
127
127
|
assert item.id is task_1.id or item.id is task_2.id
|
128
128
|
|
129
129
|
|
130
|
-
def
|
131
|
-
agent_a = Agent(
|
132
|
-
|
133
|
-
goal="My amazing goals",
|
134
|
-
llm=MODEL_NAME
|
135
|
-
)
|
136
|
-
|
137
|
-
agent_b = Agent(
|
138
|
-
role="agent b",
|
139
|
-
goal="My amazing goals",
|
140
|
-
llm=MODEL_NAME
|
141
|
-
)
|
142
|
-
|
130
|
+
def test_kickoff_without_leader():
|
131
|
+
agent_a = Agent(role="agent a", goal="My amazing goals", llm=MODEL_NAME)
|
132
|
+
agent_b = Agent(role="agent b", goal="My amazing goals", llm=MODEL_NAME)
|
143
133
|
task_1 = Task(
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
134
|
+
description="Analyze the client's business model.",
|
135
|
+
expected_output_json=True,
|
136
|
+
output_field_list=[
|
137
|
+
ResponseField(title="test1", type=str, required=True),
|
138
|
+
ResponseField(title="test2", type=list, required=True),
|
139
|
+
],
|
150
140
|
)
|
151
|
-
|
152
141
|
task_2 = Task(
|
153
142
|
description="Define the cohort.",
|
154
143
|
expected_output_json=True,
|
@@ -157,7 +146,6 @@ def test_kickoff_team_without_leader():
|
|
157
146
|
ResponseField(title="test2", type=list, required=True),
|
158
147
|
],
|
159
148
|
)
|
160
|
-
|
161
149
|
team = Team(
|
162
150
|
members=[
|
163
151
|
TeamMember(agent=agent_a, is_manager=False, task=task_1),
|
@@ -185,7 +173,6 @@ def test_kickoff_team_without_leader():
|
|
185
173
|
assert res.token_usage.total_tokens == 0 # as we dont set token usage on agent
|
186
174
|
|
187
175
|
|
188
|
-
|
189
176
|
def team_kickoff_with_task_callback():
|
190
177
|
"""
|
191
178
|
Each task has callback with callback kwargs.
|
@@ -236,7 +223,6 @@ def team_kickoff_with_task_callback():
|
|
236
223
|
assert "pytest" in demo_list[1]
|
237
224
|
|
238
225
|
|
239
|
-
|
240
226
|
def test_delegate_in_team():
|
241
227
|
"""
|
242
228
|
When the agent belongs to the team, the team manager or peers are prioritized to delegete the task.
|
@@ -279,7 +265,37 @@ def test_delegate_in_team():
|
|
279
265
|
assert "agent b" in task_1.processed_by_agents
|
280
266
|
|
281
267
|
|
268
|
+
def test_kickoff_with_leader():
|
269
|
+
agent_a = Agent(role="agent a", goal="My amazing goals", llm=MODEL_NAME)
|
270
|
+
agent_b = Agent(role="agent b", goal="My amazing goals", llm=MODEL_NAME)
|
271
|
+
task_1 = Task(
|
272
|
+
description="Analyze the client's business model.",
|
273
|
+
output_field_list=[ResponseField(title="task_1", type=str, required=True),],
|
274
|
+
)
|
275
|
+
task_2 = Task(
|
276
|
+
description="Define the cohort timeframe.",
|
277
|
+
output_field_list=[
|
278
|
+
ResponseField(title="task_2_1", type=int, required=True),
|
279
|
+
ResponseField(title="task_2_2", type=list, required=True),
|
280
|
+
],
|
281
|
+
)
|
282
|
+
team = Team(
|
283
|
+
members=[
|
284
|
+
TeamMember(agent=agent_a, is_manager=False, task=task_1),
|
285
|
+
TeamMember(agent=agent_b, is_manager=True, task=task_2),
|
286
|
+
],
|
287
|
+
)
|
288
|
+
res = team.kickoff()
|
289
|
+
|
290
|
+
assert isinstance(res, TeamOutput)
|
291
|
+
assert res.team_id is team.id
|
292
|
+
assert res.raw is not None
|
293
|
+
assert res.json_dict is not None
|
294
|
+
assert team.manager_agent.id is agent_b.id
|
295
|
+
assert len(res.task_output_list) == 2
|
296
|
+
assert [item.raw is not None for item in res.task_output_list]
|
297
|
+
assert len(team.tasks) == 2
|
298
|
+
assert team.tasks[0].output.raw == res.raw
|
299
|
+
|
282
300
|
|
283
|
-
|
284
|
-
test_kickoff_team_without_leader()
|
285
|
-
# kickoff with teamleader, async, task handling process
|
301
|
+
# async, task handling process
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|