versionhq 1.2.0.4__py3-none-any.whl → 1.2.1.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
@@ -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.network.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.0.4"
33
+ __version__ = "1.2.1.1"
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",
@@ -38,7 +38,7 @@ class Printer:
38
38
  class Logger(BaseModel):
39
39
  """
40
40
  Control CLI messages.
41
- Color: red = error, yellow = warning, blue = info (from vhq), green = info (from third party)
41
+ Color: red = error, yellow = warning, blue = info (from vhq), green = info (from third parties)
42
42
  """
43
43
 
44
44
  verbose: bool = Field(default=True)
@@ -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
 
@@ -27,73 +25,62 @@ def match_type(self, obj):
27
25
 
28
26
  GenerateSchema.match_type = match_type
29
27
  warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
30
- load_dotenv(override=True)
31
-
32
- # agentops = None
33
- # if os.environ.get("AGENTOPS_API_KEY"):
34
- # try:
35
- # import agentops # type: ignore
36
- # except ImportError:
37
- # pass
38
-
39
28
 
40
29
 
41
30
  class Formation(str, Enum):
42
31
  UNDEFINED = 0
43
32
  SOLO = 1
44
33
  SUPERVISING = 2
45
- NETWORK = 3
34
+ SQUAD = 3
46
35
  RANDOM = 4
47
36
  HYBRID = 10
48
37
 
49
38
 
50
39
  class TaskHandlingProcess(str, Enum):
51
40
  """
52
- Class representing the different processes that can be used to tackle multiple tasks.
41
+ A class representing task handling processes to tackle multiple tasks.
42
+ When the agent network has multiple tasks that connect with edges, follow the edge conditions.
53
43
  """
54
- sequential = "sequential"
55
- hierarchical = "hierarchical"
56
- consensual = "consensual"
44
+ SEQUENT = 1
45
+ HIERARCHY = 2
46
+ CONSENSUAL = 3 # either from managers or peers or (human) - most likely controlled by edge
57
47
 
58
48
 
59
- class TeamOutput(TaskOutput):
49
+ class NetworkOutput(TaskOutput):
60
50
  """
61
- 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.
62
52
  """
63
53
 
64
- 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")
65
55
  task_description: str = Field(default=None, description="store initial request (task description) from the client")
66
- task_outputs: list[TaskOutput] = Field(default=list, description="store outputs of all tasks that the team has executed")
67
- token_usage: UsageMetrics = Field(default=dict, description="processed token summary")
68
-
56
+ task_outputs: list[TaskOutput] = Field(default=list, description="store TaskOutput objects of all tasks that the network has executed")
57
+ # token_usage: UsageMetrics = Field(default=dict, description="processed token summary")
69
58
 
70
59
  def return_all_task_outputs(self) -> List[Dict[str, Any]]:
71
60
  res = [output.json_dict for output in self.task_outputs]
72
61
  return res
73
62
 
74
-
75
63
  def __str__(self):
76
64
  return (str(self.pydantic) if self.pydantic else str(self.json_dict) if self.json_dict else self.raw)
77
65
 
78
-
79
66
  def __getitem__(self, key):
80
67
  if self.pydantic and hasattr(self.pydantic, key):
81
68
  return getattr(self.pydantic, key)
82
69
  elif self.json_dict and key in self.json_dict:
83
70
  return self.json_dict[key]
84
71
  else:
85
- raise KeyError(f"Key '{key}' not found in the team output.")
72
+ raise KeyError(f"Key '{key}' not found in the output.")
86
73
 
87
74
 
88
75
 
89
76
  class Member(BaseModel):
90
77
  """
91
- A class to store a member in the network and connect the agent as a member with tasks and sharable settings.
78
+ A class to store a member (agent) in the network, with its tasks and memory/knowledge share settings.
92
79
  """
93
80
  agent: Agent | None = Field(default=None)
94
81
  is_manager: bool = Field(default=False)
95
- can_share_knowledge: bool = Field(default=True, description="whether to share the agent's knowledge in the team")
96
- 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")
97
84
  tasks: Optional[List[Task]] = Field(default_factory=list, description="tasks explicitly assigned to the agent")
98
85
 
99
86
  @property
@@ -101,9 +88,10 @@ class Member(BaseModel):
101
88
  return bool(self.tasks)
102
89
 
103
90
 
