versionhq 1.1.11.8__py3-none-any.whl → 1.1.12.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/task/model.py CHANGED
@@ -5,18 +5,17 @@ import uuid
5
5
  import inspect
6
6
  from concurrent.futures import Future
7
7
  from hashlib import md5
8
- from typing import Any, Dict, List, Set, Optional, Tuple, Callable, Type, TypeVar
8
+ from typing import Any, Dict, List, Set, Optional, Callable, Type
9
9
  from typing_extensions import Annotated, Self
10
10
 
11
- from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator, create_model, InstanceOf, field_validator
11
+ from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator, InstanceOf, field_validator
12
12
  from pydantic_core import PydanticCustomError
13
13
 
14
- from versionhq._utils.process_config import process_config
15
- from versionhq.task import TaskOutputFormat
14
+
16
15
  from versionhq.task.log_handler import TaskOutputStorageHandler
17
16
  from versionhq.task.evaluate import Evaluation, EvaluationItem
18
17
  from versionhq.tool.model import Tool, ToolSet
19
- from versionhq._utils.logger import Logger
18
+ from versionhq._utils import process_config, Logger
20
19
 
21
20
 
22
21
  class ResponseField(BaseModel):
@@ -77,9 +76,7 @@ class ResponseField(BaseModel):
77
76
  if self.properties:
78
77
  for item in self.properties:
79
78
  nested_p.update(**item._format_props())
80
-
81
- if item.required:
82
- nested_r.append(item.title)
79
+ nested_r.append(item.title)
83
80
 
