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,225 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Agent Manifest Schema
|
|
5
|
+
|
|
6
|
+
Defines the complete identity and capability manifest for Nexus registration.
|
|
7
|
+
Extends the IATP manifest (RFC-001) with Nexus-specific fields.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from typing import Literal, Optional
|
|
12
|
+
from pydantic import BaseModel, Field, field_validator
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AgentIdentity(BaseModel):
|
|
17
|
+
"""Decentralized identity for an agent."""
|
|
18
|
+
|
|
19
|
+
did: str = Field(
|
|
20
|
+
...,
|
|
21
|
+
description="Decentralized Identifier (did:nexus:...)",
|
|
22
|
+
examples=["did:nexus:carbon-auditor-v1.2.0"]
|
|
23
|
+
)
|
|
24
|
+
verification_key: str = Field(
|
|
25
|
+
...,
|
|
26
|
+
description="Ed25519 public key (base64 encoded)",
|
|
27
|
+
examples=["ed25519:abc123..."]
|
|
28
|
+
)
|
|
29
|
+
owner_id: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description="Developer/Organization ID"
|
|
32
|
+
)
|
|
33
|
+
display_name: Optional[str] = Field(
|
|
34
|
+
None,
|
|
35
|
+
description="Human-readable agent name"
|
|
36
|
+
)
|
|
37
|
+
contact: Optional[str] = Field(
|
|
38
|
+
None,
|
|
39
|
+
description="Contact email for security issues"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@field_validator("did")
|
|
43
|
+
@classmethod
|
|
44
|
+
def validate_did(cls, v: str) -> str:
|
|
45
|
+
"""Validate DID format."""
|
|
46
|
+
if not v.startswith("did:nexus:"):
|
|
47
|
+
raise ValueError("DID must start with 'did:nexus:'")
|
|
48
|
+
return v
|
|
49
|
+
|
|
50
|
+
@field_validator("verification_key")
|
|
51
|
+
@classmethod
|
|
52
|
+
def validate_key(cls, v: str) -> str:
|
|
53
|
+
"""Validate verification key format."""
|
|
54
|
+
if not v.startswith("ed25519:"):
|
|
55
|
+
raise ValueError("Verification key must be Ed25519 format")
|
|
56
|
+
return v
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class AgentCapabilities(BaseModel):
|
|
60
|
+
"""What this agent can do."""
|
|
61
|
+
|
|
62
|
+
domains: list[str] = Field(
|
|
63
|
+
default_factory=list,
|
|
64
|
+
description="Capability domains (e.g., 'data-analysis', 'code-generation')"
|
|
65
|
+
)
|
|
66
|
+
tools: list[str] = Field(
|
|
67
|
+
default_factory=list,
|
|
68
|
+
description="Available tool names"
|
|
69
|
+
)
|
|
70
|
+
max_concurrency: int = Field(
|
|
71
|
+
default=10,
|
|
72
|
+
ge=1,
|
|
73
|
+
le=1000,
|
|
74
|
+
description="Maximum concurrent requests"
|
|
75
|
+
)
|
|
76
|
+
sla_latency_ms: int = Field(
|
|
77
|
+
default=5000,
|
|
78
|
+
ge=100,
|
|
79
|
+
le=300000,
|
|
80
|
+
description="SLA latency in milliseconds"
|
|
81
|
+
)
|
|
82
|
+
idempotency: bool = Field(
|
|
83
|
+
default=False,
|
|
84
|
+
description="Whether operations are idempotent"
|
|
85
|
+
)
|
|
86
|
+
reversibility: Literal["full", "partial", "none"] = Field(
|
|
87
|
+
default="partial",
|
|
88
|
+
description="Level of operation reversibility"
|
|
89
|
+
)
|
|
90
|
+
undo_window_seconds: Optional[int] = Field(
|
|
91
|
+
default=3600,
|
|
92
|
+
description="Time window for undo operations (if reversible)"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AgentPrivacy(BaseModel):
|
|
97
|
+
"""Privacy and data handling policies."""
|
|
98
|
+
|
|
99
|
+
retention_policy: Literal["ephemeral", "session", "permanent"] = Field(
|
|
100
|
+
default="ephemeral",
|
|
101
|
+
description="How long data is retained"
|
|
102
|
+
)
|
|
103
|
+
pii_handling: Literal["reject", "anonymize", "accept"] = Field(
|
|
104
|
+
default="reject",
|
|
105
|
+
description="How PII is handled"
|
|
106
|
+
)
|
|
107
|
+
human_in_loop: bool = Field(
|
|
108
|
+
default=False,
|
|
109
|
+
description="Whether human review is part of processing"
|
|
110
|
+
)
|
|
111
|
+
training_consent: bool = Field(
|
|
112
|
+
default=False,
|
|
113
|
+
description="Whether data may be used for training"
|
|
114
|
+
)
|
|
115
|
+
data_residency: Optional[str] = Field(
|
|
116
|
+
default=None,
|
|
117
|
+
description="Required data residency region (e.g., 'us', 'eu')"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class MuteRules(BaseModel):
|
|
122
|
+
"""Agent OS Mute Agent rules attached to this agent."""
|
|
123
|
+
|
|
124
|
+
rule_hashes: list[str] = Field(
|
|
125
|
+
default_factory=list,
|
|
126
|
+
description="SHA-256 hashes of attached mute rules"
|
|
127
|
+
)
|
|
128
|
+
last_validated: Optional[datetime] = Field(
|
|
129
|
+
default=None,
|
|
130
|
+
description="When rules were last validated by Control Plane"
|
|
131
|
+
)
|
|
132
|
+
control_plane_signature: Optional[str] = Field(
|
|
133
|
+
default=None,
|
|
134
|
+
description="Control Plane signature of rule validation"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class AgentManifest(BaseModel):
|
|
139
|
+
"""
|
|
140
|
+
Complete manifest for Nexus registration.
|
|
141
|
+
|
|
142
|
+
This extends the IATP manifest (RFC-001) with Nexus-specific fields
|
|
143
|
+
for the Trust Exchange.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
schema_version: str = Field(
|
|
147
|
+
default="1.0",
|
|
148
|
+
description="Schema version for forward compatibility"
|
|
149
|
+
)
|
|
150
|
+
identity: AgentIdentity
|
|
151
|
+
capabilities: AgentCapabilities = Field(default_factory=AgentCapabilities)
|
|
152
|
+
privacy: AgentPrivacy = Field(default_factory=AgentPrivacy)
|
|
153
|
+
mute_rules: MuteRules = Field(default_factory=MuteRules)
|
|
154
|
+
|
|
155
|
+
# Nexus-specific fields
|
|
156
|
+
verification_level: Literal["verified_partner", "verified", "registered", "unknown"] = Field(
|
|
157
|
+
default="registered",
|
|
158
|
+
description="Verification tier on Nexus"
|
|
159
|
+
)
|
|
160
|
+
registered_at: Optional[datetime] = Field(
|
|
161
|
+
default=None,
|
|
162
|
+
description="When agent was registered on Nexus"
|
|
163
|
+
)
|
|
164
|
+
last_seen: Optional[datetime] = Field(
|
|
165
|
+
default=None,
|
|
166
|
+
description="Last activity timestamp"
|
|
167
|
+
)
|
|
168
|
+
trust_score: int = Field(
|
|
169
|
+
default=400,
|
|
170
|
+
ge=0,
|
|
171
|
+
le=1000,
|
|
172
|
+
description="Current trust score (0-1000)"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Attestation
|
|
176
|
+
codebase_hash: Optional[str] = Field(
|
|
177
|
+
default=None,
|
|
178
|
+
description="SHA-256 hash of agent codebase"
|
|
179
|
+
)
|
|
180
|
+
config_hash: Optional[str] = Field(
|
|
181
|
+
default=None,
|
|
182
|
+
description="SHA-256 hash of agent configuration"
|
|
183
|
+
)
|
|
184
|
+
attestation_signature: Optional[str] = Field(
|
|
185
|
+
default=None,
|
|
186
|
+
description="Control Plane signature of attestation"
|
|
187
|
+
)
|
|
188
|
+
attestation_expires: Optional[datetime] = Field(
|
|
189
|
+
default=None,
|
|
190
|
+
description="When attestation expires"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def is_attestation_valid(self) -> bool:
|
|
194
|
+
"""Check if attestation is present and not expired."""
|
|
195
|
+
if not self.attestation_signature or not self.attestation_expires:
|
|
196
|
+
return False
|
|
197
|
+
return datetime.now(timezone.utc) < self.attestation_expires
|
|
198
|
+
|
|
199
|
+
def to_iatp_manifest(self) -> dict:
|
|
200
|
+
"""Convert to IATP-compatible manifest format."""
|
|
201
|
+
return {
|
|
202
|
+
"$schema": "https://agent-os.dev/iatp/v1/manifest.schema.json",
|
|
203
|
+
"identity": {
|
|
204
|
+
"agent_id": self.identity.did.replace("did:nexus:", ""),
|
|
205
|
+
"verification_key": self.identity.verification_key,
|
|
206
|
+
"owner": self.identity.owner_id,
|
|
207
|
+
"contact": self.identity.contact,
|
|
208
|
+
},
|
|
209
|
+
"trust_level": self.verification_level,
|
|
210
|
+
"capabilities": {
|
|
211
|
+
"idempotency": self.capabilities.idempotency,
|
|
212
|
+
"max_concurrency": self.capabilities.max_concurrency,
|
|
213
|
+
"sla_latency_ms": self.capabilities.sla_latency_ms,
|
|
214
|
+
},
|
|
215
|
+
"reversibility": {
|
|
216
|
+
"level": self.capabilities.reversibility,
|
|
217
|
+
"undo_window_seconds": self.capabilities.undo_window_seconds,
|
|
218
|
+
},
|
|
219
|
+
"privacy": {
|
|
220
|
+
"retention_policy": self.privacy.retention_policy,
|
|
221
|
+
"human_in_loop": self.privacy.human_in_loop,
|
|
222
|
+
"training_consent": self.privacy.training_consent,
|
|
223
|
+
},
|
|
224
|
+
"protocol_version": "1.0",
|
|
225
|
+
}
|
nexus/schemas/receipt.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Job Receipt Schemas
|
|
5
|
+
|
|
6
|
+
Defines receipts for job completion and outcome verification.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
from typing import Literal, Optional, Any
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JobReceipt(BaseModel):
|
|
17
|
+
"""Base receipt for a job/task between agents."""
|
|
18
|
+
|
|
19
|
+
receipt_id: str = Field(
|
|
20
|
+
...,
|
|
21
|
+
description="Unique receipt identifier"
|
|
22
|
+
)
|
|
23
|
+
task_id: str = Field(
|
|
24
|
+
...,
|
|
25
|
+
description="ID of the task being receipted"
|
|
26
|
+
)
|
|
27
|
+
requester_did: str = Field(
|
|
28
|
+
...,
|
|
29
|
+
description="DID of the requesting agent"
|
|
30
|
+
)
|
|
31
|
+
provider_did: str = Field(
|
|
32
|
+
...,
|
|
33
|
+
description="DID of the providing agent"
|
|
34
|
+
)
|
|
35
|
+
task_hash: str = Field(
|
|
36
|
+
...,
|
|
37
|
+
description="SHA-256 hash of the task specification"
|
|
38
|
+
)
|
|
39
|
+
created_at: datetime = Field(
|
|
40
|
+
default_factory=datetime.utcnow,
|
|
41
|
+
description="When the receipt was created"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def compute_hash(self) -> str:
|
|
45
|
+
"""Compute deterministic hash of receipt."""
|
|
46
|
+
data = {
|
|
47
|
+
"receipt_id": self.receipt_id,
|
|
48
|
+
"task_id": self.task_id,
|
|
49
|
+
"requester_did": self.requester_did,
|
|
50
|
+
"provider_did": self.provider_did,
|
|
51
|
+
"task_hash": self.task_hash,
|
|
52
|
+
"created_at": self.created_at.isoformat(),
|
|
53
|
+
}
|
|
54
|
+
canonical = json.dumps(data, sort_keys=True)
|
|
55
|
+
return hashlib.sha256(canonical.encode()).hexdigest()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class JobCompletionReceipt(JobReceipt):
|
|
59
|
+
"""Receipt issued when a job is completed."""
|
|
60
|
+
|
|
61
|
+
outcome: Literal["success", "failure", "partial", "timeout"] = Field(
|
|
62
|
+
...,
|
|
63
|
+
description="Outcome of the job"
|
|
64
|
+
)
|
|
65
|
+
completed_at: datetime = Field(
|
|
66
|
+
default_factory=datetime.utcnow,
|
|
67
|
+
description="When the job completed"
|
|
68
|
+
)
|
|
69
|
+
duration_ms: int = Field(
|
|
70
|
+
...,
|
|
71
|
+
ge=0,
|
|
72
|
+
description="Duration of job execution in milliseconds"
|
|
73
|
+
)
|
|
74
|
+
output_hash: Optional[str] = Field(
|
|
75
|
+
default=None,
|
|
76
|
+
description="SHA-256 hash of the output (if any)"
|
|
77
|
+
)
|
|
78
|
+
error_code: Optional[str] = Field(
|
|
79
|
+
default=None,
|
|
80
|
+
description="Error code if outcome is failure"
|
|
81
|
+
)
|
|
82
|
+
error_message: Optional[str] = Field(
|
|
83
|
+
default=None,
|
|
84
|
+
description="Error message if outcome is failure"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# SCAK validation
|
|
88
|
+
scak_validated: bool = Field(
|
|
89
|
+
default=False,
|
|
90
|
+
description="Whether output was validated by SCAK"
|
|
91
|
+
)
|
|
92
|
+
scak_drift_score: Optional[float] = Field(
|
|
93
|
+
default=None,
|
|
94
|
+
ge=0.0,
|
|
95
|
+
le=1.0,
|
|
96
|
+
description="SCAK drift score (0=no drift, 1=complete drift)"
|
|
97
|
+
)
|
|
98
|
+
scak_threshold: Optional[float] = Field(
|
|
99
|
+
default=None,
|
|
100
|
+
description="Drift threshold used for validation"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class SignedReceipt(BaseModel):
|
|
105
|
+
"""A receipt with cryptographic signatures from both parties."""
|
|
106
|
+
|
|
107
|
+
receipt: JobCompletionReceipt
|
|
108
|
+
receipt_hash: str = Field(
|
|
109
|
+
...,
|
|
110
|
+
description="SHA-256 hash of the receipt"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Signatures
|
|
114
|
+
requester_signature: Optional[str] = Field(
|
|
115
|
+
default=None,
|
|
116
|
+
description="Ed25519 signature from requester"
|
|
117
|
+
)
|
|
118
|
+
requester_signed_at: Optional[datetime] = Field(
|
|
119
|
+
default=None,
|
|
120
|
+
description="When requester signed"
|
|
121
|
+
)
|
|
122
|
+
provider_signature: Optional[str] = Field(
|
|
123
|
+
default=None,
|
|
124
|
+
description="Ed25519 signature from provider"
|
|
125
|
+
)
|
|
126
|
+
provider_signed_at: Optional[datetime] = Field(
|
|
127
|
+
default=None,
|
|
128
|
+
description="When provider signed"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Nexus attestation
|
|
132
|
+
nexus_witnessed: bool = Field(
|
|
133
|
+
default=False,
|
|
134
|
+
description="Whether Nexus has witnessed this receipt"
|
|
135
|
+
)
|
|
136
|
+
nexus_signature: Optional[str] = Field(
|
|
137
|
+
default=None,
|
|
138
|
+
description="Nexus signature witnessing the receipt"
|
|
139
|
+
)
|
|
140
|
+
nexus_witnessed_at: Optional[datetime] = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="When Nexus witnessed"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
def is_fully_signed(self) -> bool:
|
|
146
|
+
"""Check if both parties have signed."""
|
|
147
|
+
return bool(self.requester_signature and self.provider_signature)
|
|
148
|
+
|
|
149
|
+
def is_nexus_witnessed(self) -> bool:
|
|
150
|
+
"""Check if Nexus has witnessed this receipt."""
|
|
151
|
+
return self.nexus_witnessed and bool(self.nexus_signature)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class DisputeReceipt(BaseModel):
|
|
155
|
+
"""Receipt for a disputed job outcome."""
|
|
156
|
+
|
|
157
|
+
dispute_id: str = Field(
|
|
158
|
+
...,
|
|
159
|
+
description="Unique dispute identifier"
|
|
160
|
+
)
|
|
161
|
+
original_receipt: Optional[SignedReceipt] = None
|
|
162
|
+
|
|
163
|
+
# Dispute details
|
|
164
|
+
disputing_party: Literal["requester", "provider"] = Field(
|
|
165
|
+
...,
|
|
166
|
+
description="Which party raised the dispute"
|
|
167
|
+
)
|
|
168
|
+
dispute_reason: str = Field(
|
|
169
|
+
...,
|
|
170
|
+
description="Reason for the dispute"
|
|
171
|
+
)
|
|
172
|
+
claimed_outcome: Literal["success", "failure", "partial"] = Field(
|
|
173
|
+
...,
|
|
174
|
+
description="Outcome claimed by disputing party"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Evidence
|
|
178
|
+
requester_logs_hash: Optional[str] = Field(
|
|
179
|
+
default=None,
|
|
180
|
+
description="Hash of requester's flight recorder logs"
|
|
181
|
+
)
|
|
182
|
+
provider_logs_hash: Optional[str] = Field(
|
|
183
|
+
default=None,
|
|
184
|
+
description="Hash of provider's flight recorder logs"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Resolution
|
|
188
|
+
resolved: bool = Field(
|
|
189
|
+
default=False,
|
|
190
|
+
description="Whether dispute has been resolved"
|
|
191
|
+
)
|
|
192
|
+
resolution_outcome: Optional[Literal["requester_wins", "provider_wins", "split"]] = Field(
|
|
193
|
+
default=None,
|
|
194
|
+
description="Resolution outcome"
|
|
195
|
+
)
|
|
196
|
+
arbiter_decision: Optional[str] = Field(
|
|
197
|
+
default=None,
|
|
198
|
+
description="Arbiter's decision explanation"
|
|
199
|
+
)
|
|
200
|
+
resolved_at: Optional[datetime] = Field(
|
|
201
|
+
default=None,
|
|
202
|
+
description="When dispute was resolved"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
created_at: datetime = Field(
|
|
206
|
+
default_factory=datetime.utcnow,
|
|
207
|
+
description="When dispute was raised"
|
|
208
|
+
)
|
nexus/tests/__init__.py
ADDED
|
File without changes
|
nexus/tests/conftest.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""Shared fixtures for Nexus tests."""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from datetime import datetime, timedelta, timezone
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
# Add parent of nexus package to path so 'nexus' is importable
|
|
12
|
+
_nexus_parent = os.path.join(os.path.dirname(__file__), "..", "..")
|
|
13
|
+
if _nexus_parent not in sys.path:
|
|
14
|
+
sys.path.insert(0, _nexus_parent)
|
|
15
|
+
|
|
16
|
+
from nexus.reputation import ReputationEngine, ReputationHistory, TrustScore, TrustTier
|
|
17
|
+
from nexus.escrow import EscrowManager
|
|
18
|
+
from nexus.schemas.manifest import (
|
|
19
|
+
AgentIdentity,
|
|
20
|
+
AgentCapabilities,
|
|
21
|
+
AgentPrivacy,
|
|
22
|
+
MuteRules,
|
|
23
|
+
AgentManifest,
|
|
24
|
+
)
|
|
25
|
+
from nexus.schemas.escrow import EscrowRequest, EscrowReceipt, EscrowStatus
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def reputation_engine():
|
|
30
|
+
"""Create a ReputationEngine with default threshold."""
|
|
31
|
+
return ReputationEngine(trust_threshold=500)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture
|
|
35
|
+
def escrow_manager(reputation_engine):
|
|
36
|
+
"""Create an EscrowManager with a reputation engine."""
|
|
37
|
+
return EscrowManager(reputation_engine=reputation_engine)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.fixture
|
|
41
|
+
def sample_identity():
|
|
42
|
+
"""Create a sample AgentIdentity."""
|
|
43
|
+
return AgentIdentity(
|
|
44
|
+
did="did:nexus:test-agent-v1",
|
|
45
|
+
verification_key="ed25519:testkey123abc",
|
|
46
|
+
owner_id="org-test-corp",
|
|
47
|
+
display_name="Test Agent",
|
|
48
|
+
contact="test@example.com",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture
|
|
53
|
+
def sample_capabilities():
|
|
54
|
+
"""Create sample AgentCapabilities."""
|
|
55
|
+
return AgentCapabilities(
|
|
56
|
+
domains=["data-analysis", "code-generation"],
|
|
57
|
+
tools=["python", "sql"],
|
|
58
|
+
max_concurrency=10,
|
|
59
|
+
sla_latency_ms=5000,
|
|
60
|
+
idempotency=True,
|
|
61
|
+
reversibility="full",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@pytest.fixture
|
|
66
|
+
def sample_privacy():
|
|
67
|
+
"""Create sample AgentPrivacy."""
|
|
68
|
+
return AgentPrivacy(
|
|
69
|
+
retention_policy="ephemeral",
|
|
70
|
+
pii_handling="reject",
|
|
71
|
+
human_in_loop=False,
|
|
72
|
+
training_consent=False,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.fixture
|
|
77
|
+
def sample_manifest(sample_identity, sample_capabilities, sample_privacy):
|
|
78
|
+
"""Create a sample AgentManifest."""
|
|
79
|
+
return AgentManifest(
|
|
80
|
+
identity=sample_identity,
|
|
81
|
+
capabilities=sample_capabilities,
|
|
82
|
+
privacy=sample_privacy,
|
|
83
|
+
verification_level="registered",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@pytest.fixture
|
|
88
|
+
def sample_history():
|
|
89
|
+
"""Create a sample ReputationHistory."""
|
|
90
|
+
return ReputationHistory(
|
|
91
|
+
agent_did="did:nexus:test-agent-v1",
|
|
92
|
+
successful_tasks=10,
|
|
93
|
+
failed_tasks=1,
|
|
94
|
+
total_tasks=11,
|
|
95
|
+
disputes_won=2,
|
|
96
|
+
disputes_lost=0,
|
|
97
|
+
uptime_days=30,
|
|
98
|
+
last_activity=datetime.now(timezone.utc),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@pytest.fixture
|
|
103
|
+
def sample_escrow_request():
|
|
104
|
+
"""Create a sample EscrowRequest."""
|
|
105
|
+
return EscrowRequest(
|
|
106
|
+
requester_did="did:nexus:requester-agent",
|
|
107
|
+
provider_did="did:nexus:provider-agent",
|
|
108
|
+
task_hash="abc123def456",
|
|
109
|
+
credits=100,
|
|
110
|
+
timeout_seconds=3600,
|
|
111
|
+
require_scak_validation=False,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def make_manifest(
|
|
116
|
+
did: str = "did:nexus:test-agent-v1",
|
|
117
|
+
owner_id: str = "org-test-corp",
|
|
118
|
+
verification_level: str = "registered",
|
|
119
|
+
domains: list[str] | None = None,
|
|
120
|
+
retention_policy: str = "ephemeral",
|
|
121
|
+
pii_handling: str = "reject",
|
|
122
|
+
training_consent: bool = False,
|
|
123
|
+
idempotency: bool = False,
|
|
124
|
+
reversibility: str = "partial",
|
|
125
|
+
trust_score: int = 400,
|
|
126
|
+
) -> AgentManifest:
|
|
127
|
+
"""Helper to create manifests with custom parameters."""
|
|
128
|
+
return AgentManifest(
|
|
129
|
+
identity=AgentIdentity(
|
|
130
|
+
did=did,
|
|
131
|
+
verification_key="ed25519:testkey123abc",
|
|
132
|
+
owner_id=owner_id,
|
|
133
|
+
),
|
|
134
|
+
capabilities=AgentCapabilities(
|
|
135
|
+
domains=domains or ["data-analysis"],
|
|
136
|
+
idempotency=idempotency,
|
|
137
|
+
reversibility=reversibility,
|
|
138
|
+
),
|
|
139
|
+
privacy=AgentPrivacy(
|
|
140
|
+
retention_policy=retention_policy,
|
|
141
|
+
pii_handling=pii_handling,
|
|
142
|
+
training_consent=training_consent,
|
|
143
|
+
),
|
|
144
|
+
verification_level=verification_level,
|
|
145
|
+
trust_score=trust_score,
|
|
146
|
+
)
|