fastapi-gsap/gsap_broker/connectors/runtime.py
Tyler J King 0987704264 feat: governed connector module
GCAP-SPEC-CONNECTOR-DESCRIPTOR-0001 implementation.

ConnectorPlugin — abstract base for governed connectors.
ConnectorRegistry — register/discover connectors.
ConnectorRuntime — wraps invoke with Chronicle lineage.
EchoConnector — dev/test example.

API endpoints:
  GET  /connectors/           — browse catalogue
  GET  /connectors/{id}/      — connector descriptor
  POST /connectors/{id}/invoke/ — governed invocation
  GET  /connectors/{id}/health/ — health check

5 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 16:42:38 -04:00

53 lines
1.9 KiB
Python

"""ConnectorRuntime — governed invocation with Chronicle emission."""
from __future__ import annotations
from typing import Any
from .base import ConnectorContext, ConnectorResult
from .registry import ConnectorRegistry
class ConnectorRuntime:
def __init__(
self, registry: ConnectorRegistry, chronicle_client: Any = None
) -> None:
self.registry = registry
self.chronicle_client = chronicle_client
async def invoke(
self,
connector_id: str,
operation: str,
parameters: dict[str, Any],
context: ConnectorContext,
) -> ConnectorResult:
connector = self.registry.get(connector_id)
if connector is None:
return ConnectorResult(success=False, error=f"Unknown connector: {connector_id}")
if connector.gsap_required and not context.gsap_context_id:
return ConnectorResult(success=False, error="GSAP context required but not provided")
result = await connector.invoke(operation, parameters, context)
# Emit Chronicle event
if connector.chronicle_enabled and self.chronicle_client is not None:
try:
cid = await self.chronicle_client.emit(
"CONNECTOR_INVOKED",
{
"connector_id": connector_id,
"operation": operation,
"parameters_cid": connector.compute_parameters_cid(parameters),
"chronicle_session_id": context.chronicle_session_id,
"gsap_context_id": context.gsap_context_id,
"pipeline_run_id": context.pipeline_run_id,
"dag_id": context.dag_id,
"success": result.success,
},
)
result.lineage_cid = cid
except Exception:
pass # Chronicle failure must not break invocation
return result