versionhq 1.2.2.3__tar.gz → 1.2.2.5__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 (152) hide show
  1. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.github/workflows/publish.yml +4 -2
  2. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/PKG-INFO +11 -9
  3. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/README.md +3 -6
  4. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent/index.md +1 -1
  5. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/index.md +1 -4
  6. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/quickstart.md +1 -1
  7. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/pyproject.toml +10 -3
  8. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/__init__.py +3 -1
  9. versionhq-1.2.2.5/src/versionhq/_utils/llm_as_a_judge.py +65 -0
  10. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/inhouse_agents.py +1 -1
  11. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/model.py +49 -29
  12. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/source_docling.py +2 -1
  13. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/storage.py +2 -1
  14. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/model.py +1 -5
  15. versionhq-1.2.2.5/src/versionhq/tool/rag_tool.py +112 -0
  16. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq.egg-info/PKG-INFO +11 -9
  17. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq.egg-info/SOURCES.txt +4 -0
  18. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq.egg-info/requires.txt +9 -2
  19. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent/agent_test.py +3 -5
  20. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/doc_test.py +3 -3
  21. versionhq-1.2.2.5/tests/sample.json +14 -0
  22. versionhq-1.2.2.5/tests/tool/rag_tool_test.py +30 -0
  23. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/usecase_test.py +16 -4
  24. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/uv.lock +146 -74
  25. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.env.sample +0 -0
  26. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.github/workflows/deploy_docs.yml +0 -0
  27. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.github/workflows/publish_testpypi.yml +0 -0
  28. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.github/workflows/run_tests.yml +0 -0
  29. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.github/workflows/security_check.yml +0 -0
  30. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.gitignore +0 -0
  31. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.pre-commit-config.yaml +0 -0
  32. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/.python-version +0 -0
  33. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/LICENSE +0 -0
  34. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/SECURITY.md +0 -0
  35. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/db/preprocess.py +0 -0
  36. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/CNAME +0 -0
  37. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/_logos/favicon.ico +0 -0
  38. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/_logos/logo192.png +0 -0
  39. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent/config.md +0 -0
  40. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent/task-handling.md +0 -0
  41. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent-network/config.md +0 -0
  42. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent-network/form.md +0 -0
  43. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent-network/index.md +0 -0
  44. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/agent-network/ref.md +0 -0
  45. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/llm/index.md +0 -0
  46. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/evaluation.md +0 -0
  47. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/index.md +0 -0
  48. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/response-field.md +0 -0
  49. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/task-execution.md +0 -0
  50. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/task-output.md +0 -0
  51. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/task-ref.md +0 -0
  52. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task/task-strc-response.md +0 -0
  53. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/task-graph/index.md +0 -0
  54. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/core/tool.md +0 -0
  55. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/stylesheets/main.css +0 -0
  56. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/docs/tags.md +0 -0
  57. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/mkdocs.yml +0 -0
  58. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/requirements-dev.txt +0 -0
  59. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/requirements.txt +0 -0
  60. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/runtime.txt +0 -0
  61. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/setup.cfg +0 -0
  62. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/__init__.py +0 -0
  63. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/i18n.py +0 -0
  64. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/logger.py +0 -0
  65. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/process_config.py +0 -0
  66. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/usage_metrics.py +0 -0
  67. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/_utils/vars.py +0 -0
  68. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/TEMPLATES/Backstory.py +0 -0
  69. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/TEMPLATES/__init__.py +0 -0
  70. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/__init__.py +0 -0
  71. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/parser.py +0 -0
  72. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent/rpm_controller.py +0 -0
  73. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent_network/__init__.py +0 -0
  74. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent_network/formation.py +0 -0
  75. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/agent_network/model.py +0 -0
  76. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/cli/__init__.py +0 -0
  77. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/__init__.py +0 -0
  78. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/customer/__init__.py +0 -0
  79. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/customer/model.py +0 -0
  80. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/product/__init__.py +0 -0
  81. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/product/model.py +0 -0
  82. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/workflow/__init__.py +0 -0
  83. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/clients/workflow/model.py +0 -0
  84. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/__init__.py +0 -0
  85. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/_utils.py +0 -0
  86. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/embedding.py +0 -0
  87. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/model.py +0 -0
  88. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/knowledge/source.py +0 -0
  89. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/llm/__init__.py +0 -0
  90. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/llm/llm_vars.py +0 -0
  91. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/llm/model.py +0 -0
  92. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/memory/__init__.py +0 -0
  93. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/memory/contextual_memory.py +0 -0
  94. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/memory/model.py +0 -0
  95. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/__init__.py +0 -0
  96. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/base.py +0 -0
  97. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/ltm_sqlite_storage.py +0 -0
  98. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/mem0_storage.py +0 -0
  99. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/rag_storage.py +0 -0
  100. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/task_output_storage.py +0 -0
  101. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/storage/utils.py +0 -0
  102. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/TEMPLATES/Description.py +0 -0
  103. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/__init__.py +0 -0
  104. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/evaluation.py +0 -0
  105. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/formatter.py +0 -0
  106. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/model.py +0 -0
  107. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task/structured_response.py +0 -0
  108. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task_graph/__init__.py +0 -0
  109. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task_graph/colors.py +0 -0
  110. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task_graph/draft.py +0 -0
  111. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/task_graph/model.py +0 -0
  112. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/__init__.py +0 -0
  113. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/cache_handler.py +0 -0
  114. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/composio_tool.py +0 -0
  115. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/composio_tool_vars.py +0 -0
  116. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/decorator.py +0 -0
  117. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq/tool/tool_handler.py +0 -0
  118. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq.egg-info/dependency_links.txt +0 -0
  119. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/src/versionhq.egg-info/top_level.txt +0 -0
  120. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/__init__.py +0 -0
  121. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent/__init__.py +0 -0
  122. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent/doc_test.py +0 -0
  123. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent_network/Prompts/Demo_test.py +0 -0
  124. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent_network/__init__.py +0 -0
  125. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent_network/agent_network_test.py +0 -0
  126. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/agent_network/doc_test.py +0 -0
  127. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/cli/__init__.py +0 -0
  128. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/clients/customer_test.py +0 -0
  129. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/clients/product_test.py +0 -0
  130. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/clients/workflow_test.py +0 -0
  131. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/conftest.py +0 -0
  132. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/formation_test.py +0 -0
  133. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/knowledge/__init__.py +0 -0
  134. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/knowledge/knowledge_test.py +0 -0
  135. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/knowledge/mock_report_compressed.pdf +0 -0
  136. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/llm/__init__.py +0 -0
  137. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/llm/llm_test.py +0 -0
  138. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/memory/__init__.py +0 -0
  139. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/memory/memory_test.py +0 -0
  140. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/__init__.py +0 -0
  141. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/doc_taskoutput_test.py +0 -0
  142. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/doc_test.py +0 -0
  143. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/eval_test.py +0 -0
  144. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/llm_connection_test.py +0 -0
  145. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task/task_test.py +0 -0
  146. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task_graph/__init__.py +0 -0
  147. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task_graph/doc_test.py +0 -0
  148. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/task_graph/task_graph_test.py +0 -0
  149. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/tool/__init__.py +0 -0
  150. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/tool/composio_test.py +0 -0
  151. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/tool/doc_test.py +0 -0
  152. {versionhq-1.2.2.3 → versionhq-1.2.2.5}/tests/tool/tool_test.py +0 -0
