Zum Artikel springen
HB CodeDocsApp herunterladen

HandbuchArchitektur

Codex-Turns: Steuern, Freigaben, Ziele und Wiederherstellung

Was in einem Codex-Run passiert: wie ein Turn startet und gesteuert wird, wer eine Freigabe beantwortet, wie ein Ziel viele Turns zu einem Run verbindet, wie Stop funktioniert und was der Desktop tut, wenn ein Turn seinen Kindprozess verliert.

Gegen den Quellcode geprüft am 30. September 2026

Auf dieser Seite

Ein Thread, ein Run: Start, Besitzer und Steuern

Ein Codex-Run in HB Code ist eine Leser-Task, die einem Turn oder einer Kette von Turns auf einem Codex-Thread folgt. Alles in diesem Kapitel hängt an diesem Leser: Freigaben erreichen ihn über die Turn-Route, Stop spricht mit ihm über einen Steuerkanal, ein Ziel gibt ihm den nächsten Turn, und die Wiederherstellung gibt ihm eine neue Route. Der Prozess, der Actor und die Turn-Route stehen im Kapitel zum App-Server. Die Outbox, die entscheidet, wann eine Nachricht gesendet wird, steht im Kapitel zur Nachrichtenzustellung.

SchrittWas der Desktop tut und was ein Fehler bedeutet
Thread öffnenSendet thread/start für eine Session ohne Codex-Thread oder thread/resume mit excludeTurns: true für eine verknüpfte. Ein Ziel, das ein Kind-Thread ist, wird auf seinen Root-Thread umgeleitet: Der Desktop folgt parentThreadId mit thread/read über höchstens 16 Vorfahren. Bei einem Fehler: Nichts wurde gesendet. Die Nachricht bleibt in der Outbox.
Thread beanspruchenSchreibt den Besitzer-Eintrag für diese Codex-Thread-ID: App-Session, Run und die pid des Codex-Kindprozesses. Bei einem Fehler: Ein anderer Run besitzt den Thread. Das Senden endet mit „Codex thread … is already running for session …“.
Start-SperreHält fest, dass dieser Run in dieser Session einen Turn startet. Kein Abschluss kann den Run schließen, bevor der Turn registriert ist. Bei einem Fehler: Ein anderer Turn-Start besitzt die Session. Nichts wurde gesendet.
turn/startSchreibt den Registereintrag „sending“ und sendet dann turn/start mit threadId, input, clientUserMessageId (der Operations-ID), Modell, Aufwand und der Zugriffsstufe. Ab hier ist das Ergebnis ungewiss. Der Desktop gibt die Antwort nach 31 Sekunden auf.
Turn registrierenSpeichert den aktiven Turn für die App-Session: Laufzeitpaar, Run, Thread, Turn und einen Steuerkanal mit 16 Plätzen. Danach weckt er die Steuerungs-Bahn der Outbox. Bei einem Fehler: Der Desktop gibt den Turn auf, den Codex schon gestartet hat.
Turn lesenDer Leser nimmt Benachrichtigungen von der Turn-Route bis turn/completed und sucht dann nach einem Ziel. Bei einem Fehler: Siehe Fehler und Wiederherstellung weiter unten.

Der Besitzer-Eintrag ist eine Map im Speicher des Desktops mit der Codex-Thread-ID als Schlüssel. Er verhindert, dass zwei App-Sessions, die denselben Thread verknüpfen, ihn gleichzeitig ausführen. Derselbe Run kann ohne Fehler erneut beanspruchen. Ein veralteter Besitzer wird entfernt, wenn sein eingetragener Codex-Kindprozess tot ist. Hat der Eintrag keine pid, wird er nach 45 Sekunden entfernt, und nur, wenn der Run nicht mehr aktiv ist. Die Sperre wird nach thread/unload freigegeben und bevor die Abschlüsse die Outbox wecken, daher findet die nächste wartende Nachricht den Thread frei.

Steuern fügt dem Turn, der gerade läuft, eine Nachricht hinzu. Der Desktop sendet turn/steer auf dem Laufzeitpaar, dem der aktive Turn gehört. Er öffnet keinen Thread, startet keinen Turn und beansprucht keinen Besitzer, denn der Leser, der schon läuft, behält alle drei.

