Use Case 029: Task-Type Routing & Agent Provisioning

Overview

Property Value
Use Case ID UC-029
Use Case Name Task-Type Routing & Agent Provisioning
Module Agent Identity โ€” LLM Gateway
Priority High
Status ๐Ÿšง Partially Implemented
Version 1.0
Last Updated June 15, 2026

Implementation status (agent-identity release, June 2026): partial. Shipping: the TaskType registry (CRUD at /ai-gateway/task-types), the dispatcher's classification-filtered resolution, and agent provisioning (agents carry AllowedTaskTypes + DefaultTaskType, set via the setup wizard / agent forms). Not yet built: the ordered model chain with a preference + health cascade (a task type currently routes to a single DefaultModelDeploymentId), the two distinct provisioning UX paths described below (purpose-picker / direct-model-picker), and seeded starter task types.

Description

This use case describes the TaskType registry โ€” the routing primitive of the Application Manager (AM) LLM Gateway โ€” and the two agent-provisioning UX paths that feed it. A TaskType binds a logical job (developer.code-generation, chat.general, analysis.financial) to an ordered modelChain of ModelDeployments, plus per-task defaults (responseSchema, timeout, maxRetries, temperature, classificationFloor). The dispatcher (UC-030) resolves a task type to the first viable deployment after a preference cascade and classification filter. Admins configure model selection once, per task type, and many agents share it โ€” so swapping the underlying model chain happens in one place.

This is part of the agent-identity release. The SDK master design is riptide-sdk/docs/plans/AGENT-IDENTITY-ARCHITECTURE.md; the AM-side plan is docs/internal/agent-identity-plan.md (ยง2 and ยง3.7). The gateway absorbs the RAF-SVC-LLM specification โ€” its task-type routing and deployment cascade become AM's design. Crucially, AM is task-types-only at the data layer: both provisioning UX paths โ€” the purpose-picker and the direct-model-picker โ€” produce the same TaskType data, so the dispatcher, dashboards, and audit see one mechanism with no special-case code. An agent's AllowedTaskTypes + DefaultTaskType replace the older AllowedProviderModels concept.

