versionhq 1.1.7.8__tar.gz → 1.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {versionhq-1.1.7.8 → versionhq-1.1.8}/PKG-INFO +2 -2
  2. {versionhq-1.1.7.8 → versionhq-1.1.8}/README.md +1 -1
  3. {versionhq-1.1.7.8 → versionhq-1.1.8}/pyproject.toml +1 -1
  4. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/__init__.py +1 -1
  5. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/product/model.py +4 -1
  6. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/workflow/model.py +5 -5
  7. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/storage/task_output_storage.py +19 -22
  8. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/task/model.py +5 -9
  9. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/team/model.py +3 -4
  10. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq.egg-info/PKG-INFO +2 -2
  11. versionhq-1.1.8/tests/clients/workflow_test.py +84 -0
  12. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/task/task_test.py +7 -0
  13. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/team/team_test.py +42 -26
  14. {versionhq-1.1.7.8 → versionhq-1.1.8}/uv.lock +1 -1
  15. versionhq-1.1.7.8/tests/clients/workflow_test.py +0 -32
  16. {versionhq-1.1.7.8 → versionhq-1.1.8}/.github/workflows/publish.yml +0 -0
  17. {versionhq-1.1.7.8 → versionhq-1.1.8}/.github/workflows/publish_testpypi.yml +0 -0
  18. {versionhq-1.1.7.8 → versionhq-1.1.8}/.github/workflows/run_tests.yml +0 -0
  19. {versionhq-1.1.7.8 → versionhq-1.1.8}/.github/workflows/security_check.yml +0 -0
  20. {versionhq-1.1.7.8 → versionhq-1.1.8}/.gitignore +0 -0
  21. {versionhq-1.1.7.8 → versionhq-1.1.8}/.pre-commit-config.yaml +0 -0
  22. {versionhq-1.1.7.8 → versionhq-1.1.8}/.python-version +0 -0
  23. {versionhq-1.1.7.8 → versionhq-1.1.8}/LICENSE +0 -0
  24. {versionhq-1.1.7.8 → versionhq-1.1.8}/SECURITY.md +0 -0
  25. {versionhq-1.1.7.8 → versionhq-1.1.8}/db/preprocess.py +0 -0
  26. {versionhq-1.1.7.8 → versionhq-1.1.8}/requirements-dev.txt +0 -0
  27. {versionhq-1.1.7.8 → versionhq-1.1.8}/requirements.txt +0 -0
  28. {versionhq-1.1.7.8 → versionhq-1.1.8}/runtime.txt +0 -0
  29. {versionhq-1.1.7.8 → versionhq-1.1.8}/setup.cfg +0 -0
  30. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/__init__.py +0 -0
  31. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/cache_handler.py +0 -0
  32. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/i18n.py +0 -0
  33. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/logger.py +0 -0
  34. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/process_config.py +0 -0
  35. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/rpm_controller.py +0 -0
  36. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/_utils/usage_metrics.py +0 -0
  37. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/agent/TEMPLATES/Backstory.py +0 -0
  38. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/agent/TEMPLATES/__init__.py +0 -0
  39. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/agent/__init__.py +0 -0
  40. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/agent/model.py +0 -0
  41. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/agent/parser.py +0 -0
  42. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/cli/__init__.py +0 -0
  43. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/__init__.py +0 -0
  44. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/customer/__init__.py +0 -0
  45. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/customer/model.py +0 -0
  46. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/product/__init__.py +0 -0
  47. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/clients/workflow/__init__.py +0 -0
  48. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/llm/__init__.py +0 -0
  49. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/llm/llm_vars.py +0 -0
  50. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/llm/model.py +0 -0
  51. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/storage/__init__.py +0 -0
  52. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/task/__init__.py +0 -0
  53. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/task/formatter.py +0 -0
  54. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/task/log_handler.py +0 -0
  55. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/team/__init__.py +0 -0
  56. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/team/team_planner.py +0 -0
  57. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/tool/__init__.py +0 -0
  58. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/tool/decorator.py +0 -0
  59. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/tool/model.py +0 -0
  60. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq/tool/tool_handler.py +0 -0
  61. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq.egg-info/SOURCES.txt +0 -0
  62. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq.egg-info/dependency_links.txt +0 -0
  63. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq.egg-info/requires.txt +0 -0
  64. {versionhq-1.1.7.8 → versionhq-1.1.8}/src/versionhq.egg-info/top_level.txt +0 -0
  65. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/__init__.py +0 -0
  66. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/agent/__init__.py +0 -0
  67. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/agent/agent_test.py +0 -0
  68. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/cli/__init__.py +0 -0
  69. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/conftest.py +0 -0
  70. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/task/__init__.py +0 -0
  71. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/team/Prompts/Demo_test.py +0 -0
  72. {versionhq-1.1.7.8 → versionhq-1.1.8}/tests/team/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: versionhq
