Appearance
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 Registry | Adapter Registry | |
|---|---|---|
| Answers | Which 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? |
| Entity | RegisteredAgent | RegisteredAdapter (secret-free wire summary) |
| Governs | whether an agent may run | how an execution request reaches a real provider |
| Connected by | RegisteredAgent.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 ReplaySee 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 Execution | Managed Adapter Execution | |
|---|---|---|
| Endpoint | POST /runtime/agent-runs | POST /runtime/agents/:agentId/execute |
| Who runs the model | The caller, on its own infrastructure | The platform, via a registered adapter |
| Caller supplies | A finished, structured AgentOutput | Raw clinical context/instructions; the platform produces the output |
execution_origin on the resulting AgentRun | "external" | "managed" |
| Whose provider credentials are used | N/A — CARC never sees them | Yours — a tenant-owned Provider Connection, never CARC's |
| When to use | You already run your own agent/model/framework | You 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 executionsAdapters 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 aRegisteredAdapter's wire representation, never logged. GET /runtime/adapters*responses only ever return the secret-freeRegisteredAdapterSummaryshape.- An unconfigured or unreachable provider never affects engine health/readiness — see
GET /ready'sdegradedfield. - 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/executeSee SDK Guide and REST API Guide for usage, and OpenAI Adapter for the first concrete provider implementation.