versionhq 1.1.7.9__py3-none-any.whl → 1.1.8.1__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.
versionhq/__init__.py CHANGED
@@ -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.9"
20
+ __version__ = "1.1.8.1"
21
21
  __all__ = [
22
22
  "Agent",
23
23
  "Customer",
@@ -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
- 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))
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
- 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
- )
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
- conn.commit()
53
+ """
54
+ )
55
+ conn.commit()
58
56
 
59
- except sqlite3.Error as e:
60
- self._logger.log(level="error", message=f"DATABASE INITIALIZATION ERROR: {e}", color="red")
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 = ?" # nosec
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()
versionhq/task/model.py CHANGED
@@ -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} - {self.description}
210
- "task_description": {self.description}
211
- "task_expected_output": {self.output_prompt}
212
- "task_tools": {", ".join([tool_called.tool.name for tool_called in self.tools_called])}
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
 
@@ -403,7 +399,7 @@ Your outputs MUST adhere to the following format and should NOT include any irre
403
399
  """
404
400
  Run the core execution logic of the task.
405
401
  To speed up the process, when the format is not expected to return, we will skip the conversion process.
406
- When the task is allowed to delegate to another agent, we will select a responsible one in order of manager_agent > peer_agent > anoymous agent.
402
+ When the task is allowed to delegate to another agent, we will select a responsible one in order of manager > peer_agent > anoymous agent.
407
403
  """
408
404
  from versionhq.agent.model import Agent
409
405
  from versionhq.team.model import Team
@@ -414,8 +410,9 @@ Your outputs MUST adhere to the following format and should NOT include any irre
414
410
  agent_to_delegate = None
415
411
 
416
412
  if hasattr(agent, "team") and isinstance(agent.team, Team):
417
- if agent.team.manager_agent:
418
- agent_to_delegate = agent.team.manager_agent
413
+ if agent.team.managers:
414
+ idling_manager_agents = [manager.agent for manager in agent.team.managers if manager.task is None]
415
+ agent_to_delegate = idling_manager_agents[0] if idling_manager_agents else agent.team.managers[0]
419
416
  else:
420
417
  peers = [member.agent for member in agent.team.members if member.is_manager == False and member.agent.id is not agent.id]
421
418
  if len(peers) > 0:
versionhq/team/model.py CHANGED
@@ -113,6 +113,9 @@ class TeamMember(ABC, BaseModel):
113
113
  is_manager: bool = Field(default=False)
114
114
  task: Optional[Task] = Field(default=None)
115
115
 
116
+ def update(self, task: Task):
117
+ self.task = task
118
+
116
119
 
117
120
  class Team(BaseModel):
118
121
  """
@@ -123,7 +126,7 @@ class Team(BaseModel):
123
126
  __hash__ = object.__hash__
124
127
  _execution_span: Any = PrivateAttr()
125
128
  _logger: Logger = PrivateAttr()
126
- # _inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
129
+ _inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
127
130
 
128
131
  id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
129
132
  name: Optional[str] = Field(default=None)
@@ -165,34 +168,47 @@ class Team(BaseModel):
165
168
 
166
169
 
167
170
  @property
168
- def manager_agent(self) -> Agent:
169
- manager_agent = [member.agent for member in self.members if member.is_manager == True]
170
- return manager_agent[0] if len(manager_agent) > 0 else None
171
+ def managers(self) -> List[TeamMember] | None:
172
+ managers = [member for member in self.members if member.is_manager == True]
173
+ return managers if len(managers) > 0 else None
171
174
 
172
175
 
173
176
  @property
174
- def manager_task(self) -> Task:
177
+ def manager_tasks(self) -> List[Task] | None:
175
178
  """
176
- Aside from the team task, return the task that the `manager_agent` needs to handle.
177
- The task is set as second priority following to the team tasks.
179
+ Tasks (incl. team tasks) handled by managers in the team.
178
180
  """
179
- task = [member.task for member in self.members if member.is_manager == True]
180
- return task[0] if len(task) > 0 else None
181
+ if self.managers:
182
+ tasks = [manager.task for manager in self.managers if manager.task is not None]
183
+ return tasks if len(tasks) > 0 else None
184
+
185
+ return None
181
186
 
