lionagi 0.9.3__tar.gz → 0.9.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 (270) hide show
  1. {lionagi-0.9.3 → lionagi-0.9.5}/PKG-INFO +1 -1
  2. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/process.py +7 -1
  3. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/save.py +1 -0
  4. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/ReAct/ReAct.py +35 -1
  5. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/ReAct/utils.py +5 -2
  6. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/chat/chat.py +7 -5
  7. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/communicate/communicate.py +2 -0
  8. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/interpret/interpret.py +2 -1
  9. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/operate/operate.py +2 -0
  10. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/base.py +26 -0
  11. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/imodel.py +14 -3
  12. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/openai_/chat_completions.py +2 -0
  13. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/session/branch.py +16 -0
  14. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/reader.py +72 -22
  15. lionagi-0.9.5/lionagi/tools/query/__init__.py +3 -0
  16. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/utils.py +6 -5
  17. lionagi-0.9.5/lionagi/version.py +1 -0
  18. {lionagi-0.9.3 → lionagi-0.9.5}/pyproject.toml +1 -1
  19. {lionagi-0.9.3 → lionagi-0.9.5}/uv.lock +1 -1
  20. lionagi-0.9.3/lionagi/version.py +0 -1
  21. {lionagi-0.9.3 → lionagi-0.9.5}/.env.example +0 -0
  22. {lionagi-0.9.3 → lionagi-0.9.5}/.github/FUNDING.yml +0 -0
  23. {lionagi-0.9.3 → lionagi-0.9.5}/.github/dependabot.yml +0 -0
  24. {lionagi-0.9.3 → lionagi-0.9.5}/.github/workflows/ci.yml +0 -0
  25. {lionagi-0.9.3 → lionagi-0.9.5}/.github/workflows/codeql.yml +0 -0
  26. {lionagi-0.9.3 → lionagi-0.9.5}/.github/workflows/docs.yml +0 -0
  27. {lionagi-0.9.3 → lionagi-0.9.5}/.github/workflows/release.yml +0 -0
  28. {lionagi-0.9.3 → lionagi-0.9.5}/.gitignore +0 -0
  29. {lionagi-0.9.3 → lionagi-0.9.5}/.pre-commit-config.yaml +0 -0
  30. {lionagi-0.9.3 → lionagi-0.9.5}/CODE_OF_CONDUCT.md +0 -0
  31. {lionagi-0.9.3 → lionagi-0.9.5}/CONTRIBUTING.md +0 -0
  32. {lionagi-0.9.3 → lionagi-0.9.5}/LICENSE +0 -0
  33. {lionagi-0.9.3 → lionagi-0.9.5}/README.md +0 -0
  34. {lionagi-0.9.3 → lionagi-0.9.5}/cookbooks/ch01_get_started.md +0 -0
  35. {lionagi-0.9.3 → lionagi-0.9.5}/cookbooks/ch02_concepts.md +0 -0
  36. {lionagi-0.9.3 → lionagi-0.9.5}/dev_tools/count_code_base_lines.py +0 -0
  37. {lionagi-0.9.3 → lionagi-0.9.5}/docs/Makefile +0 -0
  38. {lionagi-0.9.3 → lionagi-0.9.5}/docs/_static/custom.css +0 -0
  39. {lionagi-0.9.3 → lionagi-0.9.5}/docs/_templates/layout.html +0 -0
  40. {lionagi-0.9.3 → lionagi-0.9.5}/docs/conf.py +0 -0
  41. {lionagi-0.9.3 → lionagi-0.9.5}/docs/index.rst +0 -0
  42. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/action.rst +0 -0
  43. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/adapter.rst +0 -0
  44. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/branch.rst +0 -0
  45. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/branch_operations.rst +0 -0
  46. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/concepts.rst +0 -0
  47. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/element_id.rst +0 -0
  48. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/event.rst +0 -0
  49. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/form.rst +0 -0
  50. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/graph.rst +0 -0
  51. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/index.rst +0 -0
  52. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/instruct.rst +0 -0
  53. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/lib_file.rst +0 -0
  54. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/lib_nested.rst +0 -0
  55. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/lib_package.rst +0 -0
  56. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/lib_schema.rst +0 -0
  57. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/lib_validate.rst +0 -0
  58. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/log.rst +0 -0
  59. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/mail.rst +0 -0
  60. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/message.rst +0 -0
  61. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/models.rst +0 -0
  62. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/operative_step.rst +0 -0
  63. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/pile.rst +0 -0
  64. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/processor.rst +0 -0
  65. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/progression.rst +0 -0
  66. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/service.rst +0 -0
  67. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/session.rst +0 -0
  68. {lionagi-0.9.3 → lionagi-0.9.5}/docs/modules/utils.rst +0 -0
  69. {lionagi-0.9.3 → lionagi-0.9.5}/docs/tutorials/get_started.rst +0 -0
  70. {lionagi-0.9.3 → lionagi-0.9.5}/docs/tutorials/get_started_pt2.rst +0 -0
  71. {lionagi-0.9.3 → lionagi-0.9.5}/docs/tutorials/get_started_pt3.rst +0 -0
  72. {lionagi-0.9.3 → lionagi-0.9.5}/docs/tutorials/index.rst +0 -0
  73. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/__init__.py +0 -0
  74. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/_class_registry.py +0 -0
  75. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/_errors.py +0 -0
  76. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/_types.py +0 -0
  77. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/__init__.py +0 -0
  78. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/__init__.py +0 -0
  79. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/chunk.py +0 -0
  80. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/file_ops.py +0 -0
  81. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/file/params.py +0 -0
  82. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/__init__.py +0 -0
  83. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/flatten.py +0 -0
  84. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/nfilter.py +0 -0
  85. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/nget.py +0 -0
  86. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/ninsert.py +0 -0
  87. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/nmerge.py +0 -0
  88. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/npop.py +0 -0
  89. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/nset.py +0 -0
  90. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/unflatten.py +0 -0
  91. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/nested/utils.py +0 -0
  92. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/package/__init__.py +0 -0
  93. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/package/imports.py +0 -0
  94. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/package/management.py +0 -0
  95. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/package/params.py +0 -0
  96. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/package/system.py +0 -0
  97. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/parse.py +0 -0
  98. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/__init__.py +0 -0
  99. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/as_readable.py +0 -0
  100. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/extract_code_block.py +0 -0
  101. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/extract_docstring.py +0 -0
  102. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/function_to_schema.py +0 -0
  103. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/schema/json_schema.py +0 -0
  104. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/token_transform/__init__.py +0 -0
  105. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/token_transform/llmlingua.py +0 -0
  106. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/token_transform/perplexity.py +0 -0
  107. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/token_transform/synthlang.py +0 -0
  108. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/__init__.py +0 -0
  109. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/common_field_validators.py +0 -0
  110. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/fuzzy_match_keys.py +0 -0
  111. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/fuzzy_validate_mapping.py +0 -0
  112. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/string_similarity.py +0 -0
  113. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/libs/validate/validate_boolean.py +0 -0
  114. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/ReAct/__init__.py +0 -0
  115. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/__init__.py +0 -0
  116. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/_act/__init__.py +0 -0
  117. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/_act/act.py +0 -0
  118. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/brainstorm/__init__.py +0 -0
  119. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/brainstorm/brainstorm.py +0 -0
  120. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/brainstorm/prompt.py +0 -0
  121. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/chat/__init__.py +0 -0
  122. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/communicate/__init__.py +0 -0
  123. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/instruct/__init__.py +0 -0
  124. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/instruct/instruct.py +0 -0
  125. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/interpret/__init__.py +0 -0
  126. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/manager.py +0 -0
  127. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/operate/__init__.py +0 -0
  128. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/parse/__init__.py +0 -0
  129. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/parse/parse.py +0 -0
  130. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/plan/__init__.py +0 -0
  131. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/plan/plan.py +0 -0
  132. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/plan/prompt.py +0 -0
  133. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/select/__init__.py +0 -0
  134. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/select/select.py +0 -0
  135. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/select/utils.py +0 -0
  136. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/translate/__init__.py +0 -0
  137. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/translate/translate.py +0 -0
  138. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/types.py +0 -0
  139. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operations/utils.py +0 -0
  140. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/__init__.py +0 -0
  141. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/__init__.py +0 -0
  142. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/function_calling.py +0 -0
  143. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/manager.py +0 -0
  144. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/request_response_model.py +0 -0
  145. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/tool.py +0 -0
  146. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/action/utils.py +0 -0
  147. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/forms/__init__.py +0 -0
  148. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/forms/base.py +0 -0
  149. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/forms/flow.py +0 -0
  150. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/forms/form.py +0 -0
  151. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/forms/report.py +0 -0
  152. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/__init__.py +0 -0
  153. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/base.py +0 -0
  154. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/instruct.py +0 -0
  155. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/instruct_collection.py +0 -0
  156. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/node.py +0 -0
  157. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/prompts.py +0 -0
  158. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/instruct/reason.py +0 -0
  159. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/manager.py +0 -0
  160. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/__init__.py +0 -0
  161. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/field_model.py +0 -0
  162. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/model_params.py +0 -0
  163. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/note.py +0 -0
  164. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/operable_model.py +0 -0
  165. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/models/schema_model.py +0 -0
  166. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/operative.py +0 -0
  167. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/step.py +0 -0
  168. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/__init__.py +0 -0
  169. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/base.py +0 -0
  170. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/concurrent.py +0 -0
  171. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/concurrent_chunk.py +0 -0
  172. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/concurrent_sequential_chunk.py +0 -0
  173. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/params.py +0 -0
  174. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/sequential.py +0 -0
  175. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/sequential_chunk.py +0 -0
  176. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/sequential_concurrent_chunk.py +0 -0
  177. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/strategies/utils.py +0 -0
  178. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/operatives/types.py +0 -0
  179. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/__init__.py +0 -0
  180. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/_concepts.py +0 -0
  181. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/__init__.py +0 -0
  182. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/adapter.py +0 -0
  183. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/json_adapter.py +0 -0
  184. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/pandas_/__init__.py +0 -0
  185. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/pandas_/csv_adapter.py +0 -0
  186. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/pandas_/excel_adapter.py +0 -0
  187. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +0 -0
  188. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/pandas_/pd_series_adapter.py +0 -0
  189. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/adapters/types.py +0 -0
  190. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/__init__.py +0 -0
  191. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/element.py +0 -0
  192. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/event.py +0 -0
  193. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/log.py +0 -0
  194. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/pile.py +0 -0
  195. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/processor.py +0 -0
  196. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/generic/progression.py +0 -0
  197. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/graph/__init__.py +0 -0
  198. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/graph/edge.py +0 -0
  199. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/graph/graph.py +0 -0
  200. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/graph/node.py +0 -0
  201. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/__init__.py +0 -0
  202. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/exchange.py +0 -0
  203. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/mail.py +0 -0
  204. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/mailbox.py +0 -0
  205. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/manager.py +0 -0
  206. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/mail/package.py +0 -0
  207. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/__init__.py +0 -0
  208. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/action_request.py +0 -0
  209. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/action_response.py +0 -0
  210. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/assistant_response.py +0 -0
  211. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/base.py +0 -0
  212. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/instruction.py +0 -0
  213. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/manager.py +0 -0
  214. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/message.py +0 -0
  215. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/system.py +0 -0
  216. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/README.md +0 -0
  217. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/action_request.jinja2 +0 -0
  218. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/action_response.jinja2 +0 -0
  219. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/assistant_response.jinja2 +0 -0
  220. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/instruction_message.jinja2 +0 -0
  221. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/system_message.jinja2 +0 -0
  222. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/messages/templates/tool_schemas.jinja2 +0 -0
  223. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/protocols/types.py +0 -0
  224. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/__init__.py +0 -0
  225. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/__init__.py +0 -0
  226. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/chat_completion.py +0 -0
  227. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/match_endpoint.py +0 -0
  228. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/rate_limited_processor.py +0 -0
  229. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/endpoints/token_calculator.py +0 -0
  230. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/manager.py +0 -0
  231. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/__init__.py +0 -0
  232. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/anthropic_/__init__.py +0 -0
  233. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/anthropic_/messages.py +0 -0
  234. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/exa_/__init__.py +0 -0
  235. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/exa_/models.py +0 -0
  236. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/exa_/search.py +0 -0
  237. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/exa_/types.py +0 -0
  238. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/groq_/__init__.py +0 -0
  239. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/groq_/chat_completions.py +0 -0
  240. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/openai_/__init__.py +0 -0
  241. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/openrouter_/__init__.py +0 -0
  242. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/openrouter_/chat_completions.py +0 -0
  243. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/perplexity_/__init__.py +0 -0
  244. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/perplexity_/chat_completions.py +0 -0
  245. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/perplexity_/models.py +0 -0
  246. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/providers/types.py +0 -0
  247. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/service/types.py +0 -0
  248. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/session/__init__.py +0 -0
  249. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/session/prompts.py +0 -0
  250. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/session/session.py +0 -0
  251. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/settings.py +0 -0
  252. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/__init__.py +0 -0
  253. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/base.py +0 -0
  254. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/browser/__init__.py +0 -0
  255. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/browser/providers/__init__.py +0 -0
  256. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/browser/providers/browser_use_.py +0 -0
  257. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/__init__.py +0 -0
  258. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/coder.py +0 -0
  259. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/manager.py +0 -0
  260. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/providers/__init__.py +0 -0
  261. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/providers/aider_.py +0 -0
  262. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/providers/e2b_.py +0 -0
  263. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/code/sandbox.py +0 -0
  264. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/__init__.py +0 -0
  265. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/manager.py +0 -0
  266. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/providers/__init__.py +0 -0
  267. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/providers/docling_.py +0 -0
  268. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/file/writer.py +0 -0
  269. {lionagi-0.9.3 → lionagi-0.9.5}/lionagi/tools/types.py +0 -0
  270. {lionagi-0.9.3 → lionagi-0.9.5}/prompts/doc_style.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lionagi
3
- Version: 0.9.3
3
+ Version: 0.9.5
4
4
  Summary: An Intelligence Operating System.
5
5
  Author-email: HaiyangLi <quantocean.li@gmail.com>
6
6
  License: Apache License
@@ -18,6 +18,7 @@ def dir_to_files(
18
18
  max_workers: int | None = None,
19
19
  ignore_errors: bool = False,
20
20
  verbose: bool = False,
21
+ recursive: bool = False,
21
22
  ) -> list[Path]:
22
23
  """
23
24
  Recursively process a directory and return a list of file paths.
@@ -33,6 +34,8 @@ def dir_to_files(
33
34
  If None, uses the default ThreadPoolExecutor behavior.
34
35
  ignore_errors (bool): If True, log warnings for errors instead of raising exceptions.
35
36
  verbose (bool): If True, print verbose output.
37
+ recursive (bool): If True, process directories recursively (the default).
38
+ If False, only process files in the top-level directory.
36
39
 
37
40
  Returns:
38
41
  List[Path]: A list of Path objects representing the files found.
@@ -58,11 +61,14 @@ def dir_to_files(
58
61
  raise ValueError(f"Error processing {file_path}: {e}") from e
59
62
  return None
60
63
 
64
+ file_iterator = (
65
+ directory_path.rglob("*") if recursive else directory_path.glob("*")
66
+ )
61
67
  try:
62
68
  with ThreadPoolExecutor(max_workers=max_workers) as executor:
63
69
  futures = [
64
70
  executor.submit(process_file, f)
65
- for f in directory_path.rglob("*")
71
+ for f in file_iterator
66
72
  if f.is_file()
67
73
  ]
68
74
  files = [
@@ -60,6 +60,7 @@ def save_to_file(
60
60
  )
61
61
  with file_path.open("w", encoding="utf-8") as file:
62
62
  file.write(text)
63
+ file.close()
63
64
  if verbose:
64
65
  logging.info(f"Text saved to: {file_path}")
65
66
  return file_path
@@ -47,6 +47,8 @@ async def ReAct(
47
47
  analysis_model: iModel | None = None,
48
48
  verbose_analysis: bool = False,
49
49
  verbose_length: int = None,
50
+ include_token_usage_to_model: bool = True,
51
+ continue_after_failed_response: bool = False,
50
52
  **kwargs,
51
53
  ):
52
54
  outs = []
@@ -73,6 +75,8 @@ async def ReAct(
73
75
  verbose_analysis=verbose_analysis,
74
76
  display_as=display_as,
75
77
  verbose_length=verbose_length,
78
+ include_token_usage_to_model=include_token_usage_to_model,
79
+ continue_after_failed_response=continue_after_failed_response,
76
80
  **kwargs,
77
81
  ):
78
82
  analysis, str_ = i
@@ -101,6 +105,8 @@ async def ReAct(
101
105
  analysis_model=analysis_model,
102
106
  display_as=display_as,
103
107
  verbose_length=verbose_length,
108
+ include_token_usage_to_model=include_token_usage_to_model,
109
+ continue_after_failed_response=continue_after_failed_response,
104
110
  **kwargs,
105
111
  ):
106
112
  outs.append(i)
@@ -131,6 +137,8 @@ async def ReActStream(
131
137
  verbose_analysis: bool = False,
132
138
  display_as: Literal["json", "yaml"] = "yaml",
133
139
  verbose_length: int = None,
140
+ include_token_usage_to_model: bool = True,
141
+ continue_after_failed_response: bool = False,
134
142
  **kwargs,
135
143
  ) -> AsyncGenerator:
136
144
  irfm: FieldModel | None = None
@@ -213,6 +221,9 @@ async def ReActStream(
213
221
  kwargs_for_operate = copy(kwargs)
214
222
  kwargs_for_operate["actions"] = True
215
223
  kwargs_for_operate["reason"] = True
224
+ kwargs_for_operate["include_token_usage_to_model"] = (
225
+ include_token_usage_to_model
226
+ )
216
227
 
217
228
  # Step 1: Generate initial ReAct analysis
218
229
  analysis: ReActAnalysis = await branch.operate(
@@ -255,7 +266,7 @@ async def ReActStream(
255
266
  if isinstance(analysis, dict)
256
267
  else False
257
268
  )
258
- and (extensions if max_extensions else 0) > 0
269
+ and (extensions - 1 if max_extensions else 0) > 0
259
270
  ):
260
271
  new_instruction = None
261
272
  if extensions == max_extensions:
@@ -272,6 +283,9 @@ async def ReActStream(
272
283
  operate_kwargs["reason"] = True
273
284
  operate_kwargs["response_format"] = ReActAnalysis
274
285
  operate_kwargs["action_strategy"] = analysis.action_strategy
286
+ operate_kwargs["include_token_usage_to_model"] = (
287
+ include_token_usage_to_model
288
+ )
275
289
  if analysis.action_batch_size:
276
290
  operate_kwargs["action_batch_size"] = analysis.action_batch_size
277
291
  if irfm:
@@ -289,6 +303,7 @@ async def ReActStream(
289
303
  operate_kwargs["guidance"] = guide + operate_kwargs.get(
290
304
  "guidance", ""
291
305
  )
306
+ operate_kwargs["reasoning_effort"] = reasoning_effort
292
307
 
293
308
  analysis = await branch.operate(
294
309
  instruction=new_instruction,
@@ -298,6 +313,16 @@ async def ReActStream(
298
313
  )
299
314
  round_count += 1
300
315
 
316
+ if isinstance(analysis, dict) and all(
317
+ i is None for i in analysis.values()
318
+ ):
319
+ if not continue_after_failed_response:
320
+ raise ValueError(
321
+ "All values in the response are None. "
322
+ "This might be due to a failed response. "
323
+ "Set `continue_after_failed_response=True` to ignore this error."
324
+ )
325
+
301
326
  # If verbose, show round analysis
302
327
  if verbose_analysis:
303
328
  str_ = f"\n### ReAct Round No.{round_count} Analysis:\n"
@@ -329,6 +354,15 @@ async def ReActStream(
329
354
  response_format=response_format,
330
355
  **(response_kwargs or {}),
331
356
  )
357
+ if isinstance(analysis, dict) and all(
358
+ i is None for i in analysis.values()
359
+ ):
360
+ if not continue_after_failed_response:
361
+ raise ValueError(
362
+ "All values in the response are None. "
363
+ "This might be due to a failed response. "
364
+ "Set `continue_after_failed_response=True` to ignore this error."
365
+ )
332
366
  except Exception:
333
367
  out = branch.msgs.last_response.response
334
368
 
@@ -30,6 +30,8 @@ class ReActAnalysis(BaseModel):
30
30
  2) A list of planned actions to perform before finalizing,
31
31
  3) Indication whether more expansions/rounds are needed,
32
32
  4) Additional tuning knobs: how to handle validation, how to execute actions, etc.
33
+ Remember do not repeat yourself, and aim to use the most efficient way to achieve
34
+ the goal to user's satisfaction.
33
35
  """