@@ -5,6 +5,7 @@ on:
5
5
  types: [released]
6
6
 
7
7
  permissions:
8
+ id-token: write
8
9
  contents: read
9
10
 
10
11
  jobs:
@@ -58,5 +59,6 @@ jobs:
58
59
  packages-dir: dist/
59
60
  repository-url: https://upload.pypi.org/legacy/
60
61
  verbose: true
61
- user: __token__
62
- password: ${{ secrets.PYPI_API_TOKEN }}
62
+ # user: krik8235
63
+ # user: __token__
64
+ # password: ${{ secrets.PYPI_API_TOKEN }}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: versionhq
3
- Version: 1.2.2.3
3
+ Version: 1.2.2.5
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
@@ -50,7 +50,7 @@ Requires-Dist: werkzeug>=3.1.3
50
50
  Requires-Dist: typing
51
51
  Requires-Dist: json-repair
52
52
  Requires-Dist: litellm>=1.55.8
53
- Requires-Dist: openai>=1.57.0
53
+ Requires-Dist: openai>=1.64.0
54
54
  Requires-Dist: composio-openai>=0.6.9
55
55
  Requires-Dist: composio>=0.1.0
56
56
  Requires-Dist: setuptools>=75.6.0
@@ -69,7 +69,7 @@ Requires-Dist: matplotlib>=3.10.0
69
69
  Provides-Extra: docling
70
70
  Requires-Dist: docling>=2.17.0; extra == "docling"
71
71
  Provides-Extra: mem0ai
