# Service Tier Flex — Cost-optimized tier for async work

> **Scope:** stacks=["dotnet"]
> **Layer:** 2 (on-keyword)
> **Keywords:** service tier, flex tier, cost optimization, async tier, priority tier
> **Read by Claude in:** implement

**Verified against:** OpenAI 2.13.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08). **Verificação documental** da política de tiers (platform.openai.com/docs/guides/service-tiers, lido 2026-09-08), sem cláusula `provado por`: o ai-kit **referencia** o pacote `OpenAI` no `.csproj` — contrato de versão, régua = restore (`NU1102`) — mas **não o exercita**; não existe um único `using OpenAI` em `src/` (medido 2026-09-08), logo um rename de API não reprova a PR. Ver a tabela "Dois níveis de garantia" no README do kit. **O nome e o tipo da propriedade C# foram medidos por reflexão sobre a assembly `OpenAI` 2.13.0 em 2026-09-08**, e o marcador `// VERIFY` desta página foi RESOLVIDO por essa medição. Last-verified: 2026-09-08.

---

## Quando usar tier flex

Use o service tier **flex** quando o agente roda em background, sem usuário aguardando resposta:

- Relatório mensal gerado overnight (briefing, sumário financeiro, newsletter)
- Job de enriquecimento de dados disparado por evento (upload de arquivo, fim de período)
- Análise on-demand que pode demorar segundos a mais sem impacto na UX
- Qualquer completion dentro de um Worker Service / Hangfire job

**Por que usar:** tier flex troca velocidade de resposta por **custo menor**. A OpenAI processa requests flex com menor prioridade — SLA mais relaxado, desconto de custo.

> Regra: se o resultado vai para um banco de dados ou fila (não direto ao usuário), use flex.

---

## A API

> **AVISO:** service tier é **OpenAI-specific** — não é exposto no `Microsoft.Extensions.AI.ChatOptions`.
> Para setar service tier, use o `ChatClient`/`ResponsesClient` direto (obtido do Model Registry ou da configuração).
>
> Isso foi **medido**, não suposto: `Microsoft.Extensions.AI.ChatOptions` 10.9.0 tem 20 propriedades e **nenhuma** delas é service tier (reflexão sobre `Microsoft.Extensions.AI.Abstractions` 10.9.0, 2026-09-08). O caminho por abstração é `ChatOptions.AdditionalProperties["service_tier"]` **combinado com** um `RawRepresentationFactory` que traduza o valor — sem essa tradução, a chave em `AdditionalProperties` não chega ao fio.

### O tipo é um struct, não uma string — e não existe `priority`

Medido na assembly `OpenAI` 2.13.0:

| Superfície | Propriedade | Tipo | Valores |
|---|---|---|---|
| Chat Completions | `ChatCompletionOptions.ServiceTier` | `ChatServiceTier?` | `Auto`, `Default`, `Flex`, `Scale` |
| Responses | `CreateResponseOptions.ServiceTier` | `ResponseServiceTier?` | `Auto`, `Default`, `Flex`, `Scale` |

Duas correções contra a versão anterior deste standard:

1. **`ServiceTier = "flex"` não compila.** O valor é `ChatServiceTier.Flex` (um struct de valores nomeados, no estilo dos "extensible enums" do SDK), não uma `string`.
2. **`priority` não existe no SDK 2.13.0.** Os quatro valores expostos são `Auto`, `Default`, `Flex` e `Scale`. Se a conta tem tier prioritário contratado, isso não aparece como membro tipado aqui — e este standard não vai fingir que aparece.

---

## Exemplo C#

