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,65 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Knowledge Graph Node and Edge definitions.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from enum import Enum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class NodeType(Enum):
|
|
13
|
+
"""Types of nodes in the knowledge graph."""
|
|
14
|
+
ACTION = "action"
|
|
15
|
+
CONSTRAINT = "constraint"
|
|
16
|
+
PRECONDITION = "precondition"
|
|
17
|
+
POSTCONDITION = "postcondition"
|
|
18
|
+
CONTEXT = "context"
|
|
19
|
+
RESOURCE = "resource"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EdgeType(Enum):
|
|
23
|
+
"""Types of edges in the knowledge graph."""
|
|
24
|
+
REQUIRES = "requires"
|
|
25
|
+
ENABLES = "enables"
|
|
26
|
+
CONFLICTS_WITH = "conflicts_with"
|
|
27
|
+
DEPENDS_ON = "depends_on"
|
|
28
|
+
PRODUCES = "produces"
|
|
29
|
+
CONSUMES = "consumes"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class Node:
|
|
34
|
+
"""A node in the knowledge graph."""
|
|
35
|
+
id: str
|
|
36
|
+
node_type: NodeType
|
|
37
|
+
attributes: Dict[str, Any] = field(default_factory=dict)
|
|
38
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
39
|
+
|
|
40
|
+
def matches_constraint(self, constraint: Dict[str, Any]) -> bool:
|
|
41
|
+
"""Check if node matches given constraints."""
|
|
42
|
+
for key, value in constraint.items():
|
|
43
|
+
if key in self.attributes:
|
|
44
|
+
if self.attributes[key] != value:
|
|
45
|
+
return False
|
|
46
|
+
elif key in self.metadata:
|
|
47
|
+
if self.metadata[key] != value:
|
|
48
|
+
return False
|
|
49
|
+
else:
|
|
50
|
+
return False
|
|
51
|
+
return True
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class Edge:
|
|
56
|
+
"""An edge in the knowledge graph."""
|
|
57
|
+
source_id: str
|
|
58
|
+
target_id: str
|
|
59
|
+
edge_type: EdgeType
|
|
60
|
+
weight: float = 1.0
|
|
61
|
+
attributes: Dict[str, Any] = field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
def is_valid(self) -> bool:
|
|
64
|
+
"""Check if edge is valid."""
|
|
65
|
+
return self.weight > 0 and self.source_id and self.target_id
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Multidimensional Knowledge Graph implementation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Optional, Any, Set
|
|
8
|
+
from .graph_elements import Node, Edge, NodeType, EdgeType
|
|
9
|
+
from .subgraph import Subgraph, Dimension
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MultidimensionalKnowledgeGraph:
|
|
13
|
+
"""
|
|
14
|
+
A multidimensional knowledge graph that manages multiple dimensional subgraphs.
|
|
15
|
+
This implements the "Forest of Trees" approach where each dimension represents
|
|
16
|
+
a different view or constraint layer on the action space.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.dimensions: Dict[str, Dimension] = {}
|
|
21
|
+
self.subgraphs: Dict[str, Subgraph] = {}
|
|
22
|
+
self._global_nodes: Dict[str, Node] = {}
|
|
23
|
+
self._global_edges: List[Edge] = []
|
|
24
|
+
|
|
25
|
+
def add_dimension(self, dimension: Dimension) -> None:
|
|
26
|
+
"""Add a new dimension to the knowledge graph."""
|
|
27
|
+
self.dimensions[dimension.name] = dimension
|
|
28
|
+
self.subgraphs[dimension.name] = Subgraph(dimension)
|
|
29
|
+
|
|
30
|
+
def add_node_to_dimension(self, dimension_name: str, node: Node) -> None:
|
|
31
|
+
"""Add a node to a specific dimensional subgraph."""
|
|
32
|
+
if dimension_name in self.subgraphs:
|
|
33
|
+
self.subgraphs[dimension_name].add_node(node)
|
|
34
|
+
self._global_nodes[node.id] = node
|
|
35
|
+
|
|
36
|
+
def add_edge_to_dimension(self, dimension_name: str, edge: Edge) -> None:
|
|
37
|
+
"""Add an edge to a specific dimensional subgraph."""
|
|
38
|
+
if dimension_name in self.subgraphs:
|
|
39
|
+
self.subgraphs[dimension_name].add_edge(edge)
|
|
40
|
+
self._global_edges.append(edge)
|
|
41
|
+
|
|
42
|
+
def get_dimension(self, dimension_name: str) -> Optional[Dimension]:
|
|
43
|
+
"""Get a dimension by name."""
|
|
44
|
+
return self.dimensions.get(dimension_name)
|
|
45
|
+
|
|
46
|
+
def get_subgraph(self, dimension_name: str) -> Optional[Subgraph]:
|
|
47
|
+
"""Get a subgraph for a specific dimension."""
|
|
48
|
+
return self.subgraphs.get(dimension_name)
|
|
49
|
+
|
|
50
|
+
def get_all_dimensions(self) -> List[Dimension]:
|
|
51
|
+
"""Get all dimensions, sorted by priority."""
|
|
52
|
+
return sorted(self.dimensions.values(), key=lambda d: d.priority, reverse=True)
|
|
53
|
+
|
|
54
|
+
def find_relevant_dimensions(self, context: Dict[str, Any]) -> List[str]:
|
|
55
|
+
"""
|
|
56
|
+
Find dimensions that are relevant to the given context.
|
|
57
|
+
Returns dimension names sorted by priority.
|
|
58
|
+
"""
|
|
59
|
+
relevant_dimensions = []
|
|
60
|
+
|
|
61
|
+
for dim_name, dimension in self.dimensions.items():
|
|
62
|
+
# Check if context matches dimension metadata
|
|
63
|
+
if self._dimension_matches_context(dimension, context):
|
|
64
|
+
relevant_dimensions.append(dim_name)
|
|
65
|
+
|
|
66
|
+
# Sort by priority
|
|
67
|
+
relevant_dimensions.sort(
|
|
68
|
+
key=lambda d: self.dimensions[d].priority,
|
|
69
|
+
reverse=True
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return relevant_dimensions
|
|
73
|
+
|
|
74
|
+
def _dimension_matches_context(self, dimension: Dimension, context: Dict[str, Any]) -> bool:
|
|
75
|
+
"""Check if a dimension is relevant to the given context."""
|
|
76
|
+
if not context:
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
# Check if any context keys match dimension metadata
|
|
80
|
+
for key in context.keys():
|
|
81
|
+
if key in dimension.metadata:
|
|
82
|
+
return True
|
|
83
|
+
|
|
84
|
+
# If no specific metadata match, dimension is potentially relevant
|
|
85
|
+
return True
|
|
86
|
+
|
|
87
|
+
def get_pruned_action_space(
|
|
88
|
+
self,
|
|
89
|
+
dimension_name: str,
|
|
90
|
+
context: Dict[str, Any]
|
|
91
|
+
) -> List[Node]:
|
|
92
|
+
"""
|
|
93
|
+
Get the pruned action space for a specific dimension and context.
|
|
94
|
+
This is the core of the action space pruning mechanism.
|
|
95
|
+
"""
|
|
96
|
+
subgraph = self.subgraphs.get(dimension_name)
|
|
97
|
+
if not subgraph:
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
# Prune the subgraph based on context
|
|
101
|
+
pruned_subgraph = subgraph.prune_by_context(context)
|
|
102
|
+
|
|
103
|
+
# Return available actions
|
|
104
|
+
return pruned_subgraph.get_action_space()
|
|
105
|
+
|
|
106
|
+
def validate_action_across_dimensions(
|
|
107
|
+
self,
|
|
108
|
+
action_id: str,
|
|
109
|
+
dimension_names: List[str],
|
|
110
|
+
context: Optional[Dict[str, Any]] = None
|
|
111
|
+
) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
Validate an action across multiple dimensions.
|
|
114
|
+
The action must be valid in all specified dimensions.
|
|
115
|
+
"""
|
|
116
|
+
for dim_name in dimension_names:
|
|
117
|
+
subgraph = self.subgraphs.get(dim_name)
|
|
118
|
+
if not subgraph:
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
if not subgraph.validate_action(action_id, context):
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
def find_all_missing_dependencies(
|
|
127
|
+
self,
|
|
128
|
+
action_id: str,
|
|
129
|
+
dimension_names: List[str],
|
|
130
|
+
context: Dict[str, Any]
|
|
131
|
+
) -> Dict[str, List[str]]:
|
|
132
|
+
"""
|
|
133
|
+
Find all missing dependencies for an action across all dimensions.
|
|
134
|
+
Returns a dictionary mapping dimension names to lists of missing dependencies.
|
|
135
|
+
"""
|
|
136
|
+
all_missing = {}
|
|
137
|
+
|
|
138
|
+
for dim_name in dimension_names:
|
|
139
|
+
subgraph = self.subgraphs.get(dim_name)
|
|
140
|
+
if not subgraph:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
missing = subgraph.find_missing_dependencies(action_id, context)
|
|
144
|
+
if missing:
|
|
145
|
+
all_missing[dim_name] = missing
|
|
146
|
+
|
|
147
|
+
return all_missing
|
|
148
|
+
|
|
149
|
+
def get_action_constraints(
|
|
150
|
+
self,
|
|
151
|
+
action_id: str,
|
|
152
|
+
dimension_name: str
|
|
153
|
+
) -> List[Node]:
|
|
154
|
+
"""Get all constraints associated with an action in a dimension."""
|
|
155
|
+
subgraph = self.subgraphs.get(dimension_name)
|
|
156
|
+
if not subgraph:
|
|
157
|
+
return []
|
|
158
|
+
|
|
159
|
+
action_node = subgraph.get_node(action_id)
|
|
160
|
+
if not action_node:
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
constraints = []
|
|
164
|
+
for edge in subgraph._adjacency_list.get(action_id, []):
|
|
165
|
+
if edge.edge_type == EdgeType.REQUIRES:
|
|
166
|
+
target_node = subgraph.get_node(edge.target_id)
|
|
167
|
+
if target_node and target_node.node_type == NodeType.CONSTRAINT:
|
|
168
|
+
constraints.append(target_node)
|
|
169
|
+
|
|
170
|
+
return constraints
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Dimensional subgraph implementation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Dict, List, Set, Optional, Any
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from .graph_elements import Node, Edge, NodeType, EdgeType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Wildcard constant for matching any value in context
|
|
13
|
+
WILDCARD_VALUE = "*"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Dimension:
|
|
18
|
+
"""A dimension in the multidimensional knowledge graph."""
|
|
19
|
+
name: str
|
|
20
|
+
description: str
|
|
21
|
+
priority: int = 0
|
|
22
|
+
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Subgraph:
|
|
26
|
+
"""A subgraph representing a specific dimensional view of the knowledge graph."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, dimension: Dimension):
|
|
29
|
+
self.dimension = dimension
|
|
30
|
+
self.nodes: Dict[str, Node] = {}
|
|
31
|
+
self.edges: List[Edge] = []
|
|
32
|
+
self._adjacency_list: Dict[str, List[Edge]] = {}
|
|
33
|
+
|
|
34
|
+
def add_node(self, node: Node) -> None:
|
|
35
|
+
"""Add a node to the subgraph."""
|
|
36
|
+
self.nodes[node.id] = node
|
|
37
|
+
if node.id not in self._adjacency_list:
|
|
38
|
+
self._adjacency_list[node.id] = []
|
|
39
|
+
|
|
40
|
+
def add_edge(self, edge: Edge) -> None:
|
|
41
|
+
"""Add an edge to the subgraph."""
|
|
42
|
+
if edge.is_valid():
|
|
43
|
+
self.edges.append(edge)
|
|
44
|
+
if edge.source_id not in self._adjacency_list:
|
|
45
|
+
self._adjacency_list[edge.source_id] = []
|
|
46
|
+
self._adjacency_list[edge.source_id].append(edge)
|
|
47
|
+
|
|
48
|
+
def get_node(self, node_id: str) -> Optional[Node]:
|
|
49
|
+
"""Get a node by ID."""
|
|
50
|
+
return self.nodes.get(node_id)
|
|
51
|
+
|
|
52
|
+
def get_neighbors(self, node_id: str) -> List[Node]:
|
|
53
|
+
"""Get neighboring nodes."""
|
|
54
|
+
neighbors = []
|
|
55
|
+
for edge in self._adjacency_list.get(node_id, []):
|
|
56
|
+
if edge.target_id in self.nodes:
|
|
57
|
+
neighbors.append(self.nodes[edge.target_id])
|
|
58
|
+
return neighbors
|
|
59
|
+
|
|
60
|
+
def find_nodes_by_type(self, node_type: NodeType) -> List[Node]:
|
|
61
|
+
"""Find all nodes of a specific type."""
|
|
62
|
+
return [node for node in self.nodes.values() if node.node_type == node_type]
|
|
63
|
+
|
|
64
|
+
def find_nodes_by_constraint(self, constraint: Dict[str, Any]) -> List[Node]:
|
|
65
|
+
"""Find nodes matching specific constraints."""
|
|
66
|
+
return [node for node in self.nodes.values() if node.matches_constraint(constraint)]
|
|
67
|
+
|
|
68
|
+
def get_action_space(self) -> List[Node]:
|
|
69
|
+
"""Get all available actions in this subgraph."""
|
|
70
|
+
return self.find_nodes_by_type(NodeType.ACTION)
|
|
71
|
+
|
|
72
|
+
def validate_action(self, action_id: str, context: Optional[Dict[str, Any]] = None) -> bool:
|
|
73
|
+
"""Validate if an action can be executed based on graph constraints."""
|
|
74
|
+
if action_id not in self.nodes:
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
action_node = self.nodes[action_id]
|
|
78
|
+
if action_node.node_type != NodeType.ACTION:
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
# Check preconditions
|
|
82
|
+
for edge in self._adjacency_list.get(action_id, []):
|
|
83
|
+
if edge.edge_type == EdgeType.REQUIRES:
|
|
84
|
+
target_node = self.nodes.get(edge.target_id)
|
|
85
|
+
if not target_node:
|
|
86
|
+
return False
|
|
87
|
+
# If context provided, check if requirement is satisfied
|
|
88
|
+
if context:
|
|
89
|
+
if not self._is_requirement_satisfied(target_node, context):
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
return True
|
|
93
|
+
|
|
94
|
+
def _is_requirement_satisfied(self, requirement_node: Node, context: Dict[str, Any]) -> bool:
|
|
95
|
+
"""Check if a requirement node is satisfied by the context."""
|
|
96
|
+
# Check if the requirement exists in context
|
|
97
|
+
req_id = requirement_node.id
|
|
98
|
+
|
|
99
|
+
# Check if context explicitly marks this requirement as satisfied
|
|
100
|
+
if f"{req_id}_satisfied" in context:
|
|
101
|
+
return context[f"{req_id}_satisfied"]
|
|
102
|
+
|
|
103
|
+
# Check if requirement attributes are present in context
|
|
104
|
+
for key, expected_value in requirement_node.attributes.items():
|
|
105
|
+
if key in context:
|
|
106
|
+
if context[key] == expected_value:
|
|
107
|
+
return True
|
|
108
|
+
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
def find_missing_dependencies(self, action_id: str, context: Dict[str, Any]) -> List[str]:
|
|
112
|
+
"""
|
|
113
|
+
Find all missing dependencies for an action (deep traversal).
|
|
114
|
+
Returns a list of missing dependency IDs in order from root to leaf.
|
|
115
|
+
Handles circular dependencies gracefully.
|
|
116
|
+
"""
|
|
117
|
+
if action_id not in self.nodes:
|
|
118
|
+
return [f"Action '{action_id}' not found"]
|
|
119
|
+
|
|
120
|
+
visited = set()
|
|
121
|
+
in_progress = set() # Track nodes currently being processed for cycle detection
|
|
122
|
+
missing_deps = []
|
|
123
|
+
|
|
124
|
+
def traverse_dependencies(node_id: str, path: List[str]) -> None:
|
|
125
|
+
"""Recursively traverse dependencies to find missing ones."""
|
|
126
|
+
if node_id in visited:
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
# Cycle detection: if we're currently processing this node, we have a cycle
|
|
130
|
+
if node_id in in_progress:
|
|
131
|
+
return # Skip circular dependency
|
|
132
|
+
|
|
133
|
+
in_progress.add(node_id)
|
|
134
|
+
|
|
135
|
+
# Get all requirements for this node
|
|
136
|
+
for edge in self._adjacency_list.get(node_id, []):
|
|
137
|
+
if edge.edge_type == EdgeType.REQUIRES:
|
|
138
|
+
target_node = self.nodes.get(edge.target_id)
|
|
139
|
+
if target_node:
|
|
140
|
+
# Check if this requirement is satisfied
|
|
141
|
+
if not self._is_requirement_satisfied(target_node, context):
|
|
142
|
+
# This dependency is missing, check its dependencies first
|
|
143
|
+
traverse_dependencies(edge.target_id, path + [node_id])
|
|
144
|
+
# Add to missing list if not already there
|
|
145
|
+
if edge.target_id not in missing_deps:
|
|
146
|
+
missing_deps.append(edge.target_id)
|
|
147
|
+
|
|
148
|
+
in_progress.remove(node_id)
|
|
149
|
+
visited.add(node_id)
|
|
150
|
+
|
|
151
|
+
traverse_dependencies(action_id, [])
|
|
152
|
+
return missing_deps
|
|
153
|
+
|
|
154
|
+
def get_dependency_chain(self, action_id: str) -> List[List[str]]:
|
|
155
|
+
"""
|
|
156
|
+
Get all dependency chains for an action.
|
|
157
|
+
Returns a list of chains, where each chain is a list of node IDs.
|
|
158
|
+
Handles circular dependencies by detecting and skipping cycles.
|
|
159
|
+
"""
|
|
160
|
+
if action_id not in self.nodes:
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
chains = []
|
|
164
|
+
visited_in_chain = set() # Track nodes in current chain for cycle detection
|
|
165
|
+
|
|
166
|
+
def traverse_chain(node_id: str, current_chain: List[str]) -> None:
|
|
167
|
+
"""Recursively build dependency chains with cycle detection."""
|
|
168
|
+
# Cycle detection: if node is already in current chain, we have a cycle
|
|
169
|
+
if node_id in visited_in_chain:
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
visited_in_chain.add(node_id)
|
|
173
|
+
|
|
174
|
+
# Get all requirements for this node
|
|
175
|
+
requirements = []
|
|
176
|
+
for edge in self._adjacency_list.get(node_id, []):
|
|
177
|
+
if edge.edge_type == EdgeType.REQUIRES:
|
|
178
|
+
requirements.append(edge.target_id)
|
|
179
|
+
|
|
180
|
+
if not requirements:
|
|
181
|
+
# End of chain
|
|
182
|
+
chains.append(current_chain[:])
|
|
183
|
+
else:
|
|
184
|
+
# Continue traversing
|
|
185
|
+
for req_id in requirements:
|
|
186
|
+
if req_id in self.nodes:
|
|
187
|
+
traverse_chain(req_id, current_chain + [req_id])
|
|
188
|
+
|
|
189
|
+
visited_in_chain.remove(node_id)
|
|
190
|
+
|
|
191
|
+
traverse_chain(action_id, [action_id])
|
|
192
|
+
return chains
|
|
193
|
+
|
|
194
|
+
def prune_by_context(self, context: Dict[str, Any]) -> "Subgraph":
|
|
195
|
+
"""Create a pruned version of this subgraph based on context."""
|
|
196
|
+
pruned = Subgraph(self.dimension)
|
|
197
|
+
|
|
198
|
+
# Add nodes that match the context
|
|
199
|
+
for node in self.nodes.values():
|
|
200
|
+
if self._node_matches_context(node, context):
|
|
201
|
+
pruned.add_node(node)
|
|
202
|
+
|
|
203
|
+
# Add edges between matching nodes
|
|
204
|
+
for edge in self.edges:
|
|
205
|
+
if edge.source_id in pruned.nodes and edge.target_id in pruned.nodes:
|
|
206
|
+
pruned.add_edge(edge)
|
|
207
|
+
|
|
208
|
+
return pruned
|
|
209
|
+
|
|
210
|
+
def _node_matches_context(self, node: Node, context: Dict[str, Any]) -> bool:
|
|
211
|
+
"""Check if a node is relevant to the given context."""
|
|
212
|
+
if not context:
|
|
213
|
+
return True
|
|
214
|
+
|
|
215
|
+
# Check if any context attributes match node attributes
|
|
216
|
+
for key, value in context.items():
|
|
217
|
+
if key in node.attributes:
|
|
218
|
+
if node.attributes[key] == value or value == WILDCARD_VALUE:
|
|
219
|
+
return True
|
|
220
|
+
if key in node.metadata:
|
|
221
|
+
if node.metadata[key] == value or value == WILDCARD_VALUE:
|
|
222
|
+
return True
|
|
223
|
+
|
|
224
|
+
return False
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Layer 5: Listener Agent - Reference Implementation
|
|
5
|
+
|
|
6
|
+
This module provides the Listener Agent, a passive observer that monitors
|
|
7
|
+
graph states and only intervenes when configured thresholds are exceeded.
|
|
8
|
+
|
|
9
|
+
The Listener consolidates the full stack:
|
|
10
|
+
- agent-control-plane (base orchestration)
|
|
11
|
+
- scak (intelligence/knowledge)
|
|
12
|
+
- iatp (security/trust)
|
|
13
|
+
- caas (context awareness)
|
|
14
|
+
|
|
15
|
+
This is pure wiring - no logic that belongs in lower layers is redefined here.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from .listener import ListenerAgent, ListenerState, InterventionEvent, ListenerConfig
|
|
19
|
+
from .threshold_config import (
|
|
20
|
+
ThresholdConfig,
|
|
21
|
+
ThresholdType,
|
|
22
|
+
InterventionLevel,
|
|
23
|
+
ThresholdRule,
|
|
24
|
+
DEFAULT_THRESHOLDS,
|
|
25
|
+
)
|
|
26
|
+
from .state_observer import StateObserver, ObservationResult
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
# Core Listener
|
|
30
|
+
"ListenerAgent",
|
|
31
|
+
"ListenerState",
|
|
32
|
+
"InterventionEvent",
|
|
33
|
+
"ListenerConfig",
|
|
34
|
+
# Configuration
|
|
35
|
+
"ThresholdConfig",
|
|
36
|
+
"ThresholdType",
|
|
37
|
+
"InterventionLevel",
|
|
38
|
+
"ThresholdRule",
|
|
39
|
+
"DEFAULT_THRESHOLDS",
|
|
40
|
+
# Observer
|
|
41
|
+
"StateObserver",
|
|
42
|
+
"ObservationResult",
|
|
43
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Adapters for Layer 5 Integration
|
|
5
|
+
|
|
6
|
+
These adapters provide clean interfaces to the lower-layer dependencies:
|
|
7
|
+
- agent-control-plane: Base orchestration
|
|
8
|
+
- scak: Intelligence/Knowledge layer
|
|
9
|
+
- iatp: Security/Trust layer
|
|
10
|
+
- caas: Context-as-a-Service layer
|
|
11
|
+
|
|
12
|
+
The Listener Agent uses these adapters to wire together the full stack
|
|
13
|
+
without reimplementing any lower-layer logic.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .base_adapter import BaseLayerAdapter, AdapterProtocol
|
|
17
|
+
from .scak_adapter import IntelligenceAdapter
|
|
18
|
+
from .iatp_adapter import SecurityAdapter
|
|
19
|
+
from .caas_adapter import ContextAdapter
|
|
20
|
+
from .control_plane_adapter import ControlPlaneAdapter
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# Base
|
|
24
|
+
"BaseLayerAdapter",
|
|
25
|
+
"AdapterProtocol",
|
|
26
|
+
# Layer adapters
|
|
27
|
+
"IntelligenceAdapter",
|
|
28
|
+
"SecurityAdapter",
|
|
29
|
+
"ContextAdapter",
|
|
30
|
+
"ControlPlaneAdapter",
|
|
31
|
+
]
|