84
81
  props = {
85
82
  "type": schema_type,
@@ -97,8 +94,6 @@ class ResponseField(BaseModel):
97
94
  if self.properties:
98
95
  for item in self.properties:
99
96
  p.update(**item._format_props())
100
-
101
- # if item.required:
102
97
  r.append(item.title)
103
98
 
104
99
  props = {
@@ -204,12 +199,25 @@ class TaskOutput(BaseModel):
204
199
  eval_criteria = task.eval_criteria if task.eval_criteria else ["Overall competitiveness", ]
205
200
 
206
201
  for item in eval_criteria:
207
- task_1 = Task(
202
+ task_eval = Task(
208
203
  description=EVALUATE.format(task_description=task.description, task_output=self.raw, eval_criteria=str(item)),
209
204
  pydantic_output=EvaluationItem
210
205
  )
211
- res_a = task_1.execute_sync(agent=self.evaluation.responsible_agent)
212
- self.evaluation.items.append(EvaluationItem(**res_a.json_dict))
206
+ res = task_eval.execute_sync(agent=self.evaluation.responsible_agent)
207
+
208
+ if res.pydantic:
209
+ item = EvaluationItem(score=res.pydantic.score, suggestion=res.pydantic.suggestion, criteria=res.pydantic.criteria)
210
+ self.evaluation.items.append(item)
211
+
212
+ else:
213
+ try:
214
+ item = EvaluationItem(
215
+ score=float(res.json_dict["score"]), suggestion=res.json_dict["suggestion"], criteria=res.json_dict["criteria"]
216
+ )
217
+ self.evaluation.items.append(item)
218
+ except Exception as e:
219
+ Logger(verbose=True).log(level="error", message=f"Failed to convert the evaluation items: {str(e)}", color="red")
220
+ pass
213
221
 
214
222
  return self.evaluation
215
223
 
@@ -224,14 +232,6 @@ class TaskOutput(BaseModel):
224
232
 
225
233
  @property
226
234
  def json(self) -> Optional[str]:
227
- if self.output_format != TaskOutputFormat.JSON:
228
- raise ValueError(
229
- """
230
- Invalid output format requested.
231
- If you would like to access the JSON output,
232
- pleae make sure to set the output_json property for the task
233
- """
234
- )
235
235
  return json.dumps(self.json_dict)
236
236
 
237
237
 
@@ -239,7 +239,6 @@ class TaskOutput(BaseModel):
239
239
  return str(self.pydantic) if self.pydantic else str(self.json_dict) if self.json_dict else self.raw
240
240
 
241
241
 
242
-
243
242
  class Task(BaseModel):
244
243
  """
245
244
  Task to be executed by agents or teams.
@@ -286,7 +285,7 @@ class Task(BaseModel):
286
285
  processed_by_agents: Set[str] = Field(default_factory=set, description="store responsible agents' roles")
287
286
  tools_errors: int = 0
288
287
  delegations: int = 0
289
- latency: int | float = 0 # execution latency in sec
288
+ latency: int | float = 0 # job latency in sec
290
289
  tokens: int = 0 # tokens consumed
291
290
 
292
291
 
@@ -394,14 +393,6 @@ Ref. Output image: {output_formats_to_follow}
394
393
  return "\n".join(task_slices)
395
394
 
396
395
 
397
- def _get_output_format(self) -> TaskOutputFormat:
398
- if self.output_json == True:
399
- return TaskOutputFormat.JSON
400
- if self.output_pydantic == True:
401
- return TaskOutputFormat.PYDANTIC
402
- return TaskOutputFormat.RAW
403
-
404
-
405
396
  def _structure_response_format(self, data_type: str = "object", model_provider: str = "gemini") -> Dict[str, Any] | None:
406
397
  """
407
398
  Structure a response format either from`response_fields` or `pydantic_output`.
@@ -412,37 +403,38 @@ Ref. Output image: {output_formats_to_follow}
412
403
 
413
404
  response_format: Dict[str, Any] = None
414
405
 
415
- # match model_provider:
416
- # case "openai":
417
- if self.response_fields:
418
- properties, required_fields = {}, []
419
- for i, item in enumerate(self.response_fields):
420
- if item:
421
- if item.data_type is dict:
422
- properties.update(item._format_props())
423
- else:
424
- properties.update(item._format_props())
425
-
426
- required_fields.append(item.title)
427
-
428
- response_schema = {
429
- "type": "object",
430
- "properties": properties,
431
- "required": required_fields,
432
- "additionalProperties": False,
433
- }
406
+ if model_provider == "openrouter":
407
+ return response_format
434
408
 
435
- response_format = {
436
- "type": "json_schema",
437
- "json_schema": { "name": "outcome", "schema": response_schema }
438
- }
409
+ else:
410
+ if self.response_fields:
411
+ properties, required_fields = {}, []
412
+ for i, item in enumerate(self.response_fields):
413
+ if item:
414
+ if item.data_type is dict:
415
+ properties.update(item._format_props())
416
+ else:
417
+ properties.update(item._format_props())
418
+
419
+ required_fields.append(item.title)
420
+
421
+ response_schema = {
422
+ "type": "object",
423
+ "properties": properties,
424
+ "required": required_fields,
425
+ "additionalProperties": False,
426
+ }
427
+
428
+ response_format = {
429
+ "type": "json_schema",
430
+ "json_schema": { "name": "outcome", "schema": response_schema }
431
+ }
439
432
 
440
433
 
441
- elif self.pydantic_output:
442
- response_format = StructuredOutput(response_format=self.pydantic_output)._format()
434
+ elif self.pydantic_output:
435
+ response_format = StructuredOutput(response_format=self.pydantic_output)._format()
443
436
 
444
- # case "gemini":
445
- return response_format
437
+ return response_format
446
438
 
447
439
 
448
440
  def _create_json_output(self, raw: str) -> Dict[str, Any]:
@@ -507,75 +499,59 @@ Ref. Output image: {output_formats_to_follow}
507
499
  self.description = self._original_description.format(**inputs)
508
500
 
509
501
 
510
- def _create_short_term_memory(self, agent, task_output: TaskOutput) -> None:
502
+ def _create_short_and_long_term_memories(self, agent: Any, task_output: TaskOutput) -> None:
511
503
  """
512
- After the task execution, create and save short-term memory of the responsible agent.
504
+ After the task execution, create and save short-term/long-term memories in the storage.
513
505
  """
514
-
515
506
  from versionhq.agent.model import Agent
516
- from versionhq.memory.model import ShortTermMemory
507
+ from versionhq.memory.model import ShortTermMemory, MemoryMetadata, LongTermMemory
517
508
 
518
- try:
519
- if isinstance(agent, Agent) and agent.use_memory == True:
520
- if hasattr(agent, "short_term_memory"):
521
- agent.short_term_memory.save(value=task_output.raw, metadata={ "observation": self.description, }, agent=agent.role)
522
- else:
523
- agent.short_term_memory = ShortTermMemory(agent=agent, embedder_config=agent.embedder_config)
524
- agent.short_term_memory.save(value=task_output.raw, metadata={ "observation": self.description, }, agent=agent.role)
509
+ agent = agent if isinstance(agent, Agent) else Agent(role=str(agent), goal=str(agent), use_memory=True)
525
510
 
526
- except Exception as e:
527
- self._logger.log(level="error", message=f"Failed to add to short term memory: {str(e)}", color="red")
528
- pass
529
-
530
-
531
- def _create_long_term_memory(self, agent, task_output: TaskOutput) -> None:
532
- """
533
- Create and save long-term and entity memory items based on evaluation.
534
- """
535
- from versionhq.agent.model import Agent
536
- from versionhq.memory.model import LongTermMemory, LongTermMemoryItem
511
+ if agent.use_memory == False:
512
+ return None
537
513
 
538
514
  try:
539
- if isinstance(agent, Agent) and agent.use_memory == True:
540
- evaluation = task_output.evaluation if task_output.evaluation else task_output.evaluate(task=self)
541
-
542
- long_term_memory_item = LongTermMemoryItem(
543
- agent=str(agent.role),
544
- task=str(self.description),
545
- datetime=str(datetime.datetime.now()),
546
- quality=evaluation.aggregate_score,
547
- metadata={
548
- "suggestions": evaluation.suggestion_summary,
549
- "quality": evaluation.aggregate_score,
550
- },
551
- )
515
+ evaluation = task_output.evaluation if task_output.evaluation else None
516
+ memory_metadata = evaluation._create_memory_metadata() if evaluation else MemoryMetadata()
517
+
518
+ agent.short_term_memory = agent.short_term_memory if agent.short_term_memory else ShortTermMemory(agent=agent, embedder_config=agent.embedder_config)
519
+ agent.short_term_memory.save(
520
+ task_description=str(self.description),
521
+ task_output=str(task_output.raw),
522
+ agent=str(agent.role),
523
+ metadata=memory_metadata
524
+ )
552
525
 
553
- if hasattr(agent, "long_term_memory"):
554
- agent.long_term_memory.save(item=long_term_memory_item)
555
- else:
556
- agent.long_term_memory = LongTermMemory(agent=agent)
557
- agent.long_term_memory.save(item=long_term_memory_item)
526
+ agent.long_term_memory = agent.long_term_memory if agent.long_term_memory else LongTermMemory()
527
+ agent.long_term_memory.save(
528
+ task_description=str(self.description),
529
+ task_output=str(task_output.raw),
530
+ agent=str(agent.role),
531
+ metadata=memory_metadata
532
+ )
558
533
 
559
534
  except AttributeError as e:
560
535
  self._logger.log(level="error", message=f"Missing attributes for long term memory: {str(e)}", color="red")
561
536
  pass
562
537
 
563
538
  except Exception as e:
564
- self._logger.log(level="error", message=f"Failed to add to long term memory: {str(e)}", color="red")
539
+ self._logger.log(level="error", message=f"Failed to add to the memory: {str(e)}", color="red")
565
540
  pass
566
541
 
567
542
 
568
543
  # task execution
569
- def execute_sync(self, agent, context: Optional[str] = None) -> TaskOutput:
544
+ def execute_sync(self, agent, context: Optional[str | List[Any]] = None) -> TaskOutput:
570
545
  """
571
546
  Execute the task synchronously.
572
547
  When the task has context, make sure we have executed all the tasks in the context first.
573
548
  """
574
549
 
575
550
  if self.context:
576
- for task in self.context:
577
- if task.output is None:
578
- task._execute_core(agent, context)
551
+ if isinstance(self.context, list):
552
+ for task in self.context:
553
+ if isinstance(task, Task) and task.output is None:
554
+ task._execute_core(agent, context)
579
555
 
580
556
  return self._execute_core(agent, context)
581
557
 
@@ -612,7 +588,7 @@ Ref. Output image: {output_formats_to_follow}
612
588
  task_output: InstanceOf[TaskOutput] = None
613
589
  tool_output: str | list = None
614
590
  task_tools: List[List[InstanceOf[Tool]| InstanceOf[ToolSet] | Type[Tool]]] = []
615
- started_at = datetime.datetime.now()
591
+ started_at, ended_at = datetime.datetime.now(), datetime.datetime.now()
616
592
 
617
593
  if self.tools:
618
594
  for item in self.tools:
@@ -638,11 +614,16 @@ Ref. Output image: {output_formats_to_follow}
638
614
 
639
615
 
640
616
  if self.tool_res_as_final == True:
617
+ started_at = datetime.datetime.now()
641
618
  tool_output = agent.execute_task(task=self, context=context, task_tools=task_tools)
619
+ ended_at = datetime.datetime.now()
642
620
  task_output = TaskOutput(task_id=self.id, tool_output=tool_output, raw=str(tool_output) if tool_output else "")
643
621
 
644
622
  else:
623
+ started_at = datetime.datetime.now()
645
624
  raw_output = agent.execute_task(task=self, context=context, task_tools=task_tools)
625
+ ended_at = datetime.datetime.now()
626
+
646
627
  json_dict_output = self._create_json_output(raw=raw_output)
647
628
  if "outcome" in json_dict_output:
648
629
  json_dict_output = self._create_json_output(raw=str(json_dict_output["outcome"]))
@@ -656,18 +637,15 @@ Ref. Output image: {output_formats_to_follow}
656
637
  json_dict=json_dict_output
657
638
  )
658
639
 
659
- ended_at = datetime.datetime.now()
660
- self.latency = (ended_at - started_at).total_seconds()
661
640
 
641
+ self.latency = (ended_at - started_at).total_seconds()
662
642
  self.output = task_output
663
643
  self.processed_by_agents.add(agent.role)
664
644
 
665
645
  if self.should_evaluate:
666
646
  task_output.evaluate(task=self, latency=self.latency, tokens=self.tokens)
667
647
 
668
- self._create_short_term_memory(agent=agent, task_output=task_output)
669
- self._create_long_term_memory(agent=agent, task_output=task_output)
670
-
648
+ self._create_short_and_long_term_memories(agent=agent, task_output=task_output)
671
649
 
672
650
  if self.callback and isinstance(self.callback, Callable):
673
651
  kwargs = { **self.callback_kwargs, **task_output.json_dict }
@@ -697,7 +675,7 @@ Ref. Output image: {output_formats_to_follow}
697
675
 
698
676
  @property
699
677
  def key(self) -> str:
700
- output_format = TaskOutputFormat.JSON if self.response_fields else TaskOutputFormat.PYDANTIC if self.pydantic_output is not None else TaskOutputFormat.RAW
678
+ output_format = "json" if self.response_fields else "pydantic" if self.pydantic_output is not None else "raw"
701
679
  source = [self.description, output_format]
702
680
  return md5("|".join(source).encode(), usedforsecurity=False).hexdigest()
703
681
 
@@ -1,4 +1,4 @@
1
- from typing import Dict, Optional, Type, List, Any, TypeVar
1
+ from typing import Dict, Type, List, Any
2
2
 
3
3
  from pydantic import BaseModel, Field, InstanceOf
4
4
 
versionhq/team/model.py CHANGED
@@ -1,17 +1,16 @@
1
1
  import uuid
2
2
  import warnings
3
- import json
4
3
  from enum import Enum
5
4
  from dotenv import load_dotenv
6
5
  from concurrent.futures import Future
7
6
  from hashlib import md5
8
- from typing import Any, Dict, List, TYPE_CHECKING, Callable, Optional, Tuple
9
- from pydantic import UUID4, InstanceOf, Json, BaseModel, Field, PrivateAttr, field_validator, model_validator
7
+ from typing import Any, Dict, List, Callable, Optional, Tuple
8
+ from pydantic import UUID4, BaseModel, Field, PrivateAttr, field_validator, model_validator
10
9
  from pydantic._internal._generate_schema import GenerateSchema
11
10
  from pydantic_core import PydanticCustomError, core_schema
12
11
 
13
12
  from versionhq.agent.model import Agent
14
- from versionhq.task.model import Task, TaskOutput, ConditionalTask, TaskOutputFormat
13
+ from versionhq.task.model import Task, TaskOutput, ConditionalTask
15
14
  from versionhq.task.formatter import create_raw_outputs
16
15
  from versionhq.team.team_planner import TeamPlanner
17
16
  from versionhq._utils.logger import Logger
@@ -20,7 +19,6 @@ from versionhq._utils.usage_metrics import UsageMetrics
20
19
 
21
20
  initial_match_type = GenerateSchema.match_type
22
21
 
23
-
24
22
  def match_type(self, obj):
25
23
  if getattr(obj, "__name__", None) == "datetime":
26
24
  return core_schema.datetime_schema()
@@ -28,7 +26,6 @@ def match_type(self, obj):
28
26
 
29
27
 
30
28
  GenerateSchema.match_type = match_type
31
-
32
29
  warnings.filterwarnings("ignore", category=SyntaxWarning, module="pysbd")
33
30
  load_dotenv(override=True)
34
31
 
@@ -40,6 +37,16 @@ load_dotenv(override=True)
40
37
  # pass
41
38
 
42
39
 
40
+
41
+ class Formation(str, Enum):
42
+ SOLO = 1
43
+ SUPERVISING = 2
44
+ NETWORK = 3
45
+ RANDOM = 4
46
+ HYBRID = 10
47
+ UNDEFINED = 0
48
+
49
+
43
50
  class TaskHandlingProcess(str, Enum):
44
51
  """
45
52
  Class representing the different processes that can be used to tackle multiple tasks.
@@ -49,25 +56,25 @@ class TaskHandlingProcess(str, Enum):
49
56
  consensual = "consensual"
50
57
 
51
58
 
52
- class TeamOutput(BaseModel):
59
+ class TeamOutput(TaskOutput):
53
60
  """
54
- Store outputs of the tasks handled by the team.
55
- `json_dict` and `raw` store overall output of tasks that handled by the team,
56
- while `task_output_list` stores each TaskOutput instance to the tasks handled by the team members.
57
- Note that `raw` and `json_dict` will be prioritized as TeamOutput to refer over `task_output_list`.
61
+ A class to store output from the team, inherited from TaskOutput class.
58
62
  """
59
63
 
60
64
  team_id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True, description="store the team ID that generate the TeamOutput")
61
- raw: str = Field(default="", description="raw output of the team lead task handled by the team leader")
62
- pydantic: Optional[Any] = Field(default=None, description="`raw` converted to the abs. pydantic model")
63
- json_dict: Dict[str, Any] = Field(default=None, description="`raw` converted to dictionary")
64
- task_output_list: list[TaskOutput] = Field(default=list, description="store output of all the tasks that the team has executed")
65
+ 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")
65
67
  token_usage: UsageMetrics = Field(default=dict, description="processed token summary")
66
68
 
69
+
70
+ def return_all_task_outputs(self) -> List[Dict[str, Any]]:
71
+ res = [output.json_dict for output in self.task_outputs]
72
+ return res
73
+
74
+
67
75
  def __str__(self):
68
76
  return (str(self.pydantic) if self.pydantic else str(self.json_dict) if self.json_dict else self.raw)
69
77
 
70
-
71
78
  def __getitem__(self, key):
72
79
  if self.pydantic and hasattr(self.pydantic, key):
73
80
  return getattr(self.pydantic, key)
@@ -77,40 +84,16 @@ class TeamOutput(BaseModel):
77
84
  raise KeyError(f"Key '{key}' not found in the team output.")
78
85
 
79
86
 
80
- @property
81
- def json(self) -> Optional[str]:
82
- if self.tasks_output[-1].output_format != TaskOutputFormat.JSON:
83
- raise ValueError(
84
- "No JSON output found in the final task. Please make sure to set the output_json property in the final task in your team."
85
- )
86
- return json.dumps(self.json_dict)
87
-
88
-
89
- def to_dict(self) -> Dict[str, Any]:
90
- """
91
- Convert pydantic / raw output into dict and return the dict.
92
- When we only have `raw` output, return `{ output: raw }` to avoid an error
93
- """
94
-
95
- output_dict = {}
96
- if self.json_dict:
97
- output_dict.update(self.json_dict)
98
- elif self.pydantic:
99
- output_dict.update(self.pydantic.model_dump())
100
- else:
101
- output_dict.upate({ "output": self.raw })
102
- return output_dict
103
-
104
-
105
- def return_all_task_outputs(self) -> List[Dict[str, Any]]:
106
- res = [output.json_dict for output in self.task_output_list]
107
- return res
108
-
109
87
 
110
88
  class TeamMember(BaseModel):
111
- agent: Agent | None = Field(default=None, description="store the agent to be a member")
89
+ """
90
+ A class to store a team member
91
+ """
92
+ agent: Agent | None = Field(default=None)
112
93
  is_manager: bool = Field(default=False)
113
- task: Optional[Task] = Field(default=None)
94
+ can_share_knowledge: bool = Field(default=True, description="whether to share the agent's knowledge in the team")
95
+ can_share_memory: bool = Field(default=True, description="whether to share the agent's memory in the team")
96
+ task: Optional[Task] = Field(default=None, description="task assigned to the agent")
114
97
 
115
98
  @property
116
99
  def is_idling(self):
@@ -125,17 +108,19 @@ class Team(BaseModel):
125
108
 
126
109
  __hash__ = object.__hash__
127
110
  _execution_span: Any = PrivateAttr()
128
- _logger: Logger = PrivateAttr()
111
+ _logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=True))
129
112
  _inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
130
113
 
131
114
  id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
132
115
  name: Optional[str] = Field(default=None)
133
- members: List[TeamMember] = Field(default_factory=list, description="store agents' uuids and bool if it is manager")
116
+ members: List[TeamMember] = Field(default_factory=list)
117
+ formation: Optional[Formation] = Field(default=None)
118
+
119
+ # formation planning
120
+ planning_llm: Optional[Any] = Field(default=None, description="llm to generate formation")
121
+ team_tasks: Optional[List[Task]] = Field(default_factory=list, description="optional tasks for the team. can be assigned to team members later")
134
122
 
135
- # work as a team
136
- team_tasks: Optional[List[Task]] = Field(default_factory=list, description="optional tasks for the team")
137
- planning_llm: Optional[Any] = Field(default=None, description="llm to handle the planning of the team tasks (if any)")
138
- function_calling_llm: Optional[Any] = Field(default=None, description="llm to execute func after all agent execution (if any)")
123
+ # task execution rules
139
124
  prompt_file: str = Field(default="", description="path to the prompt json file to be used by the team.")
140
125
  process: TaskHandlingProcess = Field(default=TaskHandlingProcess.sequential)
141
126
 
@@ -150,7 +135,6 @@ class Team(BaseModel):
150
135
  )
151
136
  step_callback: Optional[Any] = Field(default=None, description="callback to be executed after each step for all agents execution")
152
137
 
153
- verbose: bool = Field(default=True)
154
138
  cache: bool = Field(default=True)
155
139
  memory: bool = Field(default=False, description="whether the team should use memory to store memories of its execution")
156
140
  execution_logs: List[Dict[str, Any]] = Field(default=[], description="list of execution logs for tasks")
@@ -236,7 +220,7 @@ class Team(BaseModel):
236
220
  return self
237
221
 
238
222
 
239
- def _get_responsible_agent(self, task: Task) -> Agent:
223
+ def _get_responsible_agent(self, task: Task) -> Agent | None:
240
224
  if task is None:
241
225
  return None
242
226
  else:
@@ -244,7 +228,7 @@ class Team(BaseModel):
244
228
  return None if len(res) == 0 else res[0]
245
229
 
246
230
 
247
- def _handle_team_planning(self) -> None:
231
+ def _handle_agent_formation(self) -> None:
248
232
  """
249
233
  Form a team considering agents and tasks given, and update `self.members` field:
250
234
  1. Idling managers to take the team tasks.
@@ -321,7 +305,7 @@ class Team(BaseModel):
321
305
  raw=final_task_output.raw,
322
306
  json_dict=final_task_output.json_dict,
323
307
  pydantic=final_task_output.pydantic,
324
- task_output_list=task_outputs,
308
+ task_outputs=task_outputs,
325
309
  token_usage=token_usage,
326
310
  )
327
311
 
@@ -373,7 +357,7 @@ class Team(BaseModel):
373
357
 
374
358
  responsible_agent = self._get_responsible_agent(task)
375
359
  if responsible_agent is None:
376
- self._handle_team_planning()
360
+ self._handle_agent_formation()
377
361
 
378
362
  if isinstance(task, ConditionalTask):
379
363
  skipped_task_output = task._handle_conditional_task(task_outputs, futures, task_index, was_replayed)
@@ -415,7 +399,7 @@ class Team(BaseModel):
415
399
  metrics: List[UsageMetrics] = []
416
400
 
417
401
  if self.team_tasks or self.member_tasks_without_agent:
418
- self._handle_team_planning()
402
+ self._handle_agent_formation()
419
403
 
420
404
  if kwargs_before is not None:
421
405
  for before_callback in self.before_kickoff_callbacks:
@@ -432,9 +416,6 @@ class Team(BaseModel):
432
416
  agent = member.agent
433
417
  agent.team = self
434
418
 
435
- if not agent.function_calling_llm and self.function_calling_llm:
436
- agent.function_calling_llm = self.function_calling_llm
437
-
438
419
  if self.step_callback:
439
420
  agent.callbacks.append(self.step_callback)
440
421
 
@@ -8,7 +8,11 @@ load_dotenv(override=True)
8
8
 
9
9
  class TeamPlanner:
10
10
  """
11
- Assign agents to multiple tasks.
11
+ A class to handle agent formations based on the given task description.
12
+ 1) complexity
13
+ 2) agent built (or use given agents)
14
+ 3) knowledge, memory sharing
15
+ 4) form a team
12
16
  """
13
17
 
14
18
  from versionhq.task.model import Task, ResponseField, TaskOutput
@@ -59,7 +63,6 @@ class TeamPlanner:
59
63
  return new_member_list
60
64
 
61
65
 
62
-
63
66
  def _handle_task_planning(self, context: Optional[str] = None, tools: Optional[str] = None) -> TaskOutput:
64
67
  """
65
68
  Handles the team planning by creating detailed step-by-step plans for each task.
versionhq/tool/model.py CHANGED
@@ -2,7 +2,7 @@ from abc import ABC, abstractmethod
2
2
  from inspect import signature
3
3
  from typing import Any, Dict, Callable, Type, Optional, get_args, get_origin, get_type_hints
4
4
  from typing_extensions import Self
5
- from pydantic import InstanceOf, BaseModel, ConfigDict, Field, field_validator, model_validator, PrivateAttr, create_model
5
+ from pydantic import InstanceOf, BaseModel, Field, field_validator, model_validator, PrivateAttr, create_model
6
6
  from pydantic_core import PydanticCustomError
7
7
 
8
8
  from versionhq.llm.llm_vars import SchemaType
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Version IO Sdn. Bhd.
3
+ Copyright (c) 2024-2025 Version IO Sdn. Bhd.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal