hammad-python 0.0.20__tar.gz → 0.0.21__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 (258) hide show
  1. {hammad_python-0.0.20 → hammad_python-0.0.21}/PKG-INFO +1 -1
  2. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/agent.py +321 -45
  3. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_response.py +36 -4
  4. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_stream.py +85 -9
  5. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/model.py +15 -0
  6. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_response.py +1 -1
  7. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/types/tools.py +2 -0
  8. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/logging/logger.py +8 -0
  9. {hammad_python-0.0.20 → hammad_python-0.0.21}/pyproject.toml +2 -3
  10. {hammad_python-0.0.20 → hammad_python-0.0.21}/uv.lock +231 -14
  11. hammad_python-0.0.20/.python-version +0 -1
  12. hammad_python-0.0.20/deprecated/hammad/__init__.py +0 -1
  13. hammad_python-0.0.20/deprecated/hammad/ai/__init__.py +0 -1
  14. hammad_python-0.0.20/deprecated/hammad/ai/_utils.py +0 -142
  15. hammad_python-0.0.20/deprecated/hammad/ai/completions/__init__.py +0 -45
  16. hammad_python-0.0.20/deprecated/hammad/ai/completions/client.py +0 -684
  17. hammad_python-0.0.20/deprecated/hammad/ai/completions/create.py +0 -710
  18. hammad_python-0.0.20/deprecated/hammad/ai/completions/settings.py +0 -100
  19. hammad_python-0.0.20/deprecated/hammad/ai/completions/types.py +0 -792
  20. hammad_python-0.0.20/deprecated/hammad/ai/completions/utils.py +0 -486
  21. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/__init__.py +0 -35
  22. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/client/__init__.py +0 -1
  23. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
  24. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
  25. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/client/litellm_embeddings_client.py +0 -288
  26. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/create.py +0 -159
  27. hammad_python-0.0.20/deprecated/hammad/ai/embeddings/types.py +0 -69
  28. hammad_python-0.0.20/deprecated/hammad/cache/__init__.py +0 -40
  29. hammad_python-0.0.20/deprecated/hammad/cli/__init__.py +0 -33
  30. hammad_python-0.0.20/deprecated/hammad/cli/animations.py +0 -573
  31. hammad_python-0.0.20/deprecated/hammad/cli/plugins.py +0 -777
  32. hammad_python-0.0.20/deprecated/hammad/cli/styles/__init__.py +0 -55
  33. hammad_python-0.0.20/deprecated/hammad/cli/styles/utils.py +0 -480
  34. hammad_python-0.0.20/deprecated/hammad/data/__init__.py +0 -54
  35. hammad_python-0.0.20/deprecated/hammad/data/collections/__init__.py +0 -34
  36. hammad_python-0.0.20/deprecated/hammad/data/collections/base_collection.py +0 -58
  37. hammad_python-0.0.20/deprecated/hammad/data/collections/collection.py +0 -452
  38. hammad_python-0.0.20/deprecated/hammad/data/collections/searchable_collection.py +0 -556
  39. hammad_python-0.0.20/deprecated/hammad/data/collections/vector_collection.py +0 -596
  40. hammad_python-0.0.20/deprecated/hammad/data/configurations/__init__.py +0 -35
  41. hammad_python-0.0.20/deprecated/hammad/data/configurations/configuration.py +0 -564
  42. hammad_python-0.0.20/deprecated/hammad/data/databases/__init__.py +0 -21
  43. hammad_python-0.0.20/deprecated/hammad/data/databases/database.py +0 -916
  44. hammad_python-0.0.20/deprecated/hammad/data/models/__init__.py +0 -33
  45. hammad_python-0.0.20/deprecated/hammad/data/models/base/__init__.py +0 -35
  46. hammad_python-0.0.20/deprecated/hammad/data/models/base/fields.py +0 -546
  47. hammad_python-0.0.20/deprecated/hammad/data/models/base/model.py +0 -1078
  48. hammad_python-0.0.20/deprecated/hammad/data/models/base/utils.py +0 -280
  49. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/__init__.py +0 -55
  50. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/converters.py +0 -632
  51. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/__init__.py +0 -28
  52. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
  53. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/cacheable_model.py +0 -79
  54. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/fast_model.py +0 -318
  55. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/function_model.py +0 -176
  56. hammad_python-0.0.20/deprecated/hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
  57. hammad_python-0.0.20/deprecated/hammad/data/types/__init__.py +0 -39
  58. hammad_python-0.0.20/deprecated/hammad/data/types/file.py +0 -358
  59. hammad_python-0.0.20/deprecated/hammad/data/types/multimodal/__init__.py +0 -24
  60. hammad_python-0.0.20/deprecated/hammad/data/types/multimodal/audio.py +0 -96
  61. hammad_python-0.0.20/deprecated/hammad/data/types/multimodal/image.py +0 -80
  62. hammad_python-0.0.20/deprecated/hammad/formatting/__init__.py +0 -38
  63. hammad_python-0.0.20/deprecated/hammad/formatting/json/__init__.py +0 -21
  64. hammad_python-0.0.20/deprecated/hammad/formatting/json/converters.py +0 -152
  65. hammad_python-0.0.20/deprecated/hammad/formatting/text/__init__.py +0 -63
  66. hammad_python-0.0.20/deprecated/hammad/formatting/yaml/__init__.py +0 -26
  67. hammad_python-0.0.20/deprecated/hammad/logging/__init__.py +0 -35
  68. hammad_python-0.0.20/deprecated/hammad/logging/decorators.py +0 -834
  69. hammad_python-0.0.20/deprecated/hammad/logging/logger.py +0 -954
  70. hammad_python-0.0.20/deprecated/hammad/mcp/__init__.py +0 -50
  71. hammad_python-0.0.20/deprecated/hammad/mcp/client/__init__.py +0 -1
  72. hammad_python-0.0.20/deprecated/hammad/mcp/client/client.py +0 -523
  73. hammad_python-0.0.20/deprecated/hammad/mcp/client/client_service.py +0 -393
  74. hammad_python-0.0.20/deprecated/hammad/mcp/servers/__init__.py +0 -1
  75. hammad_python-0.0.20/deprecated/hammad/performance/__init__.py +0 -36
  76. hammad_python-0.0.20/deprecated/hammad/performance/imports.py +0 -231
  77. hammad_python-0.0.20/deprecated/hammad/performance/runtime/__init__.py +0 -32
  78. hammad_python-0.0.20/deprecated/hammad/performance/runtime/decorators.py +0 -142
  79. hammad_python-0.0.20/deprecated/hammad/performance/runtime/run.py +0 -299
  80. hammad_python-0.0.20/deprecated/hammad/service/__init__.py +0 -49
  81. hammad_python-0.0.20/deprecated/hammad/service/create.py +0 -532
  82. hammad_python-0.0.20/deprecated/hammad/service/decorators.py +0 -285
  83. hammad_python-0.0.20/deprecated/hammad/typing/__init__.py +0 -407
  84. hammad_python-0.0.20/deprecated/hammad/web/__init__.py +0 -43
  85. hammad_python-0.0.20/deprecated/hammad/web/http/client.py +0 -944
  86. hammad_python-0.0.20/deprecated/hammad/web/models.py +0 -245
  87. hammad_python-0.0.20/deprecated/hammad/web/search/client.py +0 -988
  88. hammad_python-0.0.20/deprecated/hammad/web/utils.py +0 -472
  89. hammad_python-0.0.20/deprecated/tests/ai/completions/test_ai_completions_create.py +0 -244
  90. hammad_python-0.0.20/deprecated/tests/ai/completions/test_ai_completions_types.py +0 -585
  91. hammad_python-0.0.20/deprecated/tests/cache/test_performance_cache.py +0 -182
  92. hammad_python-0.0.20/deprecated/tests/cli/test_cli_plugins_animate.py +0 -134
  93. hammad_python-0.0.20/deprecated/tests/cli/test_cli_plugins_input.py +0 -227
  94. hammad_python-0.0.20/deprecated/tests/cli/test_cli_plugins_print.py +0 -181
  95. hammad_python-0.0.20/deprecated/tests/cli/test_cli_styles_utils.py +0 -125
  96. hammad_python-0.0.20/deprecated/tests/data/collections/test_data_collections_searchable_collection.py +0 -308
  97. hammad_python-0.0.20/deprecated/tests/data/collections/test_data_collections_vector_collection.py +0 -495
  98. hammad_python-0.0.20/deprecated/tests/data/configuration/test_data_configuration.py +0 -0
  99. hammad_python-0.0.20/deprecated/tests/data/databases/test_data_databases_database.py +0 -725
  100. hammad_python-0.0.20/deprecated/tests/data/models/base/test_data_models_base_fields.py +0 -468
  101. hammad_python-0.0.20/deprecated/tests/data/models/base/test_data_models_base_model.py +0 -841
  102. hammad_python-0.0.20/deprecated/tests/data/models/pydantic/test_models_pydantic_converters.py +0 -270
  103. hammad_python-0.0.20/deprecated/tests/data/models/pydantic/test_models_pydantic_models.py +0 -288
  104. hammad_python-0.0.20/deprecated/tests/data/types/test_data_types_text.py +0 -523
  105. hammad_python-0.0.20/deprecated/tests/formatting/json/test_json_converters.py +0 -134
  106. hammad_python-0.0.20/deprecated/tests/formatting/text/test_text_utils_converters.py +0 -140
  107. hammad_python-0.0.20/deprecated/tests/formatting/text/test_text_utils_markdown_converters.py +0 -338
  108. hammad_python-0.0.20/deprecated/tests/logging/test_logging_decorators.py +0 -534
  109. hammad_python-0.0.20/deprecated/tests/logging/test_logging_logger.py +0 -237
  110. hammad_python-0.0.20/deprecated/tests/mcp/test_mcp_client_services.py +0 -404
  111. hammad_python-0.0.20/deprecated/tests/mcp/test_mcp_server_services.py +0 -555
  112. hammad_python-0.0.20/deprecated/tests/performance/runtime/test_performance_runtime_decorators.py +0 -66
  113. hammad_python-0.0.20/deprecated/tests/performance/runtime/test_performance_runtime_run.py +0 -98
  114. hammad_python-0.0.20/deprecated/tests/service/test_service_create_service.py +0 -177
  115. hammad_python-0.0.20/deprecated/tests/service/test_service_serve_decorator.py +0 -175
  116. hammad_python-0.0.20/deprecated/tests/service/test_service_serve_mcp_decorator.py +0 -204
  117. hammad_python-0.0.20/deprecated/tests/typing/test_typing_utils.py +0 -243
  118. hammad_python-0.0.20/deprecated/tests/web/test_web_toolkits_http_toolkit.py +0 -369
  119. hammad_python-0.0.20/deprecated/tests/web/test_web_toolkits_openapi_toolkit.py +0 -586
  120. hammad_python-0.0.20/deprecated/tests/web/test_web_utils.py +0 -364
  121. hammad_python-0.0.20/hammad/cache/base_cache.py +0 -181
  122. hammad_python-0.0.20/hammad/cache/cache.py +0 -169
  123. hammad_python-0.0.20/hammad/cache/decorators.py +0 -261
  124. hammad_python-0.0.20/hammad/cache/file_cache.py +0 -80
  125. hammad_python-0.0.20/hammad/cache/ttl_cache.py +0 -74
  126. hammad_python-0.0.20/hammad/cli/styles/settings.py +0 -139
  127. hammad_python-0.0.20/hammad/cli/styles/types.py +0 -358
  128. hammad_python-0.0.20/hammad/data/types/text.py +0 -1066
  129. hammad_python-0.0.20/hammad/formatting/text/converters.py +0 -723
  130. hammad_python-0.0.20/hammad/formatting/text/markdown.py +0 -131
  131. hammad_python-0.0.20/hammad/formatting/yaml/converters.py +0 -5
  132. hammad_python-0.0.20/hammad/mcp/client/settings.py +0 -178
  133. hammad_python-0.0.20/hammad/mcp/servers/launcher.py +0 -1161
  134. hammad_python-0.0.20/hammad/py.typed +0 -0
  135. hammad_python-0.0.20/hammad/web/http/__init__.py +0 -1
  136. hammad_python-0.0.20/hammad/web/openapi/__init__.py +0 -1
  137. hammad_python-0.0.20/hammad/web/openapi/client.py +0 -740
  138. hammad_python-0.0.20/hammad/web/search/__init__.py +0 -1
  139. {hammad_python-0.0.20 → hammad_python-0.0.21}/.gitignore +0 -0
  140. {hammad_python-0.0.20 → hammad_python-0.0.21}/LICENSE +0 -0
  141. {hammad_python-0.0.20 → hammad_python-0.0.21}/README.md +0 -0
  142. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/__init__.py +0 -0
  143. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/_internal.py +0 -0
  144. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cache/__init__.py +0 -0
  145. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cache/base_cache.py +0 -0
  146. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cache/cache.py +0 -0
  147. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cache/decorators.py +0 -0
  148. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cache/file_cache.py +0 -0
  149. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cache/ttl_cache.py +0 -0
  150. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/__init__.py +0 -0
  151. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/_runner.py +0 -0
  152. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/animations.py +0 -0
  153. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/plugins.py +0 -0
  154. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/styles/__init__.py +0 -0
  155. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cli/styles/settings.py +0 -0
  156. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/cli/styles/types.py +0 -0
  157. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/cli/styles/utils.py +0 -0
  158. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/__init__.py +0 -0
  159. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/__init__.py +0 -0
  160. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/collection.py +0 -0
  161. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/__init__.py +0 -0
  162. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/qdrant/__init__.py +0 -0
  163. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/qdrant/index.py +0 -0
  164. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/qdrant/settings.py +0 -0
  165. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/qdrant/utils.py +0 -0
  166. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/tantivy/__init__.py +0 -0
  167. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/tantivy/index.py +0 -0
  168. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/tantivy/settings.py +0 -0
  169. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/collections/indexes/tantivy/utils.py +0 -0
  170. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/configurations/__init__.py +0 -0
  171. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/configurations/configuration.py +0 -0
  172. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/__init__.py +0 -0
  173. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/extensions/__init__.py +0 -0
  174. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/extensions/pydantic/__init__.py +0 -0
  175. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/extensions/pydantic/converters.py +0 -0
  176. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/fields.py +0 -0
  177. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/model.py +0 -0
  178. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/models/utils.py +0 -0
  179. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/sql/__init__.py +0 -0
  180. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/sql/database.py +0 -0
  181. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/sql/types.py +0 -0
  182. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/types/__init__.py +0 -0
  183. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/types/file.py +0 -0
  184. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/types/multimodal/__init__.py +0 -0
  185. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/types/multimodal/audio.py +0 -0
  186. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/data/types/multimodal/image.py +0 -0
  187. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/data/types/text.py +0 -0
  188. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/formatting/__init__.py +0 -0
  189. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/formatting/json/__init__.py +0 -0
  190. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/formatting/json/converters.py +0 -0
  191. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/formatting/text/__init__.py +0 -0
  192. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/formatting/text/converters.py +0 -0
  193. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/formatting/text/markdown.py +0 -0
  194. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/formatting/yaml/__init__.py +0 -0
  195. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/formatting/yaml/converters.py +0 -0
  196. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/__init__.py +0 -0
  197. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/__init__.py +0 -0
  198. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/run.py +0 -0
  199. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/__init__.py +0 -0
  200. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_context.py +0 -0
  201. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_event.py +0 -0
  202. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_hooks.py +0 -0
  203. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/agents/types/agent_messages.py +0 -0
  204. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/__init__.py +0 -0
  205. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/__init__.py +0 -0
  206. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/model.py +0 -0
  207. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/run.py +0 -0
  208. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/types/__init__.py +0 -0
  209. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/types/embedding_model_name.py +0 -0
  210. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/types/embedding_model_response.py +0 -0
  211. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -0
  212. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -0
  213. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/__init__.py +0 -0
  214. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/run.py +0 -0
  215. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/__init__.py +0 -0
  216. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_instructor_mode.py +0 -0
  217. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_messages.py +0 -0
  218. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_name.py +0 -0
  219. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_request.py +0 -0
  220. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_response_chunk.py +0 -0
  221. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_settings.py +0 -0
  222. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/types/language_model_stream.py +0 -0
  223. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/utils/__init__.py +0 -0
  224. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/utils/requests.py +0 -0
  225. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/language/utils/structured_outputs.py +0 -0
  226. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/model_provider.py +0 -0
  227. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/multimodal.py +0 -0
  228. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/models/reranking.py +0 -0
  229. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/types/__init__.py +0 -0
  230. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/types/base.py +0 -0
  231. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/genai/types/history.py +0 -0
  232. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/logging/__init__.py +0 -0
  233. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/logging/decorators.py +0 -0
  234. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/mcp/__init__.py +0 -0
  235. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/mcp/client/__init__.py +0 -0
  236. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/mcp/client/client.py +0 -0
  237. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/mcp/client/client_service.py +0 -0
  238. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/mcp/client/settings.py +0 -0
  239. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/mcp/servers/__init__.py +0 -0
  240. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/mcp/servers/launcher.py +0 -0
  241. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/py.typed +0 -0
  242. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/runtime/__init__.py +0 -0
  243. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/runtime/decorators.py +0 -0
  244. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/runtime/run.py +0 -0
  245. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/service/__init__.py +0 -0
  246. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/service/create.py +0 -0
  247. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/service/decorators.py +0 -0
  248. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/typing/__init__.py +0 -0
  249. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/web/__init__.py +0 -0
  250. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/web/http/__init__.py +0 -0
  251. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/web/http/client.py +0 -0
  252. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/web/models.py +0 -0
  253. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/web/openapi/__init__.py +0 -0
  254. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/web/openapi/client.py +0 -0
  255. {hammad_python-0.0.20/deprecated → hammad_python-0.0.21}/hammad/web/search/__init__.py +0 -0
  256. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/web/search/client.py +0 -0
  257. {hammad_python-0.0.20 → hammad_python-0.0.21}/hammad/web/utils.py +0 -0
  258. {hammad_python-0.0.20 → hammad_python-0.0.21}/mkdocs.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hammad-python
3
- Version: 0.0.20
3
+ Version: 0.0.21
4
4
  Author-email: Hammad Saeed <hammadaidev@gmail.com>
5
5
  License: MIT License
6
6
 
@@ -19,6 +19,8 @@ from dataclasses import dataclass, field
19
19
  from enum import Enum
20
20
  import json
21
21
 
22
+ from ...logging.logger import _get_internal_logger
23
+
22
24
  from ..types.base import BaseGenAIModel, BaseGenAIModelSettings
23
25
  from ..models.language.model import LanguageModel
24
26
  from ..models.language.types import (
@@ -53,6 +55,9 @@ if TYPE_CHECKING:
53
55
  T = TypeVar("T")
54
56
 
55
57
 
58
+ logger = _get_internal_logger(__name__)
59
+
60
+
56
61
  @dataclass
57
62
  class AgentSettings:
58
63
  """Settings object that controls the default behavior of an agent's run."""
@@ -253,6 +258,43 @@ class Agent(BaseGenAIModel, Generic[T]):
253
258
  context_format: Literal["json", "python", "markdown"] = "json",
254
259
  **kwargs: Any,
255
260
  ):
261
+ """Create a new AI agent with specified capabilities and behavior.
262
+
263
+ An agent is an intelligent assistant that can use tools, follow instructions,
264
+ and maintain context across conversations. It combines a language model with
265
+ additional capabilities like tool execution and structured output generation.
266
+
267
+ Args:
268
+ name: A human-readable name for the agent (default: "agent")
269
+ instructions: System instructions that define the agent's behavior and personality
270
+ model: The language model to use - either a LanguageModel instance or model name string
271
+ description: Optional description of what the agent does
272
+ tools: List of tools/functions the agent can call, or a single callable
273
+ settings: AgentSettings object to customize default behavior
274
+ instructor_mode: Mode for structured output generation
275
+ context_updates: When to update context - "before", "after", or both
276
+ context_confirm: Whether to confirm context updates with the user
277
+ context_strategy: How to select context updates - "selective" or "all"
278
+ context_max_retries: Maximum attempts for context update operations
279
+ context_confirm_instructions: Custom instructions for context confirmation
280
+ context_selection_instructions: Custom instructions for context selection
281
+ context_update_instructions: Custom instructions for context updates
282
+ context_format: Format for context display - "json", "python", or "markdown"
283
+ **kwargs: Additional parameters passed to the underlying language model
284
+
285
+ Example:
286
+ Basic agent:
287
+ >>> agent = Agent(name="assistant", instructions="You are helpful")
288
+
289
+ Agent with tools:
290
+ >>> def calculator(x: int, y: int) -> int:
291
+ ... return x + y
292
+ >>> agent = Agent(tools=[calculator])
293
+
294
+ Agent with custom settings:
295
+ >>> settings = AgentSettings(max_steps=5)
296
+ >>> agent = Agent(settings=settings, model="gpt-4")
297
+ """
256
298
  # Initialize BaseGenAIModel with basic parameters
257
299
  super().__init__(
258
300
  model=model if isinstance(model, str) else model.model, **kwargs
@@ -297,17 +339,44 @@ class Agent(BaseGenAIModel, Generic[T]):
297
339
  """Get the underlying language model."""
298
340
  return self._language_model
299
341
 
342
+ def _get_effective_context_settings(
343
+ self,
344
+ context_updates: Optional[
345
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
346
+ ] = None,
347
+ context_confirm: Optional[bool] = None,
348
+ context_strategy: Optional[Literal["selective", "all"]] = None,
349
+ context_max_retries: Optional[int] = None,
350
+ context_confirm_instructions: Optional[str] = None,
351
+ context_selection_instructions: Optional[str] = None,
352
+ context_update_instructions: Optional[str] = None,
353
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
354
+ ) -> dict:
355
+ """Get effective context settings, using provided parameters or defaults."""
356
+ return {
357
+ "context_updates": context_updates if context_updates is not None else self.context_updates,
358
+ "context_confirm": context_confirm if context_confirm is not None else self.context_confirm,
359
+ "context_strategy": context_strategy if context_strategy is not None else self.context_strategy,
360
+ "context_max_retries": context_max_retries if context_max_retries is not None else self.context_max_retries,
361
+ "context_confirm_instructions": context_confirm_instructions if context_confirm_instructions is not None else self.context_confirm_instructions,
362
+ "context_selection_instructions": context_selection_instructions if context_selection_instructions is not None else self.context_selection_instructions,
363
+ "context_update_instructions": context_update_instructions if context_update_instructions is not None else self.context_update_instructions,
364
+ "context_format": context_format if context_format is not None else self.context_format,
365
+ }
366
+
300
367
  def _should_update_context(
301
- self, context: AgentContext, timing: Literal["before", "after"]
368
+ self, context: AgentContext, timing: Literal["before", "after"], context_updates=None
302
369
  ) -> bool:
303
370
  """Determine if context should be updated based on timing and configuration."""
304
- if not self.context_updates:
371
+ effective_context_updates = context_updates if context_updates is not None else self.context_updates
372
+
373
+ if not effective_context_updates:
305
374
  return False
306
375
 
307
- if isinstance(self.context_updates, str):
308
- return self.context_updates == timing
376
+ if isinstance(effective_context_updates, str):
377
+ return effective_context_updates == timing
309
378
  else:
310
- return timing in self.context_updates
379
+ return timing in effective_context_updates
311
380
 
312
381
  def _create_context_confirm_model(self):
313
382
  """Create IsUpdateRequired model for context confirmation."""
@@ -334,18 +403,44 @@ class Agent(BaseGenAIModel, Generic[T]):
334
403
  if field_name:
335
404
  # Single field update
336
405
  if isinstance(context, BaseModel):
337
- field_type = context.model_fields[field_name].annotation
406
+ field_type = context.__class__.model_fields[field_name].annotation
407
+ field_info = context.__class__.model_fields[field_name]
408
+ description = getattr(field_info, 'description', f"Update the {field_name} field")
338
409
  elif isinstance(context, dict):
339
410
  field_type = type(context[field_name])
411
+ description = f"Update the {field_name} field"
340
412
  else:
341
413
  field_type = Any
414
+ description = f"Update the {field_name} field"
342
415
 
343
416
  return create_model(
344
- field_name.capitalize(), **{field_name: (field_type, ...)}
417
+ f"Update{field_name.capitalize()}",
418
+ **{field_name: (field_type, Field(description=description))}
345
419
  )
346
420
  else:
347
- # All fields update
348
- return create_model("Update", updates=(Dict[str, Any], ...))
421
+ # All fields update - create a model with the exact same fields as the context
422
+ if isinstance(context, BaseModel):
423
+ # Create a model with the same fields as the context
424
+ field_definitions = {}
425
+ for field_name, field_info in context.model_fields.items():
426
+ field_type = field_info.annotation
427
+ current_value = getattr(context, field_name)
428
+ description = getattr(field_info, 'description', f"Current value: {current_value}")
429
+ field_definitions[field_name] = (field_type, Field(description=description))
430
+
431
+ return create_model("ContextUpdate", **field_definitions)
432
+ elif isinstance(context, dict):
433
+ # Create a model with the same keys as the dict
434
+ field_definitions = {}
435
+ for key, value in context.items():
436
+ field_type = type(value)
437
+ description = f"Current value: {value}"
438
+ field_definitions[key] = (field_type, Field(description=description))
439
+
440
+ return create_model("ContextUpdate", **field_definitions)
441
+ else:
442
+ # Fallback to generic updates
443
+ return create_model("ContextUpdate", updates=(Dict[str, Any], Field(description="Dictionary of field updates")))
349
444
 
350
445
  def _perform_context_update(
351
446
  self,
@@ -353,20 +448,40 @@ class Agent(BaseGenAIModel, Generic[T]):
353
448
  model: LanguageModel,
354
449
  current_messages: List[Dict[str, Any]],
355
450
  timing: Literal["before", "after"],
451
+ effective_settings: Optional[dict] = None,
356
452
  ) -> AgentContext:
357
453
  """Perform context update with retries and error handling."""
358
454
  updated_context = context
359
-
360
- for attempt in range(self.context_max_retries):
455
+
456
+ # Use effective settings or defaults
457
+ if effective_settings is None:
458
+ effective_settings = {
459
+ "context_confirm": self.context_confirm,
460
+ "context_strategy": self.context_strategy,
461
+ "context_max_retries": self.context_max_retries,
462
+ "context_confirm_instructions": self.context_confirm_instructions,
463
+ "context_selection_instructions": self.context_selection_instructions,
464
+ "context_update_instructions": self.context_update_instructions,
465
+ "context_format": self.context_format,
466
+ }
467
+
468
+ for attempt in range(effective_settings["context_max_retries"]):
361
469
  try:
362
470
  # Check if update is needed (if confirmation is enabled)
363
- if self.context_confirm:
471
+ if effective_settings["context_confirm"]:
364
472
  confirm_model = self._create_context_confirm_model()
365
- confirm_instructions = f"Based on the conversation, determine if the context should be updated {timing} processing."
366
- if self.context_confirm_instructions:
367
- confirm_instructions += (
368
- f"\n\n{self.context_confirm_instructions}"
369
- )
473
+
474
+ # Create detailed instructions with context structure
475
+ context_structure = _format_context_for_instructions(updated_context, effective_settings["context_format"])
476
+ confirm_instructions = f"""Based on the conversation, determine if the context should be updated {timing} processing.
477
+
478
+ Current context structure:
479
+ {context_structure}
480
+
481
+ Should the context be updated based on the new information provided in the conversation?"""
482
+
483
+ if effective_settings["context_confirm_instructions"]:
484
+ confirm_instructions += f"\n\nAdditional instructions: {effective_settings['context_confirm_instructions']}"
370
485
 
371
486
  confirm_response = model.run(
372
487
  messages=current_messages
@@ -379,16 +494,23 @@ class Agent(BaseGenAIModel, Generic[T]):
379
494
  return updated_context
380
495
 
381
496
  # Perform the update based on strategy
382
- if self.context_strategy == "selective":
497
+ if effective_settings["context_strategy"] == "selective":
383
498
  # Get fields to update
384
499
  selection_model = self._create_context_selection_model(
385
500
  updated_context
386
501
  )
387
- selection_instructions = f"Select which fields in the context should be updated {timing} processing."
388
- if self.context_selection_instructions:
389
- selection_instructions += (
390
- f"\n\n{self.context_selection_instructions}"
391
- )
502
+
503
+ # Create detailed instructions with context structure
504
+ context_structure = _format_context_for_instructions(updated_context, effective_settings["context_format"])
505
+ selection_instructions = f"""Select which fields in the context should be updated {timing} processing based on the conversation.
506
+
507
+ Current context structure:
508
+ {context_structure}
509
+
510
+ Choose only the fields that need to be updated based on the new information provided in the conversation."""
511
+
512
+ if effective_settings["context_selection_instructions"]:
513
+ selection_instructions += f"\n\nAdditional instructions: {effective_settings['context_selection_instructions']}"
392
514
 
393
515
  selection_response = model.run(
394
516
  messages=current_messages
@@ -403,13 +525,17 @@ class Agent(BaseGenAIModel, Generic[T]):
403
525
  field_model = self._create_context_update_model(
404
526
  updated_context, field_name
405
527
  )
406
- field_instructions = (
407
- f"Update the {field_name} field in the context."
408
- )
409
- if self.context_update_instructions:
410
- field_instructions += (
411
- f"\n\n{self.context_update_instructions}"
412
- )
528
+ # Get current field value for context
529
+ current_value = getattr(updated_context, field_name) if isinstance(updated_context, BaseModel) else updated_context.get(field_name)
530
+
531
+ field_instructions = f"""Update the {field_name} field in the context based on the conversation.
532
+
533
+ Current value of {field_name}: {current_value}
534
+
535
+ Please provide the new value for {field_name} based on the information from the conversation."""
536
+
537
+ if effective_settings["context_update_instructions"]:
538
+ field_instructions += f"\n\nAdditional instructions: {effective_settings['context_update_instructions']}"
413
539
 
414
540
  field_response = model.run(
415
541
  messages=current_messages
@@ -429,9 +555,18 @@ class Agent(BaseGenAIModel, Generic[T]):
429
555
  else: # strategy == "all"
430
556
  # Update all fields at once
431
557
  update_model = self._create_context_update_model(updated_context)
432
- update_instructions = f"Update the context {timing} processing."
433
- if self.context_update_instructions:
434
- update_instructions += f"\n\n{self.context_update_instructions}"
558
+
559
+ # Create detailed instructions with context structure
560
+ context_structure = _format_context_for_instructions(updated_context, effective_settings["context_format"])
561
+ update_instructions = f"""Update the context {timing} processing based on the conversation.
562
+
563
+ Current context structure:
564
+ {context_structure}
565
+
566
+ Please update the appropriate fields based on the conversation. Only update fields that need to be changed based on the new information provided."""
567
+
568
+ if effective_settings["context_update_instructions"]:
569
+ update_instructions += f"\n\nAdditional instructions: {effective_settings['context_update_instructions']}"
435
570
 
436
571
  update_response = model.run(
437
572
  messages=current_messages
@@ -441,9 +576,18 @@ class Agent(BaseGenAIModel, Generic[T]):
441
576
  )
442
577
 
443
578
  # Apply the updates
444
- updated_context = _update_context_object(
445
- updated_context, update_response.output.updates
446
- )
579
+ if hasattr(update_response.output, 'updates'):
580
+ # Legacy fallback for generic updates
581
+ updated_context = _update_context_object(
582
+ updated_context, update_response.output.updates
583
+ )
584
+ else:
585
+ # New approach - extract field values directly from the response
586
+ updates_dict = {}
587
+ for field_name in (context.model_fields.keys() if isinstance(context, BaseModel) else context.keys()):
588
+ if hasattr(update_response.output, field_name):
589
+ updates_dict[field_name] = getattr(update_response.output, field_name)
590
+ updated_context = _update_context_object(updated_context, updates_dict)
447
591
 
448
592
  # Trigger context update hooks
449
593
  self.hook_manager.trigger_hooks("context_update", updated_context)
@@ -490,10 +634,20 @@ class Agent(BaseGenAIModel, Generic[T]):
490
634
  max_steps: Optional[int] = None,
491
635
  context: Optional[AgentContext] = None,
492
636
  output_type: Optional[Type[T]] = None,
637
+ context_updates: Optional[
638
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
639
+ ] = None,
640
+ context_confirm: Optional[bool] = None,
641
+ context_strategy: Optional[Literal["selective", "all"]] = None,
642
+ context_max_retries: Optional[int] = None,
643
+ context_confirm_instructions: Optional[str] = None,
644
+ context_selection_instructions: Optional[str] = None,
645
+ context_update_instructions: Optional[str] = None,
646
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
493
647
  *,
494
648
  stream: Literal[False] = False,
495
649
  **kwargs: Any,
496
- ) -> AgentResponse[T]: ...
650
+ ) -> AgentResponse[T, AgentContext]: ...
497
651
 
498
652
  @overload
499
653
  def run(
@@ -503,10 +657,20 @@ class Agent(BaseGenAIModel, Generic[T]):
503
657
  max_steps: Optional[int] = None,
504
658
  context: Optional[AgentContext] = None,
505
659
  output_type: Optional[Type[T]] = None,
660
+ context_updates: Optional[
661
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
662
+ ] = None,
663
+ context_confirm: Optional[bool] = None,
664
+ context_strategy: Optional[Literal["selective", "all"]] = None,
665
+ context_max_retries: Optional[int] = None,
666
+ context_confirm_instructions: Optional[str] = None,
667
+ context_selection_instructions: Optional[str] = None,
668
+ context_update_instructions: Optional[str] = None,
669
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
506
670
  *,
507
671
  stream: Literal[True],
508
672
  **kwargs: Any,
509
- ) -> AgentStream[T]: ...
673
+ ) -> AgentStream[T, AgentContext]: ...
510
674
 
511
675
  def run(
512
676
  self,
@@ -515,9 +679,19 @@ class Agent(BaseGenAIModel, Generic[T]):
515
679
  max_steps: Optional[int] = None,
516
680
  context: Optional[AgentContext] = None,
517
681
  output_type: Optional[Type[T]] = None,
682
+ context_updates: Optional[
683
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
684
+ ] = None,
685
+ context_confirm: Optional[bool] = None,
686
+ context_strategy: Optional[Literal["selective", "all"]] = None,
687
+ context_max_retries: Optional[int] = None,
688
+ context_confirm_instructions: Optional[str] = None,
689
+ context_selection_instructions: Optional[str] = None,
690
+ context_update_instructions: Optional[str] = None,
691
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
518
692
  stream: bool = False,
519
693
  **kwargs: Any,
520
- ) -> Union[AgentResponse[T], AgentStream[T]]:
694
+ ) -> Union[AgentResponse[T, AgentContext], AgentStream[T, AgentContext]]:
521
695
  """Runs this agent and returns a final agent response or stream.
522
696
 
523
697
  You can override defaults assigned to this agent from this function directly.
@@ -614,6 +788,18 @@ class Agent(BaseGenAIModel, Generic[T]):
614
788
  if max_steps is None:
615
789
  max_steps = self.settings.max_steps
616
790
 
791
+ # Get effective context settings
792
+ effective_context_settings = self._get_effective_context_settings(
793
+ context_updates=context_updates,
794
+ context_confirm=context_confirm,
795
+ context_strategy=context_strategy,
796
+ context_max_retries=context_max_retries,
797
+ context_confirm_instructions=context_confirm_instructions,
798
+ context_selection_instructions=context_selection_instructions,
799
+ context_update_instructions=context_update_instructions,
800
+ context_format=context_format,
801
+ )
802
+
617
803
  # Parse initial messages
618
804
  parsed_messages = parse_messages(messages)
619
805
  current_messages = parsed_messages.copy()
@@ -621,6 +807,16 @@ class Agent(BaseGenAIModel, Generic[T]):
621
807
 
622
808
  # RUN MAIN AGENTIC LOOP
623
809
  for step in range(max_steps):
810
+ # Update context before processing if configured
811
+ if context and self._should_update_context(context, "before", effective_context_settings["context_updates"]):
812
+ context = self._perform_context_update(
813
+ context=context,
814
+ model=working_model,
815
+ current_messages=current_messages,
816
+ timing="before",
817
+ effective_settings=effective_context_settings,
818
+ )
819
+
624
820
  # Format messages with instructions and context for first step only
625
821
  if step == 0:
626
822
  formatted_messages = self._format_messages_with_context(
@@ -640,7 +836,7 @@ class Agent(BaseGenAIModel, Generic[T]):
640
836
  # Get language model response
641
837
  response = working_model.run(
642
838
  messages=formatted_messages,
643
- tools=[tool.model_dump() for tool in self.tools]
839
+ tools=[tool.to_dict() for tool in self.tools]
644
840
  if self.tools
645
841
  else None,
646
842
  **model_kwargs,
@@ -663,6 +859,15 @@ class Agent(BaseGenAIModel, Generic[T]):
663
859
  steps.append(response)
664
860
  else:
665
861
  # No tool calls - this is the final step
862
+ # Update context after processing if configured
863
+ if context and self._should_update_context(context, "after", effective_context_settings["context_updates"]):
864
+ context = self._perform_context_update(
865
+ context=context,
866
+ model=working_model,
867
+ current_messages=current_messages,
868
+ timing="after",
869
+ effective_settings=effective_context_settings,
870
+ )
666
871
  return _create_agent_response_from_language_model_response(
667
872
  response=response, steps=steps, context=context
668
873
  )
@@ -680,6 +885,16 @@ class Agent(BaseGenAIModel, Generic[T]):
680
885
  **model_kwargs,
681
886
  )
682
887
 
888
+ # Update context after processing if configured
889
+ if context and self._should_update_context(context, "after", effective_context_settings["context_updates"]):
890
+ context = self._perform_context_update(
891
+ context=context,
892
+ model=working_model,
893
+ current_messages=current_messages,
894
+ timing="after",
895
+ effective_settings=effective_context_settings,
896
+ )
897
+
683
898
  return _create_agent_response_from_language_model_response(
684
899
  response=final_response, steps=steps, context=context
685
900
  )
@@ -691,8 +906,18 @@ class Agent(BaseGenAIModel, Generic[T]):
691
906
  max_steps: Optional[int] = None,
692
907
  context: Optional[AgentContext] = None,
693
908
  output_type: Optional[Type[T]] = None,
909
+ context_updates: Optional[
910
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
911
+ ] = None,
912
+ context_confirm: Optional[bool] = None,
913
+ context_strategy: Optional[Literal["selective", "all"]] = None,
914
+ context_max_retries: Optional[int] = None,
915
+ context_confirm_instructions: Optional[str] = None,
916
+ context_selection_instructions: Optional[str] = None,
917
+ context_update_instructions: Optional[str] = None,
918
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
694
919
  **kwargs: Any,
695
- ) -> AgentResponse[T]:
920
+ ) -> AgentResponse[T, AgentContext]:
696
921
  """Runs this agent asynchronously and returns a final agent response.
697
922
 
698
923
  You can override defaults assigned to this agent from this function directly.
@@ -772,6 +997,18 @@ class Agent(BaseGenAIModel, Generic[T]):
772
997
  if max_steps is None:
773
998
  max_steps = self.settings.max_steps
774
999
 
1000
+ # Get effective context settings
1001
+ effective_context_settings = self._get_effective_context_settings(
1002
+ context_updates=context_updates,
1003
+ context_confirm=context_confirm,
1004
+ context_strategy=context_strategy,
1005
+ context_max_retries=context_max_retries,
1006
+ context_confirm_instructions=context_confirm_instructions,
1007
+ context_selection_instructions=context_selection_instructions,
1008
+ context_update_instructions=context_update_instructions,
1009
+ context_format=context_format,
1010
+ )
1011
+
775
1012
  # Parse initial messages
776
1013
  parsed_messages = parse_messages(messages)
777
1014
  current_messages = parsed_messages.copy()
@@ -779,6 +1016,16 @@ class Agent(BaseGenAIModel, Generic[T]):
779
1016
 
780
1017
  # RUN MAIN AGENTIC LOOP
781
1018
  for step in range(max_steps):
1019
+ # Update context before processing if configured
1020
+ if context and self._should_update_context(context, "before", effective_context_settings["context_updates"]):
1021
+ context = self._perform_context_update(
1022
+ context=context,
1023
+ model=working_model,
1024
+ current_messages=current_messages,
1025
+ timing="before",
1026
+ effective_settings=effective_context_settings,
1027
+ )
1028
+
782
1029
  # Format messages with instructions and context for first step only
783
1030
  if step == 0:
784
1031
  formatted_messages = self._format_messages_with_context(
@@ -798,7 +1045,7 @@ class Agent(BaseGenAIModel, Generic[T]):
798
1045
  # Get language model response
799
1046
  response = await working_model.async_run(
800
1047
  messages=formatted_messages,
801
- tools=[tool.model_dump() for tool in self.tools]
1048
+ tools=[tool.to_dict() for tool in self.tools]
802
1049
  if self.tools
803
1050
  else None,
804
1051
  **model_kwargs,
@@ -821,6 +1068,15 @@ class Agent(BaseGenAIModel, Generic[T]):
821
1068
  steps.append(response)
822
1069
  else:
823
1070
  # No tool calls - this is the final step
1071
+ # Update context after processing if configured
1072
+ if context and self._should_update_context(context, "after", effective_context_settings["context_updates"]):
1073
+ context = self._perform_context_update(
1074
+ context=context,
1075
+ model=working_model,
1076
+ current_messages=current_messages,
1077
+ timing="after",
1078
+ effective_settings=effective_context_settings,
1079
+ )
824
1080
  return _create_agent_response_from_language_model_response(
825
1081
  response=response, steps=steps, context=context
826
1082
  )
@@ -838,6 +1094,16 @@ class Agent(BaseGenAIModel, Generic[T]):
838
1094
  **model_kwargs,
839
1095
  )
840
1096
 
1097
+ # Update context after processing if configured
1098
+ if context and self._should_update_context(context, "after", effective_context_settings["context_updates"]):
1099
+ context = self._perform_context_update(
1100
+ context=context,
1101
+ model=working_model,
1102
+ current_messages=current_messages,
1103
+ timing="after",
1104
+ effective_settings=effective_context_settings,
1105
+ )
1106
+
841
1107
  return _create_agent_response_from_language_model_response(
842
1108
  response=final_response, steps=steps, context=context
843
1109
  )
@@ -850,7 +1116,7 @@ class Agent(BaseGenAIModel, Generic[T]):
850
1116
  context: Optional[AgentContext] = None,
851
1117
  output_type: Optional[Type[T]] = None,
852
1118
  **kwargs: Any,
853
- ) -> AgentStream[T]:
1119
+ ) -> AgentStream[T, AgentContext]:
854
1120
  """Create a stream that yields agent steps.
855
1121
 
856
1122
  Args:
@@ -882,8 +1148,18 @@ class Agent(BaseGenAIModel, Generic[T]):
882
1148
  max_steps: Optional[int] = None,
883
1149
  context: Optional[AgentContext] = None,
884
1150
  output_type: Optional[Type[T]] = None,
1151
+ context_updates: Optional[
1152
+ Union[List[Literal["before", "after"]], Literal["before", "after"]]
1153
+ ] = None,
1154
+ context_confirm: Optional[bool] = None,
1155
+ context_strategy: Optional[Literal["selective", "all"]] = None,
1156
+ context_max_retries: Optional[int] = None,
1157
+ context_confirm_instructions: Optional[str] = None,
1158
+ context_selection_instructions: Optional[str] = None,
1159
+ context_update_instructions: Optional[str] = None,
1160
+ context_format: Optional[Literal["json", "python", "markdown"]] = None,
885
1161
  **kwargs: Any,
886
- ) -> AgentStream[T]:
1162
+ ) -> AgentStream[T, AgentContext]:
887
1163
  """Iterate over agent steps, yielding each step response.
888
1164
 
889
1165
  You can override defaults assigned to this agent from this function directly.
@@ -986,7 +1262,7 @@ class Agent(BaseGenAIModel, Generic[T]):
986
1262
  context: Optional[AgentContext] = None,
987
1263
  output_type: Optional[Type[T]] = None,
988
1264
  **kwargs: Any,
989
- ) -> AgentStream[T]:
1265
+ ) -> AgentStream[T, AgentContext]:
990
1266
  """Async iterate over agent steps, yielding each step response.
991
1267
 
992
1268
  Args:
@@ -1,12 +1,14 @@
1
1
  """hammad.genai.agents.types.agent_response"""
2
2
 
3
- from typing import List, Any, TypeVar, Literal
3
+ from typing import List, Any, TypeVar, Literal, Generic
4
4
 
5
5
  from ....cache import cached
6
+ from ....typing import get_type_description
6
7
  from ...models.language.types import (
7
8
  LanguageModelResponse,
8
9
  )
9
10
 
11
+ from .agent_context import AgentContext
10
12
 
11
13
  __all__ = [
12
14
  "AgentResponse",
@@ -40,7 +42,7 @@ def _create_agent_response_from_language_model_response(
40
42
  ) from e
41
43
 
42
44
 
43
- class AgentResponse(LanguageModelResponse[T]):
45
+ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
44
46
  """A response generated by an agent, that includes the steps and final
