agent_os_kernel 3.1.0__py3-none-any.whl
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_control_plane/__init__.py +662 -0
- agent_control_plane/a2a_adapter.py +543 -0
- agent_control_plane/adapter.py +417 -0
- agent_control_plane/agent_hibernation.py +394 -0
- agent_control_plane/agent_kernel.py +470 -0
- agent_control_plane/compliance.py +720 -0
- agent_control_plane/constraint_graphs.py +478 -0
- agent_control_plane/control_plane.py +854 -0
- agent_control_plane/example_executors.py +195 -0
- agent_control_plane/execution_engine.py +231 -0
- agent_control_plane/flight_recorder.py +846 -0
- agent_control_plane/governance_layer.py +435 -0
- agent_control_plane/hf_utils.py +563 -0
- agent_control_plane/interfaces/__init__.py +55 -0
- agent_control_plane/interfaces/kernel_interface.py +361 -0
- agent_control_plane/interfaces/plugin_interface.py +497 -0
- agent_control_plane/interfaces/protocol_interfaces.py +387 -0
- agent_control_plane/kernel_space.py +1009 -0
- agent_control_plane/langchain_adapter.py +424 -0
- agent_control_plane/lifecycle.py +3113 -0
- agent_control_plane/mcp_adapter.py +653 -0
- agent_control_plane/ml_safety.py +563 -0
- agent_control_plane/multimodal.py +727 -0
- agent_control_plane/mute_agent.py +422 -0
- agent_control_plane/observability.py +787 -0
- agent_control_plane/orchestrator.py +482 -0
- agent_control_plane/plugin_registry.py +750 -0
- agent_control_plane/policy_engine.py +954 -0
- agent_control_plane/process_isolation.py +777 -0
- agent_control_plane/shadow_mode.py +310 -0
- agent_control_plane/signals.py +493 -0
- agent_control_plane/supervisor_agents.py +430 -0
- agent_control_plane/time_travel_debugger.py +557 -0
- agent_control_plane/tool_registry.py +452 -0
- agent_control_plane/vfs.py +697 -0
- agent_kernel/__init__.py +69 -0
- agent_kernel/analyzer.py +435 -0
- agent_kernel/auditor.py +36 -0
- agent_kernel/completeness_auditor.py +237 -0
- agent_kernel/detector.py +203 -0
- agent_kernel/kernel.py +744 -0
- agent_kernel/memory_manager.py +85 -0
- agent_kernel/models.py +374 -0
- agent_kernel/nudge_mechanism.py +263 -0
- agent_kernel/outcome_analyzer.py +338 -0
- agent_kernel/patcher.py +582 -0
- agent_kernel/semantic_analyzer.py +316 -0
- agent_kernel/semantic_purge.py +349 -0
- agent_kernel/simulator.py +449 -0
- agent_kernel/teacher.py +85 -0
- agent_kernel/triage.py +152 -0
- agent_os/__init__.py +409 -0
- agent_os/_adversarial_impl.py +200 -0
- agent_os/_circuit_breaker_impl.py +232 -0
- agent_os/_mcp_metrics.py +193 -0
- agent_os/adversarial.py +20 -0
- agent_os/agents_compat.py +490 -0
- agent_os/audit_logger.py +135 -0
- agent_os/base_agent.py +651 -0
- agent_os/circuit_breaker.py +34 -0
- agent_os/cli/__init__.py +659 -0
- agent_os/cli/cmd_audit.py +128 -0
- agent_os/cli/cmd_init.py +152 -0
- agent_os/cli/cmd_policy.py +41 -0
- agent_os/cli/cmd_policy_gen.py +180 -0
- agent_os/cli/cmd_validate.py +258 -0
- agent_os/cli/mcp_scan.py +265 -0
- agent_os/cli/output.py +192 -0
- agent_os/cli/policy_checker.py +330 -0
- agent_os/compat.py +74 -0
- agent_os/constraint_graph.py +234 -0
- agent_os/content_governance.py +140 -0
- agent_os/context_budget.py +305 -0
- agent_os/credential_redactor.py +224 -0
- agent_os/diff_policy.py +89 -0
- agent_os/egress_policy.py +159 -0
- agent_os/escalation.py +276 -0
- agent_os/event_bus.py +124 -0
- agent_os/exceptions.py +180 -0
- agent_os/execution_context_policy.py +141 -0
- agent_os/github_enterprise.py +96 -0
- agent_os/health.py +20 -0
- agent_os/integrations/__init__.py +279 -0
- agent_os/integrations/a2a_adapter.py +279 -0
- agent_os/integrations/agent_lightning/__init__.py +30 -0
- agent_os/integrations/anthropic_adapter.py +420 -0
- agent_os/integrations/autogen_adapter.py +620 -0
- agent_os/integrations/base.py +1137 -0
- agent_os/integrations/compat.py +229 -0
- agent_os/integrations/config.py +98 -0
- agent_os/integrations/conversation_guardian.py +957 -0
- agent_os/integrations/crewai_adapter.py +467 -0
- agent_os/integrations/drift_detector.py +425 -0
- agent_os/integrations/dry_run.py +124 -0
- agent_os/integrations/escalation.py +582 -0
- agent_os/integrations/gemini_adapter.py +364 -0
- agent_os/integrations/google_adk_adapter.py +633 -0
- agent_os/integrations/guardrails_adapter.py +394 -0
- agent_os/integrations/health.py +197 -0
- agent_os/integrations/langchain_adapter.py +654 -0
- agent_os/integrations/llamafirewall.py +343 -0
- agent_os/integrations/llamaindex_adapter.py +188 -0
- agent_os/integrations/logging.py +191 -0
- agent_os/integrations/maf_adapter.py +631 -0
- agent_os/integrations/mistral_adapter.py +365 -0
- agent_os/integrations/openai_adapter.py +816 -0
- agent_os/integrations/openai_agents_sdk.py +406 -0
- agent_os/integrations/policy_compose.py +171 -0
- agent_os/integrations/profiling.py +144 -0
- agent_os/integrations/pydantic_ai_adapter.py +420 -0
- agent_os/integrations/rate_limiter.py +130 -0
- agent_os/integrations/rbac.py +143 -0
- agent_os/integrations/registry.py +113 -0
- agent_os/integrations/scope_guard.py +303 -0
- agent_os/integrations/semantic_kernel_adapter.py +769 -0
- agent_os/integrations/smolagents_adapter.py +629 -0
- agent_os/integrations/templates.py +178 -0
- agent_os/integrations/token_budget.py +134 -0
- agent_os/integrations/tool_aliases.py +190 -0
- agent_os/integrations/webhooks.py +177 -0
- agent_os/lite.py +208 -0
- agent_os/mcp_gateway.py +385 -0
- agent_os/mcp_message_signer.py +273 -0
- agent_os/mcp_protocols.py +161 -0
- agent_os/mcp_response_scanner.py +232 -0
- agent_os/mcp_security.py +924 -0
- agent_os/mcp_session_auth.py +231 -0
- agent_os/mcp_sliding_rate_limiter.py +184 -0
- agent_os/memory_guard.py +409 -0
- agent_os/metrics.py +134 -0
- agent_os/mute.py +428 -0
- agent_os/mute_agent.py +209 -0
- agent_os/policies/__init__.py +77 -0
- agent_os/policies/async_evaluator.py +275 -0
- agent_os/policies/backends.py +670 -0
- agent_os/policies/bridge.py +169 -0
- agent_os/policies/budget.py +85 -0
- agent_os/policies/cli.py +294 -0
- agent_os/policies/conflict_resolution.py +270 -0
- agent_os/policies/data_classification.py +252 -0
- agent_os/policies/evaluator.py +239 -0
- agent_os/policies/policy_schema.json +228 -0
- agent_os/policies/rate_limiting.py +145 -0
- agent_os/policies/schema.py +115 -0
- agent_os/policies/shared.py +331 -0
- agent_os/prompt_injection.py +694 -0
- agent_os/providers.py +182 -0
- agent_os/py.typed +0 -0
- agent_os/retry.py +81 -0
- agent_os/reversibility.py +251 -0
- agent_os/sandbox.py +432 -0
- agent_os/sandbox_provider.py +140 -0
- agent_os/secure_codegen.py +525 -0
- agent_os/security_skills.py +538 -0
- agent_os/semantic_policy.py +422 -0
- agent_os/server/__init__.py +15 -0
- agent_os/server/__main__.py +25 -0
- agent_os/server/app.py +277 -0
- agent_os/server/models.py +104 -0
- agent_os/shift_left_metrics.py +130 -0
- agent_os/stateless.py +742 -0
- agent_os/supervisor.py +148 -0
- agent_os/task_outcome.py +148 -0
- agent_os/transparency.py +181 -0
- agent_os/trust_root.py +128 -0
- agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
- agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
- agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
- agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
- agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
- agent_os_observability/__init__.py +27 -0
- agent_os_observability/dashboards.py +898 -0
- agent_os_observability/metrics.py +398 -0
- agent_os_observability/server.py +223 -0
- agent_os_observability/tracer.py +232 -0
- agent_primitives/__init__.py +24 -0
- agent_primitives/failures.py +84 -0
- agent_primitives/py.typed +0 -0
- amb_core/__init__.py +177 -0
- amb_core/adapters/__init__.py +57 -0
- amb_core/adapters/aws_sqs_broker.py +376 -0
- amb_core/adapters/azure_servicebus_broker.py +340 -0
- amb_core/adapters/kafka_broker.py +260 -0
- amb_core/adapters/nats_broker.py +285 -0
- amb_core/adapters/rabbitmq_broker.py +235 -0
- amb_core/adapters/redis_broker.py +262 -0
- amb_core/broker.py +145 -0
- amb_core/bus.py +481 -0
- amb_core/cloudevents.py +509 -0
- amb_core/dlq.py +345 -0
- amb_core/hf_utils.py +536 -0
- amb_core/memory_broker.py +410 -0
- amb_core/models.py +141 -0
- amb_core/persistence.py +529 -0
- amb_core/schema.py +294 -0
- amb_core/tracing.py +358 -0
- atr/__init__.py +640 -0
- atr/access.py +348 -0
- atr/composition.py +645 -0
- atr/decorator.py +357 -0
- atr/executor.py +384 -0
- atr/health.py +557 -0
- atr/hf_utils.py +449 -0
- atr/injection.py +422 -0
- atr/metrics.py +440 -0
- atr/policies.py +403 -0
- atr/py.typed +2 -0
- atr/registry.py +452 -0
- atr/schema.py +480 -0
- atr/tools/safe/__init__.py +75 -0
- atr/tools/safe/calculator.py +467 -0
- atr/tools/safe/datetime_tool.py +443 -0
- atr/tools/safe/file_reader.py +402 -0
- atr/tools/safe/http_client.py +316 -0
- atr/tools/safe/json_parser.py +374 -0
- atr/tools/safe/text_tool.py +537 -0
- atr/tools/safe/toolkit.py +175 -0
- caas/__init__.py +162 -0
- caas/api/__init__.py +7 -0
- caas/api/server.py +1328 -0
- caas/caching.py +834 -0
- caas/cli.py +210 -0
- caas/conversation.py +223 -0
- caas/decay.py +72 -0
- caas/detection/__init__.py +9 -0
- caas/detection/detector.py +238 -0
- caas/enrichment.py +130 -0
- caas/gateway/__init__.py +27 -0
- caas/gateway/trust_gateway.py +474 -0
- caas/hf_utils.py +479 -0
- caas/ingestion/__init__.py +23 -0
- caas/ingestion/processors.py +253 -0
- caas/ingestion/structure_parser.py +188 -0
- caas/models.py +356 -0
- caas/pragmatic_truth.py +444 -0
- caas/routing/__init__.py +10 -0
- caas/routing/heuristic_router.py +58 -0
- caas/storage/__init__.py +9 -0
- caas/storage/store.py +389 -0
- caas/triad.py +213 -0
- caas/tuning/__init__.py +9 -0
- caas/tuning/tuner.py +329 -0
- caas/vfs/__init__.py +14 -0
- caas/vfs/filesystem.py +452 -0
- cmvk/__init__.py +218 -0
- cmvk/audit.py +402 -0
- cmvk/benchmarks.py +478 -0
- cmvk/constitutional.py +904 -0
- cmvk/hf_utils.py +301 -0
- cmvk/metrics.py +473 -0
- cmvk/profiles.py +300 -0
- cmvk/py.typed +0 -0
- cmvk/types.py +12 -0
- cmvk/verification.py +956 -0
- emk/__init__.py +89 -0
- emk/causal.py +352 -0
- emk/hf_utils.py +421 -0
- emk/indexer.py +83 -0
- emk/py.typed +0 -0
- emk/schema.py +204 -0
- emk/sleep_cycle.py +347 -0
- emk/store.py +281 -0
- iatp/__init__.py +166 -0
- iatp/attestation.py +461 -0
- iatp/cli.py +317 -0
- iatp/hf_utils.py +472 -0
- iatp/ipc_pipes.py +580 -0
- iatp/main.py +412 -0
- iatp/models/__init__.py +447 -0
- iatp/policy_engine.py +337 -0
- iatp/py.typed +2 -0
- iatp/recovery.py +321 -0
- iatp/security/__init__.py +270 -0
- iatp/sidecar/__init__.py +519 -0
- iatp/telemetry/__init__.py +164 -0
- iatp/tests/__init__.py +1 -0
- iatp/tests/test_attestation.py +370 -0
- iatp/tests/test_cli.py +131 -0
- iatp/tests/test_ed25519_attestation.py +211 -0
- iatp/tests/test_models.py +130 -0
- iatp/tests/test_policy_engine.py +347 -0
- iatp/tests/test_recovery.py +281 -0
- iatp/tests/test_security.py +222 -0
- iatp/tests/test_sidecar.py +167 -0
- iatp/tests/test_telemetry.py +175 -0
- mcp_kernel_server/__init__.py +28 -0
- mcp_kernel_server/cli.py +274 -0
- mcp_kernel_server/resources.py +217 -0
- mcp_kernel_server/server.py +564 -0
- mcp_kernel_server/tools.py +1174 -0
- mute_agent/__init__.py +68 -0
- mute_agent/core/__init__.py +1 -0
- mute_agent/core/execution_agent.py +166 -0
- mute_agent/core/handshake_protocol.py +201 -0
- mute_agent/core/reasoning_agent.py +238 -0
- mute_agent/knowledge_graph/__init__.py +1 -0
- mute_agent/knowledge_graph/graph_elements.py +65 -0
- mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
- mute_agent/knowledge_graph/subgraph.py +224 -0
- mute_agent/listener/__init__.py +43 -0
- mute_agent/listener/adapters/__init__.py +31 -0
- mute_agent/listener/adapters/base_adapter.py +189 -0
- mute_agent/listener/adapters/caas_adapter.py +344 -0
- mute_agent/listener/adapters/control_plane_adapter.py +436 -0
- mute_agent/listener/adapters/iatp_adapter.py +332 -0
- mute_agent/listener/adapters/scak_adapter.py +251 -0
- mute_agent/listener/listener.py +610 -0
- mute_agent/listener/state_observer.py +436 -0
- mute_agent/listener/threshold_config.py +313 -0
- mute_agent/super_system/__init__.py +1 -0
- mute_agent/super_system/router.py +204 -0
- mute_agent/visualization/__init__.py +10 -0
- mute_agent/visualization/graph_debugger.py +502 -0
- nexus/README.md +60 -0
- nexus/__init__.py +51 -0
- nexus/arbiter.py +359 -0
- nexus/client.py +466 -0
- nexus/dmz.py +444 -0
- nexus/escrow.py +430 -0
- nexus/exceptions.py +286 -0
- nexus/pyproject.toml +36 -0
- nexus/registry.py +393 -0
- nexus/reputation.py +425 -0
- nexus/schemas/__init__.py +51 -0
- nexus/schemas/compliance.py +276 -0
- nexus/schemas/escrow.py +251 -0
- nexus/schemas/manifest.py +225 -0
- nexus/schemas/receipt.py +208 -0
- nexus/tests/__init__.py +0 -0
- nexus/tests/conftest.py +146 -0
- nexus/tests/test_arbiter.py +192 -0
- nexus/tests/test_dmz.py +194 -0
- nexus/tests/test_escrow.py +276 -0
- nexus/tests/test_exceptions.py +225 -0
- nexus/tests/test_registry.py +232 -0
- nexus/tests/test_reputation.py +328 -0
- nexus/tests/test_schemas.py +295 -0
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Tool Registry - Dynamic Tool Management and Discovery
|
|
5
|
+
|
|
6
|
+
The Tool Registry enables dynamic registration and discovery of tools for agents,
|
|
7
|
+
supporting extensibility beyond the hardcoded ActionType enum. This addresses
|
|
8
|
+
the need for flexible tool ecosystems similar to LangChain's 100+ integrations.
|
|
9
|
+
|
|
10
|
+
Research Foundations:
|
|
11
|
+
- Plugin architecture patterns for extensible systems
|
|
12
|
+
- Service registry patterns from microservices architecture
|
|
13
|
+
- Tool abstraction inspired by "Multimodal Agents: A Survey" (arXiv:2404.12390)
|
|
14
|
+
- Dynamic capability discovery for agent systems
|
|
15
|
+
|
|
16
|
+
See docs/RESEARCH_FOUNDATION.md for complete references.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import Any, Dict, List, Optional, Callable, Set
|
|
20
|
+
from dataclasses import dataclass, field
|
|
21
|
+
from enum import Enum
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
import hashlib
|
|
24
|
+
import inspect
|
|
25
|
+
import logging
|
|
26
|
+
import textwrap
|
|
27
|
+
import uuid
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ToolType(Enum):
|
|
33
|
+
"""Categories of tools available to agents"""
|
|
34
|
+
TEXT = "text"
|
|
35
|
+
VISION = "vision"
|
|
36
|
+
AUDIO = "audio"
|
|
37
|
+
CODE = "code"
|
|
38
|
+
DATABASE = "database"
|
|
39
|
+
API = "api"
|
|
40
|
+
FILE_SYSTEM = "file_system"
|
|
41
|
+
WORKFLOW = "workflow"
|
|
42
|
+
SEARCH = "search"
|
|
43
|
+
CUSTOM = "custom"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class ToolSchema:
|
|
48
|
+
"""JSON Schema definition for tool parameters"""
|
|
49
|
+
type: str = "object"
|
|
50
|
+
properties: Dict[str, Any] = field(default_factory=dict)
|
|
51
|
+
required: List[str] = field(default_factory=list)
|
|
52
|
+
description: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class Tool:
|
|
57
|
+
"""
|
|
58
|
+
A tool that can be used by agents.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
tool_id: Unique identifier for the tool
|
|
62
|
+
name: Human-readable name
|
|
63
|
+
description: What the tool does
|
|
64
|
+
tool_type: Category of the tool
|
|
65
|
+
handler: Function that executes the tool
|
|
66
|
+
parameter_schema: JSON schema for parameters
|
|
67
|
+
requires_approval: Whether tool execution requires human approval
|
|
68
|
+
risk_level: Risk score (0.0-1.0, higher = more risky)
|
|
69
|
+
content_hash: SHA-256 hash of the tool handler's source code at
|
|
70
|
+
registration time. Used to detect tampering or aliasing.
|
|
71
|
+
metadata: Additional tool metadata
|
|
72
|
+
"""
|
|
73
|
+
tool_id: str
|
|
74
|
+
name: str
|
|
75
|
+
description: str
|
|
76
|
+
tool_type: ToolType
|
|
77
|
+
handler: Callable
|
|
78
|
+
parameter_schema: ToolSchema
|
|
79
|
+
requires_approval: bool = False
|
|
80
|
+
risk_level: float = 0.0
|
|
81
|
+
content_hash: str = ""
|
|
82
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
83
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ToolRegistry:
|
|
87
|
+
"""
|
|
88
|
+
Central registry for dynamic tool management.
|
|
89
|
+
|
|
90
|
+
Features:
|
|
91
|
+
- Register tools dynamically at runtime
|
|
92
|
+
- Discover available tools by type or capability
|
|
93
|
+
- Validate tool parameters against schemas
|
|
94
|
+
- Support for multi-modal tools (text, vision, audio)
|
|
95
|
+
- Integration point for external tool providers
|
|
96
|
+
|
|
97
|
+
Usage:
|
|
98
|
+
registry = ToolRegistry()
|
|
99
|
+
|
|
100
|
+
# Register a tool
|
|
101
|
+
registry.register_tool(
|
|
102
|
+
name="web_search",
|
|
103
|
+
description="Search the web for information",
|
|
104
|
+
tool_type=ToolType.SEARCH,
|
|
105
|
+
handler=search_handler,
|
|
106
|
+
parameter_schema=search_schema
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Discover tools
|
|
110
|
+
tools = registry.get_tools_by_type(ToolType.SEARCH)
|
|
111
|
+
|
|
112
|
+
# Execute a tool
|
|
113
|
+
result = registry.execute_tool("web_search", {"query": "AI safety"})
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
def __init__(self):
|
|
117
|
+
self._tools: Dict[str, Tool] = {}
|
|
118
|
+
self._tools_by_type: Dict[ToolType, Set[str]] = {}
|
|
119
|
+
self._tools_by_name: Dict[str, str] = {} # name -> tool_id mapping
|
|
120
|
+
self._integrity_violations: List[Dict[str, Any]] = []
|
|
121
|
+
|
|
122
|
+
@staticmethod
|
|
123
|
+
def _compute_handler_hash(handler: Callable) -> str:
|
|
124
|
+
"""Compute a SHA-256 content hash of a callable's source code.
|
|
125
|
+
|
|
126
|
+
Returns an empty string if source is unavailable (e.g. built-in
|
|
127
|
+
or C-extension functions). Callers should treat an empty hash
|
|
128
|
+
as "unverifiable" rather than silently trusting the handler.
|
|
129
|
+
"""
|
|
130
|
+
try:
|
|
131
|
+
source = textwrap.dedent(inspect.getsource(handler))
|
|
132
|
+
return hashlib.sha256(source.encode("utf-8")).hexdigest()
|
|
133
|
+
except (OSError, TypeError):
|
|
134
|
+
logger.warning(
|
|
135
|
+
"Cannot compute source hash for handler %r — "
|
|
136
|
+
"source unavailable (built-in or C-extension)",
|
|
137
|
+
getattr(handler, "__qualname__", handler),
|
|
138
|
+
)
|
|
139
|
+
return ""
|
|
140
|
+
|
|
141
|
+
def register_tool(
|
|
142
|
+
self,
|
|
143
|
+
name: str,
|
|
144
|
+
description: str,
|
|
145
|
+
tool_type: ToolType,
|
|
146
|
+
handler: Callable,
|
|
147
|
+
parameter_schema: Optional[ToolSchema] = None,
|
|
148
|
+
requires_approval: bool = False,
|
|
149
|
+
risk_level: float = 0.0,
|
|
150
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
151
|
+
) -> str:
|
|
152
|
+
"""
|
|
153
|
+
Register a new tool in the registry.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
name: Tool name (must be unique)
|
|
157
|
+
description: What the tool does
|
|
158
|
+
tool_type: Category of the tool
|
|
159
|
+
handler: Function to execute the tool
|
|
160
|
+
parameter_schema: JSON schema for parameters (auto-generated if None)
|
|
161
|
+
requires_approval: Whether execution requires approval
|
|
162
|
+
risk_level: Risk score 0.0-1.0
|
|
163
|
+
metadata: Additional metadata
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
tool_id: Unique identifier for the registered tool
|
|
167
|
+
|
|
168
|
+
Raises:
|
|
169
|
+
ValueError: If tool name already exists
|
|
170
|
+
"""
|
|
171
|
+
if name in self._tools_by_name:
|
|
172
|
+
raise ValueError(f"Tool '{name}' already registered")
|
|
173
|
+
|
|
174
|
+
tool_id = str(uuid.uuid4())
|
|
175
|
+
|
|
176
|
+
# Auto-generate schema from function signature if not provided
|
|
177
|
+
if parameter_schema is None:
|
|
178
|
+
parameter_schema = self._generate_schema_from_handler(handler)
|
|
179
|
+
|
|
180
|
+
# Compute content hash for integrity verification
|
|
181
|
+
content_hash = self._compute_handler_hash(handler)
|
|
182
|
+
|
|
183
|
+
tool = Tool(
|
|
184
|
+
tool_id=tool_id,
|
|
185
|
+
name=name,
|
|
186
|
+
description=description,
|
|
187
|
+
tool_type=tool_type,
|
|
188
|
+
handler=handler,
|
|
189
|
+
parameter_schema=parameter_schema,
|
|
190
|
+
requires_approval=requires_approval,
|
|
191
|
+
risk_level=risk_level,
|
|
192
|
+
content_hash=content_hash,
|
|
193
|
+
metadata=metadata or {}
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
self._tools[tool_id] = tool
|
|
197
|
+
self._tools_by_name[name] = tool_id
|
|
198
|
+
|
|
199
|
+
if tool_type not in self._tools_by_type:
|
|
200
|
+
self._tools_by_type[tool_type] = set()
|
|
201
|
+
self._tools_by_type[tool_type].add(tool_id)
|
|
202
|
+
|
|
203
|
+
return tool_id
|
|
204
|
+
|
|
205
|
+
def unregister_tool(self, tool_id_or_name: str) -> bool:
|
|
206
|
+
"""
|
|
207
|
+
Remove a tool from the registry.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
tool_id_or_name: Tool ID or name
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
True if tool was removed, False if not found
|
|
214
|
+
"""
|
|
215
|
+
tool_id = self._resolve_tool_id(tool_id_or_name)
|
|
216
|
+
if not tool_id:
|
|
217
|
+
return False
|
|
218
|
+
|
|
219
|
+
tool = self._tools.get(tool_id)
|
|
220
|
+
if not tool:
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
del self._tools[tool_id]
|
|
224
|
+
del self._tools_by_name[tool.name]
|
|
225
|
+
self._tools_by_type[tool.tool_type].discard(tool_id)
|
|
226
|
+
|
|
227
|
+
return True
|
|
228
|
+
|
|
229
|
+
def get_tool(self, tool_id_or_name: str) -> Optional[Tool]:
|
|
230
|
+
"""Get a tool by ID or name"""
|
|
231
|
+
tool_id = self._resolve_tool_id(tool_id_or_name)
|
|
232
|
+
return self._tools.get(tool_id) if tool_id else None
|
|
233
|
+
|
|
234
|
+
def get_tools_by_type(self, tool_type: ToolType) -> List[Tool]:
|
|
235
|
+
"""Get all tools of a specific type"""
|
|
236
|
+
tool_ids = self._tools_by_type.get(tool_type, set())
|
|
237
|
+
return [self._tools[tid] for tid in tool_ids]
|
|
238
|
+
|
|
239
|
+
def get_all_tools(self) -> List[Tool]:
|
|
240
|
+
"""Get all registered tools"""
|
|
241
|
+
return list(self._tools.values())
|
|
242
|
+
|
|
243
|
+
def execute_tool(
|
|
244
|
+
self,
|
|
245
|
+
tool_id_or_name: str,
|
|
246
|
+
parameters: Dict[str, Any]
|
|
247
|
+
) -> Dict[str, Any]:
|
|
248
|
+
"""
|
|
249
|
+
Execute a registered tool.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
tool_id_or_name: Tool ID or name
|
|
253
|
+
parameters: Tool parameters
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Result dictionary with 'success', 'result', or 'error' keys
|
|
257
|
+
"""
|
|
258
|
+
tool = self.get_tool(tool_id_or_name)
|
|
259
|
+
if not tool:
|
|
260
|
+
return {
|
|
261
|
+
"success": False,
|
|
262
|
+
"error": f"Tool '{tool_id_or_name}' not found"
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
# Verify tool integrity before execution
|
|
266
|
+
integrity = self.verify_tool_integrity(tool.tool_id)
|
|
267
|
+
if not integrity["verified"]:
|
|
268
|
+
logger.warning(
|
|
269
|
+
"Tool integrity check FAILED for '%s': %s",
|
|
270
|
+
tool.name,
|
|
271
|
+
integrity["reason"],
|
|
272
|
+
)
|
|
273
|
+
self._integrity_violations.append({
|
|
274
|
+
"tool_id": tool.tool_id,
|
|
275
|
+
"tool_name": tool.name,
|
|
276
|
+
"reason": integrity["reason"],
|
|
277
|
+
"timestamp": datetime.now().isoformat(),
|
|
278
|
+
})
|
|
279
|
+
return {
|
|
280
|
+
"success": False,
|
|
281
|
+
"error": f"Tool integrity verification failed: {integrity['reason']}",
|
|
282
|
+
"tool_id": tool.tool_id,
|
|
283
|
+
"tool_name": tool.name,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
# Validate parameters against schema
|
|
287
|
+
validation_result = self.validate_parameters(tool.tool_id, parameters)
|
|
288
|
+
if not validation_result["valid"]:
|
|
289
|
+
return {
|
|
290
|
+
"success": False,
|
|
291
|
+
"error": f"Invalid parameters: {validation_result['errors']}"
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
result = tool.handler(**parameters)
|
|
296
|
+
return {
|
|
297
|
+
"success": True,
|
|
298
|
+
"result": result,
|
|
299
|
+
"tool_id": tool.tool_id,
|
|
300
|
+
"tool_name": tool.name
|
|
301
|
+
}
|
|
302
|
+
except Exception as e:
|
|
303
|
+
return {
|
|
304
|
+
"success": False,
|
|
305
|
+
"error": str(e),
|
|
306
|
+
"tool_id": tool.tool_id,
|
|
307
|
+
"tool_name": tool.name
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def validate_parameters(
|
|
311
|
+
self,
|
|
312
|
+
tool_id_or_name: str,
|
|
313
|
+
parameters: Dict[str, Any]
|
|
314
|
+
) -> Dict[str, Any]:
|
|
315
|
+
"""
|
|
316
|
+
Validate parameters against tool schema.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
{"valid": bool, "errors": List[str]}
|
|
320
|
+
"""
|
|
321
|
+
tool = self.get_tool(tool_id_or_name)
|
|
322
|
+
if not tool:
|
|
323
|
+
return {"valid": False, "errors": ["Tool not found"]}
|
|
324
|
+
|
|
325
|
+
errors = []
|
|
326
|
+
schema = tool.parameter_schema
|
|
327
|
+
|
|
328
|
+
# Check required parameters
|
|
329
|
+
for required_param in schema.required:
|
|
330
|
+
if required_param not in parameters:
|
|
331
|
+
errors.append(f"Missing required parameter: {required_param}")
|
|
332
|
+
|
|
333
|
+
# Type checking would go here (simplified for now)
|
|
334
|
+
# In production, use jsonschema library for full validation
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
"valid": len(errors) == 0,
|
|
338
|
+
"errors": errors
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
def search_tools(self, query: str) -> List[Tool]:
|
|
342
|
+
"""
|
|
343
|
+
Search tools by name or description.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
query: Search string
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
List of matching tools
|
|
350
|
+
"""
|
|
351
|
+
query_lower = query.lower()
|
|
352
|
+
matches = []
|
|
353
|
+
|
|
354
|
+
for tool in self._tools.values():
|
|
355
|
+
if (query_lower in tool.name.lower() or
|
|
356
|
+
query_lower in tool.description.lower()):
|
|
357
|
+
matches.append(tool)
|
|
358
|
+
|
|
359
|
+
return matches
|
|
360
|
+
|
|
361
|
+
def verify_tool_integrity(self, tool_id_or_name: str) -> Dict[str, Any]:
|
|
362
|
+
"""Verify that a tool's handler has not been modified since registration.
|
|
363
|
+
|
|
364
|
+
Compares the current SHA-256 hash of the handler's source code
|
|
365
|
+
against the hash recorded at registration time.
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
{"verified": bool, "reason": str, "registered_hash": str, "current_hash": str}
|
|
369
|
+
"""
|
|
370
|
+
tool = self.get_tool(tool_id_or_name)
|
|
371
|
+
if not tool:
|
|
372
|
+
return {
|
|
373
|
+
"verified": False,
|
|
374
|
+
"reason": "Tool not found",
|
|
375
|
+
"registered_hash": "",
|
|
376
|
+
"current_hash": "",
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if not tool.content_hash:
|
|
380
|
+
return {
|
|
381
|
+
"verified": False,
|
|
382
|
+
"reason": "No content hash recorded at registration (built-in or C-extension)",
|
|
383
|
+
"registered_hash": "",
|
|
384
|
+
"current_hash": "",
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
current_hash = self._compute_handler_hash(tool.handler)
|
|
388
|
+
if not current_hash:
|
|
389
|
+
return {
|
|
390
|
+
"verified": False,
|
|
391
|
+
"reason": "Cannot compute current hash — source unavailable",
|
|
392
|
+
"registered_hash": tool.content_hash,
|
|
393
|
+
"current_hash": "",
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
verified = current_hash == tool.content_hash
|
|
397
|
+
return {
|
|
398
|
+
"verified": verified,
|
|
399
|
+
"reason": "" if verified else "Handler source has been modified since registration",
|
|
400
|
+
"registered_hash": tool.content_hash,
|
|
401
|
+
"current_hash": current_hash,
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
def get_integrity_violations(self) -> List[Dict[str, Any]]:
|
|
405
|
+
"""Return all recorded integrity violations."""
|
|
406
|
+
return list(self._integrity_violations)
|
|
407
|
+
|
|
408
|
+
def _resolve_tool_id(self, tool_id_or_name: str) -> Optional[str]:
|
|
409
|
+
"""Resolve a tool name to its ID, or return ID if already an ID"""
|
|
410
|
+
if tool_id_or_name in self._tools:
|
|
411
|
+
return tool_id_or_name
|
|
412
|
+
return self._tools_by_name.get(tool_id_or_name)
|
|
413
|
+
|
|
414
|
+
def _generate_schema_from_handler(self, handler: Callable) -> ToolSchema:
|
|
415
|
+
"""Auto-generate a basic schema from function signature"""
|
|
416
|
+
sig = inspect.signature(handler)
|
|
417
|
+
properties = {}
|
|
418
|
+
required = []
|
|
419
|
+
|
|
420
|
+
for param_name, param in sig.parameters.items():
|
|
421
|
+
if param_name == "self":
|
|
422
|
+
continue
|
|
423
|
+
|
|
424
|
+
properties[param_name] = {
|
|
425
|
+
"type": "string", # Default to string, would need type hints for better
|
|
426
|
+
"description": f"Parameter {param_name}"
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if param.default == inspect.Parameter.empty:
|
|
430
|
+
required.append(param_name)
|
|
431
|
+
|
|
432
|
+
return ToolSchema(
|
|
433
|
+
type="object",
|
|
434
|
+
properties=properties,
|
|
435
|
+
required=required,
|
|
436
|
+
description=handler.__doc__ or ""
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def create_standard_tool_registry() -> ToolRegistry:
|
|
441
|
+
"""
|
|
442
|
+
Create a tool registry with standard built-in tools.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
ToolRegistry with common tools pre-registered
|
|
446
|
+
"""
|
|
447
|
+
registry = ToolRegistry()
|
|
448
|
+
|
|
449
|
+
# This would register standard tools
|
|
450
|
+
# Intentionally left minimal to show the pattern
|
|
451
|
+
|
|
452
|
+
return registry
|