```csharp
using OpenAI;
using OpenAI.Chat;
using System.ClientModel;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

// ── Opção A: usando ChatClient direto (para um job async simples) ──
var apiKey = configuration["OpenAI:ApiKey"]!;
var model  = configuration["OpenAI:Model"] ?? "gpt-4o-mini";

ChatClient chatClient = new(model, new ApiKeyCredential(apiKey));

ChatCompletionOptions flexOptions = new()
{
    ServiceTier = ChatServiceTier.Flex,   // struct de valores nomeados, medido em OpenAI 2.13.0
};

ChatCompletion result = await chatClient.CompleteChatAsync(
    messages: [new UserChatMessage(prompt)],
    options: flexOptions);

string responseText = result.Content[0].Text;

// ── Opção B: dentro de um AIAgent MAF ──
// O agente MAF usa o IChatClient abstrato — ServiceTier (OpenAI-specific) não é exposto
// pelo Microsoft.Extensions.AI.ChatOptions, então não passa direto pelo AgentRunOptions.
// Para flex tier num agente, injete-o num middleware de IChatClient que monta
// ChatCompletionOptions com ServiceTier (ver ai-agents-middleware-patterns).
// Recomendação: para jobs async simples que precisam de flex tier, prefira a Opção A
// (ChatClient direto) — é o caminho confirmado e sem indireção.

// Exemplo Worker Service — dispara o job async e não bloqueia o caller:
// services.AddHostedService<MonthlyReportWorker>();
// MonthlyReportWorker usa chatClient com flexOptions para cada completion.
```

> Para jobs que rodam no contexto de um MAF agent mas precisam de flex tier:
> o agent pode ser construído sobre um `IChatClient` wrappado em middleware que injeta
> `ServiceTier = "flex"` via `ChatCompletionOptions` — veja `ai-agents-middleware-patterns`.

---

## Decision

| Cenário | Service tier recomendado |
|---------|--------------------------|
| Chat com usuário aguardando na tela | `default` (ou `auto`) |
| Job async — relatório, enriquecimento, briefing | `flex` |
| Job de alta prioridade com SLA apertado | `ChatServiceTier.Default` — **`priority` não existe** como valor tipado no SDK 2.13.0 (medido); um tier prioritário contratado com a OpenAI não tem membro correspondente aqui |
| Carga previsível e alta, com capacidade reservada | `ChatServiceTier.Scale` |
| Batch API (24 h) | Não se aplica — Batch tem custo próprio |

> `auto` (padrão da API): OpenAI decide o tier baseado na carga. Use `flex` explícito
> quando você quer garantir o menor custo para trabalho assíncrono.

---

## Anti-patterns

| Anti-pattern | Problema |
|-------------|----------|
| Usar `flex` em completion interativa | Latência imprevisível — usuário percebe lentidão |
| Usar `Default` em batch noturno | Paga mais sem necessidade |
| Escrever `ServiceTier = "flex"` (string) | Não compila: o tipo é `ChatServiceTier` |
| Espalhar `ServiceTier = "flex"` por vários handlers | Usar middleware de ChatOptions para centralizar |
| Combinar flex tier com Batch API | São mecanismos distintos; não se somam |

---

## Checklist (verifiable by morph-eval)

- [ ] Tier flex usado somente em jobs assíncronos (Worker Service / Hangfire), nunca em handlers de request HTTP síncrono
- [ ] `ServiceTier` usa o valor tipado (`ChatServiceTier.Flex` / `ResponseServiceTier.Flex`), nunca uma string
- [ ] Nenhuma referência a um tier `priority` (não existe no SDK 2.13.0)
- [ ] Jobs com flex tier não têm SLA de latência definido no contrato com o usuário final
- [ ] Se o agente usa `IChatClient` abstrato, o `ServiceTier` foi validado que é passado corretamente

---

## References

- `ai-agents-setup` — packages e configuração do cliente OpenAI
- `ai-agents-batching` — alternativa de custo para volume alto de prompts independentes
- `ai-agents-middleware-patterns` (Onda 2) — middleware para injetar `ChatOptions` globalmente
- `ai-agents-providers-model-registry` — configuração provider-agnostic
- OpenAI Service Tiers: https://platform.openai.com/docs/guides/service-tiers (lido 2026-09-08)
- Superfície C# medida na assembly `OpenAI` 2.13.0 em 2026-09-08

---

*MORPH-SPEC by Polymorphism Tech — ai-agents/service-tier-flex.md v2.0 (2026-09-08)*