104
- class Team(BaseModel):
91
+ class AgentNetwork(BaseModel):
105
92
  """
106
- A class to store agent network that shares knowledge, memory and tools among the members.
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.
107
95
  """
108
96
 
109
97
  __hash__ = object.__hash__
@@ -118,21 +106,20 @@ class Team(BaseModel):
118
106
  should_reform: bool = Field(default=False, description="True if task exe. failed or eval scores below threshold")
119
107
 
120
108
  # formation planning
121
- planner_llm: Optional[Any] = Field(default=None, description="llm to generate and evaluate formation")
122
- 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")
123
110
 
124
111
  # task execution rules
125
112
  prompt_file: str = Field(default="", description="absolute path to the prompt json file")
126
- process: TaskHandlingProcess = Field(default=TaskHandlingProcess.sequential)
113
+ process: TaskHandlingProcess = Field(default=TaskHandlingProcess.SEQUENT)
127
114
 
128
115
  # callbacks
129
116
  pre_launch_callbacks: List[Callable[[Optional[Dict[str, Any]]], Optional[Dict[str, Any]]]] = Field(
130
117
  default_factory=list,
131
- 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"
132
119
  )
133
- post_launch_callbacks: List[Callable[[TeamOutput], TeamOutput]] = Field(
120
+ post_launch_callbacks: List[Callable[[NetworkOutput], NetworkOutput]] = Field(
134
121
  default_factory=list,
135
- 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"
136
123
  )
137
124
  step_callback: Optional[Any] = Field(default=None, description="callback to be executed after each step for all agents execution")
138
125
 
@@ -156,39 +143,37 @@ class Team(BaseModel):
156
143
  @model_validator(mode="after")
157
144
  def assess_tasks(self):
158
145
  """
159
- 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.
160
147
  """
161
148
 
162
149
  if self.tasks:
163
- if all(task in self.tasks for task in self.team_tasks) == False:
164
- 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.", {})
165
152
 
166
153
 
167
154
  num_member_tasks = 0
168
155
  for member in self.members:
169
156
  num_member_tasks += len(member.tasks)
170
157
 
171
- # if len(self.tasks) != len(self.team_tasks) + num_member_tasks:
158
+ # if len(self.tasks) != len(self.network_tasks) + num_member_tasks:
172
159
  # raise PydanticCustomError("task_validation_error", "Some tasks are missing.", {})
173
160
  return self
174
161
 
175
162
 
176
163
  @model_validator(mode="after")
177
- def check_manager_llm(self):
164
+ def check_manager(self):
178
165
  """
179
- Check if the team has a manager
166
+ Check if the agent network has a manager
180
167
  """
181
-
182
- if self.process == TaskHandlingProcess.hierarchical or self.formation == Formation.SUPERVISING:
168
+ if self.process == TaskHandlingProcess.HIERARCHY or self.formation == Formation.SUPERVISING:
183
169
  if not self.managers:
184
170
  self._logger.log(level="error", message="The process or formation created needs at least 1 manager agent.", color="red")
185
- raise PydanticCustomError(
186
- "missing_manager_llm_or_manager","Attribute `manager_llm` or `manager` is required when using hierarchical process.", {})
171
+ raise PydanticCustomError("missing_manager", "`manager` is required when using hierarchical process.", {})
187
172
 
188
- ## comment out for the formation flexibilities
189
- # if self.managers and (self.manager_tasks is None or self.team_tasks is None):
190
- # self._logger.log(level="error", message="The manager is idling. At least 1 task needs to be assigned to the manager.", color="red")
191
- # raise PydanticCustomError("missing_manager_task", "manager needs to have at least one manager task or team task.", {})
173
+ ## comment out for the formation flexibilities
174
+ # if self.managers and (self.manager_tasks is None or self.network_tasks is None):
175
+ # self._logger.log(level="error", message="The manager is idling. At least 1 task needs to be assigned to the manager.", color="red")
176
+ # raise PydanticCustomError("missing_manager_task", "manager needs to have at least one manager task or network task.", {})
192
177
 
193
178
  return self
194
179
 
@@ -196,9 +181,9 @@ class Team(BaseModel):
196
181
  @model_validator(mode="after")
197
182
  def validate_task_member_paring(self):
198
183
  """
199
- 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.
200
185
  """
201
- if self.process == TaskHandlingProcess.sequential and self.team_tasks is None:
186
+ if self.process == TaskHandlingProcess.SEQUENT and self.network_tasks is None:
202
187
  for task in self.tasks:
203
188
  if not [member.task == task for member in self.members]:
204
189
  self._logger.log(level="error", message=f"The following task needs a dedicated agent to be assinged: {task.description}", color="red")
@@ -208,7 +193,7 @@ class Team(BaseModel):
208
193
  @model_validator(mode="after")
209
194
  def validate_end_with_at_most_one_async_task(self):
210
195
  """
211
- 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
212
197
  """
213
198
 
214
199
  async_task_count = 0
@@ -221,10 +206,43 @@ class Team(BaseModel):
221
206
  break
222
207
 
223
208
  if async_task_count > 1:
224
- 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.", {})
225
210
  return self
226
211
 
227
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
+
228
246
  def _get_responsible_agent(self, task: Task) -> Agent | None:
229
247
  if task is None:
230
248
  return None
@@ -238,17 +256,16 @@ class Team(BaseModel):
238
256
 
239
257
  def _assign_tasks(self) -> None:
240
258
  """
241
- Form a team considering agents and tasks given, and update `self.members` field:
242
- 1. Idling managers to take the team tasks.
243
- 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.
244
262
  3. Create agents to handle the rest tasks.
245
263
  """
246
264
 
247
- team_planner = TeamPlanner(tasks=self.tasks, planner_llm=self.planner_llm)
248
265
  idling_managers: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == True]