3
- Version: 1.1.7.8
3
+ Version: 1.1.8
4
4
  Summary: LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -57,7 +57,7 @@ Requires-Dist: appdirs>=1.4.4
57
57
 
58
58
  ![MIT license](https://img.shields.io/badge/License-MIT-green)
59
59
  [![Publisher](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml/badge.svg)](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
60
- ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.5-blue)
60
+ ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.9-blue)
61
61
  ![python ver](https://img.shields.io/badge/Python-3.12/3.13-purple)
62
62
  ![pyenv ver](https://img.shields.io/badge/pyenv-2.5.0-orange)
63
63
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![MIT license](https://img.shields.io/badge/License-MIT-green)
4
4
  [![Publisher](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml/badge.svg)](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
5
- ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.5-blue)
5
+ ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.9-blue)
6
6
  ![python ver](https://img.shields.io/badge/Python-3.12/3.13-purple)
7
7
  ![pyenv ver](https://img.shields.io/badge/pyenv-2.5.0-orange)
8
8
 
@@ -15,7 +15,7 @@ exclude = ["test*", "__pycache__"]
15
15
 
16
16
  [project]
17
17
  name = "versionhq"
18
- version = "1.1.7.8"
18
+ version = "1.1.8"
19
19
  authors = [{ name = "Kuriko Iwai", email = "kuriko@versi0n.io" }]
20
20
  description = "LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows"
21
21
  readme = "README.md"
@@ -17,7 +17,7 @@ from versionhq.team.model import Team, TeamOutput
17
17
  from versionhq.tool.model import Tool
18
18
 
19
19
 
20
- __version__ = "1.1.7.8"
20
+ __version__ = "1.1.8"
21
21
  __all__ = [
22
22
  "Agent",
23
23
  "Customer",
@@ -34,7 +34,10 @@ class Product(BaseModel):
34
34
  id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
35
35
  name: Optional[str] = Field(default=None, description="product name")
36
36
  description: Optional[str] = Field(
37
- default=None,max_length=256,description="product description scraped from landing url or client input. cascade to the agent")
37
+ default=None,
38
+ max_length=256,
39
+ description="product description scraped from landing url or client input. cascade to the agent"
40
+ )
38
41
  provider: Optional[ProductProvider] = Field(default=None)
39
42
  audience: Optional[str] = Field(default=None, description="target audience")
40
43
  usp: Optional[str] = Field(default=None)
@@ -60,6 +60,7 @@ class MessagingComponent(ABC, BaseModel):
60
60
  default=None, description="interval to move on to the next layer. if this is the last layer, set as `None`"
61
61
  )
62
62
  score: float | InstanceOf[Score] = Field(default=None)
63
+ condition: str = Field(default=None, max_length=128, description="condition to execute the next messaging component")
63
64
 
64
65
 
65
66
  def store_scoring_result(self, scoring_subject: str, score_raw: int | Score | ScoreFormat = None):
@@ -106,7 +107,7 @@ class MessagingWorkflow(ABC, BaseModel):
106
107
  default=None, description="store `Agent` instances responsible for autopiloting this workflow. if the team exsits, this field remains as `None`")
107
108
 
108
109
  # metrics
109
- destination: Optional[str] = Field( default=None, description="destination service to launch this workflow")
110
+ destination: Optional[str | None] = Field(default=None, description="destination service to launch this workflow")
110
111
  product: InstanceOf[Product] = Field(default=None)
111
112
  customer: InstanceOf[Customer] = Field(default=None)
112
113
 
@@ -142,10 +143,9 @@ class MessagingWorkflow(ABC, BaseModel):
142
143
  if self.customer is not None:
143
144
  self.destination = self.customer.on
144
145
 
145
- else:
146
- destination_list = self.product.provider.destinations
147
- if destination_list:
148
- self.destination = destination_list[0]
146
+ elif self.product.provider is not None and self.product.provider.destinations:
147
+ self.destination = self.product.provider.destinations[0]
148
+
149
149
  return self
150
150
 
151
151
 
@@ -11,11 +11,9 @@ from versionhq._utils.logger import Logger
11
11
 
12
12
  load_dotenv(override=True)
13
13
 
14
-
15
14
  def fetch_db_storage_path():
16
- project_directory_name = os.environ.get("STORAGE_DIR", Path.cwd().name)
17
- app_author = "versionhq"
18
- data_dir = Path(appdirs.user_data_dir(project_directory_name, app_author))
15
+ directory_name = Path.cwd().name
16
+ data_dir = Path(appdirs.user_data_dir(appname=directory_name, appauthor="Version IO Sdn Bhd.", version=None, roaming=False))
19
17
  data_dir.mkdir(parents=True, exist_ok=True)
20
18
  return data_dir
21
19
 
@@ -39,25 +37,25 @@ class TaskOutputSQLiteStorage:
39
37
  Initializes the SQLite database and creates LTM table.
40
38
  """
41
39
 
42
- try:
43
- with sqlite3.connect(self.db_path) as conn:
44
- cursor = conn.cursor()
45
- cursor.execute(
46
- """
47
- CREATE TABLE IF NOT EXISTS task_outputs (
48
- task_id TEXT PRIMARY KEY,
49
- output JSON,
50
- task_index INTEGER,
51
- inputs JSON,
52
- was_replayed BOOLEAN,
53
- timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
54
- )
40
+ # try:
41
+ with sqlite3.connect(self.db_path) as conn:
42
+ cursor = conn.cursor()
43
+ cursor.execute(
55
44
  """
45
+ CREATE TABLE IF NOT EXISTS task_outputs (
46
+ task_id TEXT PRIMARY KEY,
47
+ output JSON,
48
+ task_index INTEGER,
49
+ inputs JSON,
50
+ was_replayed BOOLEAN,
51
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
56
52
  )
57
- conn.commit()
53
+ """
54
+ )
55
+ conn.commit()
58
56
 
59
- except sqlite3.Error as e:
60
- self._logger.log(level="error", message=f"DATABASE INITIALIZATION ERROR: {e}", color="red")
57
+ # except sqlite3.Error as e:
58
+ # self._logger.log(level="error", message=f"DATABASE INITIALIZATION ERROR: {e}", color="red")
61
59
 
62
60
 
63
61
  def add(self, task, output: Dict[str, Any], task_index: int, was_replayed: bool = False, inputs: Dict[str, Any] = {}):
@@ -81,13 +79,12 @@ class TaskOutputSQLiteStorage:
81
79
  try:
82
80
  with sqlite3.connect(self.db_path) as conn:
83
81
  cursor = conn.cursor()
84
-
85
82
  fields, values = [], []
86
83
  for k, v in kwargs.items():
87
84
  fields.append(f"{k} = ?")
88
85
  values.append(json.dumps(v) if isinstance(v, dict) else v)
89
86
 
90
- query = f"UPDATE latest_kickoff_task_outputs SET {', '.join(fields)} WHERE task_index = ?" # nosec
87
+ query = f"UPDATE latest_kickoff_task_outputs SET {', '.join(fields)} WHERE task_index = ?"
91
88
  values.append(task_index)
92
89
  cursor.execute(query, tuple(values))
93
90
  conn.commit()
@@ -206,10 +206,10 @@ Your outputs MUST adhere to the following format and should NOT include any irre
206
206
  @property
207
207
  def summary(self) -> str:
208
208
  return f"""
209
- Task: {self.id} - {self.description}
210
- "task_description": {self.description}
211
- "task_expected_output": {self.output_prompt}
212
- "task_tools": {", ".join([tool_called.tool.name for tool_called in self.tools_called])}
209
+ Task ID: {str(self.id)}
210
+ "Description": {self.description}
211
+ "Prompt": {self.output_prompt}
212
+ "Tools": {", ".join([tool_called.tool.name for tool_called in self.tools_called])}
213
213
  """
214
214
 
215
215
 
@@ -382,11 +382,7 @@ Your outputs MUST adhere to the following format and should NOT include any irre
382
382
  """
383
383
 
384
384
  future: Future[TaskOutput] = Future()
385
- threading.Thread(
386
- daemon=True,
387
- target=self._execute_task_async,
388
- args=(agent, context, tools, future),
389
- ).start()
385
+ threading.Thread(daemon=True, target=self._execute_task_async, args=(agent, context, tools, future)).start()
390
386
  return future
391
387
 
392
388
 
@@ -123,7 +123,7 @@ class Team(BaseModel):
123
123
  __hash__ = object.__hash__
124
124
  _execution_span: Any = PrivateAttr()
125
125
  _logger: Logger = PrivateAttr()
126
- # _inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
126
+ _inputs: Optional[Dict[str, Any]] = PrivateAttr(default=None)
127
127
 
128
128
  id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
129
129
  name: Optional[str] = Field(default=None)
@@ -382,14 +382,13 @@ class Team(BaseModel):
382
382
  futures.append((task, future, task_index))
383
383
  else:
384
384
  context = create_raw_outputs(tasks=[task,], task_outputs=([last_sync_output,] if last_sync_output else [] ))
385
- task_output = task.execute_sync(agent=responsible_agent, context=context, tools=responsible_agent.tools
386
- )
385
+ task_output = task.execute_sync(agent=responsible_agent, context=context, tools=responsible_agent.tools)
387
386
  if responsible_agent is self.manager_agent:
388
387
  lead_task_output = task_output
389
388
 
390
389
  task_outputs.append(task_output)
391
390
  # self._process_task_result(task, task_output)
392
- task._store_execution_log(task_index, was_replayed)
391
+ task._store_execution_log(task_index, was_replayed, self._inputs)
393
392
 
394
393
 
395
394
  if futures:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: versionhq
3
- Version: 1.1.7.8
3
+ Version: 1.1.8
4
4
  Summary: LLM orchestration frameworks for model-agnostic AI agents that handle complex outbound workflows
5
5
  Author-email: Kuriko Iwai <kuriko@versi0n.io>
6
6
  License: MIT License
@@ -57,7 +57,7 @@ Requires-Dist: appdirs>=1.4.4
57
57
 
58
58
  ![MIT license](https://img.shields.io/badge/License-MIT-green)
59
59
  [![Publisher](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml/badge.svg)](https://github.com/versionHQ/multi-agent-system/actions/workflows/publish.yml)
60
- ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.5-blue)
60
+ ![PyPI](https://img.shields.io/badge/PyPI-v1.1.7.9-blue)
61
61
  ![python ver](https://img.shields.io/badge/Python-3.12/3.13-purple)
62
62
  ![pyenv ver](https://img.shields.io/badge/pyenv-2.5.0-orange)
63
63
 
@@ -0,0 +1,84 @@
1
+ import os
2
+ import pytest
3
+ import datetime
4
+
5
+ from versionhq.agent.model import Agent
6
+ from versionhq.llm.model import LLM
7
+ from versionhq.clients.workflow.model import Score, ScoreFormat, MessagingWorkflow, MessagingComponent
8
+ from versionhq.clients.product.model import Product, ProductProvider
9
+
10
+
11
+ MODEL_NAME = os.environ.get("LITELLM_MODEL_NAME", "gpt-3.5-turbo")
12
+ LITELLM_API_KEY = os.environ.get("LITELLM_API_KEY")
13
+
14
+
15
+ def test_store_scores():
16
+ """
17
+ Test if the final result will be calcurated using a random subject
18
+ """
19
+
20
+ messaging_component = MessagingComponent(message="demo")
21
+ score_raw = 15
22
+ messaging_component.store_scoring_result("demo", score_raw=score_raw)
23
+
24
+ assert messaging_component.score is not None
25
+ assert messaging_component.score.result() is not None
26
+
27
+
28
+ def test_score_result():
29
+ messaging_component = MessagingComponent(message="demo")
30
+ score_raw = 15
31
+ messaging_component.store_scoring_result("demo", score_raw=score_raw)
32
+
33
+ result = messaging_component.score.result()
34
+
35
+ assert result is not None
36
+ assert result != 0
37
+
38
+
39
+ def test_setup_messaging_workflow_with_anonymous_provider():
40
+ product = Product(
41
+ description="demo p",
42
+ audience="demo audience",
43
+ usp="demo usp",
44
+ landing_url="www.com",
45
+ cohort_timeframe=30,
46
+ )
47
+ comp = MessagingComponent(message="demo")
48
+ messaging_workflow = MessagingWorkflow(
49
+ _created_at=datetime.datetime.now(),
50
+ components=[comp, ],
51
+ agents=[],
52
+ product=product,
53
+ )
54
+
55
+ assert messaging_workflow.id is not None
56
+ assert messaging_workflow.destination is None
57
+
58
+
59
+ def test_setup_messaging_workflow_with_provider():
60
+ provider = ProductProvider(
61
+ name="demo provider",
62
+ region="US",
63
+ data_pipeline=["data"],
64
+ destinations=["email", "linkedin",]
65
+ )
66
+ product = Product(
67
+ description="demo p",
68
+ audience="demo audience",
69
+ usp="demo usp",
70
+ landing_url="www.com",
71
+ cohort_timeframe=30,
72
+ provider=provider,
73
+ )
74
+ comp = MessagingComponent(message="demo")
75
+ messaging_workflow = MessagingWorkflow(
76
+ _created_at=datetime.datetime.now(),
77
+ components=[comp, ],
78
+ agents=[],
79
+ product=product,
80
+ )
81
+
82
+ assert messaging_workflow.id is not None
83
+ assert messaging_workflow.destination is not None
84
+ assert messaging_workflow.destination in provider.destinations
@@ -277,4 +277,11 @@ def test_conditional_task():
277
277
  assert conditional_res.task_id is conditional_task.id
278
278
 
279
279
 
280
+ def test_store_task_log():
281
+ task = Task(
282
+ description="Analyze the client's business model.",
283
+ output_field_list=[ResponseField(title="task_1", type=str, required=True),],
284
+ )
285
+ assert task._task_output_handler.load() is not None
286
+
280
287
  # tools, token usage
@@ -127,28 +127,17 @@ def test_form_team_without_leader():
127
127
  assert item.id is task_1.id or item.id is task_2.id
128
128
 
129
129
 
130
- def test_kickoff_team_without_leader():
131
- agent_a = Agent(
132
- role="agent a",
133
- goal="My amazing goals",
134
- llm=MODEL_NAME
135
- )
136
-
137
- agent_b = Agent(
138
- role="agent b",
139
- goal="My amazing goals",
140
- llm=MODEL_NAME
141
- )
142
-
130
+ def test_kickoff_without_leader():
131
+ agent_a = Agent(role="agent a", goal="My amazing goals", llm=MODEL_NAME)
132
+ agent_b = Agent(role="agent b", goal="My amazing goals", llm=MODEL_NAME)
143
133
  task_1 = Task(
144
- description="Analyze the client's business model.",
145
- expected_output_json=True,
146
- output_field_list=[
147
- ResponseField(title="test1", type=str, required=True),
148
- ResponseField(title="test2", type=list, required=True),
149
- ],
134
+ description="Analyze the client's business model.",
135
+ expected_output_json=True,
136
+ output_field_list=[
137
+ ResponseField(title="test1", type=str, required=True),
138
+ ResponseField(title="test2", type=list, required=True),
139
+ ],
150
140
  )
151
-
152
141
  task_2 = Task(
153
142
  description="Define the cohort.",
154
143
  expected_output_json=True,
@@ -157,7 +146,6 @@ def test_kickoff_team_without_leader():
157
146
  ResponseField(title="test2", type=list, required=True),
158
147
  ],
159
148
  )
160
-
161
149
  team = Team(
162
150
  members=[
163
151
  TeamMember(agent=agent_a, is_manager=False, task=task_1),
@@ -185,7 +173,6 @@ def test_kickoff_team_without_leader():
185
173
  assert res.token_usage.total_tokens == 0 # as we dont set token usage on agent
186
174
 
187
175
 
188
-
189
176
  def team_kickoff_with_task_callback():
190
177
  """
191
178
  Each task has callback with callback kwargs.
@@ -236,7 +223,6 @@ def team_kickoff_with_task_callback():
236
223
  assert "pytest" in demo_list[1]
237
224
 
238
225
 
239
-
240
226
  def test_delegate_in_team():
241
227
  """
242
228
  When the agent belongs to the team, the team manager or peers are prioritized to delegete the task.
@@ -279,7 +265,37 @@ def test_delegate_in_team():
279
265
  assert "agent b" in task_1.processed_by_agents
280
266
 
281
267
 
268
+ def test_kickoff_with_leader():
269
+ agent_a = Agent(role="agent a", goal="My amazing goals", llm=MODEL_NAME)
270
+ agent_b = Agent(role="agent b", goal="My amazing goals", llm=MODEL_NAME)
271
+ task_1 = Task(
272
+ description="Analyze the client's business model.",
273
+ output_field_list=[ResponseField(title="task_1", type=str, required=True),],
274
+ )
275
+ task_2 = Task(
276
+ description="Define the cohort timeframe.",
277
+ output_field_list=[
278
+ ResponseField(title="task_2_1", type=int, required=True),
279
+ ResponseField(title="task_2_2", type=list, required=True),
280
+ ],
281
+ )
282
+ team = Team(
283
+ members=[
284
+ TeamMember(agent=agent_a, is_manager=False, task=task_1),
285
+ TeamMember(agent=agent_b, is_manager=True, task=task_2),
286
+ ],
287
+ )
288
+ res = team.kickoff()
289
+
290
+ assert isinstance(res, TeamOutput)
291
+ assert res.team_id is team.id
292
+ assert res.raw is not None
293
+ assert res.json_dict is not None
294
+ assert team.manager_agent.id is agent_b.id
295
+ assert len(res.task_output_list) == 2
296
+ assert [item.raw is not None for item in res.task_output_list]
297
+ assert len(team.tasks) == 2
298
+ assert team.tasks[0].output.raw == res.raw
299
+
282
300
 
283
- if __name__ == "__main__":
284
- test_kickoff_team_without_leader()
285
- # kickoff with teamleader, async, task handling process
301
+ # async, task handling process
@@ -1644,7 +1644,7 @@ wheels = [
1644
1644
 
1645
1645
  [[package]]
1646
1646
  name = "versionhq"
1647
- version = "1.1.7.8"
1647
+ version = "1.1.8"
1648
1648
  source = { editable = "." }
1649
1649
  dependencies = [
1650
1650
  { name = "appdirs" },
@@ -1,32 +0,0 @@
1
- import os
2
- import pytest
3
- from versionhq.agent.model import Agent
4
- from versionhq.llm.model import LLM
5
- from versionhq.clients.workflow.model import Score, ScoreFormat, MessagingWorkflow, MessagingComponent
6
-
7
- MODEL_NAME = os.environ.get("LITELLM_MODEL_NAME", "gpt-3.5-turbo")
8
- LITELLM_API_KEY = os.environ.get("LITELLM_API_KEY")
9
-
10
-
11
- def test_store_scores():
12
- """
13
- Test if the final result will be calcurated using a random subject
14
- """
15
-
16
- messaging_component = MessagingComponent(message="demo")
17
- score_raw = 15
18
- messaging_component.store_scoring_result("demo", score_raw=score_raw)
19
-
20
- assert messaging_component.score is not None
21
- assert messaging_component.score.result() is not None
22
-
23
-
24
- def test_score_result():
25
- messaging_component = MessagingComponent(message="demo")
26
- score_raw = 15
27
- messaging_component.store_scoring_result("demo", score_raw=score_raw)
28
-
29
- result = messaging_component.score.result()
30
-
31
- assert result is not None
32
- assert result != 0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes