versionhq 1.2.1.0__py3-none-any.whl → 1.2.1.2__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
@@ -8,6 +8,7 @@ from dotenv import load_dotenv
8
8
  load_dotenv(override=True)
9
9
 
10
10
  from versionhq.agent.model import Agent
11
+ from versionhq.agent_network.model import AgentNetwork, NetworkOutput, Formation, Member, TaskHandlingProcess
11
12
  from versionhq.llm.model import LLM
12
13
  from versionhq.llm.llm_vars import LLM_CONTEXT_WINDOW_SIZES, PARAMS, PROVIDERS, MODELS
13
14
  from versionhq.clients.customer.model import Customer
@@ -16,10 +17,9 @@ from versionhq.clients.workflow.model import MessagingWorkflow, MessagingCompone
16
17
  from versionhq.knowledge.model import Knowledge, KnowledgeStorage
17
18
  from versionhq.knowledge.source import PDFKnowledgeSource, CSVKnowledgeSource, JSONKnowledgeSource, TextFileKnowledgeSource, ExcelKnowledgeSource, StringKnowledgeSource
18
19
  from versionhq.knowledge.source_docling import DoclingSource
19
- from versionhq.graph.model import TaskStatus, TaskGraph, Node, Edge, DependencyType
20
+ from versionhq.task_graph.model import TaskStatus, TaskGraph, Node, Edge, DependencyType
20
21
  from versionhq.task.model import Task, TaskOutput, ResponseField, TaskExecutionType
21
22
  from versionhq.task.evaluate import Evaluation, EvaluationItem
22
- from versionhq.team.model import Team, TeamOutput, Formation, Member, TaskHandlingProcess
23
23
  from versionhq.tool.model import Tool, ToolSet
24
24
  from versionhq.tool.cache_handler import CacheHandler
25
25
  from versionhq.tool.tool_handler import ToolHandler
@@ -30,10 +30,16 @@ from versionhq.memory.model import ShortTermMemory,LongTermMemory, UserMemory, M
30
30
  from versionhq.task.formation import form_agent_network
31
31
 
32
32
 
