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,364 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
Google Gemini Integration
|
|
5
|
+
|
|
6
|
+
Wraps Google's Generative AI SDK with Agent OS governance.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from agent_os.integrations.gemini_adapter import GeminiKernel
|
|
10
|
+
import google.generativeai as genai
|
|
11
|
+
|
|
12
|
+
kernel = GeminiKernel(policy=GovernancePolicy(
|
|
13
|
+
max_tokens=4096,
|
|
14
|
+
allowed_tools=["web_search"],
|
|
15
|
+
blocked_patterns=["password"],
|
|
16
|
+
))
|
|
17
|
+
|
|
18
|
+
model = genai.GenerativeModel("gemini-pro")
|
|
19
|
+
governed = kernel.wrap(model)
|
|
20
|
+
response = governed.generate_content("Hello")
|
|
21
|
+
|
|
22
|
+
Features:
|
|
23
|
+
- Pre-execution policy checks on prompts
|
|
24
|
+
- Tool call interception and validation
|
|
25
|
+
- Token limit enforcement
|
|
26
|
+
- Content filtering via blocked patterns
|
|
27
|
+
- Audit logging for all calls
|
|
28
|
+
- Health check endpoint
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import logging
|
|
34
|
+
import time
|
|
35
|
+
from dataclasses import dataclass, field
|
|
36
|
+
from datetime import datetime
|
|
37
|
+
from typing import Any
|
|
38
|
+
|
|
39
|
+
from .base import BaseIntegration, ExecutionContext, GovernancePolicy
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger("agent_os.gemini")
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
import warnings
|
|
45
|
+
with warnings.catch_warnings():
|
|
46
|
+
warnings.simplefilter("ignore", FutureWarning)
|
|
47
|
+
import google.generativeai as _genai_mod # noqa: F401
|
|
48
|
+
|
|
49
|
+
_HAS_GENAI = True
|
|
50
|
+
except ImportError:
|
|
51
|
+
_HAS_GENAI = False
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _check_genai_available() -> None:
|
|
55
|
+
"""Raise a helpful error when the ``google-generativeai`` package is missing."""
|
|
56
|
+
if not _HAS_GENAI:
|
|
57
|
+
raise ImportError(
|
|
58
|
+
"The 'google-generativeai' package is required for GeminiKernel. "
|
|
59
|
+
"Install it with: pip install google-generativeai"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass
|
|
64
|
+
class GeminiContext(ExecutionContext):
|
|
65
|
+
"""Execution context for Google Gemini interactions.
|
|
66
|
+
|
|
67
|
+
Attributes:
|
|
68
|
+
model_name: The Gemini model used for this session.
|
|
69
|
+
generation_ids: Recorded generation response identifiers.
|
|
70
|
+
function_calls: History of function calls returned by Gemini.
|
|
71
|
+
prompt_tokens: Cumulative prompt tokens consumed.
|
|
72
|
+
completion_tokens: Cumulative candidate tokens consumed.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
model_name: str = ""
|
|
76
|
+
generation_ids: list[str] = field(default_factory=list)
|
|
77
|
+
function_calls: list[dict[str, Any]] = field(default_factory=list)
|
|
78
|
+
prompt_tokens: int = 0
|
|
79
|
+
completion_tokens: int = 0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class PolicyViolationError(Exception):
|
|
83
|
+
"""Raised when a Gemini request violates governance policy."""
|
|
84
|
+
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class GeminiKernel(BaseIntegration):
|
|
89
|
+
"""Google Gemini adapter for Agent OS.
|
|
90
|
+
|
|
91
|
+
Provides governance for ``GenerativeModel.generate_content()`` calls
|
|
92
|
+
including policy enforcement, tool-call validation, token tracking,
|
|
93
|
+
and audit logging.
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
>>> kernel = GeminiKernel(policy=GovernancePolicy(max_tokens=8192))
|
|
97
|
+
>>> governed = kernel.wrap(genai.GenerativeModel("gemini-pro"))
|
|
98
|
+
>>> response = governed.generate_content("Explain quantum computing")
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(
|
|
102
|
+
self,
|
|
103
|
+
policy: GovernancePolicy | None = None,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Initialise the Gemini governance kernel.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
policy: Governance policy to enforce. Uses default when ``None``.
|
|
109
|
+
"""
|
|
110
|
+
super().__init__(policy)
|
|
111
|
+
self._wrapped_models: dict[int, Any] = {}
|
|
112
|
+
self._start_time = time.monotonic()
|
|
113
|
+
self._last_error: str | None = None
|
|
114
|
+
|
|
115
|
+
def wrap(self, model: Any) -> GovernedGeminiModel:
|
|
116
|
+
"""Wrap a Gemini GenerativeModel with governance.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
model: A ``google.generativeai.GenerativeModel`` instance.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
A ``GovernedGeminiModel`` that enforces policy on all
|
|
123
|
+
``generate_content()`` calls.
|
|
124
|
+
"""
|
|
125
|
+
_check_genai_available()
|
|
126
|
+
model_id = id(model)
|
|
127
|
+
model_name = getattr(model, "model_name", "unknown")
|
|
128
|
+
ctx = GeminiContext(
|
|
129
|
+
agent_id=f"gemini-{model_id}",
|
|
130
|
+
session_id=f"gem-{int(time.time())}",
|
|
131
|
+
policy=self.policy,
|
|
132
|
+
model_name=model_name,
|
|
133
|
+
)
|
|
134
|
+
self.contexts[ctx.agent_id] = ctx
|
|
135
|
+
self._wrapped_models[model_id] = model
|
|
136
|
+
|
|
137
|
+
return GovernedGeminiModel(
|
|
138
|
+
model=model,
|
|
139
|
+
kernel=self,
|
|
140
|
+
ctx=ctx,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def unwrap(self, governed_agent: Any) -> Any:
|
|
144
|
+
"""Retrieve the original unwrapped Gemini model.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
governed_agent: A ``GovernedGeminiModel`` or any object.
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
The original GenerativeModel if applicable, otherwise
|
|
151
|
+
*governed_agent* as-is.
|
|
152
|
+
"""
|
|
153
|
+
if isinstance(governed_agent, GovernedGeminiModel):
|
|
154
|
+
return governed_agent._model
|
|
155
|
+
return governed_agent
|
|
156
|
+
|
|
157
|
+
def health_check(self) -> dict[str, Any]:
|
|
158
|
+
"""Return adapter health status.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
A dict with ``status``, ``backend``, ``last_error``, and
|
|
162
|
+
``uptime_seconds`` keys.
|
|
163
|
+
"""
|
|
164
|
+
uptime = time.monotonic() - self._start_time
|
|
165
|
+
has_models = bool(self._wrapped_models)
|
|
166
|
+
status = "degraded" if self._last_error else "healthy"
|
|
167
|
+
return {
|
|
168
|
+
"status": status,
|
|
169
|
+
"backend": "gemini",
|
|
170
|
+
"backend_connected": has_models,
|
|
171
|
+
"last_error": self._last_error,
|
|
172
|
+
"uptime_seconds": round(uptime, 2),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class GovernedGeminiModel:
|
|
177
|
+
"""Gemini GenerativeModel wrapped with Agent OS governance.
|
|
178
|
+
|
|
179
|
+
Intercepts ``generate_content()`` for policy enforcement while
|
|
180
|
+
proxying all other attributes to the underlying model.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
def __init__(
|
|
184
|
+
self,
|
|
185
|
+
model: Any,
|
|
186
|
+
kernel: GeminiKernel,
|
|
187
|
+
ctx: GeminiContext,
|
|
188
|
+
) -> None:
|
|
189
|
+
self._model = model
|
|
190
|
+
self._kernel = kernel
|
|
191
|
+
self._ctx = ctx
|
|
192
|
+
|
|
193
|
+
def generate_content(self, contents: Any, **kwargs: Any) -> Any:
|
|
194
|
+
"""Generate content with governance enforcement.
|
|
195
|
+
|
|
196
|
+
Validates prompt content against blocked patterns, enforces
|
|
197
|
+
tool-call allowlists, checks token limits, and records an
|
|
198
|
+
audit trail.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
contents: The prompt content (string, list, or Content object).
|
|
202
|
+
**kwargs: Forwarded to ``model.generate_content()``.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
The Gemini generation response.
|
|
206
|
+
|
|
207
|
+
Raises:
|
|
208
|
+
PolicyViolationError: If a governance policy is violated.
|
|
209
|
+
"""
|
|
210
|
+
# --- pre-execution checks ---
|
|
211
|
+
content_str = str(contents)
|
|
212
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, content_str)
|
|
213
|
+
if not allowed:
|
|
214
|
+
raise PolicyViolationError(f"Content blocked: {reason}")
|
|
215
|
+
|
|
216
|
+
# Validate tools against policy
|
|
217
|
+
tools = kwargs.get("tools")
|
|
218
|
+
if tools:
|
|
219
|
+
self._validate_tools(tools)
|
|
220
|
+
|
|
221
|
+
# Audit log
|
|
222
|
+
logger.info(
|
|
223
|
+
"Gemini generate_content | agent=%s model=%s",
|
|
224
|
+
self._ctx.agent_id,
|
|
225
|
+
self._ctx.model_name,
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# --- execute ---
|
|
229
|
+
try:
|
|
230
|
+
response = self._kernel._wrapped_models.get(
|
|
231
|
+
id(self._model), self._model
|
|
232
|
+
).generate_content(contents, **kwargs)
|
|
233
|
+
except Exception as exc:
|
|
234
|
+
self._kernel._last_error = str(exc)
|
|
235
|
+
raise
|
|
236
|
+
|
|
237
|
+
# --- post-execution checks ---
|
|
238
|
+
gen_id = f"gen-{int(time.time())}-{self._ctx.call_count}"
|
|
239
|
+
self._ctx.generation_ids.append(gen_id)
|
|
240
|
+
|
|
241
|
+
# Track tokens from usage_metadata
|
|
242
|
+
usage = getattr(response, "usage_metadata", None)
|
|
243
|
+
if usage:
|
|
244
|
+
self._ctx.prompt_tokens += getattr(usage, "prompt_token_count", 0)
|
|
245
|
+
self._ctx.completion_tokens += getattr(
|
|
246
|
+
usage, "candidates_token_count", 0
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
total = self._ctx.prompt_tokens + self._ctx.completion_tokens
|
|
250
|
+
if total > self._kernel.policy.max_tokens:
|
|
251
|
+
raise PolicyViolationError(
|
|
252
|
+
f"Token limit exceeded: {total} > "
|
|
253
|
+
f"{self._kernel.policy.max_tokens}"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Check for function calls in candidates
|
|
257
|
+
candidates = getattr(response, "candidates", [])
|
|
258
|
+
for candidate in candidates:
|
|
259
|
+
content = getattr(candidate, "content", None)
|
|
260
|
+
if content is None:
|
|
261
|
+
continue
|
|
262
|
+
parts = getattr(content, "parts", [])
|
|
263
|
+
for part in parts:
|
|
264
|
+
fn_call = getattr(part, "function_call", None)
|
|
265
|
+
if fn_call is None:
|
|
266
|
+
continue
|
|
267
|
+
fn_name = getattr(fn_call, "name", "")
|
|
268
|
+
call_info = {
|
|
269
|
+
"name": fn_name,
|
|
270
|
+
"args": dict(getattr(fn_call, "args", {})),
|
|
271
|
+
"timestamp": datetime.now().isoformat(),
|
|
272
|
+
}
|
|
273
|
+
self._ctx.function_calls.append(call_info)
|
|
274
|
+
self._ctx.tool_calls.append(call_info)
|
|
275
|
+
|
|
276
|
+
if len(self._ctx.tool_calls) > self._kernel.policy.max_tool_calls:
|
|
277
|
+
raise PolicyViolationError(
|
|
278
|
+
f"Tool call limit exceeded: "
|
|
279
|
+
f"{len(self._ctx.tool_calls)} > "
|
|
280
|
+
f"{self._kernel.policy.max_tool_calls}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if self._kernel.policy.allowed_tools:
|
|
284
|
+
if fn_name not in self._kernel.policy.allowed_tools:
|
|
285
|
+
raise PolicyViolationError(
|
|
286
|
+
f"Tool not allowed: {fn_name}"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
if self._kernel.policy.require_human_approval:
|
|
290
|
+
raise PolicyViolationError(
|
|
291
|
+
f"Tool '{fn_name}' requires human approval per governance policy"
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
# Post-execute bookkeeping
|
|
295
|
+
self._kernel.post_execute(self._ctx, response)
|
|
296
|
+
|
|
297
|
+
return response
|
|
298
|
+
|
|
299
|
+
def get_context(self) -> GeminiContext:
|
|
300
|
+
"""Return the execution context with the full audit trail.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
The ``GeminiContext`` for this governed model.
|
|
304
|
+
"""
|
|
305
|
+
return self._ctx
|
|
306
|
+
|
|
307
|
+
def get_token_usage(self) -> dict[str, Any]:
|
|
308
|
+
"""Return cumulative token usage statistics.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
A dict with ``prompt_tokens``, ``completion_tokens``,
|
|
312
|
+
``total_tokens``, and ``limit``.
|
|
313
|
+
"""
|
|
314
|
+
return {
|
|
315
|
+
"prompt_tokens": self._ctx.prompt_tokens,
|
|
316
|
+
"completion_tokens": self._ctx.completion_tokens,
|
|
317
|
+
"total_tokens": self._ctx.prompt_tokens + self._ctx.completion_tokens,
|
|
318
|
+
"limit": self._kernel.policy.max_tokens,
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
def _validate_tools(self, tools: Any) -> None:
|
|
322
|
+
"""Validate tool definitions against policy allowlist.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
tools: Tool definitions from the request.
|
|
326
|
+
|
|
327
|
+
Raises:
|
|
328
|
+
PolicyViolationError: If a tool is not in the allowed list.
|
|
329
|
+
"""
|
|
330
|
+
if not self._kernel.policy.allowed_tools:
|
|
331
|
+
return
|
|
332
|
+
tool_list = tools if isinstance(tools, list) else [tools]
|
|
333
|
+
for tool in tool_list:
|
|
334
|
+
declarations = getattr(tool, "function_declarations", None)
|
|
335
|
+
if declarations:
|
|
336
|
+
for decl in declarations:
|
|
337
|
+
name = getattr(decl, "name", "") if not isinstance(decl, dict) else decl.get("name", "")
|
|
338
|
+
if name and name not in self._kernel.policy.allowed_tools:
|
|
339
|
+
raise PolicyViolationError(f"Tool not allowed: {name}")
|
|
340
|
+
|
|
341
|
+
def __getattr__(self, name: str) -> Any:
|
|
342
|
+
"""Proxy attribute access to the underlying Gemini model."""
|
|
343
|
+
return getattr(self._model, name)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def wrap_model(
|
|
347
|
+
model: Any,
|
|
348
|
+
policy: GovernancePolicy | None = None,
|
|
349
|
+
) -> GovernedGeminiModel:
|
|
350
|
+
"""Quick wrapper for Gemini GenerativeModel.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
model: A ``google.generativeai.GenerativeModel`` instance.
|
|
354
|
+
policy: Optional governance policy.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
A governed model.
|
|
358
|
+
|
|
359
|
+
Example:
|
|
360
|
+
>>> from agent_os.integrations.gemini_adapter import wrap_model
|
|
361
|
+
>>> governed = wrap_model(my_model)
|
|
362
|
+
>>> response = governed.generate_content("Hello")
|
|
363
|
+
"""
|
|
364
|
+
return GeminiKernel(policy=policy).wrap(model)
|