182
187
 
183
188
  @property
184
189
  def tasks(self):
185
190
  """
186
191
  Return all the tasks that the team needs to handle in order of priority:
187
- 1. team tasks,
192
+ 1. team tasks, -> assigned to the member
188
193
  2. manager_task,
189
194
  3. members' tasks
190
195
  """
191
- sorted_member_tasks = [member.task for member in self.members if member.is_manager == True] + [member.task for member in self.members if member.is_manager == False]
192
- return self.team_tasks + sorted_member_tasks if len(self.team_tasks) > 0 else sorted_member_tasks
196
+
197
+ team_tasks = self.team_tasks
198
+ manager_tasks = [member.task for member in self.members if member.is_manager == True and member.task is not None and member.task not in team_tasks]
199
+ member_tasks = [member.task for member in self.members if member.is_manager == False and member.task is not None and member.task not in team_tasks]
200
+
201
+ return team_tasks + manager_tasks + member_tasks
202
+
203
+
204
+ @property
205
+ def member_tasks_without_agent(self) -> List[Task] | None:
206
+ if self.members:
207
+ return [member.task for member in self.members if member.agent is None]
208
+
209
+ return None
193
210
 
194
211
 
195
- # validators
196
212
  @field_validator("id", mode="before")
197
213
  @classmethod
198
214
  def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
@@ -201,6 +217,21 @@ class Team(BaseModel):
201
217
  raise PydanticCustomError("may_not_set_field", "The 'id' field cannot be set by the user.", {})
202
218
 
203
219
 
220
+ @model_validator(mode="after")
221
+ def validate_tasks(self):
222
+ """
223
+ Validates if the model recognize all tasks that the team needs to handle.
224
+ """
225
+
226
+ if self.tasks:
227
+ if all(task in self.tasks for task in self.team_tasks) == False:
228
+ raise PydanticCustomError("task_validation_error", "`team_tasks` needs to be recognized in the task.", {})
229
+
230
+ if len(self.tasks) != len(self.team_tasks) + len([member for member in self.members if member.task is not None]):
231
+ raise PydanticCustomError("task_validation_error", "Some tasks are missing.", {})
232
+ return self
233
+
234
+
204
235
  @model_validator(mode="after")
205
236
  def check_manager_llm(self):
206
237
  """
@@ -208,37 +239,29 @@ class Team(BaseModel):
208
239
  """
209
240
 
210
241
  if self.process == TaskHandlingProcess.hierarchical:
211
- if self.manager_agent is None:
242
+ if self.managers is None:
212
243
  raise PydanticCustomError(
213
- "missing_manager_llm_or_manager_agent",
214
- "Attribute `manager_llm` or `manager_agent` is required when using hierarchical process.",
244
+ "missing_manager_llm_or_manager",
245
+ "Attribute `manager_llm` or `manager` is required when using hierarchical process.",
215
246
  {},
216
247
  )
217
248
 
218
- if (self.manager_agent is not None) and (
219
- self.members.count(self.manager_agent) > 0
220
- ):
221
- raise PydanticCustomError(
222
- "manager_agent_in_agents",
223
- "Manager agent should not be included in agents list.",
224
- {},
225
- )
249
+ if self.managers and (self.manager_tasks is None or self.team_tasks is None):
250
+ raise PydanticCustomError("missing_manager_task", "manager needs to have at least one manager task or team task.", {})
251
+
226
252
  return self
227
253
 
228
254
 
229
255
  @model_validator(mode="after")
230
256
  def validate_tasks(self):
231
257
  """
232
- Every team member should have a task to handle.
258
+ Sequential task processing without any team tasks require a task-agent pairing.
233
259
  """
234
- if self.process == TaskHandlingProcess.sequential:
260
+
261
+ if self.process == TaskHandlingProcess.sequential and self.team_tasks is None:
235
262
  for member in self.members:
236
263
  if member.task is None:
237
- raise PydanticCustomError(
238
- "missing_agent_in_task",
239
- f"Sequential process error: Agent is missing in the task with the following description: {member.task.description}",
240
- {},
241
- )
264
+ raise PydanticCustomError("missing_agent_in_task", f"Sequential process error: Agent is missing the task", {})
242
265
  return self
