mcp-mesh 0.7.21__tar.gz → 0.8.0b1__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.
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/.gitignore +10 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/PKG-INFO +2 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/__init__.py +1 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/dependency_injector.py +4 -6
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/http_wrapper.py +69 -10
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/mesh_llm_agent.py +4 -7
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/mesh_llm_agent_injector.py +2 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/provider_handlers/__init__.py +14 -1
- mcp_mesh-0.8.0b1/_mcp_mesh/engine/provider_handlers/base_provider_handler.py +228 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/provider_handlers/claude_handler.py +15 -57
- mcp_mesh-0.8.0b1/_mcp_mesh/engine/provider_handlers/gemini_handler.py +181 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/provider_handlers/openai_handler.py +8 -63
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/provider_handlers/provider_handler_registry.py +16 -10
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/response_parser.py +61 -15
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/unified_mcp_proxy.py +18 -34
- mcp_mesh-0.8.0b1/_mcp_mesh/pipeline/__init__.py +35 -0
- mcp_mesh-0.8.0b1/_mcp_mesh/pipeline/api_heartbeat/__init__.py +21 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_heartbeat/api_lifespan_integration.py +23 -49
- mcp_mesh-0.8.0b1/_mcp_mesh/pipeline/api_heartbeat/rust_api_heartbeat.py +425 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/api_pipeline.py +7 -9
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/api_server_setup.py +91 -70
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/fastapi_discovery.py +22 -23
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/middleware_integration.py +32 -24
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/route_collection.py +2 -4
- mcp_mesh-0.8.0b1/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +13 -0
- mcp_mesh-0.8.0b1/_mcp_mesh/pipeline/mcp_heartbeat/rust_heartbeat.py +695 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/__init__.py +2 -5
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/configuration.py +1 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/fastapiserver_setup.py +5 -6
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/heartbeat_loop.py +6 -7
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/startup_orchestrator.py +21 -9
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/startup_pipeline.py +3 -8
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/shared/mesh_pipeline.py +0 -2
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/reload.py +1 -3
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/__init__.py +2 -8
- mcp_mesh-0.8.0b1/_mcp_mesh/shared/config_resolver.py +270 -0
- mcp_mesh-0.8.0b1/_mcp_mesh/shared/defaults.py +139 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/fastapi_middleware_manager.py +149 -91
- mcp_mesh-0.8.0b1/_mcp_mesh/shared/host_resolver.py +48 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/server_discovery.py +115 -86
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/simple_shutdown.py +44 -86
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/execution_tracer.py +2 -6
- mcp_mesh-0.8.0b1/_mcp_mesh/tracing/redis_metadata_publisher.py +84 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/trace_context_helper.py +3 -13
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/utils.py +29 -15
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/utils/fastmcp_schema_extractor.py +2 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/mesh/__init__.py +2 -1
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/mesh/decorators.py +89 -5
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/pyproject.toml +6 -4
- mcp_mesh-0.7.21/_mcp_mesh/engine/provider_handlers/base_provider_handler.py +0 -122
- mcp_mesh-0.7.21/_mcp_mesh/generated/.openapi-generator/FILES +0 -50
- mcp_mesh-0.7.21/_mcp_mesh/generated/.openapi-generator/VERSION +0 -1
- mcp_mesh-0.7.21/_mcp_mesh/generated/.openapi-generator-ignore +0 -15
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/__init__.py +0 -90
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api/__init__.py +0 -6
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api/agents_api.py +0 -1088
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api/health_api.py +0 -764
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api/tracing_api.py +0 -303
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api_client.py +0 -798
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/api_response.py +0 -21
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/configuration.py +0 -577
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/exceptions.py +0 -217
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/__init__.py +0 -55
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_info.py +0 -158
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata.py +0 -126
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner.py +0 -139
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_metadata_dependencies_inner_one_of.py +0 -92
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration.py +0 -103
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agent_registration_metadata.py +0 -136
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/agents_list_response.py +0 -100
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/capability_info.py +0 -107
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_metadata.py +0 -112
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_agent_request.py +0 -103
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/decorator_info.py +0 -105
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_info.py +0 -103
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/dependency_resolution_info.py +0 -106
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/error_response.py +0 -91
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/health_response.py +0 -103
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request.py +0 -101
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_request_metadata.py +0 -111
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/heartbeat_response.py +0 -117
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider.py +0 -93
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_provider_resolution_info.py +0 -106
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter.py +0 -109
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner.py +0 -139
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_filter_filter_inner_one_of.py +0 -91
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_info.py +0 -101
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/llm_tool_resolution_info.py +0 -120
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_register_metadata.py +0 -112
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_agent_registration.py +0 -129
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response.py +0 -153
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_registration_response_dependencies_resolved_value_inner.py +0 -101
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_dependency_registration.py +0 -93
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_register_metadata.py +0 -107
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/mesh_tool_registration.py +0 -117
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/registration_response.py +0 -119
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/resolved_llm_provider.py +0 -110
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/rich_dependency.py +0 -93
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/root_response.py +0 -92
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/standardized_dependency.py +0 -93
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/models/trace_event.py +0 -106
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/py.typed +0 -0
- mcp_mesh-0.7.21/_mcp_mesh/generated/mcp_mesh_registry_client/rest.py +0 -259
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/__init__.py +0 -46
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/__init__.py +0 -16
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_dependency_resolution.py +0 -418
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_fast_heartbeat_check.py +0 -117
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_health_check.py +0 -140
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_orchestrator.py +0 -243
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_pipeline.py +0 -311
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_heartbeat_send.py +0 -386
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/api_heartbeat/api_registry_connection.py +0 -104
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/__init__.py +0 -25
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/dependency_resolution.py +0 -396
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/fast_heartbeat_check.py +0 -116
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_orchestrator.py +0 -311
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_pipeline.py +0 -282
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/heartbeat_send.py +0 -98
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/lifespan_integration.py +0 -84
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/llm_tools_resolution.py +0 -264
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/mcp_heartbeat/registry_connection.py +0 -79
- mcp_mesh-0.7.21/_mcp_mesh/pipeline/shared/registry_connection.py +0 -80
- mcp_mesh-0.7.21/_mcp_mesh/shared/config_resolver.py +0 -226
- mcp_mesh-0.7.21/_mcp_mesh/shared/defaults.py +0 -64
- mcp_mesh-0.7.21/_mcp_mesh/shared/host_resolver.py +0 -86
- mcp_mesh-0.7.21/_mcp_mesh/shared/registry_client_wrapper.py +0 -515
- mcp_mesh-0.7.21/_mcp_mesh/tracing/redis_metadata_publisher.py +0 -139
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/LICENSE +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/README.md +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/__init__.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/async_mcp_client.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/base_injector.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/decorator_registry.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/llm_config.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/llm_errors.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/provider_handlers/generic_handler.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/self_dependency_proxy.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/session_aware_client.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/session_manager.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/signature_analyzer.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/tool_executor.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/engine/tool_schema_builder.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/__init__.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/api_startup/route_integration.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/decorator_collection.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/fastmcpserver_discovery.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/heartbeat_preparation.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/lifespan_factory.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/mcp_startup/server_discovery.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/shared/__init__.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/shared/base_step.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/pipeline/shared/pipeline_types.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/reload_runner.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/content_extractor.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/fast_heartbeat_status.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/health_check_manager.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/logging_config.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/sse_parser.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/shared/support_types.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/agent_context_helper.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/context.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/_mcp_mesh/tracing/fastapi_tracing_middleware.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/mesh/helpers.py +0 -0
- {mcp_mesh-0.7.21 → mcp_mesh-0.8.0b1}/mesh/types.py +0 -0
|
@@ -245,3 +245,13 @@ helm/*/charts/*.tgz
|
|
|
245
245
|
helm/mcp-mesh-grafana/files/
|
|
246
246
|
helm/mcp-mesh-tempo/files/
|
|
247
247
|
*.DS_Store
|
|
248
|
+
rust-core-implementation.org
|
|
249
|
+
|
|
250
|
+
# Claude Code local files
|
|
251
|
+
.claude/memories.json
|
|
252
|
+
*.node
|
|
253
|
+
|
|
254
|
+
# NAPI-RS auto-generated build artifacts
|
|
255
|
+
src/runtime/core/index.js
|
|
256
|
+
src/runtime/core/index.d.ts
|
|
257
|
+
test/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-mesh
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0b1
|
|
4
4
|
Summary: Kubernetes-native platform for distributed MCP applications
|
|
5
5
|
Project-URL: Homepage, https://github.com/dhyansraj/mcp-mesh
|
|
6
6
|
Project-URL: Documentation, https://github.com/dhyansraj/mcp-mesh/tree/main/docs
|
|
@@ -30,6 +30,7 @@ Requires-Dist: fastmcp<3.0.0,>=2.8.0
|
|
|
30
30
|
Requires-Dist: httpx<1.0.0,>=0.25.0
|
|
31
31
|
Requires-Dist: jinja2>=3.1.0
|
|
32
32
|
Requires-Dist: litellm>=1.30.0
|
|
33
|
+
Requires-Dist: mcp-mesh-core>=0.8.0b1
|
|
33
34
|
Requires-Dist: mcp<2.0.0,>=1.9.0
|
|
34
35
|
Requires-Dist: prometheus-client<1.0.0,>=0.19.0
|
|
35
36
|
Requires-Dist: pydantic<3.0.0,>=2.4.0
|
|
@@ -14,12 +14,10 @@ import weakref
|
|
|
14
14
|
from collections.abc import Callable
|
|
15
15
|
from typing import Any
|
|
16
16
|
|
|
17
|
-
from ..shared.logging_config import (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
from .signature_analyzer import get_mesh_agent_positions, has_llm_agent_parameter
|
|
17
|
+
from ..shared.logging_config import (format_log_value, format_result_summary,
|
|
18
|
+
get_trace_prefix)
|
|
19
|
+
from .signature_analyzer import (get_mesh_agent_positions,
|
|
20
|
+
has_llm_agent_parameter)
|
|
23
21
|
|
|
24
22
|
logger = logging.getLogger(__name__)
|
|
25
23
|
|
|
@@ -387,8 +387,13 @@ class HttpMcpWrapper:
|
|
|
387
387
|
self.logger = logger
|
|
388
388
|
|
|
389
389
|
async def dispatch(self, request: Request, call_next):
|
|
390
|
-
#
|
|
390
|
+
# Read body once for processing
|
|
391
|
+
body = await request.body()
|
|
392
|
+
modified_body = body
|
|
393
|
+
|
|
394
|
+
# Extract and set trace context from headers and arguments
|
|
391
395
|
try:
|
|
396
|
+
from ..tracing.context import TraceContext
|
|
392
397
|
from ..tracing.trace_context_helper import TraceContextHelper
|
|
393
398
|
|
|
394
399
|
# DEBUG: Log incoming headers for trace propagation debugging
|
|
@@ -399,22 +404,67 @@ class HttpMcpWrapper:
|
|
|
399
404
|
f"X-Parent-Span={parent_span_header}, path={request.url.path}"
|
|
400
405
|
)
|
|
401
406
|
|
|
402
|
-
#
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
407
|
+
# Extract trace context from both headers AND arguments
|
|
408
|
+
trace_id = trace_id_header
|
|
409
|
+
parent_span = parent_span_header
|
|
410
|
+
|
|
411
|
+
# Try extracting from JSON-RPC body arguments as fallback
|
|
412
|
+
# Also strip trace fields from arguments to avoid Pydantic validation errors
|
|
413
|
+
if body:
|
|
414
|
+
try:
|
|
415
|
+
payload = json.loads(body.decode("utf-8"))
|
|
416
|
+
if payload.get("method") == "tools/call":
|
|
417
|
+
arguments = payload.get("params", {}).get(
|
|
418
|
+
"arguments", {}
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
# Extract trace context from arguments (TypeScript uses _trace_id/_parent_span)
|
|
422
|
+
if not trace_id and arguments.get("_trace_id"):
|
|
423
|
+
trace_id = arguments.get("_trace_id")
|
|
424
|
+
if not parent_span and arguments.get("_parent_span"):
|
|
425
|
+
parent_span = arguments.get("_parent_span")
|
|
426
|
+
|
|
427
|
+
# Strip trace context fields from arguments before passing to FastMCP
|
|
428
|
+
if (
|
|
429
|
+
"_trace_id" in arguments
|
|
430
|
+
or "_parent_span" in arguments
|
|
431
|
+
):
|
|
432
|
+
arguments.pop("_trace_id", None)
|
|
433
|
+
arguments.pop("_parent_span", None)
|
|
434
|
+
# Update payload with cleaned arguments
|
|
435
|
+
modified_body = json.dumps(payload).encode("utf-8")
|
|
436
|
+
self.logger.debug(
|
|
437
|
+
f"🔗 Stripped trace fields from arguments, "
|
|
438
|
+
f"trace_id={trace_id[:8] if trace_id else None}..."
|
|
439
|
+
)
|
|
440
|
+
except Exception as e:
|
|
441
|
+
self.logger.debug(
|
|
442
|
+
f"Failed to process body for trace context: {e}"
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Setup trace context if we have a trace_id
|
|
446
|
+
if trace_id:
|
|
447
|
+
trace_context = {
|
|
448
|
+
"trace_id": trace_id,
|
|
449
|
+
"parent_span": parent_span,
|
|
450
|
+
}
|
|
451
|
+
TraceContextHelper.setup_request_trace_context(
|
|
452
|
+
trace_context, self.logger
|
|
406
453
|
)
|
|
407
|
-
)
|
|
408
|
-
TraceContextHelper.setup_request_trace_context(
|
|
409
|
-
trace_context, self.logger
|
|
410
|
-
)
|
|
411
454
|
except Exception as e:
|
|
412
455
|
# Never fail request due to tracing issues
|
|
413
456
|
self.logger.warning(f"Failed to set trace context: {e}")
|
|
414
457
|
pass
|
|
415
458
|
|
|
459
|
+
# Create a new request scope with the modified body
|
|
460
|
+
async def receive():
|
|
461
|
+
return {"type": "http.request", "body": modified_body}
|
|
462
|
+
|
|
463
|
+
# Update request with modified receive
|
|
464
|
+
request._receive = receive
|
|
465
|
+
|
|
416
466
|
# Extract session ID from request
|
|
417
|
-
session_id = await self.http_wrapper.
|
|
467
|
+
session_id = await self.http_wrapper._extract_session_id_from_body(body)
|
|
418
468
|
|
|
419
469
|
if session_id:
|
|
420
470
|
# Check for existing session assignment
|
|
@@ -458,6 +508,15 @@ class HttpMcpWrapper:
|
|
|
458
508
|
# Try extracting from JSON-RPC body
|
|
459
509
|
try:
|
|
460
510
|
body = await request.body()
|
|
511
|
+
return await self._extract_session_id_from_body(body)
|
|
512
|
+
except Exception:
|
|
513
|
+
pass
|
|
514
|
+
|
|
515
|
+
return None
|
|
516
|
+
|
|
517
|
+
async def _extract_session_id_from_body(self, body: bytes) -> str:
|
|
518
|
+
"""Extract session ID from already-read request body."""
|
|
519
|
+
try:
|
|
461
520
|
if body:
|
|
462
521
|
payload = json.loads(body.decode("utf-8"))
|
|
463
522
|
if payload.get("method") == "tools/call":
|
|
@@ -14,12 +14,8 @@ from typing import Any, Dict, List, Literal, Optional, Union
|
|
|
14
14
|
from pydantic import BaseModel
|
|
15
15
|
|
|
16
16
|
from .llm_config import LLMConfig
|
|
17
|
-
from .llm_errors import (
|
|
18
|
-
|
|
19
|
-
MaxIterationsError,
|
|
20
|
-
ResponseParseError,
|
|
21
|
-
ToolExecutionError,
|
|
22
|
-
)
|
|
17
|
+
from .llm_errors import (LLMAPIError, MaxIterationsError, ResponseParseError,
|
|
18
|
+
ToolExecutionError)
|
|
23
19
|
from .provider_handlers import ProviderHandlerRegistry
|
|
24
20
|
from .response_parser import ResponseParser
|
|
25
21
|
from .tool_executor import ToolExecutor
|
|
@@ -27,7 +23,8 @@ from .tool_schema_builder import ToolSchemaBuilder
|
|
|
27
23
|
|
|
28
24
|
# Import Jinja2 for template rendering
|
|
29
25
|
try:
|
|
30
|
-
from jinja2 import Environment, FileSystemLoader, Template,
|
|
26
|
+
from jinja2 import (Environment, FileSystemLoader, Template,
|
|
27
|
+
TemplateSyntaxError)
|
|
31
28
|
except ImportError:
|
|
32
29
|
Environment = None
|
|
33
30
|
FileSystemLoader = None
|
|
@@ -431,7 +431,8 @@ class MeshLlmAgentInjector(BaseInjector):
|
|
|
431
431
|
if is_template:
|
|
432
432
|
# Templates enabled - create per-call agent with context
|
|
433
433
|
# Import signature analyzer for context detection
|
|
434
|
-
from .signature_analyzer import
|
|
434
|
+
from .signature_analyzer import \
|
|
435
|
+
get_context_parameter_name
|
|
435
436
|
|
|
436
437
|
# Detect context parameter
|
|
437
438
|
context_param_name = config_dict.get("context_param")
|
|
@@ -5,15 +5,28 @@ This package provides vendor-specific customization for different LLM providers
|
|
|
5
5
|
(Claude, OpenAI, Gemini, etc.) to optimize API calls and response handling.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from .base_provider_handler import
|
|
8
|
+
from .base_provider_handler import (
|
|
9
|
+
BASE_TOOL_INSTRUCTIONS,
|
|
10
|
+
CLAUDE_ANTI_XML_INSTRUCTION,
|
|
11
|
+
BaseProviderHandler,
|
|
12
|
+
make_schema_strict,
|
|
13
|
+
)
|
|
9
14
|
from .claude_handler import ClaudeHandler
|
|
15
|
+
from .gemini_handler import GeminiHandler
|
|
10
16
|
from .generic_handler import GenericHandler
|
|
11
17
|
from .openai_handler import OpenAIHandler
|
|
12
18
|
from .provider_handler_registry import ProviderHandlerRegistry
|
|
13
19
|
|
|
14
20
|
__all__ = [
|
|
21
|
+
# Constants
|
|
22
|
+
"BASE_TOOL_INSTRUCTIONS",
|
|
23
|
+
"CLAUDE_ANTI_XML_INSTRUCTION",
|
|
24
|
+
# Utilities
|
|
25
|
+
"make_schema_strict",
|
|
26
|
+
# Handlers
|
|
15
27
|
"BaseProviderHandler",
|
|
16
28
|
"ClaudeHandler",
|
|
29
|
+
"GeminiHandler",
|
|
17
30
|
"OpenAIHandler",
|
|
18
31
|
"GenericHandler",
|
|
19
32
|
"ProviderHandlerRegistry",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base provider handler interface for vendor-specific LLM behavior.
|
|
3
|
+
|
|
4
|
+
This module defines the abstract base class for provider-specific handlers
|
|
5
|
+
that customize how different LLM vendors (Claude, OpenAI, Gemini, etc.) are called.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import copy
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from typing import Any, Optional
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
# ============================================================================
|
|
15
|
+
# Shared Constants
|
|
16
|
+
# ============================================================================
|
|
17
|
+
|
|
18
|
+
# Base tool calling instructions shared across all providers.
|
|
19
|
+
# Claude handler adds anti-XML instruction on top of this.
|
|
20
|
+
BASE_TOOL_INSTRUCTIONS = """
|
|
21
|
+
IMPORTANT TOOL CALLING RULES:
|
|
22
|
+
- You have access to tools that you can call to gather information
|
|
23
|
+
- Make ONE tool call at a time
|
|
24
|
+
- After receiving tool results, you can make additional calls if needed
|
|
25
|
+
- Once you have all needed information, provide your final response
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# Anti-XML instruction for Claude (prevents <invoke> style tool calls).
|
|
29
|
+
CLAUDE_ANTI_XML_INSTRUCTION = (
|
|
30
|
+
'- NEVER use XML-style syntax like <invoke name="tool_name"/>'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# ============================================================================
|
|
35
|
+
# Shared Schema Utilities
|
|
36
|
+
# ============================================================================
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def make_schema_strict(
|
|
40
|
+
schema: dict[str, Any],
|
|
41
|
+
add_all_required: bool = True,
|
|
42
|
+
) -> dict[str, Any]:
|
|
43
|
+
"""
|
|
44
|
+
Make a JSON schema strict for structured output.
|
|
45
|
+
|
|
46
|
+
This is a shared utility used by OpenAI, Gemini, and Claude handlers.
|
|
47
|
+
Adds additionalProperties: false to all object types and optionally
|
|
48
|
+
ensures 'required' includes all property keys.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
schema: JSON schema to make strict
|
|
52
|
+
add_all_required: If True, set 'required' to include ALL property keys.
|
|
53
|
+
OpenAI and Gemini require this; Claude does not.
|
|
54
|
+
Default: True
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
New schema with strict constraints (original not mutated)
|
|
58
|
+
"""
|
|
59
|
+
result = copy.deepcopy(schema)
|
|
60
|
+
_add_strict_constraints_recursive(result, add_all_required)
|
|
61
|
+
return result
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _add_strict_constraints_recursive(obj: Any, add_all_required: bool) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Recursively add strict constraints to a schema object.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
obj: Schema object to process (mutated in place)
|
|
70
|
+
add_all_required: Whether to set required to all property keys
|
|
71
|
+
"""
|
|
72
|
+
if not isinstance(obj, dict):
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
# If this is an object type, add additionalProperties: false
|
|
76
|
+
if obj.get("type") == "object":
|
|
77
|
+
obj["additionalProperties"] = False
|
|
78
|
+
|
|
79
|
+
# Optionally set required to include all property keys
|
|
80
|
+
if add_all_required and "properties" in obj:
|
|
81
|
+
obj["required"] = list(obj["properties"].keys())
|
|
82
|
+
|
|
83
|
+
# Process $defs (Pydantic uses this for nested models)
|
|
84
|
+
if "$defs" in obj:
|
|
85
|
+
for def_schema in obj["$defs"].values():
|
|
86
|
+
_add_strict_constraints_recursive(def_schema, add_all_required)
|
|
87
|
+
|
|
88
|
+
# Process properties
|
|
89
|
+
if "properties" in obj:
|
|
90
|
+
for prop_schema in obj["properties"].values():
|
|
91
|
+
_add_strict_constraints_recursive(prop_schema, add_all_required)
|
|
92
|
+
|
|
93
|
+
# Process items (for arrays)
|
|
94
|
+
# items can be an object (single schema) or a list (tuple validation in older drafts)
|
|
95
|
+
if "items" in obj:
|
|
96
|
+
items = obj["items"]
|
|
97
|
+
if isinstance(items, dict):
|
|
98
|
+
_add_strict_constraints_recursive(items, add_all_required)
|
|
99
|
+
elif isinstance(items, list):
|
|
100
|
+
for item in items:
|
|
101
|
+
_add_strict_constraints_recursive(item, add_all_required)
|
|
102
|
+
|
|
103
|
+
# Process prefixItems (tuple validation in JSON Schema draft 2020-12)
|
|
104
|
+
if "prefixItems" in obj:
|
|
105
|
+
for item in obj["prefixItems"]:
|
|
106
|
+
_add_strict_constraints_recursive(item, add_all_required)
|
|
107
|
+
|
|
108
|
+
# Process anyOf, oneOf, allOf
|
|
109
|
+
for key in ("anyOf", "oneOf", "allOf"):
|
|
110
|
+
if key in obj:
|
|
111
|
+
for item in obj[key]:
|
|
112
|
+
_add_strict_constraints_recursive(item, add_all_required)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ============================================================================
|
|
116
|
+
# Base Provider Handler
|
|
117
|
+
# ============================================================================
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class BaseProviderHandler(ABC):
|
|
121
|
+
"""
|
|
122
|
+
Abstract base class for provider-specific LLM handlers.
|
|
123
|
+
|
|
124
|
+
Each vendor (Claude, OpenAI, Gemini, etc.) can have its own handler
|
|
125
|
+
that customizes request preparation, system prompt formatting, and
|
|
126
|
+
response parsing to work optimally with that vendor's API.
|
|
127
|
+
|
|
128
|
+
Handler Selection:
|
|
129
|
+
The ProviderHandlerRegistry selects handlers based on the 'vendor'
|
|
130
|
+
field from the LLM provider registration (extracted via LiteLLM).
|
|
131
|
+
|
|
132
|
+
Extensibility:
|
|
133
|
+
New handlers can be added by:
|
|
134
|
+
1. Subclassing BaseProviderHandler
|
|
135
|
+
2. Implementing required methods
|
|
136
|
+
3. Registering in ProviderHandlerRegistry
|
|
137
|
+
4. Optionally: Adding as Python entry point for auto-discovery
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
def __init__(self, vendor: str):
|
|
141
|
+
"""
|
|
142
|
+
Initialize provider handler.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
vendor: Vendor name (e.g., "anthropic", "openai", "google")
|
|
146
|
+
"""
|
|
147
|
+
self.vendor = vendor
|
|
148
|
+
|
|
149
|
+
@abstractmethod
|
|
150
|
+
def prepare_request(
|
|
151
|
+
self,
|
|
152
|
+
messages: list[dict[str, Any]],
|
|
153
|
+
tools: Optional[list[dict[str, Any]]],
|
|
154
|
+
output_type: type[BaseModel],
|
|
155
|
+
**kwargs: Any,
|
|
156
|
+
) -> dict[str, Any]:
|
|
157
|
+
"""
|
|
158
|
+
Prepare vendor-specific request parameters.
|
|
159
|
+
|
|
160
|
+
This method allows customization of the request sent to the LLM provider.
|
|
161
|
+
For example:
|
|
162
|
+
- OpenAI: Add response_format parameter for structured output
|
|
163
|
+
- Claude: Use native tool calling format
|
|
164
|
+
- Gemini: Add generation config
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
messages: List of message dicts (role, content)
|
|
168
|
+
tools: Optional list of tool schemas (OpenAI format)
|
|
169
|
+
output_type: Pydantic model for expected response
|
|
170
|
+
**kwargs: Additional model parameters
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Dictionary of parameters to pass to litellm.completion()
|
|
174
|
+
Must include at minimum: messages, tools (if provided)
|
|
175
|
+
May include vendor-specific params like response_format, temperature, etc.
|
|
176
|
+
"""
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
@abstractmethod
|
|
180
|
+
def format_system_prompt(
|
|
181
|
+
self,
|
|
182
|
+
base_prompt: str,
|
|
183
|
+
tool_schemas: Optional[list[dict[str, Any]]],
|
|
184
|
+
output_type: type[BaseModel],
|
|
185
|
+
) -> str:
|
|
186
|
+
"""
|
|
187
|
+
Format system prompt for vendor-specific requirements.
|
|
188
|
+
|
|
189
|
+
Different vendors have different best practices for system prompts:
|
|
190
|
+
- Claude: Prefers detailed instructions, handles XML well
|
|
191
|
+
- OpenAI: Structured output mode makes JSON instructions optional
|
|
192
|
+
- Gemini: System instructions separate from messages
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
base_prompt: Base system prompt (from template or config)
|
|
196
|
+
tool_schemas: Optional list of tool schemas (if tools available)
|
|
197
|
+
output_type: Pydantic model for response validation
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Formatted system prompt string optimized for this vendor
|
|
201
|
+
"""
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
def get_vendor_capabilities(self) -> dict[str, bool]:
|
|
205
|
+
"""
|
|
206
|
+
Return vendor-specific capability flags.
|
|
207
|
+
|
|
208
|
+
Override this to indicate which features the vendor supports:
|
|
209
|
+
- native_tool_calling: Vendor has native function calling
|
|
210
|
+
- structured_output: Vendor supports structured output (response_format)
|
|
211
|
+
- streaming: Vendor supports streaming responses
|
|
212
|
+
- vision: Vendor supports image inputs
|
|
213
|
+
- json_mode: Vendor has JSON response mode
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Dictionary of capability flags
|
|
217
|
+
"""
|
|
218
|
+
return {
|
|
219
|
+
"native_tool_calling": True,
|
|
220
|
+
"structured_output": False,
|
|
221
|
+
"streaming": False,
|
|
222
|
+
"vision": False,
|
|
223
|
+
"json_mode": False,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
def __repr__(self) -> str:
|
|
227
|
+
"""String representation of handler."""
|
|
228
|
+
return f"{self.__class__.__name__}(vendor='{self.vendor}')"
|
|
@@ -17,11 +17,16 @@ Features:
|
|
|
17
17
|
|
|
18
18
|
import json
|
|
19
19
|
import logging
|
|
20
|
-
from typing import Any, Optional
|
|
20
|
+
from typing import Any, Optional
|
|
21
21
|
|
|
22
22
|
from pydantic import BaseModel
|
|
23
23
|
|
|
24
|
-
from .base_provider_handler import
|
|
24
|
+
from .base_provider_handler import (
|
|
25
|
+
BASE_TOOL_INSTRUCTIONS,
|
|
26
|
+
BaseProviderHandler,
|
|
27
|
+
CLAUDE_ANTI_XML_INSTRUCTION,
|
|
28
|
+
make_schema_strict,
|
|
29
|
+
)
|
|
25
30
|
|
|
26
31
|
logger = logging.getLogger(__name__)
|
|
27
32
|
|
|
@@ -141,51 +146,6 @@ class ClaudeHandler(BaseProviderHandler):
|
|
|
141
146
|
# Default to strict for unknown types
|
|
142
147
|
return OUTPUT_MODE_STRICT
|
|
143
148
|
|
|
144
|
-
def _make_schema_strict(self, schema: dict[str, Any]) -> dict[str, Any]:
|
|
145
|
-
"""
|
|
146
|
-
Make a JSON schema strict for Claude's structured output.
|
|
147
|
-
|
|
148
|
-
Claude requires additionalProperties: false on all object types.
|
|
149
|
-
This recursively processes the schema to add this constraint.
|
|
150
|
-
|
|
151
|
-
Args:
|
|
152
|
-
schema: JSON schema dict
|
|
153
|
-
|
|
154
|
-
Returns:
|
|
155
|
-
Schema with additionalProperties: false on all objects
|
|
156
|
-
"""
|
|
157
|
-
if not isinstance(schema, dict):
|
|
158
|
-
return schema
|
|
159
|
-
|
|
160
|
-
result = schema.copy()
|
|
161
|
-
|
|
162
|
-
# If this is an object type, add additionalProperties: false
|
|
163
|
-
if result.get("type") == "object":
|
|
164
|
-
result["additionalProperties"] = False
|
|
165
|
-
|
|
166
|
-
# Recursively process nested schemas
|
|
167
|
-
if "properties" in result:
|
|
168
|
-
result["properties"] = {
|
|
169
|
-
k: self._make_schema_strict(v) for k, v in result["properties"].items()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
# Process $defs (Pydantic uses this for nested models)
|
|
173
|
-
if "$defs" in result:
|
|
174
|
-
result["$defs"] = {
|
|
175
|
-
k: self._make_schema_strict(v) for k, v in result["$defs"].items()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
# Process items for arrays
|
|
179
|
-
if "items" in result:
|
|
180
|
-
result["items"] = self._make_schema_strict(result["items"])
|
|
181
|
-
|
|
182
|
-
# Process anyOf, oneOf, allOf
|
|
183
|
-
for key in ["anyOf", "oneOf", "allOf"]:
|
|
184
|
-
if key in result:
|
|
185
|
-
result[key] = [self._make_schema_strict(s) for s in result[key]]
|
|
186
|
-
|
|
187
|
-
return result
|
|
188
|
-
|
|
189
149
|
def _apply_prompt_caching(
|
|
190
150
|
self, messages: list[dict[str, Any]]
|
|
191
151
|
) -> list[dict[str, Any]]:
|
|
@@ -302,9 +262,10 @@ class ClaudeHandler(BaseProviderHandler):
|
|
|
302
262
|
# Only add response_format in "strict" mode
|
|
303
263
|
if determined_mode == OUTPUT_MODE_STRICT:
|
|
304
264
|
# Claude requires additionalProperties: false on all object types
|
|
265
|
+
# Unlike OpenAI/Gemini, Claude doesn't require all properties in 'required'
|
|
305
266
|
if isinstance(output_type, type) and issubclass(output_type, BaseModel):
|
|
306
267
|
schema = output_type.model_json_schema()
|
|
307
|
-
strict_schema =
|
|
268
|
+
strict_schema = make_schema_strict(schema, add_all_required=False)
|
|
308
269
|
request_params["response_format"] = {
|
|
309
270
|
"type": "json_schema",
|
|
310
271
|
"json_schema": {
|
|
@@ -346,15 +307,12 @@ class ClaudeHandler(BaseProviderHandler):
|
|
|
346
307
|
# Add tool calling instructions if tools available
|
|
347
308
|
# These prevent Claude from using XML-style <invoke> syntax
|
|
348
309
|
if tool_schemas:
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
- After receiving tool results, you can make additional calls if needed
|
|
356
|
-
- Once you have all needed information, provide your final response
|
|
357
|
-
"""
|
|
310
|
+
# Use base instructions but insert anti-XML rule for Claude
|
|
311
|
+
instructions = BASE_TOOL_INSTRUCTIONS.replace(
|
|
312
|
+
"- Make ONE tool call at a time",
|
|
313
|
+
f"- Make ONE tool call at a time\n{CLAUDE_ANTI_XML_INSTRUCTION}",
|
|
314
|
+
)
|
|
315
|
+
system_content += instructions
|
|
358
316
|
|
|
359
317
|
# Add output format instructions based on mode
|
|
360
318
|
if determined_mode == OUTPUT_MODE_TEXT:
|