6. Runtime view¶
Four scenarios cover the paths that matter most: how a person signs in, how a pipeline runs, how a model is promoted and served, and how an agent turn is executed and traced. Each step names the route or function that implements it, so you can follow it in the code.
Sign-in through single sign-on¶
The gateway runs the OIDC authorization code flow against the configured issuer (Dex
in the local stack). The implementation is platform/go/internal/auth/session.go and
platform/go/internal/auth/authenticator.go.
sequenceDiagram
autonumber
actor U as Browser
participant G as Gateway
participant D as Dex (OIDC issuer)
participant I as Upstream identity provider
U->>G: GET /console.html (no session)
G-->>U: 302 /auth/login?return_to=/console.html
U->>G: GET /auth/login
G-->>U: 302 /login.html, or straight to the only provider
U->>G: GET /auth/sso/login?connector=ldap
Note over G: Set state, PKCE verifier, nonce and<br/>return-to cookies (10 minutes)
G-->>U: 302 issuer authorize URL<br/>(S256 challenge, nonce, connector_id)
U->>D: Authorization request
D->>I: Authenticate (LDAP bind, SAML, OAuth)
I-->>D: Identity and groups
D-->>U: 302 /auth/callback?code&state
U->>G: GET /auth/callback
G->>G: Compare state cookie with state parameter
G->>D: Exchange code with PKCE verifier (OIDC_TOKEN_URL)
D-->>G: ID token
G->>D: Fetch signing keys (OIDC_JWKS_URL, cached 10 minutes)
G->>G: Verify signature, issuer, audience and tenant, then check nonce
G->>G: Sign-up policy (KIONGA_SIGNUP) for a first-time subject
G-->>U: Set kionga_session (ID token, HttpOnly, 8 hours)<br/>302 to return_to
U->>G: GET /api/v1/me (cookie)
G->>G: Authenticator verifies the token, RBAC loads the access profile
G-->>U: Identity and effective permissions
What to know:
- The callback host decides where the login cookies live. If the browser starts on a
different host (for example
127.0.0.1while the callback islocalhost), the gateway first redirects to the callback's host. KIONGA_SSO_GROUP_ROLESmaps identity-provider groups to platform roles. A signed-in subject with no mapped group and no access profile gets theuserrole and reaches only/api/v1/me, access requests and personal settings until provisioned.- The session cookie is
Securewhen the callback URL is HTTPS. Production refuses a plain-HTTPOIDC_REDIRECT_URL. - Local accounts use
/auth/local/logininstead. The gateway checks abcrypthash (or the bootstrap administrator fromMLAIOPS_LOCAL_USERNAMEandMLAIOPS_LOCAL_PASSWORD), throttles per account after five failures, and issues an in-memory session cookiekionga_local_sessionfor eight hours. /auth/logoutends both kinds of session and revokes the subject's workspace sessions.
Pipeline run¶
This is the Compose path, where Prefect executes the run. Handlers are in
platform/go/internal/httpapi/server.go (submitPipeline) and
platform/go/internal/httpapi/pipeline_dispatch.go (dispatchPipeline); the flows
are in the pipeline-runner repository.
sequenceDiagram
autonumber
actor U as Console or SDK
participant G as Gateway
participant P as PostgreSQL
participant F as Prefect server
participant R as Pipeline runner
participant M as MLflow
participant K as Kafka (via REST proxy)
U->>G: POST /api/v1/pipelines/submit
G->>G: RBAC, then IAM gate for pipelines run and each override
G->>G: Preflight: project access, parameters, images, quotas, concurrency
G->>P: One transaction: run (queued) + audit event + outbox rows
G->>F: Create flow run (training-pipeline or pipeline-definition,<br/>deployment mlaiops, run_id, project_id)
F-->>G: Flow run ID
G->>P: Link run to engine ID
G-->>U: 202 Accepted (run)
loop Outbox worker, every second
G->>P: Pending outbox rows
G->>K: Publish audit and command events
G->>P: Mark published
end
F->>R: Run the flow
loop Each step
R->>G: POST /api/v1/pipelines/runs/{id}/steps (service token)
G->>P: Update step, recompute run status
R->>G: POST /api/v1/pipelines/runs/{id}/logs
end
R->>M: Log run and model artifacts
R->>G: POST /api/v1/models (register the version)
U->>G: GET /api/v1/events (SSE digest every 3 seconds)
G-->>U: Digest changed: reload the run view
Variations:
- Engine missing. Without
PREFECT_API_URLthe run is recorded and immediately marked failed at thesubmit-to-enginestep with an explanation. It is never left queued as if work were pending. - Function DAGs. A definition in
functionsmode runs through OpenFaaS. The gateway executes ready jobs from agoroutinestarted by the submit request. Without OpenFaaS, every job is marked failed with the reason. - Kubernetes Jobs. With the opt-in Kubernetes executor, container definitions run as one hardened Job per node attempt instead of through Prefect.
- Kubernetes lifecycle path. The outbox also carries
mlaiops.pipeline.commands. On Kubernetes the integration worker turns it into aKiongaPipelineRun, and the operator submits that run to KFP.
Model promotion and serving¶
Promotion changes the model's stage; deployment starts a live endpoint. Locally the serving manager runs containers on the Docker host. On Kubernetes, promotion also drives MLflow and KServe through the operator.
sequenceDiagram
autonumber
actor U as Console or SDK
participant G as Gateway
participant P as PostgreSQL
participant K as Kafka
participant W as Integration worker (Kubernetes)
participant O as Operator (Kubernetes)
participant S as Serving manager (Compose)
participant C as mlflow models serve container
U->>G: POST /api/v1/models/{id}/promote {stage}
G->>P: Model + audit + outbox (model.promoted)
G-->>U: 200 OK (model)
G->>K: Publish mlaiops.model.commands
K->>W: Poll batch (auto-commit off)
W->>O: Create or update KiongaModelPromotion
O->>O: MLflow stage transition, then create KServe InferenceService
W->>K: Commit offsets after the whole batch succeeds
U->>G: POST /api/v1/models/{id}/deploy
G->>P: Model + audit + outbox (model.deployed)
G->>S: POST /deployments {name, artifact_uri, serving_image}
S->>C: Replace container, create and start (no capabilities,<br/>no-new-privileges, PID limit)
S-->>G: Endpoint URL
G->>P: Record endpoint, status serving
G-->>U: 202 Accepted (model)
U->>G: POST /api/v1/models/{id}/predict
G->>C: POST /invocations
C-->>G: Predictions
G-->>U: Predictions
Failure behavior: if the serving manager rejects the deployment or is unreachable, the
gateway records status failed and returns 502 serving_failed. A prediction for a
model without a live endpoint returns 409 not_serving. Rollback removes the serving
container on a best-effort basis and logs a failed removal.
Agent turn with trace capture¶
The gateway proxies a turn to the agent runtime after a readiness gate. The runtime calls the model through the trace proxy and reports the session back.
sequenceDiagram
autonumber
actor U as Console or SDK
participant G as Gateway
participant A as Agent runtime
participant DB as PostgreSQL
participant T as Trace proxy
participant L as LLM provider
participant K as Kafka (via REST proxy)
participant LF as Langfuse
U->>G: POST /api/v1/agents/{id}/invoke {message, session_id}
G->>G: RBAC and project scope (404 if not visible)
G->>A: GET /healthz (3 seconds)
alt Runtime not healthy
G-->>U: 503 agent_not_ready
else Healthy
G->>A: POST /invoke with X-MLAIOps-Agent-ID,<br/>X-MLAIOps-Agent-Name, X-MLAIOps-Graph-Module
A->>DB: Load the session checkpoint
A->>T: Chat completion (OpenAI-compatible)
T->>L: Forward to LLM_UPSTREAM_URL
L-->>T: Completion with usage
T-->>A: Completion
T--)K: Trace event to mlaiops.llm.traces (asynchronous)
A--)LF: LangChain callback trace (when keys are set)
A->>DB: Save the checkpoint
A-->>G: Reply, tokens, cost, duration
G-->>U: Reply
A--)G: POST /api/v1/traces (background task, service token)
G->>DB: Upsert session and trace
end
What to know:
- The runtime endpoint is
AGENT_RUNTIME_URLin Compose (one shared runtime). On Kubernetes it is the per-agent Service named from the immutable agent ID inMLAIOPS_AGENT_NAMESPACE. - Token counts come from the model's usage metadata, never from an estimate. Cost is
computed from
MLAIOPS_COST_PER_1K_INPUTandMLAIOPS_COST_PER_1K_OUTPUT. - The trace proxy's event carries the agent, version, session ID, HTTP status and
duration, not the prompt or the provider key. It is sent from a
goroutineafter the response, and a failed send is dropped. - The
anthropicbackend calls Anthropic directly and does not pass through the trace proxy. The defaultmockbackend makes no network call. - Session reporting is best effort:
record_tracein the SDK uses a two-second timeout and ignores HTTP errors, so observability never fails a turn.