Skip to content

Model Provider Adapters

Initiative 1 adds a permanent, model-agnostic provider adapter layer to the platform. This page explains the architecture; see OpenAI Adapter for the first concrete implementation, Provider Connections (Initiative 2) for how a tenant's own credentials — never CARC's — get injected into a managed execution, and Execution Profiles (Initiative 3) for the canonical execution contract that ties an adapter, a connection, and a model configuration together.

The proof this initiative makes

The same Runtime Control Engine — unchanged policy, evidence, risk, approval, recording, replay, and metrics logic — governs three kinds of Agent Run:

  • synthetic — the engine's own in-process reference agent
  • externally submitted — a healthcare AI company ran its own model and handed the engine a finished output (External Agent Runs)
  • managed — the platform executed a real external model itself, through a provider adapter (this page)

The Runtime Control Engine never imports a provider SDK type and never knows which provider produced an output. It only ever evaluates a standardized result.

Agent Registry vs. Adapter Registry — two separate concepts

Agent RegistryAdapter Registry
AnswersWhich clinical agent is this, who owns it, what may it do, is it trusted to run?How does the platform talk to an external model/agent provider?
EntityRegisteredAgentRegisteredAdapter (secret-free wire summary)
Governswhether an agent may runhow an execution request reaches a real provider
Connected byRegisteredAgent.adapter_id (nullable — an agent may have no adapter at all)

An agent with no adapter_id can still be used via bring-your-own execution or the synthetic path — it simply cannot be executed through the managed endpoint below.

Initiative 2 adds a third, equally separate concept: the Provider Connection, which supplies WHOSE credentials a managed execution uses.

Initiative 3 adds a fourth: the Execution Profile, the canonical execution contract — model, inference parameters, timeouts/retries. As of Initiative 3, a RegisteredAgent no longer references adapter_id/provider_connection_id directly for managed execution; it references exactly one ExecutionProfile via execution_profile_id, and the profile itself carries adapter_id + provider_connection_id. RegisteredAgent.adapter_id is kept only as a deprecated, display-only field for backward compatibility — see Execution Profiles for the full resolution order and the migration story for agents registered before Initiative 3.

Target architecture

text
Clinical Application
  |
  Agent Registry            <- governs whether the agent may run
  |
  Execution Profile           <- resolves HOW execution happens (model, params, timeouts) (Initiative 3)
  |
  Provider Connection           <- resolves WHOSE tenant-owned credentials are used (Initiative 2)
  |
  Adapter Registry                 <- resolves WHICH protocol/implementation handles it
  |
  Clinical Agent Adapter             <- generic contract, TRANSIENT credentialed instance
  |
  External Model Provider (the tenant's own account)
  |
  Standardized execution result (text + citations + safe metadata)
  |
  AgentExecutionMapper                 <- bridges into AgentOutput, still no provider SDK types
  |
  Runtime Control Engine      <- UNCHANGED evidence/policy/risk/Decision Controller
  |
  Runtime Session -> Agent Run -> Decision Context Record -> Decision Replay

See Execution Profiles for the full resolution order (19 ordered checks) and Provider Connections for the credential-resolution architecture (CredentialStore) — including why the Adapter Registry's own boot-time instance is never used to execute a customer's request.

Managed execution vs. bring-your-own execution

Bring Your Own ExecutionManaged Adapter Execution
EndpointPOST /runtime/agent-runsPOST /runtime/agents/:agentId/execute
Who runs the modelThe caller, on its own infrastructureThe platform, via a registered adapter
Caller suppliesA finished, structured AgentOutputRaw clinical context/instructions; the platform produces the output
execution_origin on the resulting AgentRun"external""managed"
Whose provider credentials are usedN/A — CARC never sees themYours — a tenant-owned Provider Connection, never CARC's
When to useYou already run your own agent/model/frameworkYou want the platform to call a supported provider on your behalf, using your own account

Both land in the exact same evidence/policy/risk/Decision Controller pipeline and both are visible through the same Runtime Session, Agent Run, Decision Context Record, and Decision Replay APIs.

The generic adapter contract

Every provider adapter — OpenAI, Azure OpenAI, Google Gemini, Anthropic, a hospital-hosted model, a local model, a custom healthcare AI endpoint — implements the same ClinicalAgentProviderAdapter interface (@giggle-ai/agent-adapter-core):

ts
interface ClinicalAgentProviderAdapter {
  readonly adapterId: string;
  readonly provider: string;
  readonly version: string;
  getCapabilities(): AgentAdapterCapabilities;
  validateConfiguration(): Promise<AdapterValidationResult>;
  execute(request: ClinicalAgentExecutionRequest): Promise<ClinicalAgentExecutionResult>;
}

execute() never runs runtime policy, evidence, risk, or approval logic — it only calls the provider and returns a generic { output, citations, modelProvider, modelVersion, adapterId, executionMetadata } envelope. The engine's AgentExecutionMapper bridges that into a full AgentOutput before the unchanged evidence/policy/risk pipeline runs.

Adapter lifecycle

text
registered ("unavailable")
    |
    validateAdapter()
    |
    +-- available     <- configuration valid, ready for managed execution
    +-- misconfigured <- required configuration (e.g. an API key) missing/invalid
    +-- unavailable   <- configuration valid but not currently usable
    +-- deprecated    <- historical only, never selected for new executions

Adapters are registered only by the engine's own composition root at boot — there is no HTTP endpoint to create or edit adapter configuration.

Configuration and security considerations

  • Provider secrets (API keys, base URLs) live only in the adapter package's own config module and the process environment — never in a RegisteredAgent, never in a RegisteredAdapter's wire representation, never logged.
  • GET /runtime/adapters* responses only ever return the secret-free RegisteredAdapterSummary shape.
  • An unconfigured or unreachable provider never affects engine health/readiness — see GET /ready's degraded field.
  • No provider prompt or response text is ever logged — only safe metadata (token counts, latency, provider request id, finish reason).

APIs

text
GET  /runtime/adapters
GET  /runtime/adapters/:id
POST /runtime/adapters/:id/validate
GET  /runtime/adapters/:id/health
POST /runtime/agents/:agentId/execute

See SDK Guide and REST API Guide for usage, and OpenAI Adapter for the first concrete provider implementation.

Developer Platform v1 — Clinical Agent Runtime Control Platform