34
36
 
35
37
  # Standard ReAct strings for controlling expansions:
@@ -38,11 +40,12 @@ class ReActAnalysis(BaseModel):
38
40
  "If you are not ready to finalize, set extension_needed to True. "
39
41
  "hint: you should set extension_needed to True if the overall goal"
40
42
  "is not yet achieved. Do not set it to False, if you are just providing"
41
- "an interim answer. You have up to {extensions} expansions. Please continue."
43
+ "an interim answer. You have up to {extensions} expansions. Please "
44
+ "strategize accordingly and continue."
42
45
  )
43
46
  CONTINUE_EXT_PROMPT: ClassVar[str] = (
44
47
  "Another round is available. You may do multiple actions if needed. "
45
- "You have up to {extensions} expansions. Please continue."
48
+ "You have up to {extensions} expansions. Please strategize accordingly and continue."
46
49
  )
47
50
  ANSWER_PROMPT: ClassVar[str] = (
48
51
  "Given your reasoning and actions, please now provide the final answer "
@@ -36,6 +36,7 @@ async def chat(
36
36
  image_detail: Literal["low", "high", "auto"] = None,
37
37
  plain_content: str = None,
38
38
  return_ins_res_message: bool = False,
39
+ include_token_usage_to_model: bool = False,
39
40
  **kwargs,
40
41
  ) -> tuple[Instruction, AssistantResponse]:
41
42
  ins: Instruction = branch.msgs.create_instruction(
@@ -151,11 +152,12 @@ async def chat(
151
152
  kwargs["messages"] = [i.chat_msg for i in messages]
152
153
  imodel = imodel or branch.chat_model
153
154
 
154
- meth = (
155
- imodel.invoke
156
- if ("stream" not in kwargs or not kwargs["stream"])
157
- else imodel.stream
158
- )
155
+ meth = imodel.invoke
156
+ if "stream" not in kwargs or not kwargs["stream"]:
157
+ kwargs["include_token_usage_to_model"] = include_token_usage_to_model
158
+ else:
159
+ meth = imodel.stream
160
+
159
161
  api_call = await meth(**kwargs)
160
162
  branch._log_manager.log(Log.create(api_call))
161
163
 
@@ -35,6 +35,7 @@ async def communicate(
35
35
  fuzzy_match_kwargs=None,
36
36
  clear_messages=False,
37
37
  operative_model=None,
38
+ include_token_usage_to_model: bool = False,
38
39
  **kwargs,
39
40
  ):
40
41
  if operative_model:
@@ -80,6 +81,7 @@ async def communicate(
80
81
  image_detail=image_detail,
81
82
  plain_content=plain_content,
82
83
  return_ins_res_message=True,
84
+ include_token_usage_to_model=include_token_usage_to_model,
83
85
  **kwargs,
84
86
  )
85
87
  branch.msgs.add_message(instruction=ins)
@@ -20,7 +20,8 @@ async def interpret(
20
20
  instruction = (
21
21
  "You are given a user's raw instruction or question. Your task is to rewrite it into a clearer,"
22
22
  "more structured prompt for an LLM or system, making any implicit or missing details explicit. "
23
- "Return only the re-written prompt."
23
+ "Return only the re-written prompt. Do not assume any details not mentioned in the input, nor "
24
+ "give additional instruction than what is explicitly stated."
24
25
  )
25
26
  guidance = (
26
27
  f"Domain hint: {domain or 'general'}. "
@@ -63,6 +63,7 @@ async def operate(
63
63
  ] = "return_value",
64
64
  operative_model: type[BaseModel] = None,
65
65
  request_model: type[BaseModel] = None,
66
+ include_token_usage_to_model: bool = False,
66
67
  **kwargs,
67
68
  ) -> list | BaseModel | None | dict | str:
68
69
  if operative_model:
@@ -138,6 +139,7 @@ async def operate(
138
139
  image_detail=image_detail,
139
140
  tool_schemas=tool_schemas,
140
141
  return_ins_res_message=True,
142
+ include_token_usage_to_model=include_token_usage_to_model,
141
143
  **kwargs,
142
144
  )
143
145
  branch.msgs.add_message(instruction=ins)
@@ -349,11 +349,37 @@ class APICalling(Event):
349
349
  endpoint: EndPoint = Field(exclude=True)
350
350
  is_cached: bool = Field(default=False, exclude=True)
351
351
  should_invoke_endpoint: bool = Field(default=True, exclude=True)
352
+ include_token_usage_to_model: bool = Field(
353
+ default=False,
354
+ exclude=True,
355
+ description="Whether to include token usage information into instruction messages",
356
+ )
352
357
 
353
358
  @model_validator(mode="after")
354
359
  def _validate_streaming(self) -> Self:
355
360
  if self.payload.get("stream") is True:
356
361
  self.streaming = True
362
+
363
+ if self.include_token_usage_to_model:
364
+ if isinstance(self.payload["messages"][-1], dict):
365
+ required_tokens = self.required_tokens
366
+ self.payload["messages"][-1][
367
+ "content"
368
+ ] += f"\n\nEstimated Current Token Usage: {required_tokens}"
369
+ if "model" in self.payload:
370
+ if (
371
+ self.payload["model"].startswith("gpt-4")
372
+ or "o1mini" in self.payload["model"]
373
+ or "o1-preview" in self.payload["model"]
374
+ ):
375
+ self.payload["messages"][-1]["content"] += "/128_000"
376
+ elif "o1" in self.payload["model"]:
377
+ self.payload["messages"][-1]["content"] += "/200_000"
378
+ elif "sonnet" in self.payload["model"]:
379
+ self.payload["messages"][-1]["content"] += "/200_000"
380
+ elif "haiku" in self.payload["model"]:
381
+ self.payload["messages"][-1]["content"] += "/200_000"
382
+
357
383
  return self
358
384
 
359
385
  @property
@@ -162,7 +162,9 @@ class iModel:
162
162
  else:
163
163
  self.streaming_process_func = streaming_process_func
164
164
 
165
- def create_api_calling(self, **kwargs) -> APICalling:
165
+ def create_api_calling(
166
+ self, include_token_usage_to_model: bool = False, **kwargs
167
+ ) -> APICalling:
166
168
  """Constructs an `APICalling` object from endpoint-specific payload.
167
169
 
168
170
  Args:
@@ -183,6 +185,7 @@ class iModel:
183
185
  endpoint=self.endpoint,
184
186
  is_cached=payload.get("is_cached", False),
185
187
  should_invoke_endpoint=self.should_invoke_endpoint,
188
+ include_token_usage_to_model=include_token_usage_to_model,
186
189
  )
187
190
 
188
191
  async def process_chunk(self, chunk) -> None:
@@ -200,7 +203,12 @@ class iModel:
200
203
  return await self.streaming_process_func(chunk)
201
204
  return self.streaming_process_func(chunk)
202
205
 
203
- async def stream(self, api_call=None, **kwargs) -> AsyncGenerator:
206
+ async def stream(
207
+ self,
208
+ api_call=None,
209
+ include_token_usage_to_model: bool = False,
210
+ **kwargs,
211
+ ) -> AsyncGenerator:
204
212
  """Performs a streaming API call with the given arguments.
205
213
 
206
214
  Args:
@@ -214,7 +222,10 @@ class iModel:
214
222
  """
215
223
  if api_call is None:
216
224
  kwargs["stream"] = True
217
- api_call = self.create_api_calling(**kwargs)
225
+ api_call = self.create_api_calling(
226
+ include_token_usage_to_model=include_token_usage_to_model,
227
+ **kwargs,
228
+ )
218
229
  await self.executor.append(api_call)
219
230
 
220
231
  if (
@@ -89,6 +89,8 @@ class OpenAIChatCompletionEndPoint(ChatCompletionEndPoint):
89
89
  payload.pop("top_p", None)
90
90
  if payload["messages"][0].get("role") == "system":
91
91
  payload["messages"][0]["role"] = "developer"
92
+ else:
93
+ payload.pop("reasoning_effort", None)
92
94
 
93
95
  return {
94
96
  "payload": payload,
@@ -941,6 +941,7 @@ class Branch(Element, Communicatable, Relational):
941
941
  ] = "return_value",
942
942
  operative_model: type[BaseModel] = None,
943
943
  request_model: type[BaseModel] = None,
944
+ include_token_usage_to_model: bool = False,
944
945
  **kwargs,
945
946
  ) -> list | BaseModel | None | dict | str:
946
947
  """
@@ -1028,6 +1029,8 @@ class Branch(Element, Communicatable, Relational):
1028
1029
  Alias for `response_format`.
1029
1030
  request_model (type[BaseModel], optional):
1030
1031
  Another alias for `response_format`.
1032
+ include_token_usage_to_model:
1033
+ If `True`, includes token usage in the model messages.
1031
1034
  **kwargs:
1032
1035
  Additional keyword arguments passed to the LLM via `branch.chat()`.
1033
1036
 
@@ -1080,6 +1083,7 @@ class Branch(Element, Communicatable, Relational):
1080
1083
  operative_model=operative_model,
1081
1084
  request_model=request_model,
1082
1085
  imodel=imodel,
1086
+ include_token_usage_to_model=include_token_usage_to_model,
1083
1087
  **kwargs,
1084
1088
  )
1085
1089
 
@@ -1106,6 +1110,7 @@ class Branch(Element, Communicatable, Relational):
1106
1110
  fuzzy_match_kwargs: dict = None,
1107
1111
  clear_messages: bool = False,
1108
1112
  operative_model: type[BaseModel] = None,
1113
+ include_token_usage_to_model: bool = False,
1109
1114
  **kwargs,
1110
1115
  ):
1111
1116
  """
@@ -1190,6 +1195,7 @@ class Branch(Element, Communicatable, Relational):
1190
1195
  fuzzy_match_kwargs=fuzzy_match_kwargs,
1191
1196
  clear_messages=clear_messages,
1192
1197
  operative_model=operative_model,
1198
+ include_token_usage_to_model=include_token_usage_to_model,
1193
1199
  **kwargs,
1194
1200
  )
1195
1201
 
@@ -1639,6 +1645,7 @@ class Branch(Element, Communicatable, Relational):
1639
1645
  analysis_model: iModel | None = None,
1640
1646
  verbose: bool = False,
1641
1647
  verbose_length: int = None,
1648
+ include_token_usage_to_model: bool = True,
1642
1649
  **kwargs,
1643
1650
  ):
1644
1651
  """
@@ -1688,6 +1695,12 @@ class Branch(Element, Communicatable, Relational):
1688
1695
  analysis_model (iModel | None, optional):
1689
1696
  A custom LLM model for generating the ReAct analysis steps. If `None`,
1690
1697
  uses the branch's default `chat_model`.
1698
+ include_token_usage_to_model:
1699
+ If `True`, includes token usage in the model messages.
1700
+ verbose (bool):
1701
+ If `True`, logs detailed information about the process.
1702
+ verbose_length (int):
1703
+ If `verbose=True`, limits the length of logged strings to this value.
1691
1704
  **kwargs:
1692
1705
  Additional keyword arguments passed into the initial `branch.operate()` call.
1693
1706
 
@@ -1733,6 +1746,7 @@ class Branch(Element, Communicatable, Relational):
1733
1746
  intermediate_listable=intermediate_listable,
1734
1747
  reasoning_effort=reasoning_effort,
1735
1748
  display_as=display_as,
1749
+ include_token_usage_to_model=include_token_usage_to_model,
1736
1750
  **kwargs,
1737
1751
  )
1738
1752
 
@@ -1758,6 +1772,7 @@ class Branch(Element, Communicatable, Relational):
1758
1772
  verbose: bool = False,
1759
1773
  display_as: Literal["json", "yaml"] = "yaml",
1760
1774
  verbose_length: int = None,
1775
+ include_token_usage_to_model: bool = True,
1761
1776
  **kwargs,
1762
1777
  ) -> AsyncGenerator:
1763
1778
  from lionagi.operations.ReAct.ReAct import ReActStream
@@ -1784,6 +1799,7 @@ class Branch(Element, Communicatable, Relational):
1784
1799
  verbose_analysis=True,
1785
1800
  display_as=display_as,
1786
1801
  verbose_length=verbose_length,
1802
+ include_token_usage_to_model=include_token_usage_to_model,
1787
1803
  **kwargs,
1788
1804
  ):
1789
1805
  analysis, str_ = result
@@ -8,6 +8,7 @@ from enum import Enum
8
8
  from pydantic import BaseModel, Field, model_validator
9
9
 
10
10
  from lionagi.operatives.action.tool import Tool
11
+ from lionagi.service.endpoints.token_calculator import TokenCalculator
11
12
  from lionagi.utils import to_num
12
13
 
13
14
  from ..base import LionTool
@@ -18,10 +19,12 @@ class ReaderAction(str, Enum):
18
19
  This enumeration indicates the *type* of action the LLM wants to perform.
19
20
  - 'open': Convert a file/URL to text and store it internally for partial reads
20
21
  - 'read': Return a partial slice of the already-opened doc
22
+ - 'list_dir': List all files in a directory and store it internally for partial reads
21
23
  """
22
24
 
23
25
  open = "open"
24
26
  read = "read"
27
+ list_dir = "list_dir"
25
28
 
26
29
 
27
30
  class ReaderRequest(BaseModel):
@@ -39,6 +42,7 @@ class ReaderRequest(BaseModel):
39
42
  "Action to perform. Must be one of: "
40
43
  "- 'open': Convert a file/URL to text and store it internally for partial reads. "
41
44
  "- 'read': Return a partial slice of the already-opened doc."
45
+ "- 'list_dir': List all files in a directory."
42
46
  ),
43
47
  )
44
48
 
@@ -54,7 +58,8 @@ class ReaderRequest(BaseModel):
54
58
  None,
55
59
  description=(
56
60
  "Unique ID referencing a previously opened document. "
57
- "This field is REQUIRED if action='read'. If action='open', leave it None."
61
+ "This field is REQUIRED if action='read'. Else leave it None."
62
+ "this field starts with 'DOC_' for document and 'DIR_' for directory listing."
58
63
  ),
59
64
  )
60
65
 
@@ -74,6 +79,22 @@ class ReaderRequest(BaseModel):
74
79
  ),
75
80
  )
76
81
 
82
+ recursive: bool = Field(
83
+ False,
84
+ description=(
85
+ "Whether to recursively list files in subdirectories. Defaults to False."
86
+ "Only used if action='list_dir'."
87
+ ),
88
+ )
89
+
90
+ file_types: list[str] | None = Field(
91
+ None,
92
+ description=(
93
+ "List files with specific extensions. "
94
+ "If omitted or None, list all files. Only used if action='list_dir'."
95
+ ),
96
+ )
97
+
77
98
  @model_validator(mode="before")
78
99
  def _validate_request(cls, values):
79
100
  for k, v in values.items():
@@ -96,6 +117,7 @@ class DocumentInfo(BaseModel):
96
117
 
97
118
  doc_id: str
98
119
  length: int | None = None
120
+ num_tokens: int | None = None
99
121
 
100
122
 
101
123
  class PartialChunk(BaseModel):
@@ -150,17 +172,17 @@ class ReaderTool(LionTool):
150
172
  is_lion_system_tool = True
151
173
  system_tool_name = "reader_tool"
152
174
 
153
- from lionagi.libs.package.imports import check_import
175
+ def __init__(self):
176
+ from lionagi.libs.package.imports import check_import
154
177
 
155
- DocumentConverter = check_import(
156
- "docling",
157
- module_name="document_converter",
158
- import_name="DocumentConverter",
159
- )
178
+ DocumentConverter = check_import(
179
+ "docling",
180
+ module_name="document_converter",
181
+ import_name="DocumentConverter",
182
+ )
160
183
 
161
- def __init__(self):
162
184
  super().__init__()
163
- self.converter = ReaderTool.DocumentConverter()
185
+ self.converter = DocumentConverter()
164
186
  self.documents = {} # doc_id -> (temp_file_path, doc_length)
165
187
  self._tool = None
166
188
 
@@ -174,23 +196,18 @@ class ReaderTool(LionTool):
174
196
  request = ReaderRequest(**request)
175
197
  if request.action == "open":
176
198
  return self._open_doc(request.path_or_url)
177
- elif request.action == "read":
199
+ if request.action == "read":
178
200
  return self._read_doc(
179
201
  request.doc_id, request.start_offset, request.end_offset
180
202
  )
203
+ if request.action == "list_dir":
204
+ return self._list_dir(
205
+ request.path_or_url, request.recursive, request.file_types
206
+ )
181
207
  else:
182
208
  return ReaderResponse(success=False, error="Unknown action type")
183
209
 
184
- def _open_doc(self, source: str) -> ReaderResponse:
185
- try:
186
- result = self.converter.convert(source)
187
- text = result.document.export_to_markdown()
188
- except Exception as e:
189
- return ReaderResponse(
190
- success=False, error=f"Conversion error: {str(e)}"
191
- )
192
-
193
- doc_id = f"DOC_{abs(hash(source))}"
210
+ def _save_to_temp(self, text, doc_id):
194
211
  temp_file = tempfile.NamedTemporaryFile(
195
212
  delete=False, mode="w", encoding="utf-8"
196
213
  )
@@ -202,9 +219,26 @@ class ReaderTool(LionTool):
202
219
  self.documents[doc_id] = (temp_file.name, doc_len)
203
220
 
204
221
  return ReaderResponse(
205
- success=True, doc_info=DocumentInfo(doc_id=doc_id, length=doc_len)
222
+ success=True,
223
+ doc_info=DocumentInfo(
224
+ doc_id=doc_id,
225
+ length=doc_len,
226
+ num_tokens=TokenCalculator.tokenize(text),
227
+ ),
206
228
  )
207
229
 
230
+ def _open_doc(self, source: str) -> ReaderResponse:
231
+ try:
232
+ result = self.converter.convert(source)
233
+ text = result.document.export_to_markdown()
234
+ except Exception as e:
235
+ return ReaderResponse(
236
+ success=False, error=f"Conversion error: {str(e)}"
237
+ )
238
+
239
+ doc_id = f"DOC_{abs(hash(source))}"
240
+ return self._save_to_temp(text, doc_id)
241
+
208
242
  def _read_doc(self, doc_id: str, start: int, end: int) -> ReaderResponse:
209
243
  if doc_id not in self.documents:
210
244
  return ReaderResponse(
@@ -230,14 +264,30 @@ class ReaderTool(LionTool):
230
264
  chunk=PartialChunk(start_offset=s, end_offset=e, content=content),
231
265
  )
232
266
 
267
+ def _list_dir(
268
+ self,
269
+ directory: str,
270
+ recursive: bool = False,
271
+ file_types: list[str] | None = None,
272
+ ):
273
+ from lionagi.libs.file.process import dir_to_files
274
+
275
+ files = dir_to_files(
276
+ directory, recursive=recursive, file_types=file_types
277
+ )
278
+ files = "\n".join([str(f) for f in files])
279
+ doc_id = f"DIR_{abs(hash(directory))}"
280
+ return self._save_to_temp(files, doc_id)
281
+
233
282
  def to_tool(self):
234
283
  if self._tool is None:
235
284
 
236
285
  def reader_tool(**kwargs):
237
286
  """