243
266
 
244
267
  @model_validator(mode="after")
@@ -249,7 +272,9 @@ class Team(BaseModel):
249
272
 
250
273
  async_task_count = 0
251
274
  for task in reversed(self.tasks):
252
- if task.async_execution:
275
+ if not task:
276
+ break
277
+ elif task.async_execution:
253
278
  async_task_count += 1
254
279
  else:
255
280
  break
@@ -262,21 +287,54 @@ class Team(BaseModel):
262
287
  )
263
288
  return self
264
289
 
290
+
265
291
  def _get_responsible_agent(self, task: Task) -> Agent:
266
- res = [member.agent for member in self.members if member.task.id == task.id]
267
- return None if len(res) == 0 else res[0]
292
+ if task is None:
293
+ return None
294
+ else:
295
+ res = [member.agent for member in self.members if member.task and member.task.id == task.id]
296
+ return None if len(res) == 0 else res[0]
297
+
298
+
299
+ def _handle_team_planning(self) -> None:
300
+ """
301
+ Form a team considering agents and tasks given, and update `self.members` field:
302
+ 1. Idling managers to take the team tasks.
303
+ 2. Idling members to take the remaining tasks starting from the team tasks to member tasks.
304
+ 3. Create agents to handle the rest tasks.
305
+ """
268
306
 
269
- # setup team planner
270
- def _handle_team_planning(self):
271
307
  team_planner = TeamPlanner(tasks=self.tasks, planner_llm=self.planning_llm)
272
- result = team_planner._handle_task_planning()
308
+ idling_managers: List[TeamMember] = [member for member in self.members if member.task is None and member.is_manager is True]
309
+ idling_members: List[TeamMember] = [member for member in self.members if member.task is None and member.is_manager is False]
310
+ unassigned_tasks: List[Task] = self.member_tasks_without_agent
311
+ new_team_members: List[TeamMember] = []
312
+
313
+
314
+ if self.team_tasks:
315
+ candidates = idling_managers + idling_members
316
+ if candidates:
317
+ i = 0
318
+ while i < len(candidates):
319
+ if self.team_tasks[i]:
320
+ candidates[i].task = self.team_tasks[i]
321
+ i += 1
322
+
323
+ if len(self.team_tasks) > i:
324
+ for item in self.team_tasks[i:]:
325
+ if item not in unassigned_tasks:
326
+ unassigned_tasks = [item, ] + unassigned_tasks
273
327
 
274
- if result is not None:
275
- for task in self.tasks:
276
- task_id = task.id
277
- task.description += (
278
- result[task_id] if hasattr(result, str(task_id)) else result
279
- )
328
+ else:
329
+ for item in self.team_tasks:
330
+ if item not in unassigned_tasks:
331
+ unassigned_tasks = [item, ] + unassigned_tasks
332
+
333
+ if unassigned_tasks:
334
+ new_team_members = team_planner._handle_assign_agents(unassigned_tasks=unassigned_tasks)
335
+
336
+ if new_team_members:
337
+ self.members += new_team_members
280
338
 
281
339
 
282
340
  # task execution
@@ -333,9 +391,11 @@ class Team(BaseModel):
333
391
  token_sum = agent._token_process.get_summary()
334
392
  total_usage_metrics.add_usage_metrics(token_sum)
335
393
 
336
- if self.manager_agent and hasattr(self.manager_agent, "_token_process"):
337
- token_sum = self.manager_agent._token_process.get_summary()
338
- total_usage_metrics.add_usage_metrics(token_sum)
394
+ if self.managers:
395
+ for manager in self.managers:
396
+ if hasattr(manager.agent, "_token_process"):
397
+ token_sum = manager.agent._token_process.get_summary()
398
+ total_usage_metrics.add_usage_metrics(token_sum)
339
399
 
340
400
  self.usage_metrics = total_usage_metrics
341
401
  return total_usage_metrics
@@ -366,7 +426,7 @@ class Team(BaseModel):
366
426
 
367
427
  responsible_agent = self._get_responsible_agent(task)
368
428
  if responsible_agent is None:
369
- responsible_agent = self.manager_agent if self.manager_agent else self.members[0].agent
429
+ self._handle_team_planning()
370
430
 