Implementation note โ€” guided setup. The shipped entry point for standing up this chain is the AI Gateway โ†’ Setup wizard (/ai-gateway/setup). It walks provider account โ†’ model โ†’ deployment โ†’ task type โ†’ agent in order and shows a live readiness banner that reports real callability (a task type is callable only when it's enabled, wired to an enabled deployment whose model exists and whose provider account is enabled with a resolvable key โ€” the same guards the dispatcher applies). It lists the specific blocker when a step isn't ready, and an on-demand Run live check issues a real provider probe. See AI Gateway & Model Governance.

Actors

Actor Description Role
Provisioning Admin / Steward Holds llm.gateway.config and agents.write; registers task types and provisions agents Primary
AM LLM Gateway Hosts the TaskType registry and the ResolveTaskType resolver Supporting
AI Agent Non-human identity whose AllowedTaskTypes/DefaultTaskType are set during provisioning; later issues dispatch requests Primary
LLM Providers Backing providers reached through the resolved ModelDeployments External
AuditLog Records task-type registration/edits and agent provisioning with actor chain Supporting

Preconditions

  1. Application Manager is running; the agent-identity EF migration (creating the TaskType table in IdentityDbContext and seeding starter task types) has been applied.
  2. At least one ProviderAccount and one ModelDeployment exist (UC-028).
  3. The acting principal is authenticated (X-Api-Key or admin cookie) and holds llm.gateway.config (for task types) and/or agents.write (for provisioning).
  4. The agent being provisioned exists or is being created in the same flow (UC-025).
  5. Starter task types are seeded; on first ProviderAccount registration the admin is prompted to bind them to available deployments.

Postconditions

Success Postconditions

  1. A TaskType is persisted with its component-namespaced id ({component}.{task-name}), ordered modelChain, and defaults.
  2. An agent has AllowedTaskTypes set and a DefaultTaskType chosen, via either provisioning path.
  3. ResolveTaskType returns an ordered list of viable ModelDeployments after the preference cascade and classification filter.
  4. Starter task types are bound to real deployments, so dispatch has a working chain from day one.
  5. Registration/provisioning events are written to AuditLog.

Failure Postconditions

  1. A TaskType whose modelChain references no viable deployment (all unreachable or below classificationFloor) is rejected or flagged unroutable.
  2. A classificationFloor exceeding every chain deployment's maxClassification is rejected.
  3. An agent provisioned with no resolvable task type cannot dispatch โ€” UC-030 fails closed.
  4. Duplicate task-type ids are rejected.

Primary Flow Sequence

sequenceDiagram
    actor Admin as Provisioning Admin
    participant Web as TaskTypesController / AgentsController
    participant Med as MediatR
    participant Resolve as ResolveTaskType
    participant Repo as LlmGateway Repos
    participant Audit as AuditLog

    Admin->>Web: Register task type (id, modelChain, defaults)
    Web->>Med: RegisterTaskType command
    Med->>Repo: Validate deployments exist + classificationFloor satisfiable
    Repo-->>Med: Validation OK
    Med->>Repo: Persist TaskType
    Med->>Audit: Write registration entry
    Med-->>Web: Task type registered
    Admin->>Web: Provision agent (purpose-picker: select task types)
    Web->>Med: Set AllowedTaskTypes + DefaultTaskType
    Med->>Resolve: ResolveTaskType(DefaultTaskType)
    Resolve->>Repo: Apply cascade + classification filter
    Repo-->>Resolve: Ordered viable deployments
    Resolve-->>Med: At least one viable deployment
    Med->>Audit: Write provisioning entry
    Med-->>Web: Agent provisioned
    Web-->>Admin: Agent ready to dispatch

UC-029a: Register / Edit a Task Type & Model Chain

Triggers

  • Admin opens LLM Gateway > Task Types > New (or edits one) and submits, or POST /api/llm/task-types / PUT /api/llm/task-types/{taskType}.

Basic Flow

  1. Admin enters a component-namespaced taskType id ({component}.{task-name}, e.g. analysis.financial) and a description.
  2. Admin orders a modelChain โ€” a list of ModelDeployments tried in preference order at dispatch.
  3. Admin sets defaults: optional responseSchema (for structured output), timeout, maxRetries, optional temperature, optional classificationFloor.
  4. RegisterTaskType validates the chain references existing deployments and that at least one chain deployment's maxClassification meets the classificationFloor.
  5. The TaskType is persisted; the registration is audited.
  6. UpdateTaskType edits the chain or defaults in place โ€” every agent referencing the task type immediately picks up the new chain (the one-place-to-swap property).

Alternative Flows

  • A1: classificationFloor unsatisfiable โ€” no chain deployment's maxClassification reaches the floor; rejected with a validation error.
  • A2: Empty / all-unreachable chain โ€” task type flagged unroutable; agents may still reference it but dispatch fails closed until a viable deployment is added.
  • A3: Duplicate id โ€” taskType already registered; rejected.
  • A4: Private direct-picker task type edited by hand โ€” agent.{agentName}.direct task types are owned by the direct-picker flow; manual edits are allowed but warned (they may be overwritten on re-provisioning).

UC-029b: Resolve Task Type to Deployment (Cascade + Classification Filter)

Triggers

  • The dispatcher (UC-030) calls ResolveTaskType(taskType, requestClassification); or an admin previews resolution from the task-type editor.

Basic Flow

  1. ResolveTaskType loads the task type and its modelChain.
  2. It applies the preference cascade: walk the chain in order, keeping deployments that are not Unreachable.
  3. It applies the classification filter: drop any deployment whose maxClassification is below the request's data classification (or the task's classificationFloor).
  4. The result is an ordered list of viable ModelDeployments โ€” the first is the primary, the rest are fallbacks for retry/model-chain fallback (UC-030).
  5. If the list is non-empty, resolution succeeds; the dispatcher proceeds.

Alternative Flows

  • A1: No viable deployment โ€” every chain entry is unreachable or below classification; resolution returns empty and dispatch fails closed (Unroutable).
  • A2: Health-degraded primary โ€” a Degraded primary is kept but ranked after Healthy peers where the cascade allows.
  • A3: Classification floor stricter than request โ€” the task's classificationFloor is applied even when the request classification is lower, raising the effective filter.
sequenceDiagram
    participant Disp as LlmDispatchService
    participant Resolve as ResolveTaskType
    participant TT as TaskType Repo
    participant Dep as ModelDeployment Repo

    Disp->>Resolve: ResolveTaskType(taskType, requestClassification)
    Resolve->>TT: Load task type + modelChain
    TT-->>Resolve: Ordered chain + classificationFloor
    Resolve->>Dep: Fetch deployments in chain
    Dep-->>Resolve: Deployments (health, maxClassification)
    Resolve->>Resolve: Cascade (drop Unreachable, prefer Healthy)
    Resolve->>Resolve: Classification filter (>= max(reqClass, floor))
    alt Viable deployments remain
        Resolve-->>Disp: Ordered viable deployments
    else None viable
        Resolve-->>Disp: Empty (Unroutable, fail closed)
    end

UC-029c: Purpose-Picker Agent Provisioning

Triggers

  • Admin provisions an agent via "What will this agent do?" in the agent provisioning UI.

Basic Flow

  1. The flow lists available task types (developer.code-generation, chat.general, analysis.financial, โ€ฆ) with descriptions.
  2. Admin selects one or several task types.
  3. AM sets the agent's AllowedTaskTypes to the selected set.
  4. DefaultTaskType is set to the first selected task type.
  5. No new task type is created โ€” the agent references shared, admin-managed task types.
  6. This is the strategic path: many agents share a task type, so swapping the underlying model chain happens once in the registry (UC-029a) and propagates to all of them.