238
- A function that takes ReaderRequest to either:
287
+ A function that takes ReaderRequest to do one of:
239
288
  - open a doc (File/URL) -> returns doc_id, doc length
240
289
  - read partial text from doc -> returns chunk
290
+ - list all files in a directory -> returns list of files as doc format
241
291
  """
242
292
  return self.handle_request(
243
293
  ReaderRequest(**kwargs)
@@ -0,0 +1,3 @@
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
@@ -1022,10 +1022,14 @@ def create_path(
1022
1022
  The full Path to the new or existing file.
1023
1023
 
1024
1024
  Raises:
1025
- ValueError: If no extension or filename invalid.
1025
+ ValueError: If filename is invalid.
1026
1026
  FileExistsError: If file exists and file_exist_ok=False.
1027
1027
  """
1028
- if "/" in filename or "\\" in filename:
1028
+ if "/" in filename:
1029
+ sub_dir, filename = filename.split("/")[:-1], filename.split("/")[-1]
1030
+ directory = Path(directory) / "/".join(sub_dir)
1031
+
1032
+ if "\\" in filename:
1029
1033
  raise ValueError("Filename cannot contain directory separators.")
1030
1034
 
1031
1035
  directory = Path(directory)
@@ -1036,9 +1040,6 @@ def create_path(
1036
1040
  else:
1037
1041
  name, ext = filename, extension
1038
1042
 
1039
- if not ext:
1040
- raise ValueError("No extension provided for filename.")
1041
-
1042
1043
  # Ensure extension has a single leading dot
1043
1044
  ext = f".{ext.lstrip('.')}" if ext else ""
1044
1045
 
@@ -0,0 +1 @@
1
+ __version__ = "0.9.5"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lionagi"
3
- version = "0.9.3"
3
+ version = "0.9.5"
4
4
  description = "An Intelligence Operating System."
5
5
  authors = [
6
6
  { name = "HaiyangLi", email = "quantocean.li@gmail.com" },
@@ -1208,7 +1208,7 @@ wheels = [
1208
1208
 
1209
1209
  [[package]]
1210
1210
  name = "lionagi"
1211
- version = "0.9.3"
1211
+ version = "0.9.5"
1212
1212
  source = { editable = "." }
1213
1213
  dependencies = [
1214
1214
  { name = "aiocache" },
@@ -1 +0,0 @@
1
- __version__ = "0.9.3"
File without changes
File without changes