Nachrichtenzustellung: Outbox, Turn, Verlauf
Wie eine Nachricht in die dauerhafte Outbox gelangt, einen Codex-Turn erreicht, durch das Echo von Codex bestätigt wird und bei verlorener Antwort wartet, statt erneut gesendet zu werden.
Gegen den Quellcode geprüft am 17. September 2026
Auf dieser Seite
Das Leben einer Nachricht
- GespeichertQuittung · queueId · operationId
Eine Transaktion speichert den Anfrage-Fingerabdruck und den Outbox-Eintrag, ein Drain-Task startet, und die Quittung geht zurück. Der Composer des Desktops wird mit der Quittung geleert. Ein Turn muss noch nicht existieren.
- AngenommenrunId · threadId · turnId · acceptedAt
Wird ins Operationsregister geschrieben, wenn turn/start antwortet. Das belegt, dass ein Turn die Nachricht übernommen hat. Erst das Echo belegt, dass Codex sie aufgezeichnet hat.
- BestätigtuserMessage.clientId == operationId
Codex zeichnet die Nutzernachricht mit der operationId auf und sendet item/completed. Das Register markiert die Operation als sent, danach verlässt der Eintrag die Warteschlange.
- Keine eindeutige AntwortuserMessage.clientId im Verlauf
Bekommt turn/start keine eindeutige Antwort, sucht der Desktop die operationId im Verlauf. Gefunden heißt gesendet und entfernt. Fehlt sie oder ist der Verlauf nicht lesbar, bleibt der Eintrag mit abgeschaltetem Auto-Drain stehen und bittet darum, zuerst die Timeline zu prüfen.
Eine Nachricht hat mehrere Identitäten
| Identität | Was sie identifiziert |
|---|---|
| sessionId | Die PlanToCode-Konversation, die die Outbox besitzt. |
| queueId | Der sichtbare Eintrag in dieser Outbox. |
| operationId | Die unveränderliche Nachrichtenoperation, die über Zustellung und Wiederherstellung hinweg beibehalten wird. |
| idempotencyKey | Die Remote-Mutationsanforderung. Ihre Replay-Regeln gehören zur RPC-Schicht. |
| runId / threadId / turnId | Der Run und der genaue Agenten-Turn, der die Operation angenommen hat. Das Operationsregister speichert sie mit acceptedAt, und die Annahme einer Steuerung steht zusätzlich am Outbox-Eintrag. |
Der Submit-Dienst berechnet einen unveränderlichen Anfrage-Fingerabdruck und prüft die aufgezeichnete Operationsidentität vor der Zulassung. Der Fingerabdruck ist ein SHA-256 über sessionId, queueId, userText, promptText, attachments, codexThreadId, speedMode, accessMode, das erwartete Modell mit Aufwand, rollbackBeforeSend, source und createdAt. Er lässt intent, sendMode und expectedActiveRunId absichtlich aus, sodass eine Nachricht einreihen und dann sofort senden auf dieselbe Operation konvergiert, während das Umlenken einer Steuerung auf einen anderen Run ein Konflikt ist. Die Datenbanktransaktion beansprucht das Paar (session_id, operation_id) und speichert das Outbox-JSON zusammen damit, und ein anderer Fingerabdruck unter derselben Operations-ID kann den ursprünglichen Anspruch nicht überschreiben.
Verwahrung, Annahme und Historie sind getrennt
Jeder Moment schreibt seinen eigenen Datensatz. Die Quittung belegt nicht, dass ein Turn gestartet wurde, und ein angenommener Turn belegt nicht, dass Codex die Nachricht aufgezeichnet hat.
| Moment | Datensatz | Was es nachweist |
|---|---|---|
| Absenden | workspace_chat_outbox und workspace_chat_outbox_operation_identity, in einer Transaktion geschrieben | Verwahrung beim Desktop, die Quittung geht zurück. |
| Kurz bevor turn/start den Actor erreicht | codex_chat_operation_ledger mit Status sending | Ein Sendeversuch begann, ein Turn kann existieren. |
| turn/start antwortet | Das Ergebnis im Register erhält runId, threadId, turnId und acceptedAt | Ein Turn hat die Nachricht angenommen. |
| userMessage.clientId live oder im Verlauf gesehen | Registerstatus sent, danach wird der Outbox-Eintrag entfernt | Codex hat sie aufgezeichnet. Zustellung bestätigt. |
Der persistierte Eintragsstatus hat zwei Werte: queued und sending. Zurückgehaltene und fehlgeschlagene Einträge können mit deaktiviertem autoDrain und einem Fehler- oder Zurückhaltungsgrund zu queued zurückkehren. Sent, failed und blocked treten ebenfalls als Dienstergebnisse auf; sie sind keine zusätzlichen Werte von WorkspaceChatOutboxStatus.
| Übermittlungssteuerung | Bedeutung |
|---|---|
| intent: automatic | Verwahrung speichern und den ausgewählten Drain-Pfad zulassen. |
| intent: enqueue | An die Warteschlange anhängen und automatisch senden, sobald die Session frei ist. |
| intent: replace-latest | Legen Sie das Ersetzungsverhalten, einschließlich rollbackBeforeSend, im gespeicherten Eintrag fest. |
| sendMode: queue | Warteschlangenbasierte Zustellung verwenden. |
| sendMode: steer-running | Verwenden Sie den Steuerungs-Drain-Pfad für eine zulässige automatische Übermittlung. |
| sendMode: interrupt-running | Den aktiven Run stoppen, warten, bis er zur Ruhe gekommen ist, und diese Nachricht dann als eigenen Run starten. |
Die Validierung verknüpft die Steuerungen: enqueue verlangt sendMode queue, replace-latest verlangt interrupt-running, steer-running verlangt expectedActiveRunId, und jeder andere Modus weist dieses Feld zurück. Eine Session-Outbox hält höchstens 256 Einträge, und das Telefon wartet 20 Sekunden auf die Quittung.
Was die Composer-Aktionen tun
- Einreihenintent: enqueue
Wird ans Ende der Warteschlange angehängt und nie in einen laufenden Turn gemischt. Das Bearbeiten einer wartenden Nachricht behält ihre queueId und vergibt eine neue operationId.
- Steuernsteer-running · expectedActiveRunId
An den beobachteten Run gebunden. turn/steer fügt die Nachricht diesem Run hinzu, also gelten dessen Modell, Aufwand, Geschwindigkeit und Zugriff. Endet der Run, bevor er sie verwendet, kommt die Nachricht mit abgeschaltetem Auto-Drain zurück.
- Unterbrecheninterrupt-running
Das Modell wird geprüft, bevor der Run gestoppt wird. Die Nachricht startet, sobald der alte Run die Run- und die Turn-Registry verlassen hat, geprüft alle 25 ms, höchstens 10 s lang. Erscheint während des Wartens ein neuerer Turn, bleibt sie in der Warteschlange.
- Letzte ersetzenreplace-latest · rollbackBeforeSend
Stoppt einen laufenden Turn wie eine Unterbrechung und setzt dann den letzten Turn zurück, bevor diese Nachricht gesendet wird.
Eine Steuerungsantwort, die beweist, dass die Anweisung nicht zugelassen wurde, gibt die Operation in die automatische Warteschlangenverwahrung zurück, und Transportunsicherheit durchläuft dieselbe Abstimmung wie jeder andere Versand. Ist der alte Run nach 10 Sekunden noch nicht zur Ruhe gekommen, bleibt auch der Ersatz einer Unterbrechung in der Warteschlange. Das Bearbeiten einer wartenden Nachricht schreibt den Text neu und behält ihren Platz in der Warteschlange, sofern sie nicht sofort gesendet oder umsortiert wird. Das Entfernen löscht den wartenden Eintrag und lässt den aktiven Run unberührt.
Die Admission-Grenze steuert die sichere Wiederherstellung
- Übergabecommand_permit.send
Der reservierte Befehl geht erst an den Actor, wenn im Register sending steht und das Gate den Actor offen findet. Der Sendepfad selbst hört 31 s nach der Übergabe auf zu warten.
- Vorher gescheitertPreAdmission
Eine abgelaufene Reservierung, ein gescheitertes Schreiben von sending, ein Actor im Ruhestand oder ein geschlossener Actor. Der Eintrag kehrt mit abgeschaltetem Auto-Drain und dem Fehler in die Warteschlange zurück.
- Danach ungewissAdmissionUncertain
Eine Fehlerantwort, ein gescheitertes Schreiben, ein geschlossener Kanal, eine abgelaufene Frist oder ein gescheitertes Speichern der Annahme. Der Turn existiert vielleicht, deshalb sucht der Desktop die operationId im Verlauf. Gefunden heißt gesendet. Fehlt sie oder ist der Verlauf nicht lesbar, wird der Eintrag gehalten.
- Späte Ergebnisseexpected_sending_entry
Die Wiederherstellung ändert einen Eintrag nur, solange er noch dem Stand während des Sendens entspricht, sodass ein spätes Ergebnis nie eine neuere Entscheidung in der Warteschlange überschreibt.
Jede Session hat zwei Drain-Bahnen, normal und steer, jede mit eigener Sperre. Ein Aufwecken, das eintrifft, während eine Bahn beschäftigt ist, setzt nur ein Folgekennzeichen, das der abschließende Durchlauf zurückgibt, sodass nichts verloren geht, was an der Abschlussgrenze landet. Die Steer-Bahn lässt nur den Kopf der Warteschlange zu, nur für eine exakte Steuerung des aktiven Runs, und startet nie einen neuen Turn. Eine Steuerung, deren Run schon beendet ist, wartet am Kopf, solange ein anderer Run arbeitet, und startet danach als neuer Run.
Die Zustellbereinigung verwendet das Paar aus Warteschlange und Operation. Die Registry hält Runtime-Clients für aktive Arbeit geliehen, einschließlich der Aktivität untergeordneter Threads, und leitet die Auflösung von Freigaben an den Actor, dem die vollständige Anfrageidentität gehört.
| Fehler | Erforderliche Interpretation |
|---|---|
| Speichern der Verwahrung schlägt fehl | Beanspruchen Sie keine dauerhafte Quittung. Der Speicherung darf keine automatische Admission vorausgehen. |
| Annahme liegt vor, Historie ist verzögert | Behalten Sie den Annahmenachweis bei. Schließen Sie nicht daraus, dass die Nachricht in der Ausführung fehlt. |
Ungewisse Zustellung
Nach einem ungewissen Sendevorgang oder nach einem Neustart mit einem noch als sending markierten Eintrag liest der Desktop die eingefrorene Verlaufsroute der Operation. Die Zustellung gilt nur dann als bestätigt, wenn eine userMessage.clientId gleich der Outbox-Operations-ID vorliegt, auf dem indexierten Thread des Speicherprofils oder auf dem exakten Pfad mit seinem Vorfahren-Manifest. Geschwister-Threads werden nie durchsucht. Eine bestätigte Operation wird ins Sent-Register geschrieben, bevor die Outbox-Verwahrung entfernt wird. Fehlende Belege, ein Lesefehler oder eine abweichende Route lassen den Eintrag mit abgeschaltetem Auto-Drain sichtbar, und es gibt keine automatische Wiederholung oder Backoff.
Stop and send now ist der einzige automatische Neuversand. Die Abbildung zeigt, wann der Desktop ihn erlaubt.
- Angeforderthandoff.phase: requested
Zuerst wird das Modell geprüft. Dann hält der Eintrag Run R, seinen Thread und seinen Turn fest, mit abgeschaltetem Auto-Drain.
- Lösenturn/detachPendingInputForReplay
Bittet Codex, die Steuerung anhand ihrer operationId aus den wartenden Eingaben des Runs zu nehmen. Nur detachedForReplay oder alreadyDetachedForReplay lässt den Desktop weitermachen.
- Widerrufencodex_chat_operation_ledger
Löscht nur die Annahme für genau diesen Run, Thread und Turn. Steht im Register schon sent, wird nichts erneut gesendet.
- Eigener Turnhandoff.phase: dedicated
Der Eintrag wird mit eingeschaltetem Auto-Drain und derselben operationId wieder eingereiht und startet seinen eigenen Turn, sobald Run R zur Ruhe gekommen ist.
Was Stop macht
Stop bittet den Codex app-server, den aktuellen Turn abzubrechen. Bereits gelaufene Befehle und bereits bearbeitete Dateien bleiben, wie sie sind, lesen Sie also Timeline und Git-Diff, sobald der Run zur Ruhe gekommen ist. Eine eingereihte Nachricht entfernen, einen Run stoppen und eine Datei zurücksetzen sind drei verschiedene Aktionen, und nur die letzte berührt Ihr Arbeitsverzeichnis.