Alternative Flows

  • A1: Selected task type unroutable โ€” admin warned at provisioning time that the task type currently resolves to no viable deployment; provisioning may proceed but dispatch will fail closed until fixed.
  • A2: Zero selections โ€” provisioning blocked; an agent must have at least one allowed task type.

UC-029d: Direct-Model-Picker Agent Provisioning

Triggers

  • Admin provisions an agent via "Which models can this agent use?" in the agent provisioning UI.

Basic Flow

  1. The flow lists available ModelDeployments (model, provider, classification, health) instead of task types.
  2. Admin picks one or several deployments, in preference order.
  3. AM creates a private task type named agent.{agentName}.direct with the picked deployments as its modelChain.
  4. AM sets that private task type as both the agent's AllowedTaskTypes and its DefaultTaskType.
  5. The admin never types the words "task type" โ€” the mechanism is hidden behind a model picker.
  6. This is the simple path for one-off agents; the produced data is identical to the purpose-picker output, so the dispatcher and audit see one mechanism.

Alternative Flows

  • A1: Re-provision with a different model set โ€” the existing agent.{agentName}.direct chain is replaced; an audit entry records the change.
  • A2: Picked deployment later disabled โ€” the private chain still references it; resolution (UC-029b) filters it out and falls through to the next picked deployment.
  • A3: Name collision โ€” if agent.{agentName}.direct already exists for a different agent, AM disambiguates with the agent id.

UC-029e: Seed & Bind Starter Task Types

Triggers

  • Initial agent-identity migration runs (seeds starter task types); first ProviderAccount registration prompts the admin to bind them.

Basic Flow

  1. The initial migration seeds starter task types: developer.code-generation, developer.code-explanation, developer.code-review, chat.general, chat.customer-support, analysis.financial, analysis.legal, summarization.document, embedding.search.
  2. Default chains reference common cloud-provider deployments by intent (not yet bound to a specific account).
  3. When an admin registers their first ProviderAccount and its deployments (UC-028), AM prompts: "Bind starter task types to your available deployments?"
  4. The admin maps each starter task type's chain to one or more real ModelDeployments.
  5. UpdateTaskType persists the bound chains; the starter task types become routable.
  6. Agents provisioned via the purpose-picker can immediately select these starter types.

Alternative Flows

  • A1: Admin skips binding โ€” starter task types remain unroutable until bound; dispatch against them fails closed.
  • A2: Partial binding โ€” only some starter types are bound; the rest stay unroutable without blocking the bound ones.
  • A3: Embedding task type โ€” embedding.search binds only to embedding-capable deployments; non-embedding deployments are not offered for it.

API Endpoints

Method Path Auth Purpose
POST /api/llm/task-types X-Api-Key + llm.gateway.config Register a task type
PUT /api/llm/task-types/{taskType} X-Api-Key + llm.gateway.config Update a task type / model chain
GET /api/llm/task-types X-Api-Key + llm.gateway.read List task types (registry view)
GET /api/llm/task-types/{taskType}/resolve X-Api-Key + llm.gateway.read Resolve a task type to ordered viable deployments
POST /api/agents/{id}/provision/purpose X-Api-Key + agents.write Purpose-picker provisioning (select task types)
POST /api/agents/{id}/provision/direct X-Api-Key + agents.write Direct-model-picker provisioning (select deployments)
// POST /api/agents/{id}/provision/purpose
// Request
{
  "selectedTaskTypes": [
    "developer.code-generation",
    "developer.code-review"
  ]
}

// Response 200
{
  "agentId": "01J8ZA10AGENT00000000001",
  "allowedTaskTypes": [
    "developer.code-generation",
    "developer.code-review"
  ],
  "defaultTaskType": "developer.code-generation",
  "provisioningPath": "PurposePicker",
  "defaultTaskTypeRoutable": true
}

Business Rules

Rule Description
BR-1 Task-type ids are component-namespaced {component}.{task-name}; ids are unique
BR-2 A TaskType carries an ordered modelChain, optional responseSchema, timeout, maxRetries, optional temperature, optional classificationFloor
BR-3 Editing a task type's modelChain propagates to every agent referencing it (one place to swap)
BR-4 ResolveTaskType applies the preference cascade (drop Unreachable) then the classification filter (>= max(requestClassification, classificationFloor))
BR-5 No viable deployment after resolution is Unroutable and dispatch fails closed
BR-6 Both provisioning paths produce TaskType data; the dispatcher, dashboards, and audit see one mechanism
BR-7 Purpose-picker sets AllowedTaskTypes to the selection and DefaultTaskType to the first selected
BR-8 Direct-model-picker creates a private agent.{agentName}.direct task type and sets it as both AllowedTaskTypes and DefaultTaskType
BR-9 An agent must have at least one allowed task type; zero selections is blocked
BR-10 Starter task types are seeded in the initial migration and bound to real deployments at first ProviderAccount registration
BR-11 AllowedTaskTypes + DefaultTaskType replace the older AllowedProviderModels concept