Feld von turn/steerWert
threadIdDer Thread des aktiven Turns.
expectedTurnIdDie Turn-ID, die der Desktop registriert hat. Codex muss die Steuerung ablehnen, wenn ein anderer Turn aktiv ist.
clientUserMessageIdDie Operations-ID des Outbox-Eintrags. Dieselbe ID benennt die Nachricht später im Verlauf.
inputDer Nachrichtentext und die Anhänge, aufgebaut wie der input von turn/start.
AntwortWas sie bedeutet und was mit der Nachricht geschieht
turnId gleich expectedTurnIdCodex hat die Nachricht in den laufenden Turn übernommen. Die Operations-ID kommt in die Liste der angenommenen Steuerungen des Turns, und die Annahme wird gespeichert.
JSON-RPC-Fehler -32600Codex hat die Steuerung abgelehnt. Codex sendet diesen Code, wenn kein Turn aktiv ist, wenn der aktive Turn eine andere ID hat und wenn der Turn ein Review oder eine Komprimierung ist. Der Desktop liest nur diesen einen Code als „nicht zugelassen“. Die Nachricht bleibt in der Warteschlange.
turnId eines anderen TurnsCodex hat sie für einen Turn angenommen, den der Desktop nicht erwartet hat. Ungewiss. Der Desktop sendet sie nicht erneut. Prüfen Sie die Timeline.
Jeder andere Fehler oder ein TimeoutDie Anfrage kann angekommen sein oder auch nicht. Ungewiss, mit derselben Behandlung.
Kein aktiver Turn im Desktop oder ein Turn eines anderen RunsDer Desktop hat turn/steer nicht gesendet. Die Nachricht bleibt in der Warteschlange.

Stop and send now braucht einen weiteren Aufruf. Eine Steuerung, die Codex angenommen hat, kann im Turn noch als wartende Eingabe liegen. Der Desktop sendet turn/detachPendingInputForReplay mit derselben threadId, expectedTurnId und clientUserMessageId. Die Antworten detachedForReplay und alreadyDetachedForReplay erlauben die Wiederholung in einem neuen Turn. Die Antwort applied bedeutet, dass das Modell die Nachricht schon hat, also startet keine Wiederholung. Die Antworten recording und staleTarget sowie jeder Fehler blockieren die Wiederholung ebenfalls.

Wer eine Freigabe beantwortet

Codex bittet mit einer JSON-RPC-Anfrage um eine Freigabe und wartet auf die Antwort. Der Actor dieses Codex-Kindprozesses hält jede offene Anfrage in einer Map und muss jemanden finden, der sie anzeigen kann. Eine Anfrage, die niemand anzeigen kann, wird abgelehnt, denn ein Turn, der auf eine Antwort wartet, die nicht kommen kann, würde nie enden.