249
266
  idling_members: List[Member] = [member for member in self.members if member.is_idling and member.is_manager == False]
250
- unassigned_tasks: List[Task] = self.team_tasks + self.member_tasks_without_agent if self.team_tasks else self.member_tasks_without_agent
251
- 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] = []
252
269
 
253
270
  if idling_managers:
254
271
  idling_managers[0].tasks.extend(unassigned_tasks)
@@ -257,9 +274,9 @@ class Team(BaseModel):
257
274
  idling_members[0].tasks.extend(unassigned_tasks)
258
275
 
259
276
  else:
260
- new_team_members = team_planner._handle_assign_agents(unassigned_tasks=unassigned_tasks)
261
- if new_team_members:
262
- 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
263
280
 
264
281
 
265
282
  # task execution
@@ -278,34 +295,9 @@ class Team(BaseModel):
278
295
  return task_outputs
279
296
 
280
297
 
281
- def _create_team_output(self, task_outputs: List[TaskOutput], lead_task_output: TaskOutput = None) -> TeamOutput:
282
- """
283
- Take the output of the first task or the lead task output as the team output `raw` value.
284
- Note that `tasks` are already sorted by the importance.
285
- """
286
-
287
- if not task_outputs:
288
- self._logger.log(level="error", message="Missing task outcomes. Failed to launch the task.", color="red")
289
- raise ValueError("Failed to launch tasks")
290
-
291
- final_task_output = lead_task_output if lead_task_output is not None else task_outputs[0] #! REFINEME
292
- # final_string_output = final_task_output.raw
293
- # self._finish_execution(final_string_output)
294
- token_usage = self._calculate_usage_metrics()
295
-
296
- return TeamOutput(
297
- team_id=self.id,
298
- raw=final_task_output.raw,
299
- json_dict=final_task_output.json_dict,
300
- pydantic=final_task_output.pydantic,
301
- task_outputs=task_outputs,
302
- token_usage=token_usage,
303
- )
304
-
305
-
306
298
  def _calculate_usage_metrics(self) -> UsageMetrics:
307
299
  """
308
- Calculate and return the usage metrics that consumed by the team.
300
+ Calculate and return the usage metrics that consumed by the agent network.
309
301
  """
310
302
  total_usage_metrics = UsageMetrics()
311
303
 
@@ -325,12 +317,12 @@ class Team(BaseModel):
325
317
  return total_usage_metrics
326
318
 
327
319
 
328
- 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:
329
321
  """
330
- Executes tasks sequentially and returns the final output in TeamOutput class.
322
+ Executes tasks sequentially and returns the final output in NetworkOutput class.
331
323
  When we have a manager agent, we will start from executing manager agent's tasks.
332
324
  Priority:
333
- 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)
334
326
  """
335
327
 
336
328
  task_outputs: List[TaskOutput] = []
@@ -367,52 +359,58 @@ class Team(BaseModel):
367
359
  else:
368
360
  context = create_raw_outputs(tasks=[task,], task_outputs=([last_sync_output,] if last_sync_output else [] ))
