Zum Artikel springen
PlanToCodeDocsApp herunterladen

HandbuchArchitektur

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

Eine Nachricht wird in drei getrennten Momenten gespeichert, angenommen und bestätigt
Eine Nachricht wird in drei getrennten Momenten gespeichert, angenommen und bestätigtDie Zeichnung folgt einer Beispielnachricht aus dem Composer des Desktops von links nach rechts. Der Desktop speichert den Outbox-Eintrag in einer Transaktion und gibt die Quittung zurück, und der Composer wird geleert, bevor ein Turn existieren muss. Wenn turn/start antwortet, hält das Operationsregister fest, welcher Turn die Nachricht angenommen hat. Erst wenn Codex die Nutzernachricht mit ihrer operationId zurückmeldet, steht im Register sent, und der Eintrag verlässt die Warteschlange.
Composeram Desktop
Outbox-Eintrag
Operations­register
Codex-Kind
queued
sending
sending
Turn läuft
gespeichert
angenommen
bestätigt
senden
Quittung, Composer wird geleert
turn/start
Antwort mit Turn-ID
sent
entfernt
item/completed
zeichnet die Nutzernachricht auf
  • 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ätWas sie identifiziert
sessionIdDie PlanToCode-Konversation, die die Outbox besitzt.
queueIdDer sichtbare Eintrag in dieser Outbox.
operationIdDie unveränderliche Nachrichtenoperation, die über Zustellung und Wiederherstellung hinweg beibehalten wird.
idempotencyKeyDie Remote-Mutationsanforderung. Ihre Replay-Regeln gehören zur RPC-Schicht.
runId / threadId / turnIdDer 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.

MomentDatensatzWas es nachweist
Absendenworkspace_chat_outbox und workspace_chat_outbox_operation_identity, in einer Transaktion geschriebenVerwahrung beim Desktop, die Quittung geht zurück.
Kurz bevor turn/start den Actor erreichtcodex_chat_operation_ledger mit Status sendingEin Sendeversuch begann, ein Turn kann existieren.
turn/start antwortetDas Ergebnis im Register erhält runId, threadId, turnId und acceptedAtEin Turn hat die Nachricht angenommen.
userMessage.clientId live oder im Verlauf gesehenRegisterstatus sent, danach wird der Outbox-Eintrag entferntCodex 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.

ÜbermittlungssteuerungBedeutung
intent: automaticVerwahrung speichern und den ausgewählten Drain-Pfad zulassen.
intent: enqueueAn die Warteschlange anhängen und automatisch senden, sobald die Session frei ist.
intent: replace-latestLegen Sie das Ersetzungsverhalten, einschließlich rollbackBeforeSend, im gespeicherten Eintrag fest.
sendMode: queueWarteschlangenbasierte Zustellung verwenden.
sendMode: steer-runningVerwenden Sie den Steuerungs-Drain-Pfad für eine zulässige automatische Übermittlung.
sendMode: interrupt-runningDen 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

Einreihen wartet auf den Run, Steuern fügt sich ein, Unterbrechen beendet ihn
Einreihen wartet auf den Run, Steuern fügt sich ein, Unterbrechen beendet ihnDrei Zeilen zeigen denselben laufenden Turn R und eine Nachricht, die im selben Moment gesendet wird. Eine eingereihte Nachricht wartet, bis R endet, und startet dann ihren eigenen Run. Eine Steuerung fügt sich in R ein. Eine Unterbrechung prüft das Modell, stoppt R, wartet, bis R zur Ruhe kommt, und startet die Nachricht dann als eigenen Run, früher als die eingereihte.
Senden
Einreihen
Run R
wartet in der Warteschlange
eigener Run
Steuern
Run R
fügt sich in Run R ein
R schon beendet: eigener Run. Anderer Run aktiv: wartet auf dessen Ende.
Unterbrechen
Run R
gestoppt
stoppt Run R
wartet ≤ 10 s
eigener Run
Ohne aktiven Run startet jede Aktion einen neuen Run, sobald sie vorn in der Warteschlange steht.
  • 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

Nach der Übergabe an den Actor kann selbst ein abgelaufener Sendeversuch einen Turn gestartet haben
Nach der Übergabe an den Actor kann selbst ein abgelaufener Sendeversuch einen Turn gestartet habenDer linke Teil, nicht maßstäblich, zeigt die Schritte vor der Übergabe: Der Sendepfad reserviert einen Platz in der Befehlswarteschlange des Actors, schreibt sending ins Operationsregister und prüft, ob der Actor offen ist. Ein Fehler dort belegt, dass nichts Codex erreicht hat. Der rechte Teil ist maßstäblich in Sekunden nach der Übergabe gezeichnet. Der Actor schreibt turn/start und wartet 30 Sekunden auf die Antwort. Codex kann den Turn trotzdem starten, und eine spätere Antwort wird ignoriert, deshalb prüft der Desktop den Verlauf, statt erneut zu senden.
Operations­register
Sendepfad
App-Server-Actor
Codex-Kind
Übergabe an den Actor
Platz reserviert
sending geschrieben
Actor offen
Fehler hier: PreAdmission. Nichts hat Codex erreicht.
nicht maßstäblich
wartet auf die Antwort
Turn startet vielleicht trotzdem
turn/start, Schreiben ≤ 5 s
angenommen, nur bei rechtzeitiger Antwort
keine Antwort nach 30 s: ungewiss
Verlauf prüfen
späte Antwort ignoriert
0 s
10 s
20 s
30 s
40 s
  • Ü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.

FehlerErforderliche Interpretation
Speichern der Verwahrung schlägt fehlBeanspruchen Sie keine dauerhafte Quittung. Der Speicherung darf keine automatische Admission vorausgehen.
Annahme liegt vor, Historie ist verzögertBehalten 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.

Eine angenommene Steuerung wird nur erneut gesendet, wenn Codex bestätigt, dass sie nie angewendet wurde
Eine angenommene Steuerung wird nur erneut gesendet, wenn Codex bestätigt, dass sie nie angewendet wurdeStop and send now kann eine Steuerung zurückholen, die der laufende Turn angenommen, aber noch nicht verwendet hat. Nach einer Modellprüfung markiert der Desktop den Eintrag als angefordert und bittet Codex, die Steuerung aus den wartenden Eingaben von Run R zu lösen. Erst wenn Codex das bestätigt, widerruft der Desktop die Annahme, stoppt R, wartet, bis R zur Ruhe gekommen ist, und reiht den Eintrag mit derselben operationId wieder ein, sodass er seinen eigenen Turn startet.
Agenten-Runs
Wartende Eingabenvon Run R
Outbox-Eintrag
Operations­register
Run R
gestoppt und zur Ruhe gekommen
eigener Run
dieselbe operationId
wartet auf Anwendung
nie angewendet
sending
angefordert
freigegeben
Annahme für Run R
Stop and send now
Lösen anfragen
detachedForReplay
widerrufen
R stoppen
eigener Turn, Auto-Drain an
Jede andere Antwort oder keine Antwort sendet nichts erneut: applied, recording oder ein geänderter Turn halten den Eintrag mit dem Grund und abgeschaltetem Auto-Drain.
Kommt Run R nicht zur Ruhe, wartet der Eintrag als freigegeben. Ein späteres Lesen des Verlaufs, das die Nachricht nicht findet, reiht sie wieder ein.
  • 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.