72
- Requires-Dist: mem0ai>=0.1.48; extra == "mem0ai"
72
+ Requires-Dist: mem0ai>=0.1.55; extra == "mem0ai"
73
73
  Provides-Extra: pdfplumber
74
74
  Requires-Dist: pdfplumber>=0.11.5; extra == "pdfplumber"
75
75
  Provides-Extra: pandas
@@ -78,6 +78,11 @@ Provides-Extra: numpy
78
78
  Requires-Dist: numpy>=1.26.4; extra == "numpy"
79
79
  Provides-Extra: pygraphviz
80
80
  Requires-Dist: pygraphviz>=1.14; extra == "pygraphviz"
81
+ Provides-Extra: tools
82
+ Requires-Dist: html2text>=2024.2.26; extra == "tools"
83
+ Requires-Dist: sec-api>=1.0.28; extra == "tools"
84
+ Provides-Extra: eval
85
+ Requires-Dist: scikit-learn>=1.6.1; extra == "eval"
81
86
 
82
87
  # Overview
83
88
 
@@ -222,10 +227,7 @@ The following code snippet demonstrates agent customization:
222
227
  ```python
223
228
  import versionhq as vhq
224
229
 
225
- agent = vhq.Agent(
226
- role="Marketing Analyst",
227
- goal="my amazing goal"
228
- ) # assuming this agent was created during the network formation
230
+ agent = vhq.Agent(role="Marketing Analyst")
229
231
 
230
232
  # update the agent
231
233
  agent.update(
@@ -316,8 +318,8 @@ To create an agent network with one or more manager agents, designate members us
316
318
  ```python
317
319
  import versionhq as vhq
318
320
 
319
- agent_a = vhq.Agent(role="agent a", goal="My amazing goals", llm="llm-of-your-choice")
320
- agent_b = vhq.Agent(role="agent b", goal="My amazing goals", llm="llm-of-your-choice")
321
+ agent_a = vhq.Agent(role="agent a", llm="llm-of-your-choice")
322
+ agent_b = vhq.Agent(role="agent b", llm="llm-of-your-choice")
321
323
 