369
361
  task_output = task.execute(agent=responsible_agent, context=context)
362
+
370
363
  if self.managers and responsible_agent in [manager.agent for manager in self.managers]:
371
364
  lead_task_output = task_output
372
365
 
373
366
  task_outputs.append(task_output)
374
- # self._process_task_result(task, task_output)
375
367
  task._store_execution_log(task_index, was_replayed, self._inputs)
376
368
 
377
369
 
378
370
  if futures:
379
371
  task_outputs = self._process_async_tasks(futures, was_replayed)
380
372
 
381
- return self._create_team_output(task_outputs, lead_task_output)
373
+ if not task_outputs:
374
+ self._logger.log(level="error", message="Missing task outputs.", color="red")
375
+ raise ValueError("Missing task outputs")
376
+
377
+ final_task_output = lead_task_output if lead_task_output is not None else task_outputs[0] #! REFINEME
382
378
 
379
+ # token_usage = self._calculate_usage_metrics() #! combining with Eval
383
380
 
384
- def launch(self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None) -> TeamOutput:
381
+ return NetworkOutput(
382
+ network_id=self.id,
383
+ raw=final_task_output.raw,
384
+ json_dict=final_task_output.json_dict,
385
+ pydantic=final_task_output.pydantic,
386
+ task_outputs=task_outputs,
387
+ # token_usage=token_usage,
388
+ )
389
+
390
+
391
+ def launch(self, kwargs_pre: Optional[Dict[str, str]] = None, kwargs_post: Optional[Dict[str, Any]] = None) -> NetworkOutput:
385
392
  """
386
- Confirm and launch the formation - execute tasks and record outputs.
387
- 0. Assign an agent to a task - using conditions (manager prioritizes team_tasks) and planner_llm.
388
- 1. Address `pre_launch_callbacks` if any.
389
- 2. Handle team members' tasks in accordance with the process.
390
- 3. Address `post_launch_callbacks` if any.
393
+ Launch the agent network - executing tasks and recording their outputs.
391
394
  """
392
395
 
393
396
  metrics: List[UsageMetrics] = []
394
397
 
395
- if self.team_tasks or self.member_tasks_without_agent:
398
+ if self.network_tasks or self.member_tasks_without_agent:
396
399
  self._assign_tasks()
397
400
 
398
401
  if kwargs_pre is not None:
399
402
  for func in self.pre_launch_callbacks:
400
403
  func(**kwargs_pre)
401
404
 
402
- # self._execution_span = self._telemetry.team_execution_span(self, inputs)
403
- # self._task_output_handler.reset()
404
- # self._logging_color = "bold_purple"
405
- # i18n = I18N(prompt_file=self.prompt_file)
406
-
407
405
  for member in self.members:
408
406
  agent = member.agent
409
- agent.team = self
407
+ agent.network = self
410
408
 
411
409
  if self.step_callback:
412
410
  agent.callbacks.append(self.step_callback)
413
411
 
414
412
  if self.process is None:
415
- self.process = TaskHandlingProcess.sequential
413
+ self.process = TaskHandlingProcess.SEQUENT
416
414
 
417
415
  result = self._execute_tasks(self.tasks)
418
416
 
@@ -443,7 +441,7 @@ class Team(BaseModel):
443
441
  @property
444
442
  def manager_tasks(self) -> List[Task]:
445
443
  """
446
- Tasks (incl. team tasks) handled by managers in the team.
444
+ Tasks (incl. network tasks) handled by managers in the agent network.
447
445
  """
448
446
  res = list()
449
447
 
@@ -458,22 +456,22 @@ class Team(BaseModel):
458
456
  @property
459
457
  def tasks(self) -> List[Task]:
460
458
  """
461
- Return all the tasks that the team needs to handle in order of priority:
462
- 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
463
461
  2. manager_task,
464
462
  3. members' tasks
465
463
  """
466
464
 
467
- team_tasks = self.team_tasks
465
+ network_tasks = self.network_tasks
468
466
  manager_tasks = self.manager_tasks
469
467
  member_tasks = []
470
468
 
471
469
  for member in self.members:
472
470
  if member.is_manager == False and member.tasks:
473
- 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]
474
472
  member_tasks += a
475
473
 
476
- return team_tasks + manager_tasks + member_tasks
474
+ return network_tasks + manager_tasks + member_tasks
477
475
 
478
476
 
479
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: