agent-framework-lib 0.6.1__tar.gz → 0.6.2__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 (226) hide show
  1. {agent_framework_lib-0.6.1/agent_framework_lib.egg-info → agent_framework_lib-0.6.2}/PKG-INFO +1 -1
  2. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/__init__.py +2 -2
  3. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/context_budget.py +25 -7
  4. agent_framework_lib-0.6.2/agent_framework/core/knowledge_state.py +228 -0
  5. agent_framework_lib-0.6.2/agent_framework/core/loop_detector.py +148 -0
  6. agent_framework_lib-0.6.2/agent_framework/core/provider_calibration.py +126 -0
  7. agent_framework_lib-0.6.2/agent_framework/core/scratchpad_compressor.py +791 -0
  8. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/budget_aware_agent.py +112 -0
  9. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/token_counter.py +54 -0
  10. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2/agent_framework_lib.egg-info}/PKG-INFO +1 -1
  11. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/SOURCES.txt +3 -0
  12. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/pyproject.toml +1 -1
  13. agent_framework_lib-0.6.1/agent_framework/core/scratchpad_compressor.py +0 -391
  14. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/ARCHITECTURE.md +0 -0
  15. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/LICENSE +0 -0
  16. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/MANIFEST.in +0 -0
  17. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/README.md +0 -0
  18. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/__init__.py +0 -0
  19. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/base.py +0 -0
  20. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/__init__.py +0 -0
  21. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/a2a_router.py +0 -0
  22. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/agent_card_builder.py +0 -0
  23. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/agent_card_skill_builder.py +0 -0
  24. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/jsonrpc_dispatcher.py +0 -0
  25. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/models_jsonrpc.py +0 -0
  26. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/sse_wrapper.py +0 -0
  27. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/translation_layer.py +0 -0
  28. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/models.py +0 -0
  29. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/__init__.py +0 -0
  30. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/elasticsearch_provider.py +0 -0
  31. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/postgres_provider.py +0 -0
  32. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/chart_generation/llm_refinement_loop.py +0 -0
  33. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/__init__.py +0 -0
  34. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/activity_formatter.py +0 -0
  35. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/agent_interface.py +0 -0
  36. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/agent_provider.py +0 -0
  37. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/base_agent.py +0 -0
  38. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/context_summarizer.py +0 -0
  39. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/elasticsearch_config_provider.py +0 -0
  40. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/implementation_validator.py +0 -0
  41. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_clients.py +0 -0
  42. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_config.py +0 -0
  43. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_router.py +0 -0
  44. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/models.py +0 -0
  45. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/rich_content_prompt_unsused_to_be_deleted.py +0 -0
  46. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/state_manager.py +0 -0
  47. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/step_display_config.py +0 -0
  48. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/streaming_parts_accumulator.py +0 -0
  49. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/__init__.py +0 -0
  50. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/llamaindex_agent.py +0 -0
  51. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/llamaindex_memory_adapter.py +0 -0
  52. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/microsoft_agent.py +0 -0
  53. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/__init__.py +0 -0
  54. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/agent_mixin.py +0 -0
  55. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/base.py +0 -0
  56. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/config.py +0 -0
  57. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/manager.py +0 -0
  58. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/personalization.py +0 -0
  59. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/__init__.py +0 -0
  60. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/graphiti_provider.py +0 -0
  61. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/memori_provider.py +0 -0
  62. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/tools.py +0 -0
  63. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/__init__.py +0 -0
  64. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/api_timing_tracker.py +0 -0
  65. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/elasticsearch_circuit_breaker.py +0 -0
  66. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/elasticsearch_logging.py +0 -0
  67. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/error_handling.py +0 -0
  68. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/error_logging.py +0 -0
  69. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_auto_instrumentor.py +0 -0
  70. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics.py +0 -0
  71. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics_collector.py +0 -0
  72. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics_extractor.py +0 -0
  73. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/metrics_aggregator.py +0 -0
  74. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/metrics_config.py +0 -0
  75. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/observability_manager.py +0 -0
  76. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_instrumentor.py +0 -0
  77. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_logging_handler.py +0 -0
  78. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_metrics_recorder.py +0 -0
  79. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_setup.py +0 -0
  80. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/performance_monitor.py +0 -0
  81. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/progress_tracker.py +0 -0
  82. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/resource_manager.py +0 -0
  83. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/resource_metrics_collector.py +0 -0
  84. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/streaming_latency_tracer.py +0 -0
  85. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/timing_tracker.py +0 -0
  86. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/tracing_context.py +0 -0
  87. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/__init__.py +0 -0
  88. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/ai_content_management.py +0 -0
  89. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/markdown_converter.py +0 -0
  90. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/multimodal_integration.py +0 -0
  91. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/rich_content_validation.py +0 -0
  92. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/py.typed +0 -0
  93. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/__init__.py +0 -0
  94. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/elasticsearch_session_storage.py +0 -0
  95. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/session_storage.py +0 -0
  96. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/__init__.py +0 -0
  97. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/agent_mixin.py +0 -0
  98. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/base.py +0 -0
  99. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/__init__.py +0 -0
  100. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/chart_skill.py +0 -0
  101. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/file_access_skill.py +0 -0
  102. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/file_skill.py +0 -0
  103. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/form_skill.py +0 -0
  104. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/image_display_skill.py +0 -0
  105. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/mermaid_skill.py +0 -0
  106. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/multimodal_skill.py +0 -0
  107. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/optionsblock_skill.py +0 -0
  108. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/pdf_skill.py +0 -0
  109. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/pdf_with_images_skill.py +0 -0
  110. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/table_skill.py +0 -0
  111. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/unified_pdf_skill.py +0 -0
  112. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/web_search_skill.py +0 -0
  113. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/discovery_prompt.py +0 -0
  114. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/tools.py +0 -0
  115. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/__init__.py +0 -0
  116. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/file_storages.py +0 -0
  117. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/file_system_management.py +0 -0
  118. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/storage_optimizer.py +0 -0
  119. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/__init__.py +0 -0
  120. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/adaptive_pdf_css.py +0 -0
  121. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/base.py +0 -0
  122. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/chart_tools.py +0 -0
  123. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/file_access_tools.py +0 -0
  124. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/file_tools.py +0 -0
  125. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/html_content_analyzer.py +0 -0
  126. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/mermaid_tools.py +0 -0
  127. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/multimodal_tools.py +0 -0
  128. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_image_scaler.py +0 -0
  129. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_tools.py +0 -0
  130. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_with_images_tool.py +0 -0
  131. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/sizing_config.py +0 -0
  132. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/tabledata_tools.py +0 -0
  133. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/unified_pdf_tool.py +0 -0
  134. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/web_search_tools.py +0 -0
  135. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/__init__.py +0 -0
  136. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/path_utils.py +0 -0
  137. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/post_install.py +0 -0
  138. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/session_title_generator.py +0 -0
  139. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/source_detector.py +0 -0
  140. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/special_blocks.py +0 -0
  141. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/__init__.py +0 -0
  142. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_auth.py +0 -0
  143. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_models.py +0 -0
  144. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_router.py +0 -0
  145. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_services.py +0 -0
  146. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/api_timing_middleware.py +0 -0
  147. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/A2A_GUIDE.md +0 -0
  148. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/CREATING_AGENTS.md +0 -0
  149. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/DOCKER_SETUP.md +0 -0
  150. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/Dockerfile +0 -0
  151. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/GETTING_STARTED.md +0 -0
  152. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/MEMORY_INSTALLATION.md +0 -0
  153. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/README.md +0 -0
  154. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/TOOLS_AND_MCP_GUIDE.md +0 -0
  155. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/api-reference.md +0 -0
  156. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/configuration.md +0 -0
  157. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/docker-compose.yml +0 -0
  158. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_example_multi_skills.py +0 -0
  159. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_file_storage.py +0 -0
  160. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_mcp.py +0 -0
  161. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory.py +0 -0
  162. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_graphiti.py +0 -0
  163. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_hybrid.py +0 -0
  164. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_simple.py +0 -0
  165. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/custom_framework_agent.py +0 -0
  166. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/simple_agent.py +0 -0
  167. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/skills_demo_agent.py +0 -0
  168. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/installation-guide.md +0 -0
  169. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/documentation_generator.py +0 -0
  170. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/helper_agent.py +0 -0
  171. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/helper_ui.html +0 -0
  172. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/modern_ui.html +0 -0
  173. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/observability/kibana-llm-dashboard-setup.json +0 -0
  174. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/observability/kibana-resource-metrics-dashboard.json +0 -0
  175. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/otel_tracing_middleware.py +0 -0
  176. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/server.py +0 -0
  177. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/test_app.html +0 -0
  178. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/dependency_links.txt +0 -0
  179. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/entry_points.txt +0 -0
  180. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/requires.txt +0 -0
  181. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/top_level.txt +0 -0
  182. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/A2A_GUIDE.md +0 -0
  183. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ACTIVITY_OUTPUT_PART.md +0 -0
  184. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ARCHITECTURE_DIAGRAM.md +0 -0
  185. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/CONCURRENCE_VS_PARALLELISME_GUIDE.md +0 -0
  186. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/CREATING_AGENTS.md +0 -0
  187. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/DOCKER_SETUP.md +0 -0
  188. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ELASTICSEARCH_DATA_STRUCTURES.md +0 -0
  189. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/FILE_DOWNLOAD_LINKS.md +0 -0
  190. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/FILE_STORAGE_GUIDE.md +0 -0
  191. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/GETTING_STARTED.md +0 -0
  192. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/HISTORY_MESSAGE_FORMAT.md +0 -0
  193. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/IMPLEMENTATION_GUIDE_NEW_AGENT.md +0 -0
  194. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MEMORY_INSTALLATION.md +0 -0
  195. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MODIFICATIONS_CONCURRENCE.md +0 -0
  196. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MULTIMODAL_TOOLS_GUIDE.md +0 -0
  197. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/OBSERVABILITY_GUIDE.md +0 -0
  198. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/PYPI_PUBLISHING.md +0 -0
  199. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/QA_STREAMING_LATENCY.md +0 -0
  200. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/SPEC_CROSS_MODEL_HISTORY_CONVERSION.md +0 -0
  201. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/STREAMING_EVENTS_FRONTEND.md +0 -0
  202. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/TOOLS_AND_MCP_GUIDE.md +0 -0
  203. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/api-reference.md +0 -0
  204. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/configuration.md +0 -0
  205. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/framework_audit_remarques.md +0 -0
  206. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/installation-guide.md +0 -0
  207. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/README.md +0 -0
  208. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_context_budget_test.py +0 -0
  209. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_example_multi_skills.py +0 -0
  210. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_exemple_test.py +0 -0
  211. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_training_with_apo.py +0 -0
  212. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_custom_tools_file_storage.py +0 -0
  213. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_file_storage.py +0 -0
  214. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_mcp.py +0 -0
  215. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_graphiti.py +0 -0
  216. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_hybrid.py +0 -0
  217. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_simple.py +0 -0
  218. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_personalization.py +0 -0
  219. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/biagenttest.py +0 -0
  220. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/custom_framework_agent.py +0 -0
  221. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/dependencies/docker-compose.yaml +0 -0
  222. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/pyproject.toml +0 -0
  223. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/simple_agent.py +0 -0
  224. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/skills_demo_agent.py +0 -0
  225. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/setup.cfg +0 -0
  226. {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-framework-lib
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: A comprehensive Python framework for building and serving conversational AI agents with FastAPI
5
5
  Author-email: Sebastian Pavel <sebastian@cinco.ai>, Elliott Girard <elliott.girard@icloud.com>
6
6
  Maintainer-email: Sebastian Pavel <sebastian@cinco.ai>
@@ -32,7 +32,7 @@ Example Usage:
32
32
  create_basic_agent_server(MyAgent, port=8000)
33
33
  ```
34
34
 
35
- Version: 0.6.1
35
+ Version: 0.6.2
36
36
  Author: Cinco AI Team
37
37
  License: MIT
38
38
  """
@@ -88,7 +88,7 @@ def _auto_setup_dependencies() -> None:
88
88
  # Track if auto-setup has been done
89
89
  _AUTO_SETUP_DONE = False
90
90
 
91
- __version__ = "0.6.1"
91
+ __version__ = "0.6.2"
92
92
  __author__ = "Cinco AI Team"
93
93
  __license__ = "MIT"
94
94
  __email__ = "sebastian@cinco.ai"
@@ -10,6 +10,8 @@ import logging
10
10
  from dataclasses import dataclass
11
11
  from typing import TYPE_CHECKING
12
12
 
13
+ from agent_framework.core.provider_calibration import ProviderCalibrationRegistry
14
+
13
15
  if TYPE_CHECKING:
14
16
  from llama_index.core.llms import ChatMessage
15
17
 
@@ -102,6 +104,9 @@ class BudgetSnapshot:
102
104
  usage_percent: float
103
105
  compression_triggered: bool
104
106
  model_name: str
107
+ tool_definition_multiplier: float = 1.0
108
+ raw_tool_tokens: int = 0
109
+ estimated_tool_tokens: int = 0
105
110
 
106
111
 
107
112
  class ContextBudgetManager:
@@ -133,6 +138,8 @@ class ContextBudgetManager:
133
138
  self._sacred_zone_tokens = 0
134
139
  self._prompt_tokens = 0
135
140
  self._tool_definition_tokens = 0
141
+ self._raw_tool_tokens = 0
142
+ self._tool_definition_multiplier = 1.0
136
143
 
137
144
  # Resolution order: explicit parameter > env var > class constant
138
145
  def _resolve(param, env_key, default):
@@ -251,8 +258,8 @@ class ContextBudgetManager:
251
258
  """Compte et enregistre les tokens de la Zone Sacrée.
252
259
 
253
260
  Le system prompt est compté tel quel (tiktoken est fiable pour du texte).
254
- Les tool definitions reçoivent un multiplicateur car les providers
255
- (Anthropic notamment) les sérialisent avec un wrapping lourd.
261
+ Les tool definitions reçoivent un multiplicateur calibré par provider car
262
+ les providers sérialisent les définitions avec un wrapping lourd.
256
263
 
257
264
  Args:
258
265
  system_prompt: Prompt système complet (agent + skills + mémoire passive).
@@ -262,15 +269,20 @@ class ContextBudgetManager:
262
269
  Nombre total estimé de tokens de la Zone Sacrée.
263
270
  """
264
271
  self._prompt_tokens = self._token_counter.count_tokens(system_prompt).count
265
- raw_tool_tokens = self._token_counter.count_tokens(tool_definitions).count
266
- self._tool_definition_tokens = raw_tool_tokens * self.TOOL_DEFINITION_MULTIPLIER
272
+ self._raw_tool_tokens = self._token_counter.count_tokens(tool_definitions).count
273
+ self._tool_definition_multiplier = ProviderCalibrationRegistry.get_multiplier(
274
+ self._model_name
275
+ )
276
+ self._tool_definition_tokens = int(
277
+ self._raw_tool_tokens * self._tool_definition_multiplier
278
+ )
267
279
  self._sacred_zone_tokens = self._prompt_tokens + self._tool_definition_tokens
268
280
  logger.info(
269
- "Sacred zone: %d tokens (prompt=%d, tools=%d raw * %dx = %d)",
281
+ "Sacred zone: %d tokens (prompt=%d, tools=%d raw * %.1fx = %d)",
270
282
  self._sacred_zone_tokens,
271
283
  self._prompt_tokens,
272
- raw_tool_tokens,
273
- self.TOOL_DEFINITION_MULTIPLIER,
284
+ self._raw_tool_tokens,
285
+ self._tool_definition_multiplier,
274
286
  self._tool_definition_tokens,
275
287
  )
276
288
  if self._sacred_zone_tokens > 0.65 * self._context_window:
@@ -340,6 +352,9 @@ class ContextBudgetManager:
340
352
  usage_percent=usage,
341
353
  compression_triggered=False,
342
354
  model_name=self._model_name,
355
+ tool_definition_multiplier=self._tool_definition_multiplier,
356
+ raw_tool_tokens=self._raw_tool_tokens,
357
+ estimated_tool_tokens=int(self._raw_tool_tokens * self._tool_definition_multiplier),
343
358
  )
344
359
 
345
360
  async def enforce_budget(
@@ -576,6 +591,9 @@ class ContextBudgetManager:
576
591
  usage_percent=usage,
577
592
  compression_triggered=True,
578
593
  model_name=self._model_name,
594
+ tool_definition_multiplier=self._tool_definition_multiplier,
595
+ raw_tool_tokens=self._raw_tool_tokens,
596
+ estimated_tool_tokens=int(self._raw_tool_tokens * self._tool_definition_multiplier),
579
597
  )
580
598
 
581
599
  async def truncate_query_if_needed(
@@ -0,0 +1,228 @@
1
+ """Knowledge state tracking for scratchpad compression.
2
+
3
+ Captures and structures knowledge acquired from tool calls,
4
+ preserving it across successive compressions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import hashlib
10
+ import json
11
+ import logging
12
+ from dataclasses import dataclass
13
+ from typing import TYPE_CHECKING, Any, Literal
14
+
15
+ if TYPE_CHECKING:
16
+ from agent_framework.monitoring.token_counter import TokenCounter
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class ToolCallSignature:
23
+ """Unique identifier for a tool call based on name and argument hash."""
24
+
25
+ tool_name: str
26
+ args_hash: str
27
+
28
+ @classmethod
29
+ def from_tool_call(
30
+ cls, tool_name: str, tool_kwargs: dict[str, Any]
31
+ ) -> ToolCallSignature:
32
+ """Compute a deterministic signature from tool name and arguments.
33
+
34
+ Uses canonical JSON serialization (sorted keys, compact separators)
35
+ for the hash. Falls back to str() if JSON serialization fails.
36
+
37
+ Args:
38
+ tool_name: Name of the tool.
39
+ tool_kwargs: Dictionary of tool arguments.
40
+
41
+ Returns:
42
+ A ToolCallSignature with a SHA-256 hash of the arguments.
43
+ """
44
+ try:
45
+ canonical = json.dumps(tool_kwargs, sort_keys=True, separators=(",", ":"))
46
+ except (TypeError, ValueError):
47
+ logger.warning(
48
+ "JSON serialization failed for tool '%s' args, falling back to str()",
49
+ tool_name,
50
+ )
51
+ canonical = str(tool_kwargs)
52
+
53
+ args_hash = hashlib.sha256(canonical.encode()).hexdigest()
54
+ return cls(tool_name=tool_name, args_hash=args_hash)
55
+
56
+ def __hash__(self) -> int:
57
+ return hash((self.tool_name, self.args_hash))
58
+
59
+ def __eq__(self, other: object) -> bool:
60
+ if not isinstance(other, ToolCallSignature):
61
+ return NotImplemented
62
+ return self.tool_name == other.tool_name and self.args_hash == other.args_hash
63
+
64
+
65
+ @dataclass
66
+ class ToolResultEntry:
67
+ """Structured result of a tool call."""
68
+
69
+ signature: ToolCallSignature
70
+ tool_name: str
71
+ arguments: dict[str, Any]
72
+ status: Literal["success", "error", "truncated"]
73
+ key_data: dict[str, Any]
74
+ numeric_values: dict[str, Any]
75
+ raw_excerpt: str
76
+ timestamp: float
77
+
78
+
79
+ class KnowledgeState:
80
+ """Accumulated knowledge state, persisted across compressions."""
81
+
82
+ def __init__(self) -> None:
83
+ self._entries: dict[ToolCallSignature, ToolResultEntry] = {}
84
+
85
+ def add_entry(self, entry: ToolResultEntry) -> None:
86
+ """Add or update an entry in the registry.
87
+
88
+ Args:
89
+ entry: The tool result entry to store.
90
+ """
91
+ self._entries[entry.signature] = entry
92
+
93
+ def get_entry(self, signature: ToolCallSignature) -> ToolResultEntry | None:
94
+ """Retrieve an entry by its signature.
95
+
96
+ Args:
97
+ signature: The tool call signature to look up.
98
+
99
+ Returns:
100
+ The matching entry, or None if not found.
101
+ """
102
+ return self._entries.get(signature)
103
+
104
+ def has_signature(self, signature: ToolCallSignature) -> bool:
105
+ """Check whether a signature is already registered.
106
+
107
+ Args:
108
+ signature: The tool call signature to check.
109
+
110
+ Returns:
111
+ True if the signature exists in the registry.
112
+ """
113
+ return signature in self._entries
114
+
115
+ def get_all_entries(self) -> list[ToolResultEntry]:
116
+ """Return all entries in insertion order.
117
+
118
+ Returns:
119
+ List of all stored tool result entries.
120
+ """
121
+ return list(self._entries.values())
122
+
123
+ def get_entries_by_tool(self, tool_name: str) -> list[ToolResultEntry]:
124
+ """Return entries filtered by tool name.
125
+
126
+ Args:
127
+ tool_name: Name of the tool to filter by.
128
+
129
+ Returns:
130
+ List of entries matching the given tool name.
131
+ """
132
+ return [e for e in self._entries.values() if e.tool_name == tool_name]
133
+
134
+ def to_structured_text(self) -> str:
135
+ """Serialize the full knowledge state as structured text.
136
+
137
+ Produces a human-readable representation with sections per tool call
138
+ and tabular format for numeric data.
139
+
140
+ Returns:
141
+ Structured text representation of all entries.
142
+ """
143
+ if not self._entries:
144
+ return ""
145
+
146
+ sections: list[str] = []
147
+ for entry in self._entries.values():
148
+ lines: list[str] = []
149
+ lines.append(f"[{entry.tool_name}] status={entry.status}")
150
+
151
+ if entry.arguments:
152
+ args_str = ", ".join(
153
+ f"{k}={v!r}" for k, v in entry.arguments.items()
154
+ )
155
+ lines.append(f" args: {args_str}")
156
+
157
+ if entry.numeric_values:
158
+ lines.append(" numeric_data:")
159
+ for k, v in entry.numeric_values.items():
160
+ lines.append(f" {k}: {v}")
161
+
162
+ if entry.key_data:
163
+ lines.append(" key_data:")
164
+ for k, v in entry.key_data.items():
165
+ lines.append(f" {k}: {v}")
166
+
167
+ if entry.raw_excerpt:
168
+ lines.append(f" excerpt: {entry.raw_excerpt}")
169
+
170
+ sections.append("\n".join(lines))
171
+
172
+ return "\n\n".join(sections)
173
+
174
+ def to_compact_text(self, max_tokens: int, token_counter: TokenCounter) -> str:
175
+ """Serialize a compact version that fits within a token budget.
176
+
177
+ Prioritizes numeric data in tabular form (key: value).
178
+ Progressively adds content until the budget is reached.
179
+
180
+ Args:
181
+ max_tokens: Maximum number of tokens allowed in the output.
182
+ token_counter: Token counter instance for measuring output size.
183
+
184
+ Returns:
185
+ Compact text representation respecting the token budget.
186
+ """
187
+ if not self._entries or max_tokens <= 0:
188
+ return ""
189
+
190
+ # Phase 1: collect numeric lines (highest priority)
191
+ numeric_lines: list[str] = []
192
+ for entry in self._entries.values():
193
+ if entry.numeric_values:
194
+ for k, v in entry.numeric_values.items():
195
+ numeric_lines.append(f"{k}: {v}")
196
+
197
+ # Phase 2: collect tool status headers
198
+ header_lines: list[str] = []
199
+ for entry in self._entries.values():
200
+ header_lines.append(f"[{entry.tool_name}] status={entry.status}")
201
+
202
+ # Phase 3: collect key_data lines
203
+ key_data_lines: list[str] = []
204
+ for entry in self._entries.values():
205
+ if entry.key_data:
206
+ for k, v in entry.key_data.items():
207
+ key_data_lines.append(f"{k}: {v}")
208
+
209
+ # Phase 4: collect excerpt lines
210
+ excerpt_lines: list[str] = []
211
+ for entry in self._entries.values():
212
+ if entry.raw_excerpt:
213
+ excerpt_lines.append(f"excerpt: {entry.raw_excerpt}")
214
+
215
+ # Build output incrementally, respecting the budget
216
+ result_lines: list[str] = []
217
+
218
+ for line_group in [numeric_lines, header_lines, key_data_lines, excerpt_lines]:
219
+ for line in line_group:
220
+ candidate = "\n".join(result_lines + [line]) if result_lines else line
221
+ count = token_counter.count_tokens(candidate).count
222
+ if count <= max_tokens:
223
+ result_lines.append(line)
224
+ else:
225
+ # Budget exhausted — return what we have
226
+ return "\n".join(result_lines)
227
+
228
+ return "\n".join(result_lines)
@@ -0,0 +1,148 @@
1
+ """Loop detection for repeated tool calls in the scratchpad.
2
+
3
+ Identifies when the agent is re-executing identical tool calls by
4
+ tracking deterministic signatures and flagging duplicates above a
5
+ configurable threshold.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from collections import Counter
12
+ from dataclasses import dataclass, field
13
+
14
+ from llama_index.core.llms import ChatMessage, MessageRole
15
+
16
+ from agent_framework.core.knowledge_state import ToolCallSignature
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class LoopDetectionResult:
23
+ """Result of a loop detection analysis on the scratchpad."""
24
+
25
+ is_loop: bool
26
+ duplicate_signatures: list[tuple[ToolCallSignature, int]] = field(
27
+ default_factory=list
28
+ )
29
+ total_duplicates: int = 0
30
+
31
+
32
+ class LoopDetector:
33
+ """Detects tool call loops in the scratchpad.
34
+
35
+ Traverses ASSISTANT messages containing tool calls, computes a
36
+ ToolCallSignature for each call, and flags signatures that appear
37
+ at or above the duplicate threshold.
38
+ """
39
+
40
+ DUPLICATE_THRESHOLD: int = 2
41
+
42
+ def detect(self, scratchpad: list[ChatMessage]) -> LoopDetectionResult:
43
+ """Analyse the scratchpad and detect duplicated tool call signatures.
44
+
45
+ Args:
46
+ scratchpad: List of ChatMessage from the tool loop.
47
+
48
+ Returns:
49
+ A LoopDetectionResult indicating whether a loop was found.
50
+ """
51
+ signatures = self._extract_signatures(scratchpad)
52
+
53
+ if not signatures:
54
+ return LoopDetectionResult(is_loop=False)
55
+
56
+ counts: Counter[ToolCallSignature] = Counter(signatures)
57
+
58
+ duplicate_signatures = [
59
+ (sig, count)
60
+ for sig, count in counts.items()
61
+ if count >= self.DUPLICATE_THRESHOLD
62
+ ]
63
+
64
+ total_duplicates = sum(count for _, count in duplicate_signatures)
65
+
66
+ if duplicate_signatures:
67
+ for sig, count in duplicate_signatures:
68
+ logger.warning(
69
+ "Duplicate tool call detected: tool='%s' args_hash='%s' repeated %d times",
70
+ sig.tool_name,
71
+ sig.args_hash,
72
+ count,
73
+ )
74
+
75
+ return LoopDetectionResult(
76
+ is_loop=len(duplicate_signatures) > 0,
77
+ duplicate_signatures=duplicate_signatures,
78
+ total_duplicates=total_duplicates,
79
+ )
80
+
81
+ def _extract_signatures(
82
+ self, scratchpad: list[ChatMessage]
83
+ ) -> list[ToolCallSignature]:
84
+ """Extract all ToolCallSignatures from ASSISTANT messages.
85
+
86
+ Handles both dict-based tool calls in additional_kwargs and
87
+ ToolCallBlock objects in message blocks.
88
+
89
+ Args:
90
+ scratchpad: List of ChatMessage to scan.
91
+
92
+ Returns:
93
+ List of ToolCallSignature found in the scratchpad.
94
+ """
95
+ signatures: list[ToolCallSignature] = []
96
+
97
+ for msg in scratchpad:
98
+ if msg.role != MessageRole.ASSISTANT:
99
+ continue
100
+
101
+ # Dict-based tool calls from additional_kwargs
102
+ kwargs = msg.additional_kwargs or {}
103
+ for tc in kwargs.get("tool_calls", []):
104
+ if isinstance(tc, dict):
105
+ name = tc.get("name") or (tc.get("function") or {}).get(
106
+ "name", ""
107
+ )
108
+ arguments = tc.get("arguments") or (
109
+ tc.get("function") or {}
110
+ ).get("arguments", {})
111
+
112
+ if not name:
113
+ continue
114
+
115
+ # arguments may be a JSON string or a dict
116
+ if isinstance(arguments, str):
117
+ try:
118
+ import json
119
+
120
+ arguments = json.loads(arguments)
121
+ except (ValueError, TypeError):
122
+ arguments = {"_raw": arguments}
123
+
124
+ if not isinstance(arguments, dict):
125
+ arguments = {"_raw": str(arguments)}
126
+
127
+ signatures.append(
128
+ ToolCallSignature.from_tool_call(name, arguments)
129
+ )
130
+
131
+ # Block-based tool calls
132
+ if hasattr(msg, "blocks"):
133
+ for block in msg.blocks or []:
134
+ if type(block).__name__ == "ToolCallBlock":
135
+ name = getattr(block, "tool_name", "")
136
+ tool_kwargs = getattr(block, "tool_kwargs", {})
137
+
138
+ if not name:
139
+ continue
140
+
141
+ if not isinstance(tool_kwargs, dict):
142
+ tool_kwargs = {}
143
+
144
+ signatures.append(
145
+ ToolCallSignature.from_tool_call(name, tool_kwargs)
146
+ )
147
+
148
+ return signatures
@@ -0,0 +1,126 @@
1
+ """Provider-specific token calibration for tool definition multipliers.
2
+
3
+ Provides empirically measured multipliers that account for the overhead
4
+ each LLM provider adds when serializing tool definitions (XML wrapping,
5
+ JSON function-calling format, etc.).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from dataclasses import dataclass
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class ProviderCalibration:
18
+ """Calibration factors for an LLM provider's tool definition overhead."""
19
+
20
+ provider_name: str
21
+ tool_definition_multiplier: float
22
+ source: str
23
+ measured_date: str
24
+ notes: str = ""
25
+
26
+
27
+ class ProviderCalibrationRegistry:
28
+ """Registry of per-provider token calibration data.
29
+
30
+ Resolves the appropriate tool-definition multiplier for a given model
31
+ by detecting the provider from the model name.
32
+ """
33
+
34
+ CALIBRATIONS: dict[str, ProviderCalibration] = {
35
+ "anthropic": ProviderCalibration(
36
+ provider_name="anthropic",
37
+ tool_definition_multiplier=15.0,
38
+ source="empirical_measurement_2025-01",
39
+ measured_date="2025-01",
40
+ notes="Heavy XML/JSON wrapping for Anthropic tool definitions",
41
+ ),
42
+ "openai": ProviderCalibration(
43
+ provider_name="openai",
44
+ tool_definition_multiplier=3.0,
45
+ source="empirical_measurement_2025-01",
46
+ measured_date="2025-01",
47
+ notes="OpenAI function-calling format, moderate overhead",
48
+ ),
49
+ "google": ProviderCalibration(
50
+ provider_name="google",
51
+ tool_definition_multiplier=4.0,
52
+ source="empirical_measurement_2025-01",
53
+ measured_date="2025-01",
54
+ notes="Gemini tool-use format, overhead similar to OpenAI",
55
+ ),
56
+ }
57
+
58
+ DEFAULT_MULTIPLIER: float = 5.0
59
+
60
+ # Prefix-to-provider mapping for model name detection
61
+ _PROVIDER_PREFIXES: dict[str, str] = {
62
+ "claude": "anthropic",
63
+ "gpt": "openai",
64
+ "o1": "openai",
65
+ "o3": "openai",
66
+ "o4": "openai",
67
+ "gemini": "google",
68
+ }
69
+
70
+ @classmethod
71
+ def detect_provider(cls, model_name: str) -> str | None:
72
+ """Detect the provider from a model name.
73
+
74
+ Checks if the model name starts with or contains known prefixes.
75
+
76
+ Args:
77
+ model_name: Name of the LLM model.
78
+
79
+ Returns:
80
+ Provider name (e.g. "anthropic") or None if unrecognized.
81
+ """
82
+ lower = model_name.lower()
83
+ # Check longest prefixes first to avoid false positives
84
+ for prefix in sorted(cls._PROVIDER_PREFIXES, key=len, reverse=True):
85
+ if lower.startswith(prefix):
86
+ return cls._PROVIDER_PREFIXES[prefix]
87
+ return None
88
+
89
+ @classmethod
90
+ def get_calibration(cls, model_name: str) -> ProviderCalibration | None:
91
+ """Return the full calibration for a model, or None if unknown.
92
+
93
+ Args:
94
+ model_name: Name of the LLM model.
95
+
96
+ Returns:
97
+ ProviderCalibration if the provider is recognized, else None.
98
+ """
99
+ provider = cls.detect_provider(model_name)
100
+ if provider is None:
101
+ return None
102
+ return cls.CALIBRATIONS.get(provider)
103
+
104
+ @classmethod
105
+ def get_multiplier(cls, model_name: str) -> float:
106
+ """Resolve the tool-definition multiplier for a model.
107
+
108
+ Falls back to DEFAULT_MULTIPLIER (5.0) and logs INFO when the
109
+ provider is not recognized.
110
+
111
+ Args:
112
+ model_name: Name of the LLM model.
113
+
114
+ Returns:
115
+ The provider-specific multiplier, or the default.
116
+ """
117
+ calibration = cls.get_calibration(model_name)
118
+ if calibration is not None:
119
+ return calibration.tool_definition_multiplier
120
+
121
+ logger.info(
122
+ "No calibration for model '%s', using default multiplier %.1f",
123
+ model_name,
124
+ cls.DEFAULT_MULTIPLIER,
125
+ )
126
+ return cls.DEFAULT_MULTIPLIER