33
- __version__ = "1.2.1.0"
33
+ __version__ = "1.2.1.2"
34
34
  __all__ = [
35
35
  "Agent",
36
36
 
37
+ "AgentNetwork",
38
+ "NetworkOutput",
39
+ "Formation",
40
+ "Member",
41
+ "TaskHandlingProcess",
42
+
37
43
  "LLM",
38
44
  "LLM_CONTEXT_WINDOW_SIZES",
39
45
  "PARAMS",
@@ -70,12 +76,6 @@ __all__ = [
70
76
  "Evaluation",
71
77
  "EvaluationItem",
72
78
 
73
- "Team",
74
- "TeamOutput",
75
- "Formation",
76
- "Member",
77
- "TaskHandlingProcess",
78
-
79
79
  "Tool",
80
80
  "ToolSet",
81
81
  "CacheHandler",
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from datetime import datetime
2
3
  from typing import Optional
3
4
 
@@ -42,9 +43,55 @@ class Logger(BaseModel):
42
43
  """
43
44
 
44
45
  verbose: bool = Field(default=True)
46
+ info_file_save: bool = Field(default=False, description="whether to save INFO logs")
45
47
  _printer: Printer = PrivateAttr(default_factory=Printer)
46
48
 
47
- def log(self, level, message, color="yellow"):
49
+
50
+ def log(self, level: str, message: str, color="yellow"):
48
51
  if self.verbose:
49
52
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
50
53
  self._printer.print(f"\n{timestamp} - versionHQ [{level.upper()}]: {message}", color=color)
54
+
55
+ self._save(level=level, message=message)
56
+
57
+
58
+ def _save(self, level: str, message: str, filename: str = None):
59
+ import os
60
+ from pathlib import Path
61
+
62
+ if level.lower() == "info" and self.info_file_save == False:
63
+ return
64
+
65
+ logging_level = logging.INFO
66
+ match level:
67
+ case "warning":
68
+ logging_level = logging.WARNING
69
+ case "error":
70
+ logging_level = logging.ERROR
71
+ case _:
72
+ pass
73
+
74
+ cwd = Path.cwd()
75
+ log_file_dir = f"{cwd}/_logs"
76
+ os.makedirs(log_file_dir, exist_ok=True)
77
+ filename = filename if filename else datetime.now().strftime('%H_%M_%S_%d_%m_%Y')
78
+ abs_dir = f"{log_file_dir}/{filename}.log"
79
+
80
+ logging.basicConfig(filename=abs_dir, filemode='w', level=logging_level)
81
+ logger = logging.getLogger(__name__)
82
+ file_handler = logging.FileHandler(filename=abs_dir)
83
+ formatter = logging.Formatter('%(asctime)s : %(levelname)s : %(name)s : %(message)s')
84
+ file_handler.setFormatter(formatter)
85
+
86
+ for handler in logging.root.handlers[:]:
87
+ logging.root.removeHandler(handler)
88
+
89
+ logger.addHandler(file_handler)
90
+
91
+ match logging_level:
92
+ case logging.WARNING:
93
+ logger.warning(message)
94
+ case logging.ERROR:
95
+ logger.error(message)
96
+ case _:
97
+ logger.info(message)
@@ -39,3 +39,10 @@ vhq_formation_planner = Agent(
39
39
  "Random is a formation where a single agent handles tasks, asking help from other agents without sharing its memory or knowledge. Typical usecase is that an email agent drafts promo message for the given audience, asking insights on tones from other email agents which oversee other customer clusters, or an agent calls the external, third party agent to deploy the campaign. ",
40
40
  ]
41
41
  )
42
+
43
+
44
+ vhq_agent_creator = Agent(
45
+ role="vhq-Agent Creator",
46
+ goal="build an agent that can handle the given task",
47
+ llm="gemini/gemini-2.0-flash-exp",
48
+ )
versionhq/agent/model.py CHANGED
@@ -95,7 +95,7 @@ class Agent(BaseModel):
95
95
  user_prompt_template: Optional[str] = Field(default=None, description="user prompt template")
96
96
 
97
97
  # task execution rules
98
- team: Optional[List[Any]] = Field(default=None, description="Team to which the agent belongs")
98
+ network: Optional[List[Any]] = Field(default=None, description="store a list of agent networks that the agent belong as a member")
99
99
  allow_delegation: bool = Field(default=False,description="if the agent can delegate the task to another agent or ask some help")
100
100
  max_retry_limit: int = Field(default=2 ,description="max. number of retry for the task execution when an error occurs")
101
101
  maxit: Optional[int] = Field(default=25,description="max. number of total optimization loops conducted when an error occurs")
@@ -553,7 +553,7 @@ class Agent(BaseModel):
553
553
 
554
554
 
555
555
  ## comment out for now
556
- # if self.team and self.team._train:
556
+ # if self.network and self.network._train:
557
557
  # task_prompt = self._training_handler(task_prompt=task_prompt)
558
558
  # else:
559
559
  # task_prompt = self._use_trained_data(task_prompt=task_prompt)
@@ -1,7 +1,6 @@
1
1
  import uuid
2
2
  import warnings
3
3
  from enum import Enum
4
- from dotenv import load_dotenv
5
4
  from concurrent.futures import Future
6
5
  from hashlib import md5
7
6
  from typing import Any, Dict, List, Callable, Optional, Tuple
@@ -10,9 +9,8 @@ from pydantic._internal._generate_schema import GenerateSchema
10
9
  from pydantic_core import PydanticCustomError, core_schema
11
10
 
12
11
  from versionhq.agent.model import Agent
13
- from versionhq.task.model import Task, TaskOutput, TaskExecutionType
12
+ from versionhq.task.model import Task, TaskOutput, TaskExecutionType, ResponseField
14
13
  from versionhq.task.formatter import create_raw_outputs
15
- from versionhq.team.team_planner import TeamPlanner
16
14
  from versionhq._utils.logger import Logger
17
15
  from versionhq._utils.usage_metrics import UsageMetrics
18
16
 
@@ -41,21 +39,21 @@ class Formation(str, Enum):
41
39
  class TaskHandlingProcess(str, Enum):
42
40
  """
43
41
  A class representing task handling processes to tackle multiple tasks.
44
- When the team has multiple tasks that connect with edges, follow the edge conditions.
42
+ When the agent network has multiple tasks that connect with edges, follow the edge conditions.
45
43
  """
46
44
  SEQUENT = 1
47
45
  HIERARCHY = 2
48
46
  CONSENSUAL = 3 # either from managers or peers or (human) - most likely controlled by edge
49
47
 
50
48
 
51
- class TeamOutput(TaskOutput):
49
+ class NetworkOutput(TaskOutput):
52
50
  """
53
- A class to store output from the team, inherited from TaskOutput class.
51
+ A class to store output from the network, inherited from TaskOutput class.
54
52
  """
55
53
 
56
- team_id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True, description="store the team ID that generate the TeamOutput")
54
+ network_id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True, description="store the network ID as an identifier that generate the output")
57
55
  task_description: str = Field(default=None, description="store initial request (task description) from the client")
58
- task_outputs: list[TaskOutput] = Field(default=list, description="store TaskOutput objects of all tasks that the team has executed")
56
+ task_outputs: list[TaskOutput] = Field(default=list, description="store TaskOutput objects of all tasks that the network has executed")
59
57
  # token_usage: UsageMetrics = Field(default=dict, description="processed token summary")
60
58
 
61
59
  def return_all_task_outputs(self) -> List[Dict[str, Any]]:
@@ -71,18 +69,18 @@ class TeamOutput(TaskOutput):
71
69
  elif self.json_dict and key in self.json_dict:
72
70
  return self.json_dict[key]
73
71
  else:
74
- raise KeyError(f"Key '{key}' not found in the team output.")
72
+ raise KeyError(f"Key '{key}' not found in the output.")
75
73
 
76
74
 
77
75
 
78
76
  class Member(BaseModel):
79
77
  """
80
- A class to store a member in the team and connect the agent as a member with tasks and memory/knowledge share settings.
78
+ A class to store a member (agent) in the network, with its tasks and memory/knowledge share settings.
81
79
  """
82
80
  agent: Agent | None = Field(default=None)
83
81
  is_manager: bool = Field(default=False)
84
- can_share_knowledge: bool = Field(default=True, description="whether to share the agent's knowledge in the team")
85
- can_share_memory: bool = Field(default=True, description="whether to share the agent's memory in the team")
82
+ can_share_knowledge: bool = Field(default=True, description="whether to share the agent's knowledge in the network")
83
+ can_share_memory: bool = Field(default=True, description="whether to share the agent's memory in the network")
86
84
  tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks explicitly assigned to the agent")
87
85
 
88
86
  @property
@@ -90,10 +88,10 @@ class Member(BaseModel):
90
88
  return bool(self.tasks)
91
89
 
92
90
 
93
- class Team(BaseModel):
91
+ class AgentNetwork(BaseModel):
94
92
  """
95
- A class to store a team with members and tasks.
96
- Tasks can be 1. multiple individual tasks, 2. multiple dependant tasks connected via Graph, and 3. hybrid.
93
+ A class to store a agent network with agent members and their tasks.
94
+ Tasks can be 1. multiple individual tasks, 2. multiple dependant tasks connected via TaskGraph, and 3. hybrid.
97
95
  """
98
96
 
99
97
  __hash__ = object.__hash__
@@ -108,8 +106,7 @@ class Team(BaseModel):
108
106
  should_reform: bool = Field(default=False, description="True if task exe. failed or eval scores below threshold")
109
107
 
110
108
  # formation planning
111
- planner_llm: Optional[Any] = Field(default=None, description="llm to generate and evaluate formation")
112
- team_tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks without dedicated agents to handle")
109
+ network_tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks without dedicated agents")
113
110
 
114
111
  # task execution rules
115
112
  prompt_file: str = Field(default="", description="absolute path to the prompt json file")
@@ -118,11 +115,11 @@ class Team(BaseModel):
118
115
  # callbacks
119
116
  pre_launch_callbacks: List[Callable[[Optional[Dict[str, Any]]], Optional[Dict[str, Any]]]] = Field(
120
117
  default_factory=list,
121
- description="list of callback functions to be executed before the team launch. i.e., adjust inputs"
118
+ description="list of callback functions to be executed before the network launch. i.e., adjust inputs"
122
119
  )
123
- post_launch_callbacks: List[Callable[[TeamOutput], TeamOutput]] = Field(
120
+ post_launch_callbacks: List[Callable[[NetworkOutput], NetworkOutput]] = Field(
124
121
  default_factory=list,
125
- description="list of callback functions to be executed after the team launch. i.e., store the result in repo"
122
+ description="list of callback functions to be executed after the network launch. i.e., store the result in repo"
126
123
  )
127
124
  step_callback: Optional[Any] = Field(default=None, description="callback to be executed after each step for all agents execution")
128
125
 
@@ -146,19 +143,19 @@ class Team(BaseModel):
146
143
  @model_validator(mode="after")
147
144
  def assess_tasks(self):
148
145
  """
149
- Validates if the model recognize all tasks that the team needs to handle.
146
+ Validates if the model recognize all tasks that the network needs to handle.
150
147
  """
151
148
 
152
149
  if self.tasks:
153
- if all(task in self.tasks for task in self.team_tasks) == False:
154
- raise PydanticCustomError("task_validation_error", "`team_tasks` needs to be recognized in the task.", {})
150
+ if all(task in self.tasks for task in self.network_tasks) == False:
151
+ raise PydanticCustomError("task_validation_error", "`network_tasks` needs to be recognized in the task.", {})
155
152
 
156
153
 
157
154
  num_member_tasks = 0
158
155
  for member in self.members:
159
156
  num_member_tasks += len(member.tasks)
160
157
 
161
- # if len(self.tasks) != len(self.team_tasks) + num_member_tasks:
158
+ # if len(self.tasks) != len(self.network_tasks) + num_member_tasks:
162
159
  # raise PydanticCustomError("task_validation_error", "Some tasks are missing.", {})
163
160
  return self
164
161
 
@@ -166,7 +163,7 @@ class Team(BaseModel):
166
163
  @model_validator(mode="after")
167
164
  def check_manager(self):
168
165
  """
169
- Check if the team has a manager
166
+ Check if the agent network has a manager
170
167
  """
171
168
  if self.process == TaskHandlingProcess.HIERARCHY or self.formation == Formation.SUPERVISING:
172
169
  if not self.managers:
@@ -174,9 +171,9 @@ class Team(BaseModel):
174
171
  raise PydanticCustomError("missing_manager", "`manager` is required when using hierarchical process.", {})
175
172
 
176
173
  ## comment out for the formation flexibilities
177
- # if self.managers and (self.manager_tasks is None or self.team_tasks is None):
174
+ # if self.managers and (self.manager_tasks is None or self.network_tasks is None):
178
175
  # self._logger.log(level="error", message="The manager is idling. At least 1 task needs to be assigned to the manager.", color="red")
179
- # raise PydanticCustomError("missing_manager_task", "manager needs to have at least one manager task or team task.", {})
176
+ # raise PydanticCustomError("missing_manager_task", "manager needs to have at least one manager task or network task.", {})
180
177
 
181
178
  return self
182
179
 
@@ -184,9 +181,9 @@ class Team(BaseModel):
184
181
  @model_validator(mode="after")
185
182
  def validate_task_member_paring(self):
186
183
  """
187
- Sequential task processing without any team tasks require a task-agent pairing.
184
+ Sequential task processing without any network_tasks require a task-agent pairing.
188
185
  """
189
- if self.process == TaskHandlingProcess.SEQUENT and self.team_tasks is None:
186
+ if self.process == TaskHandlingProcess.SEQUENT and self.network_tasks is None:
190
187
  for task in self.tasks:
191
188
  if not [member.task == task for member in self.members]:
192
189
  self._logger.log(level="error", message=f"The following task needs a dedicated agent to be assinged: {task.description}", color="red")
@@ -196,7 +193,7 @@ class Team(BaseModel):
196
193
  @model_validator(mode="after")
197
194
  def validate_end_with_at_most_one_async_task(self):
198
195
  """
199
- Validates that the team completes max. one asynchronous task by counting tasks traversed backward
196
+ Validates that the agent network completes max. one asynchronous task by counting tasks traversed backward
200
197
  """
201
198
 
202
199
  async_task_count = 0
@@ -209,10 +206,43 @@ class Team(BaseModel):
209
206
  break
210
207
 
211
208
  if async_task_count > 1:
212
- raise PydanticCustomError("async_task_count", "The team must end with max. one asynchronous task.", {})
209
+ raise PydanticCustomError("async_task_count", "The agent network must end with at maximum one asynchronous task.", {})
213
210
  return self
214
211
 
215
212
 
213
+ @staticmethod
214
+ def handle_assigning_agents(unassigned_tasks: List[Task]) -> List[Member]:
215
+ """
216
+ Build an agent and assign it with a task. Return a list of Member connecting the agent created and the task given.
217
+ """
218
+
219
+ from versionhq.agent.inhouse_agents import vhq_agent_creator
220
+
221
+ new_member_list: List[Member] = []
222
+
223
+ for unassgined_task in unassigned_tasks:
224
+ task = Task(
225
+ description=f"""
226
+ Based on the following task summary, draft a AI agent's role and goal in concise manner.
227
+ Task summary: {unassgined_task.summary}
228
+ """,
229
+ response_fields=[
230
+ ResponseField(title="goal", data_type=str, required=True),
231
+ ResponseField(title="role", data_type=str, required=True),
232
+ ],
233
+ )
234
+ res = task.execute(agent=vhq_agent_creator)
235
+ agent = Agent(
236
+ role=res.json_dict["role"] if "role" in res.json_dict else res.raw,
237
+ goal=res.json_dict["goal"] if "goal" in res.json_dict else task.description
238
+ )
239
+ if agent.id:
240
+ member = Member(agent=agent, tasks=[unassgined_task], is_manager=False)
241
+ new_member_list.append(member)
242
+
243
+ return new_member_list
244
+
245
+
216
246
  def _get_responsible_agent(self, task: Task) -> Agent | None:
217
247
  if task is None:
218
248
  return None
@@ -226,17 +256,16 @@ class Team(BaseModel):
226
256
 
227
257
  def _assign_tasks(self) -> None:
228
258
  """
229
- Form a team considering agents and tasks given, and update `self.members` field:
230
- 1. Idling managers to take the team tasks.
231
- 2. Idling members to take the remaining tasks starting from the team tasks to member tasks.
259
+ Form a agent network considering given agents and tasks, and update `self.members` field:
260
+ 1. Idling managers to take the network tasks.
261
+ 2. Idling members to take the remaining tasks starting from the network tasks to member tasks.
232
262
  3. Create agents to handle the rest tasks.
233
263
  """
234
264
 
235
- team_planner = TeamPlanner(tasks=self.tasks, planner_llm=self.planner_llm)
236
265
  idling_managers: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == True]
237
266
  idling_members: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == False]
238
- unassigned_tasks: List[Task] = self.team_tasks + self.member_tasks_without_agent if self.team_tasks else self.member_tasks_without_agent
239
- new_team_members: List[Member] = []
267
+ unassigned_tasks: List[Task] = self.network_tasks + self.member_tasks_without_agent if self.network_tasks else self.member_tasks_without_agent
268
+ new_members: List[Member] = []
240
269
 
241
270
  if idling_managers:
242
271
  idling_managers[0].tasks.extend(unassigned_tasks)
@@ -245,9 +274,9 @@ class Team(BaseModel):
245
274
  idling_members[0].tasks.extend(unassigned_tasks)
246
275
 
247
276
  else:
248
- new_team_members = team_planner._handle_assign_agents(unassigned_tasks=unassigned_tasks)
249
- if new_team_members:
250
- self.members += new_team_members
277
+ new_members = self.handle_assigning_agents(unassigned_tasks=unassigned_tasks)
278
+ if new_members:
279
+ self.members += new_members
251
280
 
252
281
 
253
282
  # task execution
@@ -268,7 +297,7 @@ class Team(BaseModel):
268
297
 
269
298
  def _calculate_usage_metrics(self) -> UsageMetrics:
270
299
  """
271
- Calculate and return the usage metrics that consumed by the team.
300
+ Calculate and return the usage metrics that consumed by the agent network.
272
301
  """
273
302
  total_usage_metrics = UsageMetrics()
274
303
 
@@ -288,12 +317,12 @@ class Team(BaseModel):
288
317
  return total_usage_metrics
289
318
 
290
319
 
291
- def _execute_tasks(self, tasks: List[Task], start_index: Optional[int] = 0, was_replayed: bool = False) -> TeamOutput:
320
+ def _execute_tasks(self, tasks: List[Task], start_index: Optional[int] = 0, was_replayed: bool = False) -> NetworkOutput:
292
321
  """
293
- Executes tasks sequentially and returns the final output in TeamOutput class.
322
+ Executes tasks sequentially and returns the final output in NetworkOutput class.
294
323
  When we have a manager agent, we will start from executing manager agent's tasks.
295
324
  Priority:
296
- 1. Team tasks > 2. Manager task > 3. Member tasks (in order of index)
325
+ 1. Network tasks > 2. Manager task > 3. Member tasks (in order of index)
297
326
  """
298
327
 
299
328
  task_outputs: List[TaskOutput] = []
@@ -330,6 +359,7 @@ class Team(BaseModel):
330
359
  else:
331
360
  context = create_raw_outputs(tasks=[task,], task_outputs=([last_sync_output,] if last_sync_output else [] ))
332
361
  task_output = task.execute(agent=responsible_agent, context=context)
362
+
333
363
  if self.managers and responsible_agent in [manager.agent for manager in self.managers]:
334
364
  lead_task_output = task_output
335
365
 
@@ -341,15 +371,15 @@ class Team(BaseModel):
341
371
  task_outputs = self._process_async_tasks(futures, was_replayed)
342
372
 
343
373
  if not task_outputs:
344
- self._logger.log(level="error", message="Missing task outcomes. Failed to launch the task.", color="red")
345
- raise ValueError("Failed to launch tasks")
374
+ self._logger.log(level="error", message="Missing task outputs.", color="red")
375
+ raise ValueError("Missing task outputs")
346
376
 
347
377
  final_task_output = lead_task_output if lead_task_output is not None else task_outputs[0] #! REFINEME
348
378
 
349
379
  # token_usage = self._calculate_usage_metrics() #! combining with Eval
350
380
 
351
- return TeamOutput(
352
- team_id=self.id,
381
+ return NetworkOutput(
382
+ network_id=self.id,
353
383
  raw=final_task_output.raw,
354
384
  json_dict=final_task_output.json_dict,
355
385
  pydantic=final_task_output.pydantic,
@@ -358,33 +388,23 @@ class Team(BaseModel):
358
388
  )
359
389
 
360
390
 
361
-
362
- def launch(self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None) -> TeamOutput:
391
+ def launch(self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None) -> NetworkOutput:
363
392
  """
364
- Confirm and launch the formation - execute tasks and record outputs.
365
- 0. Assign an agent to a task - using conditions (manager prioritizes team_tasks) and planner_llm.
366
- 1. Address `pre_launch_callbacks` if any.
367
- 2. Handle team members' tasks in accordance with the process.
368
- 3. Address `post_launch_callbacks` if any.
393
+ Launch the agent network - executing tasks and recording their outputs.
369
394
  """
370
395
 
371
396
  metrics: List[UsageMetrics] = []
372
397
 
373
- if self.team_tasks or self.member_tasks_without_agent:
398
+ if self.network_tasks or self.member_tasks_without_agent:
374
399
  self._assign_tasks()
375
400
 
376
401
  if kwargs_pre is not None:
377
402
  for func in self.pre_launch_callbacks:
378
403
  func(**kwargs_pre)
379
404
 
380
- # self._execution_span = self._telemetry.team_execution_span(self, inputs)
381
- # self._task_output_handler.reset()
382
- # self._logging_color = "bold_purple"
383
- # i18n = I18N(prompt_file=self.prompt_file)
384
-
385
405
  for member in self.members:
386
406
  agent = member.agent
387
- agent.team = self
407
+ agent.network = self
388
408
 
389
409
  if self.step_callback:
390
410
  agent.callbacks.append(self.step_callback)
@@ -421,7 +441,7 @@ class Team(BaseModel):
421
441
  @property
422
442
  def manager_tasks(self) -> List[Task]:
423
443
  """
424
- Tasks (incl. team tasks) handled by managers in the team.
444
+ Tasks (incl. network tasks) handled by managers in the agent network.
425
445
  """
426
446
  res = list()
427
447
 
@@ -436,22 +456,22 @@ class Team(BaseModel):
436
456
  @property
437
457
  def tasks(self) -> List[Task]:
438
458
  """
439
- Return all the tasks that the team needs to handle in order of priority:
440
- 1. team tasks, -> assigned to the member
459
+ Return all the tasks that the agent network needs to handle in order of priority:
460
+ 1. network_tasks, -> assigned to the member
441
461
  2. manager_task,
442
462
  3. members' tasks
443
463
  """
444
464
 
445
- team_tasks = self.team_tasks
465
+ network_tasks = self.network_tasks
446
466
  manager_tasks = self.manager_tasks
447
467
  member_tasks = []
448
468
 
449
469
  for member in self.members:
450
470
  if member.is_manager == False and member.tasks:
451
- a = [item for item in member.tasks if item not in team_tasks and item not in manager_tasks]
471
+ a = [item for item in member.tasks if item not in network_tasks and item not in manager_tasks]
452
472
  member_tasks += a
453
473
 
454
- return team_tasks + manager_tasks + member_tasks
474
+ return network_tasks + manager_tasks + member_tasks
455
475
 
456
476
 
457
477
  @property
@@ -1,7 +1,7 @@
1
1
  import uuid
2
2
  from abc import ABC
3
- from datetime import date, datetime, time, timedelta
4
- from typing import Any, Dict, List, Callable, Type, Optional, get_args, get_origin
3
+ from datetime import datetime
4
+ from typing import Any, Dict, List, Optional
5
5
  from typing_extensions import Self
6
6
  from pydantic import UUID4, InstanceOf, BaseModel, ConfigDict, Field, field_validator, model_validator
7
7
  from pydantic_core import PydanticCustomError
@@ -9,7 +9,7 @@ from pydantic_core import PydanticCustomError
9
9
  from versionhq.clients.product.model import Product
10
10
  from versionhq.clients.customer.model import Customer
11
11
  from versionhq.agent.model import Agent
12
- from versionhq.team.model import Team
12
+ from versionhq.agent_network.model import AgentNetwork
13
13
  from versionhq.tool.composio_tool_vars import ComposioAppName
14
14
 
15
15
 
@@ -102,8 +102,8 @@ class MessagingWorkflow(ABC, BaseModel):
102
102
  messaging_components: List[MessagingComponent] = Field(default_factory=list, description="store messaging components in the workflow")
103
103
 
104
104
  # responsible tean or agents
105
- team: Optional[Team] = Field(default=None, description="store a responsibile team to autopilot the workflow")
106
- agents: Optional[List[Agent]] = Field(default=None, description="store responsible agents. None when the team exists")
105
+ agent_network: Optional[AgentNetwork] = Field(default=None, description="store a responsibile agent network to autopilot the workflow")
106
+ agents: Optional[List[Agent]] = Field(default=None, description="store responsible agents. None when the `agent_network` fields has a value")
107
107
 
108
108
  # metrics
109
109
  destination: Optional[ComposioAppName | str] = Field(default=None, description="destination service to launch the workflow")
@@ -140,16 +140,16 @@ class MessagingWorkflow(ABC, BaseModel):
140
140
  return self
141
141
 
142
142
 
143
- def reassign_agent_or_team(self, agents: List[Agent] = None, team: Team = None) -> None:
143
+ def reassign_agent(self, agents: List[Agent] = None, agent_network: AgentNetwork = None) -> None:
144
144
  """
145
- Fire unresponsible agents/team and assign new one.
145
+ Switch agents
146
146
  """
147
147
 
148
- if not agents and not team:
149
- raise ValueError("Need to add at least 1 agent or team.")
148
+ if not agents and not agent_network:
149
+ raise ValueError("Missing agent or agent network to assign.")
150
150
 
151
151
  self.agents = agents
152
- self.team = team
152
+ self.agent_network = agent_network
153
153
  self.updated_at = datetime.datetime.now()
154
154
 
155
155
 
@@ -265,7 +265,7 @@ class PDFKnowledgeSource(BaseFileKnowledgeSource):
265
265
  import os
266
266
  os.system("uv add pdfplumber --optional pdfplumber")
267
267
  except:
268
- raise ImportError("pdfplumber is not installed. Please install it with: uv add pdfplumber --optional pdfplumber")
268
+ raise ImportError("pdfplumber is not installed. Please install it with: $ uv add versionhq[pdfplumber]")
269
269
 
270
270
 
271
271
  def add(self) -> None:
@@ -394,7 +394,7 @@ class ExcelKnowledgeSource(BaseFileKnowledgeSource):
394
394
  except:
395
395
  missing_package = str(e).split()[-1]
396
396
  raise ImportError(
397
- f"{missing_package} is not installed. Please install it with: pip install {missing_package}"
397
+ f"{missing_package} is not installed. Please install it with: $ uv add versionhq[{missing_package}]"
398
398
  )
399
399
 
400
400
 
@@ -56,7 +56,7 @@ class DoclingSource(BaseKnowledgeSource):
56
56
  super().__init__(*args, **kwargs)
57
57
 
58
58
  else:
59
- raise ImportError("The docling package is required. Please install the package using: $ uv add docling.")
59
+ raise ImportError("The docling package is required. Please install the package using: $ uv add versionhq[docling]")
60
60
  # else:
61
61
  # super().__init__(*args, **kwargs)
62
62
 
versionhq/memory/model.py CHANGED
@@ -125,7 +125,7 @@ class ShortTermMemory(Memory):
125
125
 
126
126
  from versionhq.storage.mem0_storage import Mem0Storage
127
127
  except:
128
- raise ImportError("Mem0 is not installed. Please install it with `uv pip install mem0ai`.")
128
+ raise ImportError("Mem0 is not installed. Please install it with `$ uv add versionhq[mem0ai]`.")
129
129
 
130
130
  storage = Mem0Storage(type="stm", agent=agent)
131
131
  else:
@@ -5,7 +5,7 @@ from pydantic import BaseModel
5
5
 
6
6
  from versionhq.task.model import Task
7
7
  from versionhq.agent.model import Agent
8
- from versionhq.team.model import Team, Member, Formation
8
+ from versionhq.agent_network.model import AgentNetwork, Member, Formation
9
9
  from versionhq.agent.inhouse_agents import vhq_formation_planner
10
10
  from versionhq._utils import Logger
11
11
 
@@ -16,7 +16,7 @@ def form_agent_network(
16
16
  agents: List[Agent] = None,
17
17
  context: str = None,
18
18
  formation: Type[Formation] = None
19
- ) -> Team | None:
19
+ ) -> AgentNetwork | None:
20
20
  """
21
21
  Make a formation of agents from the given task description, expected outcome, agents (optional), and context (optional).
22
22
  """
@@ -91,7 +91,7 @@ def form_agent_network(
91
91
  created_agents = [Agent(role=item, goal=item) for item in res.pydantic.agent_roles]
92
92
  created_tasks = [Task(description=item) for item in res.pydantic.task_descriptions]
93
93
 
94
- team_tasks = []
94
+ network_tasks = []
95
95
  members = []
96
96
  leader = str(res.pydantic.leader_agent)
97
97
 
@@ -106,11 +106,11 @@ def form_agent_network(
106
106
 
107
107
 
108
108
  if len(created_agents) < len(created_tasks):
109
- team_tasks.extend(created_tasks[len(created_agents):len(created_tasks)])
109
+ network_tasks.extend(created_tasks[len(created_agents):len(created_tasks)])
110
110
 
111
111
  members.sort(key=lambda x: x.is_manager == False)
112
- team = Team(members=members, formation=_formation, team_tasks=team_tasks, planner_llm=vhq_formation_planner.llm)
113
- return team
112
+ network = AgentNetwork(members=members, formation=_formation, network_tasks=network_tasks)
113
+ return network
114
114
 
115
115
  else:
116
116
  res = res.json_dict
@@ -122,7 +122,7 @@ def form_agent_network(
122
122
  created_agents = [Agent(role=item, goal=item) for item in res["agent_roles"]]
123
123
  created_tasks = [Task(description=item) for item in res["task_descriptions"]]
124
124
 
125
- team_tasks = []
125
+ network_tasks = []
126
126
  members = []
127
127
  leader = str(res["leader_agent"])
128
128
 
@@ -136,11 +136,11 @@ def form_agent_network(
136
136
  members.append(member)
137
137
 
138
138
  if len(created_agents) < len(created_tasks):
139
- team_tasks.extend(created_tasks[len(created_agents):len(created_tasks)])
139
+ network_tasks.extend(created_tasks[len(created_agents):len(created_tasks)])
140
140
 
141
141
  members.sort(key=lambda x: x.is_manager == False)
142
- team = Team( members=members, formation=_formation, team_tasks=team_tasks, planner_llm=vhq_formation_planner.llm)
143
- return team
142
+ network = AgentNetwork(members=members, formation=_formation, network_tasks=network_tasks)
143
+ return network
144
144
 
145
145
 
146
146
  except Exception as e:
versionhq/task/model.py CHANGED
@@ -613,10 +613,11 @@ Ref. Output image: {output_formats_to_follow}
613
613
  """
614
614
 
615
615
  from versionhq.agent.model import Agent
616
- from versionhq.team.model import Team
616
+ from versionhq.agent_network.model import AgentNetwork
617
617
 
618
618
  self.prompt_context = context
619
619
  task_output: InstanceOf[TaskOutput] = None
620
+ raw_output: str = None
620
621
  tool_output: str | list = None
621
622
  task_tools: List[List[InstanceOf[Tool]| InstanceOf[ToolSet] | Type[Tool]]] = []
622
623
  started_at, ended_at = datetime.datetime.now(), datetime.datetime.now()
@@ -626,15 +627,15 @@ Ref. Output image: {output_formats_to_follow}
626
627
  if isinstance(item, ToolSet) or isinstance(item, Tool) or type(item) == Tool:
627
628
  task_tools.append(item)
628
629
 
629
- if self.allow_delegation:
630
+ if self.allow_delegation == True:
630
631
  agent_to_delegate = None
631
632
 
632
- if hasattr(agent, "team") and isinstance(agent.team, Team):
633
- if agent.team.managers:
634
- idling_manager_agents = [manager.agent for manager in agent.team.managers if manager.is_idling]
635
- agent_to_delegate = idling_manager_agents[0] if idling_manager_agents else agent.team.managers[0]
633
+ if hasattr(agent, "network") and isinstance(agent.network, AgentNetwork):
634
+ if agent.network.managers:
635
+ idling_manager_agents = [manager.agent for manager in agent.network.managers if manager.is_idling]
636
+ agent_to_delegate = idling_manager_agents[0] if idling_manager_agents else agent.network.managers[0]
636
637
  else:
637
- peers = [member.agent for member in agent.team.members if member.is_manager == False and member.agent.id is not agent.id]
638
+ peers = [member.agent for member in agent.network.members if member.is_manager == False and member.agent.id is not agent.id]
638
639
  if len(peers) > 0:
639
640
  agent_to_delegate = peers[0]
640
641
  else:
@@ -673,7 +674,7 @@ Ref. Output image: {output_formats_to_follow}
673
674
  self.output = task_output
674
675
  self.processed_agents.add(agent.role)
675
676
 
676
- if self.should_evaluate:
677
+ if self.should_evaluate and raw_output: # eval only when raw output exsits
677
678
  task_output.evaluate(task=self)
678
679
 
679
680
  self._create_short_and_long_term_memories(agent=agent, task_output=task_output)
@@ -5,7 +5,7 @@ import matplotlib.pyplot as plt
5
5
  from abc import ABC
6
6
  from typing import List, Any, Optional, Callable, Dict, Type, Tuple
7
7
 
8
- from pydantic import BaseModel, InstanceOf, Field, UUID4, PrivateAttr, field_validator
8
+ from pydantic import BaseModel, InstanceOf, Field, UUID4, field_validator
9
9
  from pydantic_core import PydanticCustomError
10
10
 
11
11
  from versionhq.task.model import Task, TaskOutput
@@ -13,26 +13,6 @@ from versionhq.agent.model import Agent
13
13
  from versionhq._utils.logger import Logger
14
14
 
15
15
 
16
- def gen_network():
17
- goal = "make a promo plan to increase gross sales of Temu, an ecommerce site with affordable items."
18
- agent = Agent(
19
- role="Network Generator", goal="draft a best graph with nodes (tasks) and edges", llm="gemini-2.0", maxit=1,
20
- knowledge_sources=["https://en.wikipedia.org/wiki/Graph_theory", "https://www.temu.com", ]
21
- )
22
- class Outcome(BaseModel):
23
- task_descriptions: list[str]
24
-
25
-
26
- task = Task(
27
- description=" Create a team of specialized agents designed to automate the following task and deliver the expected outcome. Consider the necessary roles for each agent with a clear task description. If you think we neeed a leader to handle the automation, return a leader_agent role as well, but if not, leave the a leader_agent role blank. ",
28
- pydantic_output=Outcome
29
- )
30
- task = Task(
31
- description="Form best network with nodes and edges for the task described as following: Draft a promo plan for the client.",
32
- pydantic_output=Edge
33
- )
34
- res = task.execute(agent=agent)
35
-
36
16
  class TaskStatus(enum.Enum):
37
17
  """
38
18
  Enum to track the task execution status
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: versionhq
3
- Version: 1.2.1.0
3
+ Version: 1.2.1.2
4
4
  Summary: An agentic orchestration framework for building agent networks that handle task automation.
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -117,10 +117,10 @@ A Python framework for agentic orchestration that handles complex task automatio
117
117
  - [Supervising](#supervising)
118
118
  - [Technologies Used](#technologies-used)
119
119
  - [Project Structure](#project-structure)
120
- - [Setting Up a Project](#setting-up-a-project)
121
- - [1. Installing package manager](#1-installing-package-manager)
122
- - [2. Installing dependencies](#2-installing-dependencies)
123
- - [3. Adding env secrets to .env file](#3-adding-env-secrets-to-env-file)
120
+ - [Setting Up Your Project](#setting-up-your-project)
121
+ - [Installing package manager](#installing-package-manager)
122
+ - [Installing dependencies](#installing-dependencies)
123
+ - [Adding env secrets to .env file](#adding-env-secrets-to-env-file)
124
124
  - [Contributing](#contributing)
125
125
  - [Steps](#steps)
126
126
  - [Package Management with uv](#package-management-with-uv)
@@ -256,7 +256,7 @@ agent.update(
256
256
  res = network.launch()
257
257
  ```
258
258
 
259
- This will form a network with multiple agents on `Formation` and return `TaskOutput` object with output in JSON, plane text, Pydantic model format with evaluation.
259
+ This will form a network with multiple agents on `Formation` and return `TaskOutput` object with output in JSON, plane text, Pydantic model format with evaluation.
260
260
 
261
261
 
262
262
  ### Executing tasks
@@ -266,81 +266,87 @@ You can simply build an agent using `Agent` model and execute the task using `Ta
266
266
  By default, agents prioritize JSON over plane text outputs.
267
267
 
268
268
 
269
- ```python
270
- import versionhq as vhq
271
- from pydantic import BaseModel
269
+ ```python
270
+ import versionhq as vhq
271
+ from pydantic import BaseModel
272
272
 
273
- class CustomOutput(BaseModel):
274
- test1: str
275
- test2: list[str]
273
+ class CustomOutput(BaseModel):
274
+ test1: str
275
+ test2: list[str]
276
276
 
277
- def dummy_func(message: str, test1: str, test2: list[str]) -> str:
278
- return f"""{message}: {test1}, {", ".join(test2)}"""
277
+ def dummy_func(message: str, test1: str, test2: list[str]) -> str:
278
+ return f"""{message}: {test1}, {", ".join(test2)}"""
279
279
 
280
- task = vhq.Task(
281
- description="Amazing task",
282
- pydantic_output=CustomOutput,
283
- callback=dummy_func,
284
- callback_kwargs=dict(message="Hi! Here is the result: ")
285
- )
280
+ task = vhq.Task(
281
+ description="Amazing task",
282
+ pydantic_output=CustomOutput,
283
+ callback=dummy_func,
284
+ callback_kwargs=dict(message="Hi! Here is the result: ")
285
+ )
286
286
 
287
- res = task.execute(context="amazing context to consider.")
288
- print(res)
289
- ```
287
+ res = task.execute(context="amazing context to consider.")
288
+ print(res)
289
+ ```
290
290
 
291
291
 
292
292
  This will return a `TaskOutput` object that stores response in plane text, JSON, and Pydantic model: `CustomOutput` formats with a callback result, tool output (if given), and evaluation results (if given).
293
293
 
294
- ```python
295
- res == TaskOutput(
296
- task_id=UUID('<TASK UUID>'),
297
- raw='{\"test1\":\"random str\", \"test2\":[\"str item 1\", \"str item 2\", \"str item 3\"]}',
298
- json_dict={'test1': 'random str', 'test2': ['str item 1', 'str item 2', 'str item 3']},
299
- pydantic=<class '__main__.CustomOutput'>,
300
- tool_output=None,
301
- callback_output='Hi! Here is the result: random str, str item 1, str item 2, str item 3', # returned a plain text summary
302
- evaluation=None
303
- )
304
- ```
294
+ ```python
295
+ res == TaskOutput(
296
+ task_id=UUID('<TASK UUID>'),
297
+ raw='{\"test1\":\"random str\", \"test2\":[\"str item 1\", \"str item 2\", \"str item 3\"]}',
298
+ json_dict={'test1': 'random str', 'test2': ['str item 1', 'str item 2', 'str item 3']},
299
+ pydantic=<class '__main__.CustomOutput'>,
300
+ tool_output=None,
301
+ callback_output='Hi! Here is the result: random str, str item 1, str item 2, str item 3', # returned a plain text summary
302
+ evaluation=None
303
+ )
304
+ ```
305
305
 
306
306
  ### Supervising
307
307
 
308
- ```python
309
- import versionhq as vhq
308
+ To create an agent network with one or more manager agents, designate members using the `is_manager` tag.
310
309
 
311
- agent_a = vhq.Agent(role="agent a", goal="My amazing goals", llm="llm-of-your-choice")
312
- agent_b = vhq.Agent(role="agent b", goal="My amazing goals", llm="llm-of-your-choice")
310
+ ```python
311
+ import versionhq as vhq
313
312
 
314
- task_1 = vhq.Task(
315
- description="Analyze the client's business model.",
316
- response_fields=[vhq.ResponseField(title="test1", data_type=str, required=True),],
317
- allow_delegation=True
318
- )
313
+ agent_a = vhq.Agent(role="agent a", goal="My amazing goals", llm="llm-of-your-choice")
314
+ agent_b = vhq.Agent(role="agent b", goal="My amazing goals", llm="llm-of-your-choice")
319
315
 
320
- task_2 = vhq.Task(
321
- description="Define the cohort.",
322
- response_fields=[ResponseField(title="test1", data_type=int, required=True),],
323
- allow_delegation=False
324
- )
316
+ task_1 = vhq.Task(
317
+ description="Analyze the client's business model.",
318
+ response_fields=[vhq.ResponseField(title="test1", data_type=str, required=True),],
319
+ allow_delegation=True
320
+ )
325
321
 
326
- team = vhq.Team(
327
- members=[
328
- vhq.Member(agent=agent_a, is_manager=False, task=task_1),
329
- vhq.Member(agent=agent_b, is_manager=True, task=task_2),
330
- ],
331
- )
332
- res = team.launch()
333
- ```
322
+ task_2 = vhq.Task(
323
+ description="Define a cohort.",
324
+ response_fields=[vhq.ResponseField(title="test1", data_type=int, required=True),],
325
+ allow_delegation=False
326
+ )
327
+
328
+ network =vhq.AgentNetwork(
329
+ members=[
330
+ vhq.Member(agent=agent_a, is_manager=False, tasks=[task_1]),
331
+ vhq.Member(agent=agent_b, is_manager=True, tasks=[task_2]), # Agent B as a manager
332
+ ],
333
+ )
334
+ res = network.launch()
335
+
336
+ assert isinstance(res, vhq.NetworkOutput)
337
+ assert not [item for item in task_1.processed_agents if "vhq-Delegated-Agent" == item]
338
+ assert [item for item in task_1.processed_agents if "agent b" == item]
339
+ ```
334
340
 
335
341
  This will return a list with dictionaries with keys defined in the `ResponseField` of each task.
336
342
 
337
- Tasks can be delegated to a team manager, peers in the team, or completely new agent.
343
+ Tasks can be delegated to a manager, peers within the agent network, or a completely new agent.
338
344
 
339
345
  <hr />
340
346
 
341
347
  ## Technologies Used
342
348
 
343
- **Graph Theory (Analysis and Visualization)**
349
+ **Task Graph**
344
350
 
345
351
  * [NetworkX](https://networkx.org/documentation/stable/reference/introduction.html): A Python package to analyze, create, and manipulate complex graph networks.
346
352
  * [Matplotlib](https://matplotlib.org/stable/index.html): Visualization library
@@ -401,16 +407,19 @@ src/
401
407
  │ └── ...
402
408
 
403
409
  └── uploads/ [.gitignore] # Local directory to store uploaded files such as graphviz diagrams generatd by `Network` class
404
- |
410
+
411
+ └── _logs/ [.gitignore] # Local directory to store error/warning logs for debugging
412
+
413
+
405
414
  pyproject.toml # Project config
406
415
 
407
416
  ```
408
417
 
409
418
  <hr />
410
419
 
411
- ## Setting Up a Project
420
+ ## Setting Up Your Project
412
421
 
413
- ### 1. Installing package manager
422
+ ### Installing package manager
414
423
 
415
424
  For MacOS:
416
425
 
@@ -424,7 +433,7 @@ pyproject.toml # Project config
424
433
  ```
425
434
 
426
435
 
427
- ### 2. Installing dependencies
436
+ ### Installing dependencies
428
437
 
429
438
  ```
430
439
  uv venv
@@ -457,7 +466,7 @@ pyproject.toml # Project config
457
466
 
458
467
  - `torch`/`Docling` related errors: Set up default Python version either `3.11.x` or `3.12.x` (same as AssertionError)
459
468
 
460
- ### 3. Adding env secrets to .env file
469
+ ### Adding env secrets to .env file
461
470
 
462
471
  Create `.env` file in the project root and add following:
463
472
 
@@ -470,6 +479,7 @@ Create `.env` file in the project root and add following:
470
479
  [OTHER_LLM_INTERFACE_PROVIDER_OF_YOUR_CHOICE]_API_KEY=your-api-key
471
480
  ```
472
481
 
482
+
473
483
  <hr />
474
484
 
475
485
  ## Contributing
@@ -574,7 +584,7 @@ Common issues and solutions:
574
584
 
575
585
  * Issues related to dependencies: `rm -rf uv.lock`, `uv cache clean`, `uv venv`, and run `uv pip install -r requirements.txt -v`.
576
586
 
577
- * Issues related to the AI agents or RAG system: Check the `output.log` file for detailed error messages and stack traces.
587
+ * Issues related to agents and other systems: Check `_logs` directory for detailed error messages and stack traces.
578
588
 
579
589
  * Issues related to `Python quit unexpectedly`: Check [this stackoverflow article](https://stackoverflow.com/questions/59888499/macos-catalina-python-quit-unexpectedly-error).
580
590
 
@@ -1,17 +1,19 @@
1
- versionhq/__init__.py,sha256=OvDVdnABXYcdjKCYL58tOw2duy59rQ2lxc7e1AoxUjc,2781
1
+ versionhq/__init__.py,sha256=nv3StURywg_U4o7_lKbqPuby1xjSphOkY9B6Ra5ORHA,2817
2
2
  versionhq/_utils/__init__.py,sha256=dzoZr4cBlh-2QZuPzTdehPUCe9lP1dmRtauD7qTjUaA,158
3
3
  versionhq/_utils/i18n.py,sha256=TwA_PnYfDLA6VqlUDPuybdV9lgi3Frh_ASsb_X8jJo8,1483
4
- versionhq/_utils/logger.py,sha256=2qkODR6y8ApOoMjQZVecTboXvCLrMy2v_mTSOnNMKFY,1581
4
+ versionhq/_utils/logger.py,sha256=IxSlr2Vi7AXaxj5Fuy8LRzEovaIFVwcbWTgJnASsHN8,3155
5
5
  versionhq/_utils/process_config.py,sha256=jbPGXK2Kb4iyCugJ3FwRJuU0wL5Trq2x4xFQz2uOyFY,746
6
6
  versionhq/_utils/usage_metrics.py,sha256=NXF18dn5NNvGK7EsQ4AAghpR8ppYOjMx6ABenLLHnmM,1066
7
7
  versionhq/_utils/vars.py,sha256=bZ5Dx_bFKlt3hi4-NNGXqdk7B23If_WaTIju2fiTyPQ,57
8
8
  versionhq/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- versionhq/agent/inhouse_agents.py,sha256=vSobrH1gXDWlaNsiges3sqETeUrEssRzQvCZCY2hQZA,2374
10
- versionhq/agent/model.py,sha256=kSYCAiRxF62ztj-S-_KfN0mhPKikjbFZ0fy2Yj5J7Jo,25400
9
+ versionhq/agent/inhouse_agents.py,sha256=snDtgDmvZB2bZKH_RTcz5uFOMl3MTjLJwTQBebFt8hk,2532
10
+ versionhq/agent/model.py,sha256=HiEQulVjXx6fWGaP-DBWmiZv5uwXFPd4S8jyBU3ydm0,25442
11
11
  versionhq/agent/parser.py,sha256=riG0dkdQCxH7uJ0AbdVdg7WvL0BXhUgJht0VtQvxJBc,4082
12
12
  versionhq/agent/rpm_controller.py,sha256=grezIxyBci_lDlwAlgWFRyR5KOocXeOhYkgN02dNFNE,2360
13
13
  versionhq/agent/TEMPLATES/Backstory.py,sha256=IAhGnnt6VUMe3wO6IzeyZPDNu7XE7Uiu3VEXUreOcKs,532
14
14
  versionhq/agent/TEMPLATES/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ versionhq/agent_network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ versionhq/agent_network/model.py,sha256=P3Ntr_OIK60EXjEfaEm31HTBFypZfVr__0aC4VBt9G0,19353
15
17
  versionhq/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
18
  versionhq/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
19
  versionhq/clients/customer/__init__.py,sha256=-YXh1FQfvpfLacK8SUC7bD7Wx_eIEi4yrkCC_cUasFg,217
@@ -19,22 +21,20 @@ versionhq/clients/customer/model.py,sha256=_AtaVVMm9MgCwrQ-HTRQ2oXUMKrSCEfZwE2Jd
19
21
  versionhq/clients/product/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
22
  versionhq/clients/product/model.py,sha256=3w__pug9XRe4LIm9wX8C8WKqi40r081Eb1q2vWk9UaU,3694
21
23
  versionhq/clients/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- versionhq/clients/workflow/model.py,sha256=FNftenLLoha0bkivrjId32awLHAkBwIT8iNljdic_bw,6003
23
- versionhq/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- versionhq/graph/model.py,sha256=k4NbNn0D3r3ujfkQHOsfiiEJRxZx7iK5DczBnOyn1ik,23912
24
+ versionhq/clients/workflow/model.py,sha256=fqmTx8Y6P6i-sK045ENO88GDbf4WYY4hUA26RfEH8Ek,6011
25
25
  versionhq/knowledge/__init__.py,sha256=qW7IgssTA4_bFFV9ziOcYRfGjlq1c8bkb-HnfWknpuQ,567
26
26
  versionhq/knowledge/_utils.py,sha256=YWRF8U533cfZes_gZqUvdj-K24MD2ri1R0gjc_aPYyc,402
27
27
  versionhq/knowledge/embedding.py,sha256=KfHc__1THxb5jrg1EMrF-v944RDuIr2hE0l-MtM3Bp0,6826
28
28
  versionhq/knowledge/model.py,sha256=w29mrJv1kiznCh4P4yJMUQxIuyRw1Sk0XYtBXzCxaG4,1786
29
- versionhq/knowledge/source.py,sha256=HxlwK7E5qWMknJeswnFCCdTIOB01hV4JrEiMGkp7j1E,13631
30
- versionhq/knowledge/source_docling.py,sha256=hhHn3rS4KVsFKEPWcfllM8VxSL86PckZdAHDZNQNOq8,5411
29
+ versionhq/knowledge/source.py,sha256=-hEUPtJUHHMx4rUKtiHl19J8xAMw-WVBw34zwa2jZ08,13630
30
+ versionhq/knowledge/source_docling.py,sha256=mg7bgvKePHn2LlA_XzSFCbS0zOo9xfu_aNOf5cEo6c4,5421
31
31
  versionhq/knowledge/storage.py,sha256=7oxCg3W9mFjYH1YmuH9kFtTbNxquzYFjuUjd_TlsB9E,8170
32
32
  versionhq/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  versionhq/llm/llm_vars.py,sha256=wjQK20cKvph6Vq1v71o4d16zBGcHlwq0bzOT_zWno7w,7041
34
34
  versionhq/llm/model.py,sha256=wlzDUMEyIOm808d1vzqu9gmbB4ch-s_EUvwFR60gR80,17177
35
35
  versionhq/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  versionhq/memory/contextual_memory.py,sha256=tCsOOAUnfrOL7YiakqGoi3uShzzS870TmGnlGd3z_A4,3556
37
- versionhq/memory/model.py,sha256=4wow2O3UuMZ0AbC2NyxddGZac3-_GjNZbK9wsA015NA,8145
37
+ versionhq/memory/model.py,sha256=MPO8dDP5eAuk9td6bMOq5j2huLzCADFJDrTujHhcWQY,8150
38
38
  versionhq/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  versionhq/storage/base.py,sha256=p-Jas0fXQan_qotnRD6seQxrT2lj-uw9-SmHQhdppcs,355
40
40
  versionhq/storage/ltm_sqlite_storage.py,sha256=wdUiuwHfJocdk0UGqyrdU4S5Nae1rgsoRNu3LWmGFcI,3951
@@ -44,15 +44,14 @@ versionhq/storage/task_output_storage.py,sha256=E1t_Fkt78dPYIOl3MP7LfQ8oGtjlzxBu
44
44
  versionhq/storage/utils.py,sha256=ByYXPoEIGJYLUqz-DWjbCAnneNrH1otiYbp12SCILpM,747
45
45
  versionhq/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  versionhq/task/evaluate.py,sha256=WdUgjbZL62XrxyWe5MTz29scfzwmuAHGxJ7GvAB8Fmk,3954
47
- versionhq/task/formation.py,sha256=8YQxGZ7cs7Q-a7UnwheHxXei9LSt1AWpCQmQiN1ZkgI,6423
47
+ versionhq/task/formation.py,sha256=gBrFmMHvoyqdK9wEa9aBkZImEQV3GMDDX6-RDpw0pEo,6421
48
48
  versionhq/task/formatter.py,sha256=N8Kmk9vtrMtBdgJ8J7RmlKNMdZWSmV8O1bDexmCWgU0,643
49
49
  versionhq/task/log_handler.py,sha256=LT7YnO7gcPR9IZS7eRvMjnHh8crMBFtqduxd8dxIbkk,1680
50
- versionhq/task/model.py,sha256=aXsFRhpmIyfoYpF8BU2cBU4nh4OsaSxc9D98DJ9auqE,30624
50
+ versionhq/task/model.py,sha256=H7ZYZpp_1mrw_MlKjLr6gMJztqyhPkdeoolIzZSF68Y,30756
51
51
  versionhq/task/structured_response.py,sha256=4q-hQPu7oMMHHXEzh9YW4SJ7N5eCZ7OfZ65juyl_jCI,5000
52
52
  versionhq/task/TEMPLATES/Description.py,sha256=V-4kh8xpQTKOcDMi2xnuP-fcNk6kuoz1_5tYBlDLQWQ,420
53
- versionhq/team/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- versionhq/team/model.py,sha256=88l2lxlAZGIauRJr607IMbV7jP3FIvveVHrT7O4AVpk,18614
55
- versionhq/team/team_planner.py,sha256=Zc3zvhPR7T0O8RQoq9CKOrvrll4klemY1rONLFeJ96M,3663
53
+ versionhq/task_graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ versionhq/task_graph/model.py,sha256=TsszoTJFeJ4TfSdLAjcGa9QSQyf9Uy3WmechTw0qL3k,22832
56
55
  versionhq/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
56
  versionhq/tool/cache_handler.py,sha256=iL8FH7X0G-cdT0uhJwzuhLDaadTXOdfybZcDy151-es,1085
58
57
  versionhq/tool/composio_tool.py,sha256=38mEiVvTkuw1BLD233Bl1Gwxbpss1yfQiZLTWwX6BdA,8648
@@ -60,8 +59,8 @@ versionhq/tool/composio_tool_vars.py,sha256=FvBuEXsOQUYnN7RTFxT20kAkiEYkxWKkiVtg
60
59
  versionhq/tool/decorator.py,sha256=C4ZM7Xi2gwtEMaSeRo-geo_g_MAkY77WkSLkAuY0AyI,1205
61
60
  versionhq/tool/model.py,sha256=PO4zNWBZcJhYVur381YL1dy6zqurio2jWjtbxOxZMGI,12194
62
61
  versionhq/tool/tool_handler.py,sha256=2m41K8qo5bGCCbwMFferEjT-XZ-mE9F0mDUOBkgivOI,1416
63
- versionhq-1.2.1.0.dist-info/LICENSE,sha256=cRoGGdM73IiDs6nDWKqPlgSv7aR4n-qBXYnJlCMHCeE,1082
64
- versionhq-1.2.1.0.dist-info/METADATA,sha256=Ilxj9ZEYzoFzEnzdDE6umFKruSRN3pmcm_D2LvpVi8A,21854
65
- versionhq-1.2.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
66
- versionhq-1.2.1.0.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
67
- versionhq-1.2.1.0.dist-info/RECORD,,
62
+ versionhq-1.2.1.2.dist-info/LICENSE,sha256=cRoGGdM73IiDs6nDWKqPlgSv7aR4n-qBXYnJlCMHCeE,1082
63
+ versionhq-1.2.1.2.dist-info/METADATA,sha256=SjmFRj8FztRldIYEtsObQlY5XTk6mWL-zmr6sCaSWAY,22116
64
+ versionhq-1.2.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
65
+ versionhq-1.2.1.2.dist-info/top_level.txt,sha256=DClQwxDWqIUGeRJkA8vBlgeNsYZs4_nJWMonzFt5Wj0,10
66
+ versionhq-1.2.1.2.dist-info/RECORD,,
@@ -1,92 +0,0 @@
1
- import os
2
- from typing import Any, List, Optional, Dict
3
- from pydantic import BaseModel, Field
4
-
5
-
6
- class TeamPlanner:
7
- """
8
- A class to handle agent formations based on the given task description.
9
- 1) complexity
10
- 2) agent built (or use given agents)
11
- 3) knowledge, memory sharing
12
- 4) form a team
13
- """
14
-
15
- from versionhq.task.model import Task, ResponseField, TaskOutput
16
- from versionhq.agent.model import Agent
17
-
18
-
19
- def __init__(self, tasks: List[Task], planner_llm: Optional[Any] = None):
20
- self.tasks = tasks
21
- self.planner_llm = planner_llm if planner_llm else os.environ.get("DEFAULT_MODEL_NAME")
22
-
23
-
24
- def _handle_assign_agents(self, unassigned_tasks: List[Task]) -> List[Any]:
25
- """
26
- Build an agent and assign it a task, then return a list of Member connecting the agent created and the task given.
27
- """
28
-
29
- from versionhq.agent.model import Agent
30
- from versionhq.task.model import Task, ResponseField
31
- from versionhq.team.model import Member
32
-
33
- new_member_list: List[Member] = []
34
- agent_creator = Agent(
35
- role="agent_creator",
36
- goal="build an ai agent that can competitively handle the task given",
37
- llm=self.planner_llm,
38
- )
39
-
40
- for unassgined_task in unassigned_tasks:
41
- task = Task(
42
- description=f"""
43
- Based on the following task summary, draft a AI agent's role and goal in concise manner.
44
- Task summary: {unassgined_task.summary}
45
- """,
46
- response_fields=[
47
- ResponseField(title="goal", data_type=str, required=True),
48
- ResponseField(title="role", data_type=str, required=True),
49
- ],
50
- )
51
- res = task.execute(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 = Member(agent=agent, tasks=[unassgined_task], is_manager=False)
58
- new_member_list.append(team_member)
59
-
60
- return new_member_list
61
-
62
-
63
- def _handle_task_planning(self, context: Optional[str] = None, tools: Optional[str] = None) -> TaskOutput:
64
- """
65
- Handles the team planning by creating detailed step-by-step plans for each task.
66
- """
67
-
68
- from versionhq.agent.model import Agent
69
- from versionhq.task.model import Task
70
-
71
- team_planner = Agent(
72
- role="team planner",
73
- 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.",
74
- llm=self.planner_llm,
75
- )
76
-
77
- task_summary_list = [task.summary for task in self.tasks]
78
-
79
- class TeamPlanIdea(BaseModel):
80
- plan: str | Dict[str, Any] = Field(default=None, description="a decriptive plan to be executed by the team")
81
-
82
-
83
- task = Task(
84
- description=f"""
85
- 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.
86
-
87
- Task summaries: {" ".join(task_summary_list)}
88
- """,
89
- pydantic_output=TeamPlanIdea
90
- )
91
- output = task.execute(agent=team_planner, context=context, tools=tools)
92
- return output
File without changes
File without changes