Eine Codex-Freigabe wartet nur auf einen Menschen, solange jemand sie anzeigen kann
Eine Codex-Freigabe wartet nur auf einen Menschen, solange jemand sie anzeigen kannSechs Bahnen über einer Achse in Sekunden, maßstäblich. Jede Bahn ist eine Freigabeanfrage, die bei 0 Sekunden eintrifft. Eine Anfrage für einen Turn mit aktiver Route öffnet eine Karte ohne Frist, und ein Telefon nimmt sie nach 24 Sekunden mit run.chatResolveApproval an. Eine Anfrage aus einem Subagent-Thread wird vom Beobachter des Runs beansprucht und öffnet eine Karte in der Root-Session. Eine Subagent-Anfrage, die niemand beansprucht, wird abgelehnt, wenn ihr Fenster von 30 Sekunden endet. Eine Anfrage ohne Route und ohne Beobachter wird sofort abgelehnt. Eine Anfrage, deren Turn nach 14 Sekunden abschließt, wird mit dem Turn abgelehnt. Mit der Zugriffsstufe Unrestricted nimmt der Leser die Anfrage an, und es öffnet sich keine Karte.
Eigener TurnTurn-Route ist aktiv
Subagent-ThreadBeobachter beansprucht sie
Subagent-Threadniemand beansprucht sie
Kein Abnehmerkeine Route, kein Beobachter
Turn endet zuerstturn/completed
UnrestrictedapprovalPolicy never
Freigabeanfrage trifft ein
Karte in der Session, ohne Frist
angenommen
run.chatResolveApproval
Karte in der Root-Session, ohne Frist
beansprucht
wartet auf einen Anspruch: 30 s
abgelehnt
sofort abgelehnt
Karte offen
mit dem Turn abgelehnt
vom Leser angenommen, keine Karte
0 s
10 s
20 s
30 s
  • Turn-Routeitem/*/requestApproval

    Eine Anfrage für einen Turn, den ein Run liest, geht an diesen Leser. Die Karte hat keine Frist. Sie schließt mit einer Antwort, mit dem Ende des Turns oder mit serverRequest/resolved.

  • Anspruch eines BeobachtersUNROUTED_APPROVAL_CLAIM_TIMEOUT · 30 s

    Eine Anfrage ohne Route wird verteilt. Der Beobachter des Root-Runs oder eines beobachteten Threads muss sie innerhalb von 30 Sekunden beanspruchen. Nach einem Anspruch hat die Karte keine Frist.

  • Vom Desktop abgelehntdecline

    Sofort ohne Route und ohne Beobachter oder ohne unterstützte Entscheidung. Nach 30 Sekunden ohne Anspruch. Mit turn/completed, bei einem aufgegebenen Turn und wenn der Actor stoppt.

  • Antwortrun.chatResolveApproval

    Wird jedem laufenden Codex-Kindprozess angeboten, dem zuletzt verwendeten zuerst. Der Actor, der die Anfrage hält, prüft Anfrage-, Thread-, Turn- und Item-ID und schreibt die Antwort.

KarteAnfragemethode und angebotene Entscheidungen
Befehlitem/commandExecution/requestApproval. Bietet die Liste in availableDecisions an. Ohne Liste: accept, decline, cancel. Eine Netzwerkanfrage fügt acceptForSession hinzu. Ein vorgeschlagenes Befehlspräfix oder ein Netzwerk-Host fügt „breit annehmen“ hinzu.
Dateiänderungitem/fileChange/requestApproval. Bietet accept, acceptForSession, decline, cancel an.
Berechtigungenitem/permissions/requestApproval. Bietet accept, acceptForSession, decline an.
  • Die Zustellung hat zwei Wege. Eine Anfrage für einen Turn mit einer aktiven Route geht an den Leser dieses Turns, der die Karte in der Session zeigt. Eine Anfrage ohne Route wird an Beobachter verteilt. Anfragen aus Subagent-Threads nehmen diesen Weg, weil kein Leser ihre Turns besitzt.
  • Ein Beobachter muss eine verteilte Anfrage innerhalb von 30 Sekunden beanspruchen. Der Beobachter des Runs weist zuerst nach, dass der Thread zu seinem Root-Thread gehört, mit einer Grenze von 10 Sekunden für diese Prüfung. Eine nicht beanspruchte Anfrage wird abgelehnt, wenn die 30 Sekunden enden.
  • Eine Anfrage ohne unterstützte Entscheidung und eine Anfrage ohne Route und ohne Beobachter werden sofort abgelehnt.
  • Codex kann dieselbe Anfrage nach einer Wiederverbindung erneut senden. Eine identische Anfrage behält ihren Platz. Bei einer anderen Anfrage mit derselben ID lehnt der Desktop diese ID ab und schließt die Karte.
  • Wenn turn/completed eintrifft, lehnt der Actor jede offene Anfrage dieses Turns ab, bevor der Leser den Abschluss sieht. Das Aufgeben eines Turns und das Herunterfahren des Actors tun dasselbe.
  • serverRequest/resolved von Codex schließt die Karte als anderswo erledigt. Während des initialize-Handshakes kann es keine Karte geben, daher wird eine Freigabeanfrage abgelehnt.

Eine Antwort aus dem Desktop-Fenster oder von einem Telefon nimmt einen einzigen Weg. Ein Telefon ruft run.chatResolveApproval auf, und der Desktop bietet die Antwort jedem laufenden Codex-Kindprozess an, den zuletzt verwendeten zuerst. Jeder Actor vergleicht Anfrage-ID, Thread-ID, Turn-ID und Item-ID mit seiner Map, also nimmt genau ein Kindprozess sie an. Eine Entscheidung, die die Anfrage nicht angeboten hat, wird abgewiesen.

Die Zugriffsstufe Unrestricted sendet approvalPolicy never. Trifft trotzdem eine Anfrage ein, beantwortet der Leser sie ohne Karte. Er wählt die erste Entscheidung, die die Anfrage anbietet, aus acceptForSession, accept und „breit annehmen“. Die anderen Zugriffsstufen senden approvalPolicy on-request.

Ziele: viele Turns in einem Run

Ein Ziel ist Zustand, den Codex an einem Thread hält: eine Zielvorgabe, ein Status, ein Token-Budget und Zähler. Solange der Status active ist, startet Codex den nächsten Turn von selbst, wenn ein Turn endet. Der Desktop startet diese Turns nicht. Er findet jeden und hängt einen Leser an, und die ganze Kette bleibt ein Chat-Run mit einer Operations-ID.

Ein Codex-Ziel verbindet viele Turns zu einem Run, und Stop pausiert zuerst das Ziel
Ein Codex-Ziel verbindet viele Turns zu einem Run, und Stop pausiert zuerst das ZielVier Bahnen, nicht maßstäblich. Der Desktop setzt das Ziel mit thread/goal/set auf active. Codex startet Turn 1. Nach jedem Turn sendet der Leser thread/goal/get, liest active und hängt sich mit thread/resume an den nächsten Turn. Ein Chat-Run deckt alle drei Turns ab. Stop kommt während Turn 3. Der Desktop setzt das Ziel zuerst auf paused und sendet dann turn/interrupt. Turn 3 endet als interrupted, das Ziel ist pausiert, und der Run endet.
nach Stop
Zielstatusvon Codex gehalten
DesktopLeser des Runs
Turnsvon Codex gestartet
Chat-Runeine Operations-ID
active
paused
Turn 1
Turn 2
Turn 3
ein Run für alle drei Turns
thread/goal/set: active
goal/get: active
thread/resume hängt an
active
hängt an
zuerst set: paused
turn/interrupt
interrupted
das Ziel ist pausiert, also endet der Run
nicht maßstäblich
  • Zielthread/goal/get · set · clear

    Zustand, den Codex am Thread hält: Zielvorgabe, Status, Token-Budget und Zähler. Solange der Status active ist, startet Codex den nächsten Turn von selbst.

  • Anhängenthread/resume · 3 × 250 ms

    Nach jedem Turn liest der Leser das Ziel. Solange es active ist, setzt der Leser den Thread fort und nimmt den neuesten Turn: eine neue Turn-ID oder einen Turn, der noch läuft.

  • Ein RunOperations-ID

    Alle Turns der Kette gehören zu einem Chat-Run mit einer Operations-ID. Eine Steuerung, die zwischen zwei Turns gesendet wird, wartet auf den nächsten Turn.

  • Reihenfolge bei Stopstatus: paused · turn/interrupt

    Die Pause kommt zuerst und wiederholt bei Transportfehlern alle 250 ms. Das Unterbrechen hat 8 Sekunden, um den Leser zu erreichen, und 8 Sekunden für die Antwort. Bei einem Fehler gibt der Desktop den Turn auf.

MethodeVerwendung
thread/goal/getLiest das Ziel. Der Leser ruft es nach jedem Turn auf.
thread/goal/setSetzt objective, status oder tokenBudget. Ein tokenBudget von null löscht das Budget.
thread/goal/clearEntfernt das Ziel.

Ein Ziel hat die Felder objective, status, tokenBudget, tokensUsed, timeUsedSeconds, createdAt und updatedAt. Der Status ist einer von active, paused, blocked, usageLimited, budgetLimited und complete. Der Leser folgt der Kette nur, solange der Status active ist.

  • Ein Ziel-Run startet mit thread/goal/set und dem Status active. Er sendet kein turn/start. Codex startet den ersten Turn.
  • Nach jedem Turn sendet der Leser thread/goal/get. Solange das Ziel active ist, sendet er thread/resume mit excludeTurns: false und nimmt den neuesten Turn. Ein Turn zählt, wenn seine ID neu ist oder wenn er noch läuft. Der Leser versucht es 3-mal im Abstand von 250 ms und liest dann das Ziel erneut.
  • Ein laufender Turn bekommt eine Turn-Route und wird wie jeder andere Turn gelesen. Ein Turn, der schon abgeschlossen ist, wird aus dem Snapshot in der resume-Antwort abgeschlossen.
  • Jeder Codex-Chat-Run endet mit derselben Prüfung. Eine Nachricht an einen Thread mit einem aktiven Ziel bleibt daher ein Run, bis das Ziel den Status active verlässt. Ein Run, der kein aktives Ziel findet, sucht trotzdem einmal mit thread/resume nach einem neueren Turn und endet dann.
  • Eine Steuerung, die zwischen zwei Turns eintrifft, wartet. Jeder neue Turn weckt die Steuerungs-Bahn der Outbox erneut.
  • Ein Ziel-Run entlädt seinen Thread am Ende mit thread/unload. Ein fehlgeschlagenes Entladen wird dort nur protokolliert.

Stop ist eine Leiter mit vier Stufen

Stop markiert den Run als abgebrochen und arbeitet dann eine Leiter ab. Die Reihenfolge ist für Ziele wichtig: Einem Turn, der unterbrochen wird, während sein Ziel noch active ist, würde sofort ein neuer Turn folgen.

SchrittAufruf, Grenze und Fehler
Auf den Turn wartenKeiner. Ein Run, der noch keinen registrierten Turn hat, wird alle 25 ms geprüft. Grenze: 45 Sekunden. Bei einem Fehler: Stop meldet, dass der Abbruch nicht bestätigt wurde. Der Run läuft weiter.
Ziel pausierenthread/goal/set mit dem Status paused. Grenze: Wiederholt bei Transportfehlern alle 250 ms, ohne Obergrenze. Bei einem Fehler: „No goal exists“ zählt als erledigt. Ein dauerhafter Fehler löscht die Abbruchmarke, und der Run läuft weiter.
Unterbrechenturn/interrupt, gesendet vom Leser des Turns über dessen Steuerkanal. Grenze: 8 Sekunden, um den Leser zu erreichen, dann 8 Sekunden für die Antwort. Bei einem Fehler: Der Desktop geht zur nächsten Stufe.
AufgebenDer Actor lehnt die offenen Freigaben des Turns ab, verwirft die Turn-Route und schreibt turn/interrupt selbst. Grenze: 5 Sekunden, um den Befehl einzureihen. Bei einem Fehler: Stop meldet beide Fehler.

Codex beantwortet turn/interrupt, wenn der Turn angehalten hat, und sendet turn/completed mit dem Status interrupted. Der Leser nimmt diesen Abschluss als Ende des Turns, und der Run endet als abgebrochen. Einen Run, der zwischen turn/start und der Registrierung des Turns abgebrochen wurde, behandelt der Run selbst: Er pausiert das Ziel und gibt den neuen Turn auf, und er wiederholt beides bei Transportfehlern alle 250 ms.

Die Fünf-Sekunden-Regel nach einem Fehler

Codex meldet ein Problem in einem Turn mit einer error-Benachrichtigung, und das Feld willRetry sagt, ob Codex weitermacht. Der Fehler allein beendet den Turn nie. Der Turn endet mit turn/completed, und der Leser wartet darauf, aber nur 5 Sekunden.

Nach einem Fehler ohne erneuten Versuch hat ein Codex-Turn 5 Sekunden für den Abschluss
Nach einem Fehler ohne erneuten Versuch hat ein Codex-Turn 5 Sekunden für den AbschlussDrei Turns auf einer Achse in Sekunden, maßstäblich. Turn A bekommt einen Fehler mit willRetry: true und läuft weiter. Bei 0 Sekunden bekommt er einen Fehler mit willRetry: false. turn/completed folgt 1,8 Sekunden später, und der Turn scheitert mit dem gespeicherten Fehler. Turn B bekommt denselben Fehler bei 0 Sekunden und kein turn/completed. Der Leser wartet 5 Sekunden, und der Turn sieht weiter wie ein laufender Turn aus. Dann lässt der Leser ihn scheitern. Turn C hat keinen Fehler. Nach turn/completed liest der Leser 75 Millisekunden weiter, maßstäblich als dünner Balken gezeichnet, und verwirft dann die Route.
Turn AAbschluss folgt
Turn Bnichts folgt
Turn Ckein Fehler
Turn läuft
error, willRetry: true: läuft weiter
wartet
fehlgeschlagen, mit gespeichertem Fehler
error, willRetry: false
turn/completed
Turn läuft
kein turn/completed: wartet 5 s
Turn scheitert
der Turn sieht weiter wie ein laufender Turn aus
Turn läuft
abgeschlossen, Route verworfen
turn/completed
75 ms Drain
0 s
1 s
2 s
3 s
4 s
5 s
  • Fehler mit erneutem Versucherror { willRetry: true }

    Der Leser ignoriert ihn. Codex versucht es erneut, und der Turn läuft weiter.

  • AbschlussfristTURN_FAILURE_SETTLEMENT_TIMEOUT · 5 s

    Beginnt mit dem ersten Fehler ohne erneuten Versuch. Der Fehler wird gespeichert. turn/completed innerhalb des Fensters beendet den Turn als fehlgeschlagen, welchen Status es auch nennt.

  • Frist endetFailed

    Es kam kein turn/completed. Der Leser lässt den Turn mit dem gespeicherten Fehler scheitern und verwirft die Turn-Route. Er sendet kein turn/interrupt.

  • DrainTURN_POST_TERMINAL_DRAIN_TIMEOUT · 75 ms

    Nach einem sauberen turn/completed nimmt der Leser späte Item-Benachrichtigungen an, bis 75 ms ohne eine vergehen. Dann schließt er offene Freigabekarten und verwirft die Route.

Was der Leser siehtErgebnis des Turns
error mit willRetry: trueNichts ändert sich. Codex versucht es erneut.
error mit willRetry: falseDer Fehler wird gespeichert, und die Frist von 5 Sekunden beginnt. Ein zweiter Fehler ersetzt den gespeicherten und behält die erste Frist.
turn/completed mit dem Status failedFehlgeschlagen, mit dem Fehler des Abschlusses, sonst mit dem gespeicherten Fehler.
turn/completed mit dem Status completed nach einem gespeicherten FehlerFehlgeschlagen, mit dem gespeicherten Fehler.
turn/completed mit dem Status interruptedFehlgeschlagen, wenn ein Fehler gespeichert ist. Sonst unterbrochen, und der Run endet als abgebrochen.
Kein turn/completed innerhalb von 5 SekundenFehlgeschlagen, mit dem gespeicherten Fehler. Der Leser verwirft die Turn-Route.
Die Route schließt nach einem gespeicherten FehlerFehlgeschlagen, mit dem gespeicherten Fehler. Es wird kein Wiedereinstieg versucht.
turn/completed ohne FehlerAbgeschlossen. Der Leser liest weiter, bis 75 ms Stille vergehen, und verwirft dann die Route.

Der Leser wacht alle 100 ms auf, wenn keine Benachrichtigung eintrifft. Er nutzt diesen Takt für Stop-Anfragen und für die Frist, und ein stiller Turn scheitert nie allein wegen der Stille. Den Drain von 75 ms gibt es, weil Codex die letzten Item-Benachrichtigungen kurz nach turn/completed senden kann. Dieselben 5 Sekunden gelten für einen Subagent-Thread: Nach einem Fehler ohne erneuten Versuch zählt sein Thread nach 5 Sekunden nicht mehr als aktiv für den Kindprozess.

turn/completed und ein Fehler ohne erneuten Versuch werden auf einer vollen Turn-Route nie verworfen. Sie warten in einer eigenen Bahn in der Reihenfolge ihres Eintreffens, und gewöhnliche Events für diesen Turn werden verworfen, solange einer wartet.

Geht die Turn-Route verloren, fragt der Desktop nach genau diesem Turn

Der Leser hat ein Signal für eine verlorene Verbindung: Seine Turn-Route schließt, während kein Fehler gespeichert ist. Der Actor schließt jede Route, wenn er stoppt, zum Beispiel wenn das stdout des Kindprozesses schließt. Der Desktop fragt Codex dann, was aus dem Turn geworden ist, und er fragt nach genau diesem Turn. Ein Turn kann nicht in einen anderen Prozess wechseln. Ein neuer Codex-Kindprozess lädt den Thread aus dem gespeicherten Verlauf und meldet einen Turn, der noch lief, als interrupted. Die Antwort ist nur dann inProgress, wenn der antwortende Kindprozess den Turn noch ausführt.

Geht der Codex-Kindprozess verloren, fragt der Leser einen neuen Kindprozess, was aus dem Turn geworden ist
Geht der Codex-Kindprozess verloren, fragt der Leser einen neuen Kindprozess, was aus dem Turn geworden istVier Bahnen, nicht maßstäblich. Der Codex-Kindprozess A führt Turn T aus, und der Leser nimmt Benachrichtigungen von Route A. Das stdout von Kindprozess A schließt. Die Route schließt, und der Leser sieht eine verlorene Verbindung. Er wartet höchstens 1 Sekunde und least einen Client für dasselbe Profilpaar, was Kindprozess B startet. Der Leser sendet thread/resume und nimmt Turn T aus der Antwort. Kindprozess B lädt den Thread aus dem gespeicherten Verlauf und führt keinen Turn aus, also meldet er Turn T als interrupted. Es öffnet sich keine Route. Die Timeline bekommt während der Lücke keine neuen Zeilen. Dann werden ihre Zeilen mit dem Snapshot des Turns abgeglichen. Der Run hat kein aktives Ziel, also scheitert er mit der Meldung, dass der Turn unterbrochen wurde.
Kindprozess Acodex-app-server
Kindprozess Bdasselbe Profilpaar
Turn-Leserein Chat-Run
TimelineDesktop und Telefone
Turn T läuft
stdout schließt
Thread geladen, kein Turn läuft
von der Registry gestartet
liest Route A
wartet max. 1 s
der Run scheitert: Turn unterbrochen
Live-Zeilen
keine neuen Zeilen
Zeilen mit dem Snapshot abgeglichen
thread/resume, genau dieser Turn
interrupted
Route schließt: Verbindung verloren
nicht maßstäblich
Führt der antwortende Kindprozess den Turn noch aus, ist die Antwort inProgress. Dann öffnet der Actor eine neue Route, und der Leser liest weiter. Ist die Antwort completed, schließt der Snapshot den Run ab. Mit einem aktiven Ziel wartet der Run auf den nächsten Turn des Ziels.
  • Verlorene VerbindungConnectionLost

    Die Turn-Route schließt, und kein Fehler ist gespeichert. Nur dieser Fehler startet einen Wiedereinstieg. Bei jedem anderen Fehler ohne Endstatus gibt der Desktop den Turn auf.

  • Neuer Clientlease_codex_app_server_for_runtime

    Der Leser wartet bis zu 1 Sekunde darauf, dass der alte Client schließt, und least dasselbe Laufzeitpaar. Die Registry startet einen neuen Kindprozess, wenn der alte weg ist.

  • Wiedereinstiegthread/resume { excludeTurns: false }

    Der Desktop nimmt den Turn mit der erwarteten ID. Die festgehaltenen Zugriffseinstellungen des Turns, die pid des Besitzers und die Beobachter gehen auf den neuen Client über.

  • Antwortinterrupted · inProgress · completed · failed

    Ein neuer Kindprozess meldet einen Turn, der noch lief, als interrupted. Ohne Fehler scheitert der Run, oder er wartet auf den nächsten Turn eines aktiven Ziels. In einen Turn wird einmal wieder eingestiegen.

  • Nur eine verlorene Verbindung startet einen Wiedereinstieg. Bei jedem anderen Fehler, der kein Endstatus ist, gibt der Desktop den Turn mit turn/interrupt auf.
  • Der Leser wartet bis zu 1 Sekunde darauf, dass der alte Client schließt. Dann least er einen Client für dasselbe Laufzeitpaar, und die Registry startet einen neuen Kindprozess, wenn der alte weg ist.
  • Die Zugriffseinstellungen, die der alte Client für den Turn festgehalten hat, gehen auf den neuen Client über, und der Besitzer-Eintrag bekommt die neue pid.
  • Hat der Client gewechselt, werden die Beobachter für Subagent-Freigaben und für Agent-Nachrichten gestoppt und am neuen Client neu gestartet.
  • Der Wiedereinstieg ist thread/resume mit excludeTurns: false. Der Desktop nimmt den Turn mit der erwarteten ID aus der Antwort. Hat die Antwort keinen solchen Turn, scheitert der Run, und der Desktop gibt den Turn auf.
Status in der AntwortWas der Run tut
inProgressDer antwortende Kindprozess führt den Turn noch aus. Der Actor öffnet eine neue Turn-Route, und der Leser registriert den Turn erneut und liest weiter.
completedDer Snapshot schließt den Run ab. Es wird keine Route geöffnet.
interrupted ohne FehlerDie Antwort eines neuen Kindprozesses für einen Turn, der noch lief. Ein Run mit einem aktiven Ziel wartet auf den nächsten Turn des Ziels. Jeder andere Run scheitert mit „Codex app-server turn was interrupted“.
interrupted mit einem Fehler oder failedDer Run scheitert mit diesem Fehler.

Bei jeder Antwort gleicht der Desktop zuerst die Zeilen auf dem Bildschirm mit dem Snapshot des Turns ab. So bleibt die Arbeit, die Codex vor dem Verlust gespeichert hat, in der Timeline. In einen Turn wird einmal wieder eingestiegen. Scheitert auch die neue Route, endet der Run mit diesem Fehler. Zwischen zwei Turns eines Ziels hat der Leser keine Route, die er verlieren kann. Dort stellt er die Verbindung stattdessen bei Transportfehlern von thread/goal/get und thread/resume wieder her, höchstens 2-mal in Folge.

Kind-Threads, beobachtete Threads, Rollback

Ein Codex-Agent kann Subagents starten, und jeder Subagent ist ein eigener Thread unter dem Root-Thread. Kein Run des Desktops besitzt ihre Turns. Der Desktop listet sie auf, speichert, wo ihre Dateien liegen, und folgt einem nur live, solange ein Fenster ihn zeigt.

MechanismusWie es funktioniert und seine Grenzen
Kind-Listethread/list mit ancestorThreadId, sourceKinds: ["subAgentThreadSpawn"] und useStateDbOnly: true, auf dem Profil, dem der Root-Thread gehört. Threads, die die Session verknüpft und der Index nicht kennt, werden mit thread/source/read ergänzt. Grenzen: 100 Threads pro Seite, höchstens 25 Seiten. Eine längere Liste wird gekürzt und protokolliert.
Kind-Pfadthread/started für einen Kind-Thread nennt dessen JSONL-Pfad, und der Desktop speichert ihn. Ein Chat-Run wartet auf diese Speicherungen, bevor er endet. Eine fehlgeschlagene Speicherung nimmt den Codex-Kindprozess außer Dienst, wie ein fehlgeschlagenes thread/unload.
Beobachteter ThreadEin Fenster, das einen Subagent zeigt, registriert eine Beobachtung für das Paar aus Session und Thread. Die erste Beobachtung startet einen Folger, der die Benachrichtigungen des Threads ohne Route in Live-Zeilen umwandelt. Der Folger stoppt, wenn die letzte Beobachtung freigegeben ist und kein Turn des Threads live ist. Grenzen: Watch-ID höchstens 256 Bytes. Der Root des Threads muss der Root der Session sein, geprüft innerhalb von 10 Sekunden.
FolgerAbonniert die Aktivität und die Freigaben ohne Route des Clients. Wenn der Client verschwindet, abonniert er erneut. Nach dem Ende des Turns des Kind-Threads gleicht er die Live-Zeilen mit dem Verlauf ab. Grenzen: Abonniert nach 1 Sekunde erneut. 3 Abgleichsversuche.
Rollbackthread/resume mit excludeTurns: true, thread/turns/list mit limit 1 und absteigender Reihenfolge, dann thread/revert mit beforeTurnId. Grenzen: Abgewiesen, solange der neueste Turn inProgress ist, und für eine exakte externe JSONL-Quelle.
Live-Einstellungenthread/settings/update auf dem Laufzeitpaar des aktiven Turns, mit Modell und Aufwand zusammen, der Zugriffsstufe oder beidem. Ohne aktiven Turn wird nichts gesendet. Die gespeicherten Einstellungen gelten beim nächsten turn/start.

Ohne Beobachter folgt nichts einem Subagent-Thread. Seine Benachrichtigungen bleiben ohne Route, und der Desktop liest den Thread aus dem Verlauf, wenn Sie ihn öffnen. Eine Freigabe von einem Subagent braucht keine Beobachtung: Der Beobachter des Root-Runs beansprucht sie, wie der Abschnitt zu Freigaben beschreibt.