diff --git a/TODO.md b/TODO.md index eb99a67..df04727 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,5 @@ # Bugs -- Codex 0.163 notifications byre doesn't know - The service's codex is 0.163.0, and its app-server sends `thread/readState/changed`, which `internal/codex` rejects as `unrecognised method` (a `protocol_errors` entry in `/api/admin/status`). Regenerate the types with `go generate ./internal/codex` against the installed CLI and handle or ignore the new methods. - # M1 — One agent end to end - Cancel a queued message diff --git a/docs/codex-protocol.md b/docs/codex-protocol.md index c112288..eafba8b 100644 --- a/docs/codex-protocol.md +++ b/docs/codex-protocol.md @@ -43,7 +43,7 @@ Closing stdin ends the process. - `turn/started`, `turn/completed` (`turn.status` `completed`, `interrupted` or `failed` with `turn.error`). A failed request to the model also sends an `error` notification first, with `willRetry`. - `item/started` and `item/completed` with a `ThreadItem`: `userMessage`, `agentMessage` (`text`), `reasoning`, `commandExecution` (`command`, `aggregatedOutput`, `exitCode`), `fileChange`, `mcpToolCall`, `contextCompaction` and others. - `item/agentMessage/delta` (`itemId`, `delta`) streams an agent message; the deltas join to the completed item's `text`. `item/commandExecution/outputDelta` and the reasoning deltas stream the same way. -- `thread/tokenUsage/updated` carries `last` and `total` token counts and `modelContextWindow`; `account/rateLimits/updated` the account's rate-limit windows (the same snapshot `account/rateLimits/read` returns on request, as `rateLimits`); `thread/status/changed`, `mcpServer/startupStatus/updated`, `account/updated` and `remoteControl/status/changed` also arrive. +- `thread/tokenUsage/updated` carries `last` and `total` token counts and `modelContextWindow`; `account/rateLimits/updated` the account's rate-limit windows (the same snapshot `account/rateLimits/read` returns on request, as `rateLimits`); `thread/status/changed`, `thread/readState/changed`, `mcpServer/startupStatus/updated`, `account/updated` and `remoteControl/status/changed` also arrive. - Lines that aren't a JSON object, don't parse, or carry a notification method outside `notificationParams` go to `Options.OnBadLine`; parsed notifications are still delivered as events. `Event.Decode` returns the notification's generated params type. Besides `item/tool/call`, server requests (approvals, user input) shouldn't arrive with approvals off; if one does, command and file-change approvals are accepted and anything else gets a JSON-RPC error. diff --git a/internal/codex/protocol.gen.go b/internal/codex/protocol.gen.go index 3458573..4604acb 100644 --- a/internal/codex/protocol.gen.go +++ b/internal/codex/protocol.gen.go @@ -1,10 +1,10 @@ -// Code generated by go run ./gen from the codex-cli 0.159.0 app-server schema. DO NOT EDIT. +// Code generated by go run ./gen from the codex-cli 0.163.0 app-server schema. DO NOT EDIT. package codex import "encoding/json" -const SchemaVersion = "codex-cli 0.159.0" +const SchemaVersion = "codex-cli 0.163.0" const ( MethodInitialize = "initialize" @@ -20,6 +20,7 @@ const ( MethodError = "error" MethodThreadStarted = "thread/started" MethodThreadStatusChanged = "thread/status/changed" + MethodThreadReadStateChanged = "thread/readState/changed" MethodThreadArchived = "thread/archived" MethodThreadDeleted = "thread/deleted" MethodThreadUnarchived = "thread/unarchived" @@ -29,6 +30,7 @@ const ( MethodThreadNameUpdated = "thread/name/updated" MethodThreadAttachmentUpdated = "thread/attachment/updated" MethodThreadGoalUpdated = "thread/goal/updated" + MethodThreadPredictionUpdated = "thread/prediction/updated" MethodThreadGoalCleared = "thread/goal/cleared" MethodThreadQueueChanged = "thread/queue/changed" MethodProjectChanged = "project/changed" @@ -130,6 +132,7 @@ var notificationParams = map[string]func() any{ MethodError: func() any { return &ErrorNotification{} }, MethodThreadStarted: func() any { return &ThreadStartedNotification{} }, MethodThreadStatusChanged: func() any { return &ThreadStatusChangedNotification{} }, + MethodThreadReadStateChanged: func() any { return &ThreadReadStateChangedNotification{} }, MethodThreadArchived: func() any { return &ThreadArchivedNotification{} }, MethodThreadDeleted: func() any { return &ThreadDeletedNotification{} }, MethodThreadUnarchived: func() any { return &ThreadUnarchivedNotification{} }, @@ -139,6 +142,7 @@ var notificationParams = map[string]func() any{ MethodThreadNameUpdated: func() any { return &ThreadNameUpdatedNotification{} }, MethodThreadAttachmentUpdated: func() any { return &ThreadAttachmentUpdatedNotification{} }, MethodThreadGoalUpdated: func() any { return &ThreadGoalUpdatedNotification{} }, + MethodThreadPredictionUpdated: func() any { return &ThreadPredictionUpdatedNotification{} }, MethodThreadGoalCleared: func() any { return &ThreadGoalClearedNotification{} }, MethodThreadQueueChanged: func() any { return &ThreadQueueChangedNotification{} }, MethodProjectChanged: func() any { return &ProjectChangedNotification{} }, @@ -367,8 +371,9 @@ const ( ) const ( - MessagePhaseCommentary MessagePhase = "commentary" - MessagePhaseFinalAnswer MessagePhase = "final_answer" + MessagePhaseCommentary MessagePhase = "commentary" + MessagePhasePartialAnswer MessagePhase = "partial_answer" + MessagePhaseFinalAnswer MessagePhase = "final_answer" ) const ( @@ -489,6 +494,7 @@ const ( ) const ( + ResponseItemTypeAdditionalTools = "additional_tools" ResponseItemTypeMessage = "message" ResponseItemTypeAgentMessage = "agent_message" ResponseItemTypeReasoning = "reasoning" @@ -518,6 +524,11 @@ const ( ModeKindDefault ModeKind = "default" ) +const ( + ThreadUnreadPositionTypeThreadStart = "threadStart" + ThreadUnreadPositionTypeTurn = "turn" +) + const ( AdditionalContextKindUntrusted AdditionalContextKind = "untrusted" AdditionalContextKindApplication AdditionalContextKind = "application" @@ -591,6 +602,11 @@ const ( ThreadGoalStatusComplete ThreadGoalStatus = "complete" ) +const ( + ThreadPredictionResultTypeCompleted = "completed" + ThreadPredictionResultTypeFailed = "failed" +) + const ( ProjectChangeTypeCreated ProjectChangeType = "created" ProjectChangeTypeUpdated ProjectChangeType = "updated" @@ -1079,6 +1095,7 @@ type MisalignmentSteer struct { type MisalignmentErrorDetails struct { DetailedExplanation string `json:"detailedExplanation,omitempty"` ErrorType string `json:"errorType,omitempty"` + ReviewTarget string `json:"reviewTarget,omitempty"` Steer *MisalignmentSteer `json:"steer,omitempty"` } @@ -1297,6 +1314,7 @@ type Turn struct { ID string `json:"id"` Items []ThreadItem `json:"items"` ItemsView TurnItemsView `json:"itemsView,omitempty"` + RootTurnID string `json:"rootTurnId,omitempty"` StartedAt int64 `json:"startedAt,omitempty"` Status TurnStatus `json:"status"` } @@ -1371,12 +1389,14 @@ type ResponsesApiWebSearchAction struct { } type ContentItem struct { - AudioURL string `json:"audio_url,omitempty"` - Detail ImageDetail `json:"detail,omitempty"` - FileID string `json:"file_id,omitempty"` - ImageURL string `json:"image_url,omitempty"` - Text string `json:"text,omitempty"` - Type string `json:"type"` + Annotations []json.RawMessage `json:"annotations,omitempty"` + AudioURL string `json:"audio_url,omitempty"` + Detail ImageDetail `json:"detail,omitempty"` + FileID string `json:"file_id,omitempty"` + ImageURL string `json:"image_url,omitempty"` + Logprobs []json.RawMessage `json:"logprobs,omitempty"` + Text string `json:"text,omitempty"` + Type string `json:"type"` } type AgentMessageInputContent struct { @@ -1502,26 +1522,27 @@ type ThreadResumeResponse struct { } type ThreadForkParams struct { - ApprovalPolicy AskForApproval `json:"approvalPolicy,omitempty"` - ApprovalsReviewer ApprovalsReviewer `json:"approvalsReviewer,omitempty"` - BaseInstructions string `json:"baseInstructions,omitempty"` - BeforeTurnID string `json:"beforeTurnId,omitempty"` - Config map[string]any `json:"config,omitempty"` - Cwd string `json:"cwd,omitempty"` - DeferGoalContinuation bool `json:"deferGoalContinuation,omitempty"` - DeveloperInstructions string `json:"developerInstructions,omitempty"` - Ephemeral bool `json:"ephemeral,omitempty"` - ExcludeTurns bool `json:"excludeTurns,omitempty"` - LastTurnID string `json:"lastTurnId,omitempty"` - Model string `json:"model,omitempty"` - ModelProvider string `json:"modelProvider,omitempty"` - Path string `json:"path,omitempty"` - Permissions string `json:"permissions,omitempty"` - RuntimeWorkspaceRoots []AbsolutePathBuf `json:"runtimeWorkspaceRoots,omitempty"` - Sandbox SandboxMode `json:"sandbox,omitempty"` - ServiceTier string `json:"serviceTier,omitempty"` - ThreadID string `json:"threadId"` - ThreadSource ThreadSource `json:"threadSource,omitempty"` + ApprovalPolicy AskForApproval `json:"approvalPolicy,omitempty"` + ApprovalsReviewer ApprovalsReviewer `json:"approvalsReviewer,omitempty"` + BaseInstructions string `json:"baseInstructions,omitempty"` + BeforeTurnID string `json:"beforeTurnId,omitempty"` + Config map[string]any `json:"config,omitempty"` + Cwd string `json:"cwd,omitempty"` + DeferGoalContinuation bool `json:"deferGoalContinuation,omitempty"` + DeveloperInstructions string `json:"developerInstructions,omitempty"` + Ephemeral bool `json:"ephemeral,omitempty"` + ExcludeTurns bool `json:"excludeTurns,omitempty"` + ExperimentalPredictionMode bool `json:"experimentalPredictionMode,omitempty"` + LastTurnID string `json:"lastTurnId,omitempty"` + Model string `json:"model,omitempty"` + ModelProvider string `json:"modelProvider,omitempty"` + Path string `json:"path,omitempty"` + Permissions string `json:"permissions,omitempty"` + RuntimeWorkspaceRoots []AbsolutePathBuf `json:"runtimeWorkspaceRoots,omitempty"` + Sandbox SandboxMode `json:"sandbox,omitempty"` + ServiceTier string `json:"serviceTier,omitempty"` + ThreadID string `json:"threadId"` + ThreadSource ThreadSource `json:"threadSource,omitempty"` } type ThreadForkResponse struct { @@ -1552,8 +1573,19 @@ type ThreadReadParams struct { ThreadID string `json:"threadId"` } +type ThreadUnreadPosition struct { + TurnID string `json:"turnId,omitempty"` + Type string `json:"type"` +} + +type ThreadReadState struct { + FirstUnread *ThreadUnreadPosition `json:"firstUnread,omitempty"` + Revision string `json:"revision"` +} + type ThreadReadResponse struct { - Thread Thread `json:"thread"` + ReadState *ThreadReadState `json:"readState,omitempty"` + Thread Thread `json:"thread"` } type AdditionalContextKind string @@ -1571,6 +1603,7 @@ type TurnToolOutput struct { Name string `json:"name"` Namespace string `json:"namespace,omitempty"` Output FunctionCallOutputBody `json:"output"` + Retain bool `json:"retain,omitempty"` } type TurnStartParams struct { @@ -1588,9 +1621,11 @@ type TurnStartParams struct { Model string `json:"model,omitempty"` MultiAgentMode MultiAgentMode `json:"multiAgentMode,omitempty"` OutputSchema json.RawMessage `json:"outputSchema,omitempty"` + ParentTurnID string `json:"parentTurnId,omitempty"` Permissions string `json:"permissions,omitempty"` Personality Personality `json:"personality,omitempty"` ResponsesapiClientMetadata map[string]string `json:"responsesapiClientMetadata,omitempty"` + RootTurnID string `json:"rootTurnId,omitempty"` RuntimeWorkspaceRoots []AbsolutePathBuf `json:"runtimeWorkspaceRoots,omitempty"` SandboxPolicy *SandboxPolicy `json:"sandboxPolicy,omitempty"` ServiceTier string `json:"serviceTier,omitempty"` @@ -1710,6 +1745,11 @@ type ThreadStatusChangedNotification struct { ThreadID string `json:"threadId"` } +type ThreadReadStateChangedNotification struct { + ReadState ThreadReadState `json:"readState"` + ThreadID string `json:"threadId"` +} + type ThreadArchivedNotification struct { ThreadID string `json:"threadId"` } @@ -1766,6 +1806,17 @@ type ThreadGoalUpdatedNotification struct { TurnID string `json:"turnId,omitempty"` } +type ThreadPredictionResult struct { + Text string `json:"text,omitempty"` + Type string `json:"type"` +} + +type ThreadPredictionUpdatedNotification struct { + Result ThreadPredictionResult `json:"result"` + SourceTurnID string `json:"sourceTurnId"` + ThreadID string `json:"threadId"` +} + type ThreadGoalClearedNotification struct { ThreadID string `json:"threadId"` } @@ -2119,6 +2170,7 @@ type McpToolCallProgressNotification struct { type McpServerOauthLoginCompletedNotification struct { Error string `json:"error,omitempty"` + LoginID string `json:"loginId,omitempty"` Name string `json:"name"` Success bool `json:"success"` ThreadID string `json:"threadId,omitempty"`