322
324
  task_1 = vhq.Task(
323
325
  description="Analyze the client's business model.",
@@ -141,10 +141,7 @@ The following code snippet demonstrates agent customization:
141
141
  ```python
142
142
  import versionhq as vhq
143
143
 
144
- agent = vhq.Agent(
145
- role="Marketing Analyst",
146
- goal="my amazing goal"
147
- ) # assuming this agent was created during the network formation
144
+ agent = vhq.Agent(role="Marketing Analyst")
148
145
 
149
146
  # update the agent
150
147
  agent.update(
@@ -235,8 +232,8 @@ To create an agent network with one or more manager agents, designate members us
235
232
  ```python
236
233
  import versionhq as vhq
237
234
 
238
- agent_a = vhq.Agent(role="agent a", goal="My amazing goals", llm="llm-of-your-choice")
239
- agent_b = vhq.Agent(role="agent b", goal="My amazing goals", llm="llm-of-your-choice")
235
+ agent_a = vhq.Agent(role="agent a", llm="llm-of-your-choice")
236
+ agent_b = vhq.Agent(role="agent b", llm="llm-of-your-choice")
240
237
 
241
238
  task_1 = vhq.Task(
242
239
  description="Analyze the client's business model.",
@@ -7,7 +7,7 @@ tags:
7
7
 
8
8
  <class>`class` versionhq.agent.model.<bold>Agent<bold></class>
9
9
 
10
- A Pydantic class to store `Agent` objects and handle `Task` execution as well as `LLM` configuration.
10
+ A Pydantic class to store an `Agent` object that handles `Task` execution.
11
11
 
12
12
 
13
13
  ## Quick Start
@@ -113,10 +113,7 @@ The following code snippet demonstrates agent customization:
113
113
  ```python
114
114
  import versionhq as vhq
115
115
 
116
- agent = vhq.Agent(
117
- role="Marketing Analyst",
118
- goal="my amazing goal"
119
- ) # assuming this agent was created during the network formation
116
+ agent = vhq.Agent(role="Marketing Analyst")
120
117
 
121
118
  # update the agent
122
119
  agent.update(
@@ -48,7 +48,7 @@ def dummy_func(message: str, test1: str, test2: list[str]) -> str:
48
48
  return f"""{message}: {test1}, {", ".join(test2)}"""
49
49
 
50
50
 
51
- agent = vhq.Agent(role="demo", goal="amazing project goal")
51
+ agent = vhq.Agent(role="demo manager")
52
52
 
53
53
  task = vhq.Task(
54
54
  description="Amazing task",
@@ -15,7 +15,7 @@ exclude = ["test*", "__pycache__", "*.egg-info"]
15
15
 
16
16
  [project]
17
17
  name = "versionhq"
18
- version = "1.2.2.3"
18
+ version = "1.2.2.5"
19
19
  authors = [{ name = "Kuriko Iwai", email = "kuriko@versi0n.io" }]
20
20
  description = "An agentic orchestration framework for building agent networks that handle task automation."
21
21
  readme = "README.md"
@@ -30,7 +30,7 @@ dependencies = [
30
30
  "typing",
31
31
  "json-repair",
32
32
  "litellm>=1.55.8",
33
- "openai>=1.57.0",
33
+ "openai>=1.64.0",
34
34
  "composio-openai>=0.6.9",
35
35
  "composio>=0.1.0",
36
36
  "setuptools>=75.6.0",
@@ -71,7 +71,7 @@ docling = [
71
71
  "docling>=2.17.0",
72
72
  ]
73
73
  mem0ai = [
74
- "mem0ai>=0.1.48",
74
+ "mem0ai>=0.1.55",
75
75
  ]
76
76
  pdfplumber = [
77
77
  "pdfplumber>=0.11.5",
@@ -85,6 +85,13 @@ numpy = [
85
85
  pygraphviz = [
86
86
  "pygraphviz>=1.14",
87
87
  ]
88
+ tools = [
89
+ "html2text>=2024.2.26",
90
+ "sec-api>=1.0.28",
91
+ ]
92
+ eval = [
93
+ "scikit-learn>=1.6.1",
94
+ ]
88
95
 
89
96
  [tool.uv]
90
97
  dev-dependencies = [
@@ -21,6 +21,7 @@ from versionhq.task_graph.model import TaskStatus, TaskGraph, Node, Edge, Depend
21
21
  from versionhq.task.model import Task, TaskOutput, ResponseField, TaskExecutionType
22
22
  from versionhq.task.evaluation import Evaluation, EvaluationItem
23
23
  from versionhq.tool.model import Tool, ToolSet
24
+ from versionhq.tool.rag_tool import RagTool
24
25
  from versionhq.tool.cache_handler import CacheHandler
25
26
  from versionhq.tool.tool_handler import ToolHandler
26
27
  from versionhq.tool.composio_tool import ComposioHandler
@@ -31,7 +32,7 @@ from versionhq.agent_network.formation import form_agent_network
31
32
  from versionhq.task_graph.draft import workflow
32
33
 
33
34
 
34
- __version__ = "1.2.2.3"
35
+ __version__ = "1.2.2.5"
35
36
  __all__ = [
36
37
  "Agent",
37
38
 
@@ -80,6 +81,7 @@ __all__ = [
80
81
 
81
82
  "Tool",
82
83
  "ToolSet",
84
+ "RagTool",
83
85
  "CacheHandler",
84
86
  "ToolHandler",
85
87
  "ComposioHandler",
@@ -0,0 +1,65 @@
1
+ import json
2
+ import numpy as np
3
+ from sklearn.metrics import precision_score, recall_score, roc_auc_score, cohen_kappa_score
4
+ from typing import List, Tuple, Dict, Any
5
+ from pathlib import Path
6
+
7
+
8
+ class LLMJudge:
9
+
10
+ class MockLLM:
11
+ def _generate(self, prompt: str) -> str:
12
+ return str(np.random.random())
13
+
14
+
15
+ def __init__(self, model: MockLLM = None):
16
+ self.model = model if model else self.MockLLM()
17
+
18
+
19
+ def judge_summary(self, original_text: str, summary: str) -> float:
20
+ prompt = f"""Evaluate the quality of the following summary on a scale of 0 to 1, where 0 is poor and 1 is excellent.
21
+ Consider accuracy, completeness, and conciseness.
22
+ Original text: {original_text}
23
+ Summary: {summary}
24
+ Quality score:"""
25
+ response = self.model._generate(prompt)
26
+ score = float(response.strip())
27
+ return score
28
+
29
+
30
+ def generate_summaries(file_path: str, data: List[Dict[str, Any]] = None, summarizer: Any = None) -> List[Tuple[str, str, float]]:
31
+ """Generates a list of tuple with an original text, summary text, and human judge score."""
32
+ if not data:
33
+ with open(file_path, 'r') as file:
34
+ data = json.load(file)
35
+ summaries = []
36
+ for item in data:
37
+ original_text = item['text']
38
+ summary = summarizer.summarize(original_text)
39
+ human_score = item['human_score']
40
+ summaries.append((original_text, summary, human_score))
41
+
42
+ return summaries
43
+
44
+
45
+ def validate(judge: LLMJudge, data: List[Tuple[str, str, float]], threshold: float = 0.5):
46
+ human_scores = []
47
+ predicted_scores = []
48
+
49
+ for original_text, summary, human_score in data:
50
+ predicted_score = judge.judge_summary(original_text=original_text, summary=summary)
51
+ human_scores.append(human_score)
52
+ predicted_scores.append(predicted_score)
53
+
54
+ human_binary = [1 if score >= threshold else 0 for score in human_scores]
55
+ pred_binary = [1 if score >= threshold else 0 for score in predicted_scores]
56
+ precision = precision_score(human_binary, pred_binary, zero_division=0)
57
+ recall = recall_score(human_binary, pred_binary, zero_division=0)
58
+ auroc = roc_auc_score(human_binary, pred_binary, average='weighted')
59
+ kappa = cohen_kappa_score(human_binary, pred_binary)
60
+ return {
61
+ "precision": precision,
62
+ "recall": recall,
63
+ "auroc": auroc,
64
+ "cohen_kappa": kappa
65
+ }
@@ -38,7 +38,7 @@ vhq_formation_planner = Agent(
38
38
  "Solo is a formation where a single agent with tools, knowledge, and memory handles tasks indivudually. When self-learning mode is on - it will turn into Random formation. Typical usecase is an email agent drafts promo message for the given audience using their own knowledge.",
39
39
  "Supervising is a formation where the leader agent gives directions, while sharing its knowledge and memory with subbordinates.Subordinates can be solo agents or networks. Typical usecase is that the leader agent strategizes an outbound campaign plan and assigns components such as media mix or message creation to subordinate agents.",
40
40
  "Network is a formation where multple agents can share tasks, knowledge, and memory among network members without hierarchy. Typical usecase is that an email agent and social media agent share the product knowledge and deploy multi-channel outbound campaign. ",
41
- "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. ",
41
+ "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.",
42
42
  ]
43
43
  )
44
44
 
@@ -8,7 +8,7 @@ from pydantic import UUID4, BaseModel, Field, InstanceOf, PrivateAttr, model_val
8
8
  from pydantic_core import PydanticCustomError
9
9
 
10
10
  from versionhq.llm.model import LLM, DEFAULT_CONTEXT_WINDOW_SIZE, DEFAULT_MODEL_NAME, PROVIDERS
11
- from versionhq.tool.model import Tool, ToolSet
11
+ from versionhq.tool.model import Tool, ToolSet, BaseTool
12
12
  from versionhq.knowledge.model import BaseKnowledgeSource, Knowledge
13
13
  from versionhq.memory.contextual_memory import ContextualMemory
14
14
  from versionhq.memory.model import ShortTermMemory, LongTermMemory, UserMemory
@@ -35,11 +35,11 @@ class Agent(BaseModel):
35
35
  config: Optional[Dict[str, Any]] = Field(default=None, exclude=True, description="values to add to the Agent class")
36
36
 
37
37
  id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
38
- role: str = Field(description="role of the agent - used in summary and logs")
39
- goal: str = Field(description="concise goal of the agent (details are set in the Task instance)")
38
+ role: str = Field(description="required. agent's role")
39
+ goal: Optional[str] = Field(default=None)
40
40
  backstory: Optional[str] = Field(default=None, description="developer prompt to the llm")
41
41
  skillsets: Optional[List[str]] = Field(default_factory=list)
42
- tools: Optional[List[InstanceOf[Tool | ToolSet] | Type[Tool] | Any]] = Field(default_factory=list)
42
+ tools: Optional[List[Any]] = Field(default_factory=list)
43
43
 
44
44
  # knowledge
45
45
  knowledge_sources: Optional[List[BaseKnowledgeSource | Any]] = Field(default=None)
@@ -92,7 +92,7 @@ class Agent(BaseModel):
92
92
 
93
93
  @model_validator(mode="after")
94
94
  def validate_required_fields(self) -> Self:
95
- required_fields = ["role", "goal"]
95
+ required_fields = ["role",]
96
96
  for field in required_fields:
97
97
  if getattr(self, field) is None:
98
98
  raise ValueError(f"{field} must be provided either directly or through config")
@@ -122,29 +122,41 @@ class Agent(BaseModel):
122
122
  """
123
123
  Similar to the LLM set up, when the agent has tools, we will declare them using the Tool class.
124
124
  """
125
- if not self.tools:
126
- pass
125
+ from versionhq.tool.rag_tool import RagTool
127
126
 
128
- else:
129
- tool_list = []
127
+ if not self.tools:
128
+ return self
130
129
 
131
- for item in self.tools:
132
- if isinstance(item, Tool) or isinstance(item, ToolSet):
130
+ tool_list = []
131
+ for item in self.tools:
132
+ match item:
133
+ case RagTool() | BaseTool():
133
134
  tool_list.append(item)
134
135
 
135
- elif isinstance(item, dict) and "func" in item:
136
- tool = Tool(**item)
137
- tool_list.append(tool)
136
+ case Tool():
137
+ if item.func is not None:
138
+ tool_list.append(item)
138
139
 
139
- elif type(item) is Tool and hasattr(item, "func"):
140
- tool_list.append(item)
140
+ case ToolSet():
141
+ if item.tool and item.tool.func is not None:
142
+ tool_list.append(item)
141
143
 
142
- else:
143
- Logger(**self.loger_config, filename=self.key).log(level="error", message=f"Tool {str(item)} is missing a function.", color="red")
144
- raise PydanticCustomError("invalid_tool", f"The tool {str(item)} is missing a function.", {})
144
+ case dict():
145
+ if "func" in item:
146
+ tool = Tool(func=item["func"])
147
+ for k, v in item.items():
148
+ if k in Tool.model_fields.keys() and k != "func" and v is not None:
149
+ setattr(tool, k, v)
150
+ tool_list.append(tool)
145
151
 
146
- self.tools = tool_list
152
+ case _:
153
+ if item.__base__ == BaseTool or item.__base__ == RagTool or item.__base__ == Tool:
154
+ tool_list.append(item)
155
+ else:
156
+ Logger(**self._logger_config, filename=self.key).log(level="error", message=f"Tool {str(item)} is missing a function.", color="red")
157
+ raise PydanticCustomError("invalid_tool", f"The tool {str(item)} is missing a function.", {})
147
158
 
159
+ self.tools = tool_list
148
160
  return self
149
161
 
150
162
 
@@ -158,9 +170,9 @@ class Agent(BaseModel):
158
170
  from versionhq.agent.TEMPLATES.Backstory import BACKSTORY_FULL, BACKSTORY_SHORT
159
171
  backstory = ""
160
172
  skills = ", ".join([item for item in self.skillsets]) if self.skillsets else ""
161
- tools = ", ".join([item.name for item in self.tools if hasattr(item, "name")]) if self.tools else ""
173
+ tools = ", ".join([item.name for item in self.tools if hasattr(item, "name") and item.name is not None]) if self.tools else ""
162
174
  role = self.role.lower()
163
- goal = self.goal.lower()
175
+ goal = self.goal.lower() if self.goal else ""
164
176
 
165
177
  if self.tools or self.skillsets:
166
178
  backstory = BACKSTORY_FULL.format(role=role, goal=goal, skills=skills, tools=tools)
@@ -199,7 +211,7 @@ class Agent(BaseModel):
199
211
  if isinstance(item, BaseKnowledgeSource):
200
212
  knowledge_sources.append(item)
201
213
 
202
- elif isinstance(item, str) and "http" in item:
214
+ elif isinstance(item, str) and "http" in item and DoclingSource._validate_url(url=item) == True:
203
215
  docling_fp.append(item)
204
216
 
205
217
  elif isinstance(item, str):
@@ -223,8 +235,8 @@ class Agent(BaseModel):
223
235
 
224
236
  self._knowledge = Knowledge(sources=knowledge_sources, embedder_config=self.embedder_config, collection_name=collection_name)
225
237
 
226
- except:
227
- Logger(**self._logger_config, filename=self.key).log(level="warning", message="We cannot find the format for the source. Add BaseKnowledgeSource objects instead.", color="yellow")
238
+ except Exception as e:
239
+ Logger(**self._logger_config, filename=self.key).log(level="warning", message=f"We cannot find the format for the source. Add BaseKnowledgeSource objects instead. {str(e)}", color="yellow")
228
240
 
229
241
  return self
230
242
 
@@ -482,7 +494,7 @@ class Agent(BaseModel):
482
494
  Defines and executes a task when it is not given and returns TaskOutput object.
483
495
  """
484
496
 
485
- if not self.goal or not self.role:
497
+ if not self.role or not self.goal:
486
498
  return None
487
499
 
488
500
  from versionhq.task.model import Task
@@ -506,10 +518,13 @@ class Agent(BaseModel):
506
518
  """
507
519
 
508
520
  from versionhq.task.model import Task
521
+ from versionhq.tool.rag_tool import RagTool
509
522
  from versionhq.knowledge._utils import extract_knowledge_context
510
523
 
511
524
  task: InstanceOf[Task] = task
512
- tools: Optional[List[InstanceOf[Tool | ToolSet] | Type[Tool]]] = task_tools + self.tools if task.can_use_agent_tools else task_tools
525
+ all_tools: Optional[List[Tool | ToolSet | RagTool | Type[BaseTool]]] = task_tools + self.tools if task.can_use_agent_tools else task_tools
526
+ rag_tools: Optional[List[RagTool]] = [item for item in all_tools if isinstance(item, RagTool)] if all_tools else None
527
+ tools: Optional[List[Tool | ToolSet | RagTool | Type[BaseTool]]] = [item for item in all_tools if not isinstance(item, RagTool)] if all_tools else None
513
528
 
514
529
  if self.max_rpm and self._rpm_controller:
515
530
  self._rpm_controller._reset_request_count()
@@ -523,6 +538,12 @@ class Agent(BaseModel):
523
538
  if agent_knowledge_context:
524
539
  task_prompt += agent_knowledge_context
525
540
 
541
+ if rag_tools:
542
+ for item in rag_tools:
543
+ rag_tool_context = item.run(agent=self, query=task.description)
544
+ if rag_tool_context:
545
+ task_prompt += ",".join(rag_tool_context) if isinstance(rag_tool_context, list) else str(rag_tool_context)
546
+
526
547
  if self.with_memory == True:
527
548
  contextual_memory = ContextualMemory(
528
549
  memory_config=self.memory_config, stm=self.short_term_memory, ltm=self.long_term_memory, um=self.user_memory
@@ -533,7 +554,6 @@ class Agent(BaseModel):
533
554
  if memory.strip() != "":
534
555
  task_prompt += memory.strip()
535
556
 
536
-
537
557
  ## comment out for now
538
558
  # if self.networks and self.networks._train:
539
559
  # task_prompt = self._training_handler(task_prompt=task_prompt)
@@ -575,7 +595,7 @@ class Agent(BaseModel):
575
595
 
576
596
 
577
597
  def __repr__(self):
578
- return f"Agent(role={self.role}, goal={self.goal}"
598
+ return f"Agent(role={self.role}, id={str(self.id)}"
579
599
 
580
600
  def __str__(self):
581
601
  return super().__str__()
@@ -83,7 +83,8 @@ class DoclingSource(BaseKnowledgeSource):
83
83
  yield chunk.text
84
84
 
85
85
 
86
- def _validate_url(self, url: str) -> bool:
86
+ @staticmethod
87
+ def _validate_url(url: str) -> bool:
87
88
  try:
88
89
  result = urlparse(url)
89
90
  return all(
@@ -125,7 +125,8 @@ class KnowledgeStorage(BaseKnowledgeStorage):
125
125
  def search(self, query: List[str], limit: int = 3, filter: Optional[dict] = None, score_threshold: float = 0.35) -> List[Dict[str, Any]]:
126
126
  with suppress_logging():
127
127
  if self.collection:
128
- fetched = self.collection.query(query_texts=query, n_results=limit, where=filter)
128
+ query_texts = ", ".join(query) if isinstance(query, list) else str(query)
129
+ fetched = self.collection.query(query_texts=query_texts, n_results=limit, where=filter)
129
130
  results = []
130
131
  for i in range(len(fetched["ids"][0])):
131
132
  result = {
@@ -43,7 +43,6 @@ class BaseTool(ABC, BaseModel):
43
43
  { "__annotations__": { k: v for k, v in cls._run.__annotations__.items() if k != "return" }},
44
44
  )
45
45
 
46
-
47
46
  @field_validator("properties", mode="before")
48
47
  @classmethod
49
48
  def _default_properties(cls, v: Dict[str, Any]) -> Dict[str, Any]:
@@ -81,10 +80,9 @@ class BaseTool(ABC, BaseModel):
81
80
  return self
82
81
 
83
82
  @abstractmethod
84
- def _run(self, *args: Any, **kwargs: Any,) -> Any:
83
+ def _run(self, *args: Any, **kwargs: Any) -> Any:
85
84
  """any handling"""
86
85
 
87
-
88
86
  @staticmethod
89
87
  def _get_arg_annotations(annotation: type[Any] | None) -> str:
90
88
  if annotation is None:
@@ -143,11 +141,9 @@ class BaseTool(ABC, BaseModel):
143
141
  return create_model(schema_name, **fields)
144
142
 
145
143
 
146
-
147
144
  class Tool(BaseTool):
148
145
  func: Callable = Field(default=None)
149
146
 
150
-
151
147
  @model_validator(mode="after")
152
148
  def validate_func(self) -> Self:
153
149
  if not self.func and not self._run:
@@ -0,0 +1,112 @@
1
+ import re
2
+ import requests
3
+ import html2text
4
+ import gzip
5
+ import http.client
6
+ import urllib.request
7
+ from urllib.request import Request
8
+ from textwrap import dedent
9
+ from typing import Any, Optional, List, Dict
10
+
11
+ from pydantic import Field
12
+
13
+ from versionhq.agent.model import Agent
14
+ from versionhq.tool.model import BaseTool
15
+ from versionhq._utils.logger import Logger
16
+
17
+
18
+
19
+ class RagTool(BaseTool):
20
+ """A Pydantic class to store a RAG tool object. Inherited from BaseTool"""
21
+
22
+ api_key_name: str = Field(default=None)
23
+ api_endpoint: Optional[str] = Field(default=None)
24
+
25
+ url: Optional[str] = Field(default=None, description="url to scrape")
26
+ headers: Optional[Dict[str, Any]] = Field(default_factory=dict, description="request headers")
27
+
28
+ sources: Optional[List[Any]] = Field(default_factory=list, description="indexed data sources")
29
+ query: Optional[str] = Field(default=None)
30
+ text: Optional[str] = Field(default=None, description="text data source")
31
+
32
+
33
+ def _sanitize_source_code(self, source_code: str | bytes = None) -> str | None:
34
+ if not source_code:
35
+ return None
36
+
37
+ if isinstance(source_code, bytes):
38
+ source_code = source_code.decode('utf-8')
39
+
40
+ h = html2text.HTML2Text()
41
+ h.ignore_links = False
42
+ text = h.handle(source_code)
43
+ text = re.sub(r"[^a-zA-Z$0-9\s\n]", "", text)
44
+ return dedent(text)
45
+
46
+
47
+ def _scrape_url(self, url: str = None) -> str | None:
48
+ url = url if url else self.url
49
+
50
+ if not url:
51
+ return None
52
+
53
+ http.client.HTTPConnection.debuglevel = 1
54
+
55
+ try:
56
+ req = Request(url=url, headers=self.headers, origin_req_host=url, method="GET")
57
+ res = ""
58
+
59
+ with urllib.request.urlopen(req) as url:
60
+ if url.info().get("Content-Encoding") == "gzip":
61
+ res = gzip.decompress(url.read())
62
+ else:
63
+ res = url.read()
64
+
65
+ text = self._sanitize_source_code(source_code=res)
66
+ return text
67
+
68
+ except requests.exceptions.HTTPError as e:
69
+ Logger().log(level="error", message=f"HTTP error occurred: {str(e)}", color="red")
70
+ return None
71
+
72
+ except Exception as e:
73
+ Logger().log(level="error", message=f"Error fetching URL {self.api_endpoint}: {str(e)}", color="red")
74
+ return None
75
+
76
+
77
+ def store_data(self, agent: Agent = None) -> None:
78
+ """Stores retrieved data in the storage"""
79
+ if not agent:
80
+ return
81
+
82
+ text = self.text if self.text else self._scrape_url(self.url)
83
+ self.text = text
84
+ knowledge_sources = [*agent.knowledge_sources, str(text), ] if agent.knowledge_sources else [str(text),]
85
+ agent.update(knowledge_sources=knowledge_sources)
86
+
87
+
88
+ def _run(self, agent: Agent = None, query: str = None) -> List[str]:
89
+ query = query if query else self.query
90
+
91
+ if not query or not agent:
92
+ text = self.text if self.text else self._scrape_url(self.url)
93
+ self.text = text
94
+ return [text,]
95
+
96
+ else:
97
+ results, res = [], []
98
+ if agent._knowledge:
99
+ res = agent._knowledge.query(query=[query], limit=5)
100
+ else:
101
+ self.store_data(agent=agent)
102
+ res = agent._knowledge.query(query=[query], limit=5)
103
+
104
+ for item in res:
105
+ if isinstance(item, dict):
106
+ results.append(item["context"])
107
+ else:
108
+ results.append(str(item))
109
+ return results
110
+
111
+ def run(self, *args, **kwargs):
112
+ return self._run(*args, **kwargs)