Modo ChatGPT, Submodo Chat — Protocolo Real (traces da sessão)
The chat submode protocol reconstructed from 40 captured traces — typing throttle, attestation, UI efforts, multi-turn
Modo ChatGPT, Submodo Chat — Protocolo Real
Part of openai-research. Source: 40 real traces captured via bezetacil v4 in the main process (net-fetch-hook) during the test session — not static RE.
Nomenclatura UI → payload
| Seletor na UI | model no payload | thinking_effort no payload |
|---|---|---|
| Instant | gpt-5-5-instant | ausente |
| Medium | gpt-5-5-thinking | standard |
| High | gpt-5-5-thinking | extended |
| Model 5.6 Sol / 5.5 (Model menu) | /models web slugs | per selection |
The chat submode UI efforts are own: standard (UI Medium) e extended (UI High) — different from the codex scale (low/medium/high/xhigh). The "Instant" is a separate slug (gpt-5-5-instant), without thinking_effort in the payload.
O ciclo por mensagem (ordem real capturada)
1. User TYPES → POST /f/conversation/prepare (debounced por tecla)
body: {action: next, client_prepare_state: sent, partial_query: {…partial text…},
model, thinking_effort, conversation_id?}
← {conduit_token} — typing throttle: pre-caches the conversation
(partial_query carries the PARTIAL TEXT — prepare runs on every keystroke)
2. User SENDS → GET /backend-api/ios/attestation_challenge
headers: + x-sentinel-dc: {DeviceCheck token}
← {attestation_challenge: gAAAAAB…}
3. POST /f/conversation
body: {action: next, client_prepare_state: "success",
messages: [t6r completo — a mensagem do usuário],
app_attest_challenge: gAAAAAB…,
supported_encodings: [v1],
model, thinking_effort, conversation_id?, parent_message_id?,
local_function_signatures: [handoff]}
← SSE: delta protocol v1 (ver abaixo; see [flow-a-manual-step-by-step](flow-a-manual-step-by-step.md) for the full literal request)
4. Multi-turn: conversation_id + parent_message_id (última assistant message)
Diferenças do que a RE estática reconstruiu (correções impostas pelos traces)
| Campo | RE estática dizia | Trace real |
|---|---|---|
| user message field | partial_query | messages (full t6r) — partial_query is only the typing throttle |
client_prepare_state | 'sent' | 'success' no conversation (verified 2026-08-26/27 on real payloads); 'sent' only in the prepare |
app_attest_challenge | absent | mandatory on conversation (attestation, not sentinel) |
supported_encodings | não existia | ['v1'] |
thinking_effort | low/medium/high | standard/extended (UI Medium/High) |
| "Instant" | effort | slug separado (gpt-5-5-instant), sem effort |
| sentinel/PoW | necessário | AUSENTE no submodo chat do desktop — o mecanismo é attestation |
local_function_signatures | só no submodo work | PRESENTE também no submodo chat (a tool handoff é oferecida sempre no modo ChatGPT) |
O prepare como throttle (os 40 traces)
The prepare fires on every keystroke (debounced): partial_query carries the growing partial text ('qual a cor do elefante' → '…azul ou rosa? re' → '…responda em poucas palavras'). The server pre-processes the conversation while the user types — that is why long web sessions freeze: continuous PoW + prepare (the insight that preceded the PoW discovery).
Prepares sem partial_query (só conversation_id) = prepare de background ao abrir a conversa.
local_function_signatures — the client-declared tool mechanism
Beyond the server-side tool registry (web.run — executed server-side, results interleaved as role: tool), the chat submode body carries local_function_signatures — functions declared by the client in the request, callable by the model, executed by the client, with the result reinjected as role: 'tool' (the observed handoff loop). The handoff tool is the live example. For a standalone harness this is the extension point to add own tools to the chat submode without touching OpenAI's server: declare the signature, execute in the harness, inject the result back.
The handoff trigger card ("Continue in work mode" + countdown vs "Stay") is renderer-local UX — no dedicated request observed in the captured traffic (the task poll/creation happens through other channels); the pending-task state drives the card.
O handoff → task → role=tool loop (trace [37])
A conversa do chat chamou handoff → task criada no Work → o resultado voltou como role: 'tool' no próximo prepare/conversation, com client_prepare_state: 'success'. O loop chat→task→resultado dentro da mesma conversa web, confirmado nos traces.
6. TypeScript types (as built by the renderer builder)
The renderer builder (asar) emits (the fields below are literal in the builder):
// ── enums ────────────────────────────────────────────────────────────────
export type ConversationOrigin = 'tpp' | 'non-tpp' | string // 'tpp' = Work tasks (sidebar filter)
export type ConversationAction2 = 'next' // only 'next' in the builder
// ── the conversation body (renderer builder) ─────────────────────────────
export interface RendererConversationBody {
action: ConversationAction2
attachment_mime_types?: string[] // present when attachments exist; else undefined
client_prepare_state: 'sent' | 'success' | 'failure'
conversation_id?: string // undefined for a brand-new conversation
continue_from_shared_conversation_id?: string // shared-conversation path; undefined otherwise
conversation_origin?: ConversationOrigin
locale?: string
local_function_signatures?: import('./flow-a-tool-protocol').LocalFunctionSignature[]
message_id?: string
messages: import('./flow-a-tool-protocol').ConversationMessage[]
model: string
parent_message_id?: string
service_tier?: string // 'default' observed
supported_encodings: ['v1']
system_hints?: unknown[] // omitted when empty
thinking_effort?: string // 'standard' | 'extended' (chat scale); undefined for Instant
timezone: string // Intl.DateTimeFormat().resolvedOptions().timeZone
timezone_offset_min: number
is_client_thread?: boolean // only when the thread has no server conversation
}
Cross-references
- attestation-flow — o mecanismo de integridade do submodo chat
- work-submode-protocol — o submodo work
- auth-and-link-session — o token e as claims
- probes — os traces e a metodologia
- flow-definitions — onde o submodo chat se encaixa nos fluxos
- flow-a-manual-step-by-step — a sequência validada (A1) com headers/bodies literais
- flow-a-tool-protocol — o contrato validado de tool calling local
- postmortem-flow-a-2026-08-27 — as falhas (403) e as lições do ciclo A
No x-codex-turn-state in the chat submode
Observed: the x-codex-turn-state header appears zero times in the chat submode flow (verified against the net-fetch-hook captured traffic). The sticky routing turn-state is a mechanism of the codex backend (work submode + Codex mode), not the chat submode — the web flow keeps turn state in the session/topic via the resume_conversation_token instead.