371
431
  if isinstance(task, ConditionalTask):
372
432
  skipped_task_output = task._handle_conditional_task(task_outputs, futures, task_index, was_replayed)
@@ -377,19 +437,18 @@ class Team(BaseModel):
377
437
  # self._log_task_start(task, responsible_agent)
378
438
 
379
439
  if task.async_execution:
380
- context = create_raw_outputs(tasks=[task, ],task_outputs=([last_sync_output,] if last_sync_output else []))
440
+ context = create_raw_outputs(tasks=[task, ], task_outputs=([last_sync_output,] if last_sync_output else []))
381
441
  future = task.execute_async(agent=responsible_agent, context=context, tools=responsible_agent.tools)
382
442
  futures.append((task, future, task_index))
383
443
  else:
384
444
  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
- )
387
- if responsible_agent is self.manager_agent:
445
+ task_output = task.execute_sync(agent=responsible_agent, context=context, tools=responsible_agent.tools)
446
+ if self.managers and responsible_agent in [manager.agent for manager in self.managers]:
388
447
  lead_task_output = task_output
389
448
 
390
449
  task_outputs.append(task_output)
391
450
  # self._process_task_result(task, task_output)
392
- task._store_execution_log(task_index, was_replayed)
451
+ task._store_execution_log(task_index, was_replayed, self._inputs)
393
452
 
394
453
 
395
454
  if futures:
@@ -401,15 +460,16 @@ class Team(BaseModel):
401
460
  def kickoff(self, kwargs_before: Optional[Dict[str, str]] = None, kwargs_after: Optional[Dict[str, Any]] = None) -> TeamOutput:
402
461
  """
403
462
  Kickoff the team:
404
- 0. Plan the team action if we have `team_tasks` using `planning_llm`.
463
+ 0. Assign an agent to a task - using conditions (manager prioritizes team_tasks) and planning_llm.
405
464
  1. Address `before_kickoff_callbacks` if any.
406
- 2. Handle team members' tasks in accordance with the `process`.
465
+ 2. Handle team members' tasks in accordance with the process.
407
466
  3. Address `after_kickoff_callbacks` if any.
408
467
  """
409
468
 
410
469
  metrics: List[UsageMetrics] = []
411
470
 
412
- if len(self.team_tasks) > 0 or self.planning_llm is not None:
471
+
472
+ if self.team_tasks or self.member_tasks_without_agent:
413
473
  self._handle_team_planning()
414
474
 
415
475
  if kwargs_before is not None:
@@ -3,37 +3,80 @@ from dotenv import load_dotenv
3
3
  from typing import Any, List, Optional
4
4
  from pydantic import BaseModel, Field
5
5
 
6
- from versionhq.agent.model import Agent
7
- from versionhq.task.model import Task, ResponseField
8
-
9
6
  load_dotenv(override=True)
10
7
 
11
8
 
12
9
  class TeamPlanner:
13
10
  """
14
- (Optional) Plan how the team should handle multiple tasks using LLM.
11
+ Assign agents to multiple tasks.
15
12
  """
16
13
 
14
+ from versionhq.task.model import Task, ResponseField, TaskOutput
15
+ from versionhq.agent.model import Agent
16
+
17
+
17
18
  def __init__(self, tasks: List[Task], planner_llm: Optional[Any] = None):
18
19
  self.tasks = tasks
