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,175 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Unit tests for IATP telemetry module.
|
|
5
|
+
"""
|
|
6
|
+
import shutil
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from iatp.models import (
|
|
13
|
+
AgentCapabilities,
|
|
14
|
+
CapabilityManifest,
|
|
15
|
+
PrivacyContract,
|
|
16
|
+
RetentionPolicy,
|
|
17
|
+
)
|
|
18
|
+
from iatp.telemetry import FlightRecorder, TraceIDGenerator
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@pytest.fixture
|
|
22
|
+
def temp_log_dir():
|
|
23
|
+
"""Create a temporary directory for logs."""
|
|
24
|
+
temp_dir = Path(tempfile.mkdtemp())
|
|
25
|
+
yield temp_dir
|
|
26
|
+
shutil.rmtree(temp_dir)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_trace_id_generation():
|
|
30
|
+
"""Test trace ID generation."""
|
|
31
|
+
trace_id1 = TraceIDGenerator.generate()
|
|
32
|
+
trace_id2 = TraceIDGenerator.generate()
|
|
33
|
+
|
|
34
|
+
assert trace_id1 != trace_id2
|
|
35
|
+
assert len(trace_id1) > 0
|
|
36
|
+
assert len(trace_id2) > 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_create_tracing_context():
|
|
40
|
+
"""Test creating a tracing context."""
|
|
41
|
+
trace_id = TraceIDGenerator.generate()
|
|
42
|
+
context = TraceIDGenerator.create_context(trace_id, "test-agent")
|
|
43
|
+
|
|
44
|
+
assert context.trace_id == trace_id
|
|
45
|
+
assert context.agent_id == "test-agent"
|
|
46
|
+
assert context.parent_trace_id is None
|
|
47
|
+
assert context.timestamp is not None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_flight_recorder_log_request(temp_log_dir):
|
|
51
|
+
"""Test logging a request."""
|
|
52
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
53
|
+
trace_id = "test-trace-123"
|
|
54
|
+
|
|
55
|
+
recorder.log_request(
|
|
56
|
+
trace_id=trace_id,
|
|
57
|
+
agent_id="test-agent",
|
|
58
|
+
payload={"task": "test"},
|
|
59
|
+
quarantined=False
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
63
|
+
assert len(logs) == 1
|
|
64
|
+
assert logs[0]["type"] == "request"
|
|
65
|
+
assert logs[0]["trace_id"] == trace_id
|
|
66
|
+
assert logs[0]["agent_id"] == "test-agent"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_flight_recorder_log_response(temp_log_dir):
|
|
70
|
+
"""Test logging a response."""
|
|
71
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
72
|
+
trace_id = "test-trace-456"
|
|
73
|
+
|
|
74
|
+
recorder.log_response(
|
|
75
|
+
trace_id=trace_id,
|
|
76
|
+
agent_id="test-agent",
|
|
77
|
+
response={"status": "success"},
|
|
78
|
+
status_code=200,
|
|
79
|
+
latency_ms=123.45
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
83
|
+
assert len(logs) == 1
|
|
84
|
+
assert logs[0]["type"] == "response"
|
|
85
|
+
assert logs[0]["status_code"] == 200
|
|
86
|
+
assert logs[0]["latency_ms"] == 123.45
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_flight_recorder_log_error(temp_log_dir):
|
|
90
|
+
"""Test logging an error."""
|
|
91
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
92
|
+
trace_id = "test-trace-789"
|
|
93
|
+
|
|
94
|
+
recorder.log_error(
|
|
95
|
+
trace_id=trace_id,
|
|
96
|
+
agent_id="test-agent",
|
|
97
|
+
error="Connection timeout",
|
|
98
|
+
details={"timeout": 30}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
102
|
+
assert len(logs) == 1
|
|
103
|
+
assert logs[0]["type"] == "error"
|
|
104
|
+
assert logs[0]["error"] == "Connection timeout"
|
|
105
|
+
assert logs[0]["details"]["timeout"] == 30
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_flight_recorder_log_blocked(temp_log_dir):
|
|
109
|
+
"""Test logging a blocked request."""
|
|
110
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
111
|
+
trace_id = "test-trace-blocked"
|
|
112
|
+
|
|
113
|
+
manifest = CapabilityManifest(
|
|
114
|
+
agent_id="test-agent",
|
|
115
|
+
capabilities=AgentCapabilities(),
|
|
116
|
+
privacy_contract=PrivacyContract(
|
|
117
|
+
retention=RetentionPolicy.FOREVER
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
recorder.log_blocked_request(
|
|
122
|
+
trace_id=trace_id,
|
|
123
|
+
agent_id="test-agent",
|
|
124
|
+
payload={"sensitive": "data"},
|
|
125
|
+
reason="Privacy violation",
|
|
126
|
+
manifest=manifest
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
130
|
+
assert len(logs) == 1
|
|
131
|
+
assert logs[0]["type"] == "blocked"
|
|
132
|
+
assert logs[0]["reason"] == "Privacy violation"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_flight_recorder_multiple_logs(temp_log_dir):
|
|
136
|
+
"""Test multiple log entries for the same trace."""
|
|
137
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
138
|
+
trace_id = "test-trace-multi"
|
|
139
|
+
|
|
140
|
+
recorder.log_request(trace_id, "agent1", {"req": 1}, quarantined=False)
|
|
141
|
+
recorder.log_response(trace_id, "agent1", {"resp": 1}, 200, 100.0)
|
|
142
|
+
recorder.log_request(trace_id, "agent2", {"req": 2}, quarantined=False)
|
|
143
|
+
recorder.log_response(trace_id, "agent2", {"resp": 2}, 200, 150.0)
|
|
144
|
+
|
|
145
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
146
|
+
assert len(logs) == 4
|
|
147
|
+
assert logs[0]["type"] == "request"
|
|
148
|
+
assert logs[1]["type"] == "response"
|
|
149
|
+
assert logs[2]["type"] == "request"
|
|
150
|
+
assert logs[3]["type"] == "response"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_flight_recorder_sensitive_data_scrubbed(temp_log_dir):
|
|
154
|
+
"""Test that sensitive data is scrubbed in logs."""
|
|
155
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
156
|
+
trace_id = "test-trace-sensitive"
|
|
157
|
+
|
|
158
|
+
recorder.log_request(
|
|
159
|
+
trace_id=trace_id,
|
|
160
|
+
agent_id="test-agent",
|
|
161
|
+
payload={"card": "4532-1234-5678-9010"},
|
|
162
|
+
quarantined=False
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
logs = recorder.get_trace_logs(trace_id)
|
|
166
|
+
payload_str = str(logs[0]["payload"])
|
|
167
|
+
assert "4532-1234-5678-9010" not in payload_str
|
|
168
|
+
assert "[CREDIT_CARD_REDACTED]" in payload_str
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def test_flight_recorder_nonexistent_trace(temp_log_dir):
|
|
172
|
+
"""Test retrieving logs for a nonexistent trace."""
|
|
173
|
+
recorder = FlightRecorder(log_dir=temp_log_dir)
|
|
174
|
+
logs = recorder.get_trace_logs("nonexistent-trace")
|
|
175
|
+
assert logs == []
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
MCP Kernel Server - Expose Agent OS primitives through Model Context Protocol.
|
|
5
|
+
|
|
6
|
+
This package provides:
|
|
7
|
+
- CMVK verification as MCP tool
|
|
8
|
+
- IATP trust signing as MCP tool
|
|
9
|
+
- VFS filesystem as MCP resource
|
|
10
|
+
- Governed execution as MCP tool
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from mcp_kernel_server.server import KernelMCPServer
|
|
14
|
+
from mcp_kernel_server.tools import (
|
|
15
|
+
CMVKVerifyTool,
|
|
16
|
+
KernelExecuteTool,
|
|
17
|
+
IATPSignTool,
|
|
18
|
+
)
|
|
19
|
+
from mcp_kernel_server.resources import VFSResource
|
|
20
|
+
|
|
21
|
+
__version__ = "3.1.0"
|
|
22
|
+
__all__ = [
|
|
23
|
+
"KernelMCPServer",
|
|
24
|
+
"CMVKVerifyTool",
|
|
25
|
+
"KernelExecuteTool",
|
|
26
|
+
"IATPSignTool",
|
|
27
|
+
"VFSResource",
|
|
28
|
+
]
|
mcp_kernel_server/cli.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
CLI for MCP Kernel Server.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
# For Claude Desktop (stdio transport)
|
|
8
|
+
mcp-kernel-server --stdio
|
|
9
|
+
|
|
10
|
+
# For development (HTTP transport)
|
|
11
|
+
mcp-kernel-server --http --port 8080
|
|
12
|
+
|
|
13
|
+
Claude Desktop Integration:
|
|
14
|
+
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"agent-os": {
|
|
19
|
+
"command": "mcp-kernel-server",
|
|
20
|
+
"args": ["--stdio"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import argparse
|
|
27
|
+
import asyncio
|
|
28
|
+
import logging
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
from mcp_kernel_server.server import KernelMCPServer, ServerConfig
|
|
33
|
+
|
|
34
|
+
# Configure logging to stderr (stdout is for MCP protocol)
|
|
35
|
+
logging.basicConfig(
|
|
36
|
+
level=logging.INFO,
|
|
37
|
+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
38
|
+
stream=sys.stderr
|
|
39
|
+
)
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def parse_args():
|
|
44
|
+
"""Parse command line arguments."""
|
|
45
|
+
parser = argparse.ArgumentParser(
|
|
46
|
+
description="MCP Kernel Server - Agent OS primitives via Model Context Protocol",
|
|
47
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
48
|
+
epilog="""
|
|
49
|
+
Examples:
|
|
50
|
+
# For Claude Desktop integration
|
|
51
|
+
mcp-kernel-server --stdio
|
|
52
|
+
|
|
53
|
+
# For development/testing
|
|
54
|
+
mcp-kernel-server --http --port 8080
|
|
55
|
+
|
|
56
|
+
# With custom policy mode
|
|
57
|
+
mcp-kernel-server --stdio --policy-mode permissive
|
|
58
|
+
|
|
59
|
+
Claude Desktop Setup:
|
|
60
|
+
Add to claude_desktop_config.json:
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"agent-os": {
|
|
64
|
+
"command": "mcp-kernel-server",
|
|
65
|
+
"args": ["--stdio"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
"""
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"--stdio",
|
|
73
|
+
action="store_true",
|
|
74
|
+
help="Use stdio transport (for Claude Desktop)"
|
|
75
|
+
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--http",
|
|
78
|
+
action="store_true",
|
|
79
|
+
help="Use HTTP transport (for development)"
|
|
80
|
+
)
|
|
81
|
+
parser.add_argument(
|
|
82
|
+
"--port", "-p",
|
|
83
|
+
type=int,
|
|
84
|
+
default=8080,
|
|
85
|
+
help="Port for HTTP transport (default: 8080)"
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--host", "-H",
|
|
89
|
+
type=str,
|
|
90
|
+
default="127.0.0.1",
|
|
91
|
+
help="Host for HTTP transport (default: 127.0.0.1)"
|
|
92
|
+
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"--policy-mode",
|
|
95
|
+
choices=["strict", "permissive", "audit"],
|
|
96
|
+
default="strict",
|
|
97
|
+
help="Policy enforcement mode (default: strict)"
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--cmvk-threshold",
|
|
101
|
+
type=float,
|
|
102
|
+
default=0.85,
|
|
103
|
+
help="CMVK verification threshold (default: 0.85)"
|
|
104
|
+
)
|
|
105
|
+
parser.add_argument(
|
|
106
|
+
"--version", "-v",
|
|
107
|
+
action="store_true",
|
|
108
|
+
help="Show version and exit"
|
|
109
|
+
)
|
|
110
|
+
parser.add_argument(
|
|
111
|
+
"--list-tools",
|
|
112
|
+
action="store_true",
|
|
113
|
+
help="List available tools and exit"
|
|
114
|
+
)
|
|
115
|
+
parser.add_argument(
|
|
116
|
+
"--list-prompts",
|
|
117
|
+
action="store_true",
|
|
118
|
+
help="List available prompts and exit"
|
|
119
|
+
)
|
|
120
|
+
parser.add_argument(
|
|
121
|
+
"--json",
|
|
122
|
+
action="store_true",
|
|
123
|
+
help="Output in JSON format (for listing tools/prompts)"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return parser.parse_args()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def print_tools():
|
|
130
|
+
"""Print available tools."""
|
|
131
|
+
print("Available MCP Tools:")
|
|
132
|
+
print()
|
|
133
|
+
print(" cmvk_verify")
|
|
134
|
+
print(" Verify claims across multiple AI models to detect hallucinations")
|
|
135
|
+
print(" Arguments: claim (required), context, models, threshold")
|
|
136
|
+
print()
|
|
137
|
+
print(" kernel_execute")
|
|
138
|
+
print(" Execute actions through the Agent OS kernel with policy enforcement")
|
|
139
|
+
print(" Arguments: action (required), params, agent_id (required), policies, context")
|
|
140
|
+
print()
|
|
141
|
+
print(" iatp_sign")
|
|
142
|
+
print(" Create a trust attestation for inter-agent communication")
|
|
143
|
+
print(" Arguments: attester_id (required), subject_id (required), trust_level, claims")
|
|
144
|
+
print()
|
|
145
|
+
print(" iatp_verify")
|
|
146
|
+
print(" Verify trust relationship before agent-to-agent communication")
|
|
147
|
+
print(" Arguments: source_agent (required), target_agent (required), action, data_classification")
|
|
148
|
+
print()
|
|
149
|
+
print(" iatp_reputation")
|
|
150
|
+
print(" Query or modify agent reputation across the trust network")
|
|
151
|
+
print(" Arguments: agent_id (required), action (required), reason")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def print_prompts():
|
|
155
|
+
"""Print available prompts."""
|
|
156
|
+
print("Available MCP Prompts:")
|
|
157
|
+
print()
|
|
158
|
+
print(" governed_agent")
|
|
159
|
+
print(" Instructions for operating as a governed agent under Agent OS")
|
|
160
|
+
print(" Arguments: agent_id (required), policies")
|
|
161
|
+
print()
|
|
162
|
+
print(" verify_claim")
|
|
163
|
+
print(" Instructions for verifying a claim using CMVK")
|
|
164
|
+
print(" Arguments: claim (required)")
|
|
165
|
+
print()
|
|
166
|
+
print(" safe_execution")
|
|
167
|
+
print(" Template for executing actions safely through the kernel")
|
|
168
|
+
print(" Arguments: action (required), params (required)")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def main():
|
|
172
|
+
"""Main entry point."""
|
|
173
|
+
args = parse_args()
|
|
174
|
+
|
|
175
|
+
if args.version:
|
|
176
|
+
from mcp_kernel_server import __version__
|
|
177
|
+
if args.json:
|
|
178
|
+
import json
|
|
179
|
+
print(json.dumps({
|
|
180
|
+
"name": "mcp-kernel-server",
|
|
181
|
+
"version": __version__,
|
|
182
|
+
"description": "Agent OS MCP Server for kernel-level AI agent governance"
|
|
183
|
+
}, indent=2))
|
|
184
|
+
else:
|
|
185
|
+
print(f"mcp-kernel-server {__version__}")
|
|
186
|
+
print(f"Agent OS MCP Server for kernel-level AI agent governance")
|
|
187
|
+
return 0
|
|
188
|
+
|
|
189
|
+
if args.list_tools:
|
|
190
|
+
if args.json:
|
|
191
|
+
import json
|
|
192
|
+
tools = [
|
|
193
|
+
{"name": "cmvk_verify", "description": "Verify claims across multiple AI models to detect hallucinations"},
|
|
194
|
+
{"name": "kernel_execute", "description": "Execute actions through the Agent OS kernel with policy enforcement"},
|
|
195
|
+
{"name": "iatp_sign", "description": "Create a trust attestation for inter-agent communication"},
|
|
196
|
+
{"name": "iatp_verify", "description": "Verify trust relationship before agent-to-agent communication"},
|
|
197
|
+
{"name": "iatp_reputation", "description": "Query or modify agent reputation across the trust network"}
|
|
198
|
+
]
|
|
199
|
+
print(json.dumps(tools, indent=2))
|
|
200
|
+
else:
|
|
201
|
+
print_tools()
|
|
202
|
+
return 0
|
|
203
|
+
|
|
204
|
+
if args.list_prompts:
|
|
205
|
+
if args.json:
|
|
206
|
+
import json
|
|
207
|
+
prompts = [
|
|
208
|
+
{"name": "governed_agent", "description": "Instructions for operating as a governed agent under Agent OS"},
|
|
209
|
+
{"name": "verify_claim", "description": "Instructions for verifying a claim using CMVK"},
|
|
210
|
+
{"name": "safe_execution", "description": "Template for executing actions safely through the kernel"}
|
|
211
|
+
]
|
|
212
|
+
print(json.dumps(prompts, indent=2))
|
|
213
|
+
else:
|
|
214
|
+
print_prompts()
|
|
215
|
+
return 0
|
|
216
|
+
|
|
217
|
+
# Default to stdio if neither specified
|
|
218
|
+
if not args.stdio and not args.http:
|
|
219
|
+
args.stdio = True
|
|
220
|
+
|
|
221
|
+
# Build config
|
|
222
|
+
config = ServerConfig(
|
|
223
|
+
host=args.host,
|
|
224
|
+
port=args.port,
|
|
225
|
+
policy_mode=args.policy_mode,
|
|
226
|
+
cmvk_threshold=args.cmvk_threshold
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Create server
|
|
230
|
+
server = KernelMCPServer(config)
|
|
231
|
+
|
|
232
|
+
# Run
|
|
233
|
+
try:
|
|
234
|
+
if args.stdio:
|
|
235
|
+
logger.info("Starting MCP Kernel Server with stdio transport")
|
|
236
|
+
logger.info(f"Policy mode: {args.policy_mode}")
|
|
237
|
+
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
|
|
238
|
+
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
|
|
239
|
+
|
|
240
|
+
asyncio.run(server.run_stdio())
|
|
241
|
+
else:
|
|
242
|
+
# HTTP transport
|
|
243
|
+
logger.info(f"Starting MCP Kernel Server on http://{args.host}:{args.port}")
|
|
244
|
+
logger.info(f"Policy mode: {args.policy_mode}")
|
|
245
|
+
logger.info("Tools: cmvk_verify, kernel_execute, iatp_sign, iatp_verify, iatp_reputation")
|
|
246
|
+
logger.info("Prompts: governed_agent, verify_claim, safe_execution")
|
|
247
|
+
logger.info("Press Ctrl+C to stop")
|
|
248
|
+
|
|
249
|
+
asyncio.run(server.start())
|
|
250
|
+
asyncio.get_event_loop().run_forever()
|
|
251
|
+
|
|
252
|
+
except KeyboardInterrupt:
|
|
253
|
+
logger.info("Shutting down...")
|
|
254
|
+
except Exception as e:
|
|
255
|
+
# Sanitize startup errors for JSON mode to prevent info leakage
|
|
256
|
+
is_known = isinstance(e, (ValueError, PermissionError, OSError))
|
|
257
|
+
msg = "A validation or system error occurred." if is_known else "An internal error occurred during server startup"
|
|
258
|
+
|
|
259
|
+
if getattr(args, "json", False):
|
|
260
|
+
import json
|
|
261
|
+
print(json.dumps({
|
|
262
|
+
"status": "error",
|
|
263
|
+
"message": msg,
|
|
264
|
+
"type": "StartupError" if is_known else "InternalError"
|
|
265
|
+
}, indent=2))
|
|
266
|
+
else:
|
|
267
|
+
logger.exception(f"Server error: {msg}")
|
|
268
|
+
return 1
|
|
269
|
+
|
|
270
|
+
return 0
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
if __name__ == "__main__":
|
|
274
|
+
sys.exit(main() or 0)
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
MCP Resources for Agent OS VFS.
|
|
5
|
+
|
|
6
|
+
Exposes the Agent Virtual File System as MCP resources,
|
|
7
|
+
allowing agents to read/write structured memory.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Dict, Optional
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ResourceContent:
|
|
18
|
+
"""Content returned from VFS resource."""
|
|
19
|
+
uri: str
|
|
20
|
+
mime_type: str
|
|
21
|
+
content: Any
|
|
22
|
+
metadata: dict = field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class VFSResource:
|
|
26
|
+
"""
|
|
27
|
+
Agent Virtual File System as MCP Resource.
|
|
28
|
+
|
|
29
|
+
Provides structured memory access through standard paths:
|
|
30
|
+
- /vfs/{agent_id}/mem/working/* - Ephemeral working memory
|
|
31
|
+
- /vfs/{agent_id}/mem/episodic/* - Experience logs
|
|
32
|
+
- /vfs/{agent_id}/policy/* - Read-only policies
|
|
33
|
+
|
|
34
|
+
Stateless Design:
|
|
35
|
+
- All state stored in external backend (memory/redis/s3)
|
|
36
|
+
- No session state maintained in server
|
|
37
|
+
- Horizontally scalable
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
uri_template = "vfs://{agent_id}/{path}"
|
|
41
|
+
|
|
42
|
+
# Backend storage (in production: Redis, S3, DynamoDB)
|
|
43
|
+
_storage: Dict[str, Dict[str, Any]] = {}
|
|
44
|
+
|
|
45
|
+
def __init__(self, config: Optional[dict] = None):
|
|
46
|
+
self.config = config or {}
|
|
47
|
+
self.backend = self.config.get("backend", "memory")
|
|
48
|
+
|
|
49
|
+
def list_resources(self, agent_id: str) -> list:
|
|
50
|
+
"""List available resources for an agent."""
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
"uri": f"vfs://{agent_id}/mem/working",
|
|
54
|
+
"name": "Working Memory",
|
|
55
|
+
"description": "Ephemeral working memory for current task",
|
|
56
|
+
"mimeType": "application/json"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"uri": f"vfs://{agent_id}/mem/episodic",
|
|
60
|
+
"name": "Episodic Memory",
|
|
61
|
+
"description": "Agent experience and history logs",
|
|
62
|
+
"mimeType": "application/json"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"uri": f"vfs://{agent_id}/policy",
|
|
66
|
+
"name": "Policies",
|
|
67
|
+
"description": "Agent policies and constraints (read-only)",
|
|
68
|
+
"mimeType": "application/json"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
async def read(self, uri: str) -> ResourceContent:
|
|
73
|
+
"""Read from VFS path."""
|
|
74
|
+
agent_id, path = self._parse_uri(uri)
|
|
75
|
+
|
|
76
|
+
# Initialize agent storage if needed
|
|
77
|
+
if agent_id not in self._storage:
|
|
78
|
+
self._storage[agent_id] = self._init_agent_storage(agent_id)
|
|
79
|
+
|
|
80
|
+
# Navigate to path
|
|
81
|
+
content = self._get_path(self._storage[agent_id], path)
|
|
82
|
+
|
|
83
|
+
return ResourceContent(
|
|
84
|
+
uri=uri,
|
|
85
|
+
mime_type="application/json",
|
|
86
|
+
content=content,
|
|
87
|
+
metadata={
|
|
88
|
+
"agent_id": agent_id,
|
|
89
|
+
"path": path,
|
|
90
|
+
"timestamp": datetime.now(timezone.utc).isoformat()
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
async def write(self, uri: str, content: Any) -> ResourceContent:
|
|
95
|
+
"""Write to VFS path (if allowed)."""
|
|
96
|
+
agent_id, path = self._parse_uri(uri)
|
|
97
|
+
|
|
98
|
+
# Check write permissions
|
|
99
|
+
if path.startswith("policy"):
|
|
100
|
+
raise PermissionError(f"Cannot write to policy path: {path}")
|
|
101
|
+
|
|
102
|
+
# Initialize agent storage if needed
|
|
103
|
+
if agent_id not in self._storage:
|
|
104
|
+
self._storage[agent_id] = self._init_agent_storage(agent_id)
|
|
105
|
+
|
|
106
|
+
# Write to path
|
|
107
|
+
self._set_path(self._storage[agent_id], path, content)
|
|
108
|
+
|
|
109
|
+
return ResourceContent(
|
|
110
|
+
uri=uri,
|
|
111
|
+
mime_type="application/json",
|
|
112
|
+
content={"status": "written", "path": path},
|
|
113
|
+
metadata={
|
|
114
|
+
"agent_id": agent_id,
|
|
115
|
+
"path": path,
|
|
116
|
+
"timestamp": datetime.now(timezone.utc).isoformat()
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def _parse_uri(self, uri: str) -> tuple:
|
|
121
|
+
"""Parse VFS URI into agent_id and path."""
|
|
122
|
+
# Handle vfs://agent_id/path format
|
|
123
|
+
if uri.startswith("vfs://"):
|
|
124
|
+
uri = uri[6:]
|
|
125
|
+
|
|
126
|
+
parts = uri.split("/", 1)
|
|
127
|
+
agent_id = parts[0]
|
|
128
|
+
path = parts[1] if len(parts) > 1 else ""
|
|
129
|
+
|
|
130
|
+
return agent_id, path
|
|
131
|
+
|
|
132
|
+
def _init_agent_storage(self, agent_id: str) -> dict:
|
|
133
|
+
"""Initialize storage structure for an agent."""
|
|
134
|
+
return {
|
|
135
|
+
"mem": {
|
|
136
|
+
"working": {
|
|
137
|
+
"_meta": {"type": "working_memory", "ephemeral": True}
|
|
138
|
+
},
|
|
139
|
+
"episodic": {
|
|
140
|
+
"_meta": {"type": "episodic_memory"},
|
|
141
|
+
"sessions": []
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"policy": {
|
|
145
|
+
"_meta": {"type": "policies", "read_only": True},
|
|
146
|
+
"default": {
|
|
147
|
+
"name": "default",
|
|
148
|
+
"rules": [
|
|
149
|
+
{"action": "*", "effect": "allow"}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
def _get_path(self, storage: dict, path: str) -> Any:
|
|
156
|
+
"""Navigate storage to get value at path."""
|
|
157
|
+
if not path:
|
|
158
|
+
return storage
|
|
159
|
+
|
|
160
|
+
current = storage
|
|
161
|
+
for part in path.split("/"):
|
|
162
|
+
if not part:
|
|
163
|
+
continue
|
|
164
|
+
if isinstance(current, dict) and part in current:
|
|
165
|
+
current = current[part]
|
|
166
|
+
else:
|
|
167
|
+
return None
|
|
168
|
+
return current
|
|
169
|
+
|
|
170
|
+
def _set_path(self, storage: dict, path: str, value: Any):
|
|
171
|
+
"""Navigate storage to set value at path."""
|
|
172
|
+
parts = [p for p in path.split("/") if p]
|
|
173
|
+
|
|
174
|
+
current = storage
|
|
175
|
+
for part in parts[:-1]:
|
|
176
|
+
if part not in current:
|
|
177
|
+
current[part] = {}
|
|
178
|
+
current = current[part]
|
|
179
|
+
|
|
180
|
+
if parts:
|
|
181
|
+
current[parts[-1]] = value
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class VFSResourceTemplate:
|
|
185
|
+
"""
|
|
186
|
+
MCP Resource Template for dynamic VFS paths.
|
|
187
|
+
|
|
188
|
+
Allows clients to discover available resources dynamically.
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
uri_template = "vfs://{agent_id}/{path}"
|
|
192
|
+
name = "Agent VFS"
|
|
193
|
+
description = "Virtual File System for agent memory and policies"
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def get_templates() -> list:
|
|
197
|
+
"""Return MCP resource templates."""
|
|
198
|
+
return [
|
|
199
|
+
{
|
|
200
|
+
"uriTemplate": "vfs://{agent_id}/mem/working/{key}",
|
|
201
|
+
"name": "Working Memory Item",
|
|
202
|
+
"description": "Read/write ephemeral working memory",
|
|
203
|
+
"mimeType": "application/json"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"uriTemplate": "vfs://{agent_id}/mem/episodic/{session_id}",
|
|
207
|
+
"name": "Episodic Session",
|
|
208
|
+
"description": "Read/write session history",
|
|
209
|
+
"mimeType": "application/json"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"uriTemplate": "vfs://{agent_id}/policy/{policy_name}",
|
|
213
|
+
"name": "Policy",
|
|
214
|
+
"description": "Read agent policy (read-only)",
|
|
215
|
+
"mimeType": "application/json"
|
|
216
|
+
}
|
|
217
|
+
]
|