Skip to content

Provider Connections

Initiative 2 adds Customer-Owned Model Credentials: managed execution must run against a tenant's own provider account, never against CARC's (Giggle AI Innovation's) own credentials. This page explains the credential/ownership half of that architecture; see Execution Profiles (Initiative 3) for the execution- configuration half — model, inference parameters, timeouts/retries — which no longer lives here.

The commercial model this enforces

Bring your model. Bring your provider account. CARC adds runtime control.

CARC does not pay for customer model usage, does not store provider credentials in plaintext, and remains provider-agnostic. Giggle AI Innovation's own provider credentials exist only for internal development, testing, and controlled product demonstrations — never as a fallback for a real tenant's workload.

Four separate concepts, permanently

Registered AgentExecution ProfileProvider ConnectionAdapter Registry
AnswersWhat may this agent do?How should the model execute?Whose account/credentials are used?How does CARC talk to a provider protocol?
EntityRegisteredAgentExecutionProfileProviderConnectionRegisteredAdapterSummary
Linked fromagent's execution_profile_idprofile's provider_connection_idprofile's adapter_id
Tenant-scoped?YesYesYes — always looked up under the requesting agent's own tenantNo — shared across tenants

A ProviderConnection never contains model, temperature, timeout, or retry configuration — that's exclusively ExecutionProfile's concern (see Execution Profiles for the full resolution order a managed execution goes through). A single connection may back many execution profiles — e.g. one tenant OpenAI account behind both a fast-triage profile and a structured-clinical profile using different models.

Target architecture

text
Clinical Application
  |
  Agent Registry              <- governs whether the agent may run
  |
  Execution Profile             <- resolves HOW execution happens (model, params, timeouts)
  |
  Provider Connection            <- resolves WHOSE credentials are used
  |
  CredentialStore                 <- resolves the raw credential (never logged/returned)
  |
  ProviderAdapterFactory            <- builds a TRANSIENT, tenant-credentialed adapter instance
  |
  External Model Provider (the tenant's own account)
  |
  Standardized execution result (text + citations + safe metadata)
  |
  Runtime Control Engine      <- UNCHANGED evidence/policy/risk/Decision Controller

The Adapter Registry's own registered instance is never used to execute a customer's request — it only reports capabilities/status. Every managed execution builds a fresh adapter instance from the resolved ProviderConnection's credentials and the resolved ExecutionProfile's model/parameters, uses it exactly once, and discards it.

Provider Connection lifecycle

text
pending  ──validate (ok)──>  valid  ──disable──> disabled ──enable──> valid
   ▲                            │
   └──────rotate-credential─────┘
                (back to pending — must be re-validated)

any status ──delete──> deleting (transient, then removed)
  • pending — just created or just rotated; not yet usable.
  • valid — passed validation; may serve managed execution.
  • invalid — last validation failed (see last_validation_error_code).
  • disabled — operator-paused; reversible via /enable.
  • deleting — deletion in progress; rejected if any ExecutionProfile still references the connection via provider_connection_id.

Validation is presence/shape-only (confirms a managed-execution factory exists for the provider, and that the stored credential is retrievable and non-blank) — it never makes a live call to the provider, and it no longer checks anything model-related (there is no model at this level — see Execution Profiles for where model compatibility is actually checked, at managed-execution time).

Credential storage

Raw credentials are never stored on the ProviderConnection record — credential_reference is an opaque pointer into a CredentialStore (@giggle-ai/credential-store):

  • gcp_secret_manager (production) — backed by Google Secret Manager. Secret names use only system-generated opaque identifiers, never a raw tenant string, display name, or credential fragment: carc-provider-{opaque-tenant-id}-{opaque-connection-id}. The secret name stays stable across credential rotations — rotation adds a new Secret Manager version under the same name. Labels are limited to managed-by=carc, resource-type=provider-connection, provider, and environment — never a tenant name or clinical data.
  • in_memory (dev/test only) — unencrypted process memory; the engine refuses to boot with this backend when ENVIRONMENT looks production-like (see Operations).

Configuration and security considerations

  • credential/RotateCredentialInput.credential are write-only — no response from any endpoint ever echoes them back, and the request logger never logs request bodies at all (see Security).
  • GET /runtime/provider-connections* responses only ever return the ProviderConnection shape, which has no field that could hold a raw credential.
  • Deleting a connection also deletes its underlying stored credential.
  • There is no public endpoint that can create a connection flagged as Giggle-owned/internal — that seeding happens only in the engine's own composition root at boot, scoped to the configured default tenant.

APIs

text
POST   /runtime/provider-connections
GET    /runtime/provider-connections
GET    /runtime/provider-connections/{id}
PATCH  /runtime/provider-connections/{id}
DELETE /runtime/provider-connections/{id}
POST   /runtime/provider-connections/{id}/validate
POST   /runtime/provider-connections/{id}/rotate-credential
POST   /runtime/provider-connections/{id}/enable
POST   /runtime/provider-connections/{id}/disable

SDK usage

ts
const connection = await runtime.createProviderConnection({
  provider: "openai",
  displayName: "Acme Health — OpenAI Production",
  credential: process.env.ACME_OPENAI_API_KEY!,
});
await runtime.validateProviderConnection(connection.connection_id);

Continue in Execution Profiles — a connection alone doesn't make an agent executable; it must be referenced from an ExecutionProfile, which the agent then references via executionProfileId.

See SDK Guide and REST API Guide for full reference.

Developer Platform v1 — Clinical Agent Runtime Control Platform