45
47
  output during the agent's execution."""
46
48
 
@@ -55,7 +57,7 @@ class AgentResponse(LanguageModelResponse[T]):
55
57
  empty.
56
58
  """
57
59
 
58
- context: Any = None
60
+ context: AgentContext = None
59
61
  """
60
62
  The final context object after agent execution.
61
63
 
@@ -77,7 +79,7 @@ class AgentResponse(LanguageModelResponse[T]):
77
79
  # NOTE:
78
80
  # added +1 to include final step in the output
79
81
  output += f"\n>>> Steps: {len(self.steps) + 1}"
80
- output += f"\n>>> Tool Calls: {len(self.tool_calls) if self.tool_calls else 0}"
82
+ output += f"\n>>> Output Type: {get_type_description(type(self.output))}"
81
83
 
82
84
  # Calculate total tool calls across all steps
83
85
  total_tool_calls = 0
@@ -87,4 +89,34 @@ class AgentResponse(LanguageModelResponse[T]):
87
89
 
88
90
  output += f"\n>>> Total Tool Calls: {total_tool_calls}"
89
91
 
92
+ # Show context if available
93
+ if self.context:
94
+ output += f"\n>>> Final Context: {self._format_context_display(self.context)}"
95
+
90
96
  return output
97
+
98
+ def _format_context_display(self, context: AgentContext) -> str:
99
+ """Format context for display in string representation."""
100
+ if context is None:
101
+ return "None"
102
+
103
+ try:
104
+ # For Pydantic models, show as dict
105
+ if hasattr(context, 'model_dump'):
106
+ context_dict = context.model_dump()
107
+ elif isinstance(context, dict):
108
+ context_dict = context
109
+ else:
110
+ return str(context)
111
+
112
+ # Format as compact JSON-like string
113
+ items = []
114
+ for key, value in context_dict.items():
115
+ if isinstance(value, str):
116
+ items.append(f"{key}='{value}'")
117
+ else:
118
+ items.append(f"{key}={value}")
119
+
120
+ return "{" + ", ".join(items) + "}"
121
+ except Exception:
122
+ return str(context)