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.
- {agent_framework_lib-0.6.1/agent_framework_lib.egg-info → agent_framework_lib-0.6.2}/PKG-INFO +1 -1
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/__init__.py +2 -2
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/context_budget.py +25 -7
- agent_framework_lib-0.6.2/agent_framework/core/knowledge_state.py +228 -0
- agent_framework_lib-0.6.2/agent_framework/core/loop_detector.py +148 -0
- agent_framework_lib-0.6.2/agent_framework/core/provider_calibration.py +126 -0
- agent_framework_lib-0.6.2/agent_framework/core/scratchpad_compressor.py +791 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/budget_aware_agent.py +112 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/token_counter.py +54 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2/agent_framework_lib.egg-info}/PKG-INFO +1 -1
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/SOURCES.txt +3 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/pyproject.toml +1 -1
- agent_framework_lib-0.6.1/agent_framework/core/scratchpad_compressor.py +0 -391
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/ARCHITECTURE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/LICENSE +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/MANIFEST.in +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/README.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/base.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/a2a_router.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/agent_card_builder.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/agent_card_skill_builder.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/jsonrpc_dispatcher.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/models_jsonrpc.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/sse_wrapper.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/endpoints/translation_layer.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/models.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/elasticsearch_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/a2a/providers/postgres_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/chart_generation/llm_refinement_loop.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/activity_formatter.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/agent_interface.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/agent_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/base_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/context_summarizer.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/elasticsearch_config_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/implementation_validator.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_clients.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_config.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/model_router.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/models.py +0 -0
- {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
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/state_manager.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/step_display_config.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/streaming_parts_accumulator.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/llamaindex_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/llamaindex_memory_adapter.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/implementations/microsoft_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/agent_mixin.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/base.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/config.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/manager.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/personalization.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/graphiti_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/providers/memori_provider.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/memory/tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/api_timing_tracker.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/elasticsearch_circuit_breaker.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/elasticsearch_logging.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/error_handling.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/error_logging.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_auto_instrumentor.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics_collector.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/llm_metrics_extractor.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/metrics_aggregator.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/metrics_config.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/observability_manager.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_instrumentor.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_logging_handler.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_metrics_recorder.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/otel_setup.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/performance_monitor.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/progress_tracker.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/resource_manager.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/resource_metrics_collector.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/streaming_latency_tracer.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/timing_tracker.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/monitoring/tracing_context.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/ai_content_management.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/markdown_converter.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/multimodal_integration.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/processing/rich_content_validation.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/py.typed +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/elasticsearch_session_storage.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/session/session_storage.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/agent_mixin.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/base.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/chart_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/file_access_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/file_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/form_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/image_display_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/mermaid_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/multimodal_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/optionsblock_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/pdf_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/pdf_with_images_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/table_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/unified_pdf_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/builtin/web_search_skill.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/discovery_prompt.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/skills/tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/file_storages.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/file_system_management.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/storage/storage_optimizer.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/adaptive_pdf_css.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/base.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/chart_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/file_access_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/file_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/html_content_analyzer.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/mermaid_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/multimodal_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_image_scaler.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/pdf_with_images_tool.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/sizing_config.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/tabledata_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/unified_pdf_tool.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/tools/web_search_tools.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/path_utils.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/post_install.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/session_title_generator.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/source_detector.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/utils/special_blocks.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/__init__.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_auth.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_models.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_router.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/admin_services.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/api_timing_middleware.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/A2A_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/CREATING_AGENTS.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/DOCKER_SETUP.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/Dockerfile +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/GETTING_STARTED.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/MEMORY_INSTALLATION.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/README.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/TOOLS_AND_MCP_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/api-reference.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/configuration.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/docker-compose.yml +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_example_multi_skills.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_file_storage.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_mcp.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_graphiti.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_hybrid.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/agent_with_memory_simple.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/custom_framework_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/simple_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/examples/skills_demo_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/docs/installation-guide.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/documentation_generator.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/helper_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/helper_ui.html +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/modern_ui.html +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/observability/kibana-llm-dashboard-setup.json +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/observability/kibana-resource-metrics-dashboard.json +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/otel_tracing_middleware.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/server.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/web/test_app.html +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/dependency_links.txt +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/entry_points.txt +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/requires.txt +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework_lib.egg-info/top_level.txt +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/A2A_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ACTIVITY_OUTPUT_PART.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ARCHITECTURE_DIAGRAM.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/CONCURRENCE_VS_PARALLELISME_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/CREATING_AGENTS.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/DOCKER_SETUP.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/ELASTICSEARCH_DATA_STRUCTURES.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/FILE_DOWNLOAD_LINKS.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/FILE_STORAGE_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/GETTING_STARTED.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/HISTORY_MESSAGE_FORMAT.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/IMPLEMENTATION_GUIDE_NEW_AGENT.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MEMORY_INSTALLATION.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MODIFICATIONS_CONCURRENCE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/MULTIMODAL_TOOLS_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/OBSERVABILITY_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/PYPI_PUBLISHING.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/QA_STREAMING_LATENCY.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/SPEC_CROSS_MODEL_HISTORY_CONVERSION.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/STREAMING_EVENTS_FRONTEND.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/TOOLS_AND_MCP_GUIDE.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/api-reference.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/configuration.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/framework_audit_remarques.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/docs/installation-guide.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/README.md +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_context_budget_test.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_example_multi_skills.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_exemple_test.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_training_with_apo.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_custom_tools_file_storage.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_file_storage.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_mcp.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_graphiti.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_hybrid.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_memory_simple.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/agent_with_personalization.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/biagenttest.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/custom_framework_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/dependencies/docker-compose.yaml +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/pyproject.toml +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/simple_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/examples/skills_demo_agent.py +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/setup.cfg +0 -0
- {agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/setup.py +0 -0
{agent_framework_lib-0.6.1/agent_framework_lib.egg-info → agent_framework_lib-0.6.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-framework-lib
|
|
3
|
-
Version: 0.6.
|
|
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.
|
|
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.
|
|
91
|
+
__version__ = "0.6.2"
|
|
92
92
|
__author__ = "Cinco AI Team"
|
|
93
93
|
__license__ = "MIT"
|
|
94
94
|
__email__ = "sebastian@cinco.ai"
|
{agent_framework_lib-0.6.1 → agent_framework_lib-0.6.2}/agent_framework/core/context_budget.py
RENAMED
|
@@ -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
|
|
255
|
-
|
|
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
|
-
|
|
266
|
-
self.
|
|
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 *
|
|
281
|
+
"Sacred zone: %d tokens (prompt=%d, tools=%d raw * %.1fx = %d)",
|
|
270
282
|
self._sacred_zone_tokens,
|
|
271
283
|
self._prompt_tokens,
|
|
272
|
-
|
|
273
|
-
self.
|
|
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
|