19
- self.planner_llm = (
20
- planner_llm if planner_llm != None else os.environ.get("LITELLM_MODEL_NAME")
20
+ self.planner_llm = planner_llm if planner_llm else os.environ.get("LITELLM_MODEL_NAME")
21
+
22
+
23
+ def _handle_assign_agents(self, unassigned_tasks: List[Task]) -> List[Any]:
24
+ """
25
+ Build an agent and assign it a task, then return a list of TeamMember connecting the agent created and the task given.
26
+ """
27
+
28
+ from versionhq.agent.model import Agent
29
+ from versionhq.task.model import Task, ResponseField
30
+ from versionhq.team.model import TeamMember
31
+
32
+ new_member_list: List[TeamMember] = []
33
+ agent_creator = Agent(
34
+ role="agent_creator",
35
+ goal="build an ai agent that can competitively handle the task given",
36
+ llm=self.planner_llm,
21
37
  )
22
38
 
23
- def _handle_task_planning(self) -> BaseModel:
39
+ for unassgined_task in unassigned_tasks:
40
+ task = Task(
41
+ description=f"""
42
+ Based on the following task summary, draft a AI agent's role and goal in concise manner.
43
+ Task summary: {unassgined_task.summary}
44
+ """,
45
+ expected_output_json=True,
46
+ output_field_list=[
47
+ ResponseField(title="goal", type=str, required=True),
48
+ ResponseField(title="role", type=str, required=True),
49
+ ],
50
+ )
51
+ res = task.execute_sync(agent=agent_creator)
52
+ agent = Agent(
53
+ role=res.json_dict["role"] if "role" in res.json_dict else res.raw,
54
+ goal=res.json_dict["goal"] if "goal" in res.json_dict else task.description
55
+ )
56
+ if agent.id:
57
+ team_member = TeamMember(agent=agent, task=unassgined_task, is_manager=False)
58
+ new_member_list.append(team_member)
59
+
60
+ return new_member_list
61
+
62
+
63
+
64
+ def _handle_task_planning(self, context: Optional[str] = None, tools: Optional[str] = None) -> TaskOutput:
24
65
  """
25
66
  Handles the team planning by creating detailed step-by-step plans for each task.
26
67
  """
27
68
 
28
- planning_agent = Agent(
29
- role="Task Execution Planner",
30
- goal="Your goal is to create an extremely detailed, step-by-step plan based on the tasks and tools available to each agent so that they can perform the tasks in an exemplary manner",
31
- backstory="You have a strong ability to design efficient organizational structures and task processes, minimizing unnecessary steps.",
69
+ from versionhq.agent.model import Agent
70
+ from versionhq.task.model import Task, ResponseField
71
+
72
+ team_planner = Agent(
73
+ role="team planner",
74
+ goal="Plan extremely detailed, step-by-step plan based on the tasks and tools available to each agent so that they can perform the tasks in an exemplary manner and assign a task to each agent.",
32
75
  llm=self.planner_llm,
33
76
  )
34
77
 
35
78
  task_summary_list = [task.summary for task in self.tasks]
36
- task_to_handle = Task(
79
+ task = Task(
37
80
  description=f"""
38
81
  Based on the following task summaries, create the most descriptive plan that the team can execute most efficiently. Take all the task summaries - task's description and tools available - into consideration. Your answer only contains a dictionary.
39
82
 
@@ -42,14 +85,9 @@ class TeamPlanner:
42
85
  expected_output_json=False,
43
86
  expected_output_pydantic=True,
44
87
  output_field_list=[
45
- ResponseField(title=f"{task.id}", type=str, required=True)
88
+ ResponseField(title="task", type=str, required=True)
46
89
  for task in self.tasks
47
90
  ],
48
91
  )
49
- task_output = task_to_handle.execute_sync(agent=planning_agent)
50
-
51
- if isinstance(task_output.pydantic, BaseModel):
52
- return task_output.pydantic
53
-
54
- else:
55
- return None
92
+ output = task.execute_sync(agent=team_planner, context=context, tools=tools)
93
+ return output
versionhq/tool/model.py CHANGED
@@ -137,7 +137,6 @@ class Tool(ABC, BaseModel):
137
137
  The response will be cascaded to the Task and stored in the TaskOutput.
138
138
  """
139
139
 
140
- print(f"Using the tool: {self.name}")
141
140
  result = None
142
141
 
143
142
  if self.func is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: versionhq
3
- Version: 1.1.7.9
3
+ Version: 1.1.8.1
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
@@ -1,4 +1,4 @@
1
- versionhq/__init__.py,sha256=bz4C48jhCjkQjethRmtw4_Ha_3OUdDDytk6PBCemiZU,871
1
+ versionhq/__init__.py,sha256=vDnsppEwUlpBHeAcl8jCKzt8SaGylbfIND1PjgjY2s8,871
2
2
  versionhq/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  versionhq/_utils/cache_handler.py,sha256=zDQKzIn7vp-M2-uepHFxgJstjfftZS5mzXKL_-4uVvI,370
4
4
  versionhq/_utils/i18n.py,sha256=TwA_PnYfDLA6VqlUDPuybdV9lgi3Frh_ASsb_X8jJo8,1483
@@ -23,20 +23,20 @@ versionhq/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  versionhq/llm/llm_vars.py,sha256=YZoXqFBW7XpclUZ14_AAz7WOjoyCXnGcI959GSpX2q0,5343
24
24
  versionhq/llm/model.py,sha256=mXzSuf1s6MebGT7_yqgNppde0NIlAF8bjIXAp2MZ9Uw,8247
25
25
  versionhq/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
- versionhq/storage/task_output_storage.py,sha256=RxvF_lSRUuo2Af3zMAuc1aOymx1e6e_5VJ2y757_Hu0,4910
26
+ versionhq/storage/task_output_storage.py,sha256=xoBJHeqUyQt6iJoR1WQTghP-fyxXL66qslpX1QC2-4o,4827
27
27
  versionhq/task/__init__.py,sha256=g4mCATnn1mUXxsfQ5p6IpPawr8O421wVIT8kMKEcxQw,180
28
28
  versionhq/task/formatter.py,sha256=N8Kmk9vtrMtBdgJ8J7RmlKNMdZWSmV8O1bDexmCWgU0,643
29
29
  versionhq/task/log_handler.py,sha256=KJRrcNZgFSKhlNzvtYFnvtp6xukaF1s7ifX9u4zWrN8,1683
30
- versionhq/task/model.py,sha256=bUmERE6AZfs8qh2Hb9LES5BLUlXrkrOUyWxCU27M1ic,19317
30
+ versionhq/task/model.py,sha256=F6yd8oPJ6cjH0PcGZru7eska7Qu6lEtMDyjgn-ZnAfE,19394
31
31
  versionhq/team/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
- versionhq/team/model.py,sha256=T_71FarXEzAxrTn_8yYVWMwLS9p-UxSovexZtHYnYn0,18066
33
- versionhq/team/team_planner.py,sha256=B1UOn_DYVVterUn2CAd80jfO4sViJCCXPJA3abSSugg,2143
32
+ versionhq/team/model.py,sha256=Liq0PUHncZAJyjjmqOL5mmt5E0Z0dBfhTmtRjUZQWiE,20369
33
+ versionhq/team/team_planner.py,sha256=uzX2yed7A7gNSs6qH5jIq2zXMVF5BwQQ4HPATsB9DSQ,3675
34
34
  versionhq/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  versionhq/tool/decorator.py,sha256=Y-j4jkoujD5LUvpe8uf3p5Zagk2XVaRKC9rkIE-2geo,1189
36
- versionhq/tool/model.py,sha256=s-y8323ikd5m5U2HG59ATgFW6L7yIFiPLLdOpeXQ8RI,6874
36
+ versionhq/tool/model.py,sha256=GjhQdlAyl2MGu4iiiFW7LqBWaaXhdlRQz2OGHhmr9FM,6828
37
37
  versionhq/tool/tool_handler.py,sha256=esUqGp8HoREesai8fmh2klAf04Sjpsacmb03C7F6sNQ,1541
38
- versionhq-1.1.7.9.dist-info/LICENSE,sha256=7CCXuMrAjPVsUvZrsBq9DsxI2rLDUSYXR_qj4yO_ZII,1077
39
- versionhq-1.1.7.9.dist-info/METADATA,sha256=xv6DizWz6aDv59VePfs4pUnRClJK9WHuy-2T_4-_52g,15919
40
- versionhq-1.1.7.9.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
41
- versionhq-1.1.7.9.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
42
- versionhq-1.1.7.9.dist-info/RECORD,,
38
+ versionhq-1.1.8.1.dist-info/LICENSE,sha256=7CCXuMrAjPVsUvZrsBq9DsxI2rLDUSYXR_qj4yO_ZII,1077
39
+ versionhq-1.1.8.1.dist-info/METADATA,sha256=7_hZDC_4H87AwyP_TtICbEv0XB_9DtUNI-80xjqqSBU,15919
40
+ versionhq-1.1.8.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
41
+ versionhq-1.1.8.1.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
42
+ versionhq-1.1.8.1.dist-info/RECORD,,