Data Requirements

TaskType

Field Type Constraints
TaskType string Primary key; component-namespaced {component}.{task-name}; unique
Description string Max 1000 chars
ModelChain ordered list of Guid Each references a ModelDeployment; preference order
ResponseSchema string? (JSON Schema) Optional; enables structured-output enforcement
Timeout int (ms/s) > 0
MaxRetries int โ‰ฅ 0
Temperature decimal? Optional; provider-clamped range
ClassificationFloor enum? Optional minimum classification the task requires
IsPrivate bool True for agent.{agentName}.direct direct-picker task types

Agent provisioning fields (on AgentIdentity โ€” see UC-025)

Field Type Constraints
AllowedTaskTypes set of string Each references a TaskType; non-empty
DefaultTaskType string Must be in AllowedTaskTypes
ProvisioningPath enum PurposePicker or DirectModelPicker (reporting only)

Security Considerations

  • Authentication: API routes require X-Api-Key; Web admin routes require the admin cookie.
  • Authorization / capabilities: task-type registry writes gated by llm.gateway.config; agent provisioning gated by agents.write; reads by llm.gateway.read. Capabilities compose into roles via the existing RBAC model.
  • Data protection: task types and chains carry no secrets; provider credentials stay on ProviderAccount (UC-028) and are never referenced in task-type data.
  • Audit: task-type registration/edits and both provisioning paths write AuditLog entries with actor chain. Direct-picker chain replacement is audited so the swap is forensically visible.
  • PII handling: task-type and provisioning data carry no end-user PII; classificationFloor is the lever that keeps high-classification work off low-classification deployments โ€” enforced at resolution and again at dispatch (UC-030).

Testing Scenarios

ID Scenario Expected Result
T-1 Register a task type with a valid ordered chain Persisted; routable; registration audited
T-2 Register with classificationFloor no chain deployment satisfies Rejected with validation error
T-3 Register with an empty / all-unreachable chain Flagged Unroutable; agents may reference but dispatch fails closed
T-4 Register a duplicate task-type id Rejected
T-5 Edit a shared task type's chain All referencing agents pick up the new chain immediately
T-6 ResolveTaskType with all-healthy chain Ordered viable deployments returned, primary first
T-7 ResolveTaskType with Unreachable primary Primary dropped; next chain entry returned as primary
T-8 ResolveTaskType where every entry is below classification Empty result; Unroutable; dispatch fails closed
T-9 ResolveTaskType with Degraded primary Primary kept but ranked after Healthy peers
T-10 classificationFloor stricter than request classification Effective filter raised to the floor
T-11 Purpose-picker: select two task types AllowedTaskTypes = both; DefaultTaskType = first selected
T-12 Purpose-picker: zero selections Provisioning blocked
T-13 Purpose-picker: select an unroutable task type Admin warned; provisioning may proceed; dispatch fails closed until fixed
T-14 Direct-picker: select two deployments Private agent.{agentName}.direct task type created with both as chain; set as AllowedTaskTypes + DefaultTaskType
T-15 Direct-picker: re-provision with different deployments Private chain replaced; change audited
T-16 Direct-picker: picked deployment later disabled Resolution filters it out; falls through to next picked deployment
T-17 Both paths produce identical task-type data shape Dispatcher and audit see one mechanism; no special-case branch
T-18 Initial migration seeds starter task types All nine starter types present
T-19 First ProviderAccount registration prompts binding Admin prompted; bound chains become routable
T-20 Admin skips starter binding Starter types remain unroutable; dispatch against them fails closed
T-21 embedding.search offered only embedding-capable deployments Non-embedding deployments not offered for binding
T-22 Caller lacks llm.gateway.config registering a task type 403; no change
T-23 Caller lacks agents.write provisioning an agent 403; no change
T-24 DefaultTaskType set outside AllowedTaskTypes Rejected by validation
T-25 Agent with no resolvable task type issues a dispatch UC-030 fails closed (Unroutable)
  • UC-025: Agent Identity Registration & Lifecycle โ€” the agent that carries AllowedTaskTypes/DefaultTaskType.
  • UC-028: LLM Provider Account & Deployment Management โ€” the deployments task-type chains resolve to.
  • UC-030: LLM Request Dispatch โ€” consumes ResolveTaskType output as the first dispatch step.

Revision History

Version Date Author Notes
1.0 June 9, 2026 Platform Architecture Team Initial draft