diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index d97a0ac6f4..da2f744b3b 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -6201,6 +6201,26 @@ }, "type": "object" }, + "ThreadSectionChangedNotification": { + "description": "Broadcast after a successful move into, within, or out of a section.", + "properties": { + "sectionId": { + "description": "Destination section, or `null` when the thread was removed from its section.", + "type": [ + "string", + "null" + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "sectionId", + "threadId" + ], + "type": "object" + }, "ThreadSettings": { "properties": { "activePermissionProfile": { @@ -7408,6 +7428,26 @@ "title": "Thread/name/updatedNotification", "type": "object" }, + { + "properties": { + "method": { + "enum": [ + "thread/section/changed" + ], + "title": "Thread/section/changedNotificationMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/ThreadSectionChangedNotification" + } + }, + "required": [ + "method", + "params" + ], + "title": "Thread/section/changedNotification", + "type": "object" + }, { "properties": { "method": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 22b81519fc..1e2d366694 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -4882,6 +4882,26 @@ "title": "Thread/name/updatedNotification", "type": "object" }, + { + "properties": { + "method": { + "enum": [ + "thread/section/changed" + ], + "title": "Thread/section/changedNotificationMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/v2/ThreadSectionChangedNotification" + } + }, + "required": [ + "method", + "params" + ], + "title": "Thread/section/changedNotification", + "type": "object" + }, { "properties": { "method": { @@ -25245,6 +25265,28 @@ }, "type": "object" }, + "ThreadSectionChangedNotification": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Broadcast after a successful move into, within, or out of a section.", + "properties": { + "sectionId": { + "description": "Destination section, or `null` when the thread was removed from its section.", + "type": [ + "string", + "null" + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "sectionId", + "threadId" + ], + "title": "ThreadSectionChangedNotification", + "type": "object" + }, "ThreadSectionCreateParams": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "Parameters for creating an independently persisted thread section.", diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 3204a638de..84707c0e18 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -17143,6 +17143,26 @@ "title": "Thread/name/updatedNotification", "type": "object" }, + { + "properties": { + "method": { + "enum": [ + "thread/section/changed" + ], + "title": "Thread/section/changedNotificationMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/ThreadSectionChangedNotification" + } + }, + "required": [ + "method", + "params" + ], + "title": "Thread/section/changedNotification", + "type": "object" + }, { "properties": { "method": { @@ -22948,6 +22968,28 @@ }, "type": "object" }, + "ThreadSectionChangedNotification": { + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Broadcast after a successful move into, within, or out of a section.", + "properties": { + "sectionId": { + "description": "Destination section, or `null` when the thread was removed from its section.", + "type": [ + "string", + "null" + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "sectionId", + "threadId" + ], + "title": "ThreadSectionChangedNotification", + "type": "object" + }, "ThreadSectionCreateParams": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "Parameters for creating an independently persisted thread section.", diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadSectionChangedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadSectionChangedNotification.json new file mode 100644 index 0000000000..c959b4b2e2 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadSectionChangedNotification.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Broadcast after a successful move into, within, or out of a section.", + "properties": { + "sectionId": { + "description": "Destination section, or `null` when the thread was removed from its section.", + "type": [ + "string", + "null" + ] + }, + "threadId": { + "type": "string" + } + }, + "required": [ + "sectionId", + "threadId" + ], + "title": "ThreadSectionChangedNotification", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst index cfe744de5b..93ab4e11c0 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst index 72a89ab3b2..1cadc724fc 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/typescript/ServerNotification.ts b/codex-rs/app-server-protocol/schema/typescript/ServerNotification.ts index 4af7a4307a..87fcbcbb7a 100644 --- a/codex-rs/app-server-protocol/schema/typescript/ServerNotification.ts +++ b/codex-rs/app-server-protocol/schema/typescript/ServerNotification.ts @@ -73,6 +73,7 @@ import type { ThreadRealtimeStartedNotification } from "./v2/ThreadRealtimeStart import type { ThreadRealtimeTranscriptDeltaNotification } from "./v2/ThreadRealtimeTranscriptDeltaNotification"; import type { ThreadRealtimeTranscriptDoneNotification } from "./v2/ThreadRealtimeTranscriptDoneNotification"; import type { ThreadRevertedNotification } from "./v2/ThreadRevertedNotification"; +import type { ThreadSectionChangedNotification } from "./v2/ThreadSectionChangedNotification"; import type { ThreadSettingsUpdatedNotification } from "./v2/ThreadSettingsUpdatedNotification"; import type { ThreadStartedNotification } from "./v2/ThreadStartedNotification"; import type { ThreadStatusChangedNotification } from "./v2/ThreadStatusChangedNotification"; @@ -90,4 +91,4 @@ import type { WindowsWorldWritableWarningNotification } from "./v2/WindowsWorldW /** * Notification sent from the server to the client. */ -export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/readState/changed", "params": ThreadReadStateChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/deleted", "params": ThreadDeletedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "thread/reverted", "params": ThreadRevertedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/attachment/updated", "params": ThreadAttachmentUpdatedNotification } | { "method": "thread/goal/updated", "params": ThreadGoalUpdatedNotification } | { "method": "thread/prediction/updated", "params": ThreadPredictionUpdatedNotification } | { "method": "thread/goal/cleared", "params": ThreadGoalClearedNotification } | { "method": "thread/queue/changed", "params": ThreadQueueChangedNotification } | { "method": "project/changed", "params": ProjectChangedNotification } | { "method": "thread/project/updated", "params": ThreadProjectUpdatedNotification } | { "method": "thread/environment/connected", "params": EnvironmentConnectionNotification } | { "method": "thread/environment/disconnected", "params": EnvironmentConnectionNotification } | { "method": "thread/settings/updated", "params": ThreadSettingsUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "autoApprovalReview/strictReviewRequired", "params": StrictReviewRequiredNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "rawResponse/completed", "params": RawResponseCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "process/outputDelta", "params": ProcessOutputDeltaNotification } | { "method": "process/exited", "params": ProcessExitedNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/fileChange/patchUpdated", "params": FileChangePatchUpdatedNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "mcpServer/event/stream/notification", "params": McpServerEventStreamNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/gatewayOAuth/changed", "params": GatewayOAuthChangedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "remoteControl/status/changed", "params": RemoteControlStatusChangedNotification } | { "method": "externalAgentConfig/import/progress", "params": ExternalAgentConfigImportProgressNotification } | { "method": "externalAgentConfig/import/completed", "params": ExternalAgentConfigImportCompletedNotification } | { "method": "fs/changed", "params": FsChangedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "model/verification", "params": ModelVerificationNotification } | { "method": "modelProvider/authRecoveryStarted", "params": AuthRecoveryNotification } | { "method": "modelProvider/authRecoveryCompleted", "params": AuthRecoveryNotification } | { "method": "turn/moderationMetadata", "params": TurnModerationMetadataNotification } | { "method": "model/safetyBuffering/updated", "params": ModelSafetyBufferingUpdatedNotification } | { "method": "warning", "params": WarningNotification } | { "method": "guardianWarning", "params": GuardianWarningNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/item/started", "params": ThreadRealtimeItemStartedNotification } | { "method": "thread/realtime/item/transcript/delta", "params": ThreadRealtimeItemTranscriptDeltaNotification } | { "method": "thread/realtime/item/completed", "params": ThreadRealtimeItemCompletedNotification } | { "method": "thread/realtime/transcript/delta", "params": ThreadRealtimeTranscriptDeltaNotification } | { "method": "thread/realtime/transcript/done", "params": ThreadRealtimeTranscriptDoneNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/sdp", "params": ThreadRealtimeSdpNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification }; +export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/readState/changed", "params": ThreadReadStateChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/deleted", "params": ThreadDeletedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "thread/reverted", "params": ThreadRevertedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/section/changed", "params": ThreadSectionChangedNotification } | { "method": "thread/attachment/updated", "params": ThreadAttachmentUpdatedNotification } | { "method": "thread/goal/updated", "params": ThreadGoalUpdatedNotification } | { "method": "thread/prediction/updated", "params": ThreadPredictionUpdatedNotification } | { "method": "thread/goal/cleared", "params": ThreadGoalClearedNotification } | { "method": "thread/queue/changed", "params": ThreadQueueChangedNotification } | { "method": "project/changed", "params": ProjectChangedNotification } | { "method": "thread/project/updated", "params": ThreadProjectUpdatedNotification } | { "method": "thread/environment/connected", "params": EnvironmentConnectionNotification } | { "method": "thread/environment/disconnected", "params": EnvironmentConnectionNotification } | { "method": "thread/settings/updated", "params": ThreadSettingsUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "autoApprovalReview/strictReviewRequired", "params": StrictReviewRequiredNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "rawResponse/completed", "params": RawResponseCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "process/outputDelta", "params": ProcessOutputDeltaNotification } | { "method": "process/exited", "params": ProcessExitedNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/fileChange/patchUpdated", "params": FileChangePatchUpdatedNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "mcpServer/event/stream/notification", "params": McpServerEventStreamNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/gatewayOAuth/changed", "params": GatewayOAuthChangedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "remoteControl/status/changed", "params": RemoteControlStatusChangedNotification } | { "method": "externalAgentConfig/import/progress", "params": ExternalAgentConfigImportProgressNotification } | { "method": "externalAgentConfig/import/completed", "params": ExternalAgentConfigImportCompletedNotification } | { "method": "fs/changed", "params": FsChangedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "model/verification", "params": ModelVerificationNotification } | { "method": "modelProvider/authRecoveryStarted", "params": AuthRecoveryNotification } | { "method": "modelProvider/authRecoveryCompleted", "params": AuthRecoveryNotification } | { "method": "turn/moderationMetadata", "params": TurnModerationMetadataNotification } | { "method": "model/safetyBuffering/updated", "params": ModelSafetyBufferingUpdatedNotification } | { "method": "warning", "params": WarningNotification } | { "method": "guardianWarning", "params": GuardianWarningNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/item/started", "params": ThreadRealtimeItemStartedNotification } | { "method": "thread/realtime/item/transcript/delta", "params": ThreadRealtimeItemTranscriptDeltaNotification } | { "method": "thread/realtime/item/completed", "params": ThreadRealtimeItemCompletedNotification } | { "method": "thread/realtime/transcript/delta", "params": ThreadRealtimeTranscriptDeltaNotification } | { "method": "thread/realtime/transcript/done", "params": ThreadRealtimeTranscriptDoneNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/sdp", "params": ThreadRealtimeSdpNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification }; diff --git a/codex-rs/app-server-protocol/schema/typescript/ServerNotificationEnvelope.ts b/codex-rs/app-server-protocol/schema/typescript/ServerNotificationEnvelope.ts index a5b07d304d..3bc76db45e 100644 --- a/codex-rs/app-server-protocol/schema/typescript/ServerNotificationEnvelope.ts +++ b/codex-rs/app-server-protocol/schema/typescript/ServerNotificationEnvelope.ts @@ -73,6 +73,7 @@ import type { ThreadRealtimeStartedNotification } from "./v2/ThreadRealtimeStart import type { ThreadRealtimeTranscriptDeltaNotification } from "./v2/ThreadRealtimeTranscriptDeltaNotification"; import type { ThreadRealtimeTranscriptDoneNotification } from "./v2/ThreadRealtimeTranscriptDoneNotification"; import type { ThreadRevertedNotification } from "./v2/ThreadRevertedNotification"; +import type { ThreadSectionChangedNotification } from "./v2/ThreadSectionChangedNotification"; import type { ThreadSettingsUpdatedNotification } from "./v2/ThreadSettingsUpdatedNotification"; import type { ThreadStartedNotification } from "./v2/ThreadStartedNotification"; import type { ThreadStatusChangedNotification } from "./v2/ThreadStatusChangedNotification"; @@ -100,4 +101,4 @@ export type ServerNotificationEnvelope = { * Optional so clients can decode notifications from older app-server * versions. Current app-server versions always populate it. */ -emittedAtMs?: number, } & ({ "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/readState/changed", "params": ThreadReadStateChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/deleted", "params": ThreadDeletedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "thread/reverted", "params": ThreadRevertedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/attachment/updated", "params": ThreadAttachmentUpdatedNotification } | { "method": "thread/goal/updated", "params": ThreadGoalUpdatedNotification } | { "method": "thread/prediction/updated", "params": ThreadPredictionUpdatedNotification } | { "method": "thread/goal/cleared", "params": ThreadGoalClearedNotification } | { "method": "thread/queue/changed", "params": ThreadQueueChangedNotification } | { "method": "project/changed", "params": ProjectChangedNotification } | { "method": "thread/project/updated", "params": ThreadProjectUpdatedNotification } | { "method": "thread/environment/connected", "params": EnvironmentConnectionNotification } | { "method": "thread/environment/disconnected", "params": EnvironmentConnectionNotification } | { "method": "thread/settings/updated", "params": ThreadSettingsUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "autoApprovalReview/strictReviewRequired", "params": StrictReviewRequiredNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "rawResponse/completed", "params": RawResponseCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "process/outputDelta", "params": ProcessOutputDeltaNotification } | { "method": "process/exited", "params": ProcessExitedNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/fileChange/patchUpdated", "params": FileChangePatchUpdatedNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "mcpServer/event/stream/notification", "params": McpServerEventStreamNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/gatewayOAuth/changed", "params": GatewayOAuthChangedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "remoteControl/status/changed", "params": RemoteControlStatusChangedNotification } | { "method": "externalAgentConfig/import/progress", "params": ExternalAgentConfigImportProgressNotification } | { "method": "externalAgentConfig/import/completed", "params": ExternalAgentConfigImportCompletedNotification } | { "method": "fs/changed", "params": FsChangedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "model/verification", "params": ModelVerificationNotification } | { "method": "modelProvider/authRecoveryStarted", "params": AuthRecoveryNotification } | { "method": "modelProvider/authRecoveryCompleted", "params": AuthRecoveryNotification } | { "method": "turn/moderationMetadata", "params": TurnModerationMetadataNotification } | { "method": "model/safetyBuffering/updated", "params": ModelSafetyBufferingUpdatedNotification } | { "method": "warning", "params": WarningNotification } | { "method": "guardianWarning", "params": GuardianWarningNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/item/started", "params": ThreadRealtimeItemStartedNotification } | { "method": "thread/realtime/item/transcript/delta", "params": ThreadRealtimeItemTranscriptDeltaNotification } | { "method": "thread/realtime/item/completed", "params": ThreadRealtimeItemCompletedNotification } | { "method": "thread/realtime/transcript/delta", "params": ThreadRealtimeTranscriptDeltaNotification } | { "method": "thread/realtime/transcript/done", "params": ThreadRealtimeTranscriptDoneNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/sdp", "params": ThreadRealtimeSdpNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification }); +emittedAtMs?: number, } & ({ "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/readState/changed", "params": ThreadReadStateChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/deleted", "params": ThreadDeletedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "thread/reverted", "params": ThreadRevertedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/section/changed", "params": ThreadSectionChangedNotification } | { "method": "thread/attachment/updated", "params": ThreadAttachmentUpdatedNotification } | { "method": "thread/goal/updated", "params": ThreadGoalUpdatedNotification } | { "method": "thread/prediction/updated", "params": ThreadPredictionUpdatedNotification } | { "method": "thread/goal/cleared", "params": ThreadGoalClearedNotification } | { "method": "thread/queue/changed", "params": ThreadQueueChangedNotification } | { "method": "project/changed", "params": ProjectChangedNotification } | { "method": "thread/project/updated", "params": ThreadProjectUpdatedNotification } | { "method": "thread/environment/connected", "params": EnvironmentConnectionNotification } | { "method": "thread/environment/disconnected", "params": EnvironmentConnectionNotification } | { "method": "thread/settings/updated", "params": ThreadSettingsUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "autoApprovalReview/strictReviewRequired", "params": StrictReviewRequiredNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "rawResponse/completed", "params": RawResponseCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "process/outputDelta", "params": ProcessOutputDeltaNotification } | { "method": "process/exited", "params": ProcessExitedNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "item/fileChange/patchUpdated", "params": FileChangePatchUpdatedNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "mcpServer/startupStatus/updated", "params": McpServerStatusUpdatedNotification } | { "method": "mcpServer/event/stream/notification", "params": McpServerEventStreamNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/gatewayOAuth/changed", "params": GatewayOAuthChangedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "remoteControl/status/changed", "params": RemoteControlStatusChangedNotification } | { "method": "externalAgentConfig/import/progress", "params": ExternalAgentConfigImportProgressNotification } | { "method": "externalAgentConfig/import/completed", "params": ExternalAgentConfigImportCompletedNotification } | { "method": "fs/changed", "params": FsChangedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "model/verification", "params": ModelVerificationNotification } | { "method": "modelProvider/authRecoveryStarted", "params": AuthRecoveryNotification } | { "method": "modelProvider/authRecoveryCompleted", "params": AuthRecoveryNotification } | { "method": "turn/moderationMetadata", "params": TurnModerationMetadataNotification } | { "method": "model/safetyBuffering/updated", "params": ModelSafetyBufferingUpdatedNotification } | { "method": "warning", "params": WarningNotification } | { "method": "guardianWarning", "params": GuardianWarningNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/item/started", "params": ThreadRealtimeItemStartedNotification } | { "method": "thread/realtime/item/transcript/delta", "params": ThreadRealtimeItemTranscriptDeltaNotification } | { "method": "thread/realtime/item/completed", "params": ThreadRealtimeItemCompletedNotification } | { "method": "thread/realtime/transcript/delta", "params": ThreadRealtimeTranscriptDeltaNotification } | { "method": "thread/realtime/transcript/done", "params": ThreadRealtimeTranscriptDoneNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/sdp", "params": ThreadRealtimeSdpNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification }); diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ThreadSectionChangedNotification.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadSectionChangedNotification.ts new file mode 100644 index 0000000000..96f124fba4 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ThreadSectionChangedNotification.ts @@ -0,0 +1,12 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Broadcast after a successful move into, within, or out of a section. + */ +export type ThreadSectionChangedNotification = { threadId: string, +/** + * Destination section, or `null` when the thread was removed from its section. + */ +sectionId: string | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index 4ec94e59a4..c536f8c9cd 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -582,6 +582,7 @@ export type { ThreadSearchResult } from "./ThreadSearchResult"; export type { ThreadSearchSortKey } from "./ThreadSearchSortKey"; export type { ThreadSection } from "./ThreadSection"; export type { ThreadSectionAppearance } from "./ThreadSectionAppearance"; +export type { ThreadSectionChangedNotification } from "./ThreadSectionChangedNotification"; export type { ThreadSectionCreateParams } from "./ThreadSectionCreateParams"; export type { ThreadSectionCreateResponse } from "./ThreadSectionCreateResponse"; export type { ThreadSectionDeleteParams } from "./ThreadSectionDeleteParams"; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index 0f33510e37..bf2ebde276 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -2017,6 +2017,7 @@ server_notification_definitions! { ThreadReverted => "thread/reverted" (v2::ThreadRevertedNotification), SkillsChanged => "skills/changed" (v2::SkillsChangedNotification), ThreadNameUpdated => "thread/name/updated" (v2::ThreadNameUpdatedNotification), + ThreadSectionChanged => "thread/section/changed" (v2::ThreadSectionChangedNotification), ThreadAttachmentUpdated => "thread/attachment/updated" (v2::ThreadAttachmentUpdatedNotification), ThreadGoalUpdated => "thread/goal/updated" (v2::ThreadGoalUpdatedNotification), #[experimental("thread/prediction/updated")] diff --git a/codex-rs/app-server-protocol/src/protocol/v2/thread.rs b/codex-rs/app-server-protocol/src/protocol/v2/thread.rs index 2eeb8926d0..aba591b950 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/thread.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/thread.rs @@ -1130,6 +1130,20 @@ pub struct ThreadSectionMoveParams { #[ts(export_to = "v2/")] pub struct ThreadSectionMoveResponse {} +/// Broadcast after a successful move into, within, or out of a section. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ThreadSectionChangedNotification { + pub thread_id: String, + /// Destination section, or `null` when the thread was removed from its section. + #[schemars( + required, + schema_with = "crate::protocol::serde_helpers::nullable_string_schema" + )] + pub section_id: Option, +} + #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "lowercase")] #[ts(rename_all = "lowercase")] diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 061c0839a6..069e3fa0cf 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -44,6 +44,13 @@ These errors are not evidence that history is exhausted; callers can retry. A successful response with `nextCursor: null` still indicates exhaustion. Default scan-and-repair requests retain their filesystem fallback. +# Thread section moves + +After a successful `thread/section/move`, the app-server broadcasts +`thread/section/changed` to its connected clients. The notification carries +`threadId` and the destination `sectionId`, which is null for a removal. +Moves within a section also emit this event so clients can refresh its order. + # Shutdown admission errors When graceful shutdown rejects new work, app-server returns JSON-RPC error diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index abc25df657..c234acbc8b 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -1470,7 +1470,9 @@ impl MessageProcessor { .await } ClientRequest::ThreadSectionMove { params, .. } => { - self.thread_processor.thread_section_move(params).await + self.thread_processor + .thread_section_move(request_id.clone(), params) + .await } ClientRequest::ThreadSectionList { params, .. } => { self.thread_processor.thread_section_list(params).await diff --git a/codex-rs/app-server/src/notification_media.rs b/codex-rs/app-server/src/notification_media.rs index 99e4d1e1cb..1e3d3d91c1 100644 --- a/codex-rs/app-server/src/notification_media.rs +++ b/codex-rs/app-server/src/notification_media.rs @@ -66,6 +66,7 @@ pub(crate) fn without_notification_media(notification: ServerNotification) -> Se | ServerNotification::ThreadReverted(_) | ServerNotification::SkillsChanged(_) | ServerNotification::ThreadNameUpdated(_) + | ServerNotification::ThreadSectionChanged(_) | ServerNotification::ThreadAttachmentUpdated(_) | ServerNotification::ThreadGoalUpdated(_) | ServerNotification::ThreadPredictionUpdated(_) diff --git a/codex-rs/app-server/src/request_processors/thread_processor.rs b/codex-rs/app-server/src/request_processors/thread_processor.rs index 1ef252dcbf..45153612f6 100644 --- a/codex-rs/app-server/src/request_processors/thread_processor.rs +++ b/codex-rs/app-server/src/request_processors/thread_processor.rs @@ -32,6 +32,7 @@ use codex_app_server_protocol::ThreadSampleParams; use codex_app_server_protocol::ThreadSampleResponse; use codex_app_server_protocol::ThreadSection; use codex_app_server_protocol::ThreadSectionAppearance; +use codex_app_server_protocol::ThreadSectionChangedNotification; use codex_app_server_protocol::ThreadSectionMoveParams; use codex_app_server_protocol::ThreadSectionMoveResponse; use codex_config::types::WindowsSandboxModeToml; @@ -785,6 +786,7 @@ impl ThreadRequestProcessor { pub(crate) async fn thread_section_move( &self, + request_id: ConnectionRequestId, params: ThreadSectionMoveParams, ) -> Result, JSONRPCErrorError> { let ThreadSectionMoveParams { @@ -812,17 +814,23 @@ impl ThreadRequestProcessor { }) .transpose()?; - { - let _thread_list_state_permit = self.acquire_thread_list_state_permit().await?; - self.thread_manager - .move_thread_to_section(thread_uuid, section_id.as_deref(), before_thread_uuid) - .await - .map_err(|err| core_thread_write_error("move thread in section", err))?; - } - - Ok(Some(ClientResponsePayload::ThreadSectionMove( - ThreadSectionMoveResponse {}, - ))) + let _thread_list_state_permit = self.acquire_thread_list_state_permit().await?; + self.thread_manager + .move_thread_to_section(thread_uuid, section_id.as_deref(), before_thread_uuid) + .await + .map_err(|err| core_thread_write_error("move thread in section", err))?; + self.outgoing + .send_response(request_id, ThreadSectionMoveResponse {}) + .await; + self.outgoing + .send_server_notification(ServerNotification::ThreadSectionChanged( + ThreadSectionChangedNotification { + thread_id: thread_uuid.to_string(), + section_id, + }, + )) + .await; + Ok(None) } pub(crate) async fn thread_memory_mode_set( diff --git a/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs b/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs index 6bd618c752..fb0711c994 100644 --- a/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs +++ b/codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs @@ -791,7 +791,7 @@ pub(super) async fn send_initialize_request( .await } -async fn start_thread(stream: &mut WsClient, id: i64) -> Result { +pub(super) async fn start_thread(stream: &mut WsClient, id: i64) -> Result { send_request( stream, "thread/start", diff --git a/codex-rs/app-server/tests/suite/v2/thread_sections.rs b/codex-rs/app-server/tests/suite/v2/thread_sections.rs index e374d6e839..f3f126e2da 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_sections.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_sections.rs @@ -1,3 +1,11 @@ +use super::connection_handling_websocket::connect_websocket; +use super::connection_handling_websocket::read_error_for_id; +use super::connection_handling_websocket::read_notification_for_method; +use super::connection_handling_websocket::read_response_for_id; +use super::connection_handling_websocket::send_initialize_request; +use super::connection_handling_websocket::send_request; +use super::connection_handling_websocket::spawn_websocket_server; +use super::connection_handling_websocket::start_thread; use anyhow::Result; use app_test_support::MockResponsesConfig; use app_test_support::TestAppServer; @@ -38,6 +46,58 @@ use uuid::Uuid; const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); +#[tokio::test] +async fn thread_section_moves_notify_other_clients() -> Result<()> { + let responses = create_mock_responses_server_repeating_assistant("Done").await; + let codex_home = TempDir::new()?; + MockResponsesConfig::new(&responses.uri()) + .enable_feature(Feature::Sqlite) + .write(codex_home.path())?; + let (mut server, address) = spawn_websocket_server(codex_home.path()).await?; + let mut writer = connect_websocket(address).await?; + let mut observer = connect_websocket(address).await?; + for client in [&mut writer, &mut observer] { + send_initialize_request(client, /*id*/ 1, "section-test").await?; + read_response_for_id(client, /*id*/ 1).await?; + } + let first = start_thread(&mut writer, /*id*/ 2).await?; + let second = start_thread(&mut writer, /*id*/ 3).await?; + + // A failed write must not invalidate the observer's last known section. + send_request( + &mut writer, + "thread/section/move", + /*id*/ 4, + Some(json!({"threadId": first, "sectionId": Uuid::new_v4().to_string()})), + ) + .await?; + read_error_for_id(&mut writer, /*id*/ 4).await?; + + let pinned = Some(PINNED_THREAD_SECTION_ID); + for (thread, destination, before) in [ + (&first, pinned, None), + (&second, pinned, None), + (&second, pinned, Some(&first)), + (&second, None, None), + ] { + send_request( + &mut writer, + "thread/section/move", + /*id*/ 5, + Some(json!({"threadId": thread, "sectionId": destination, "beforeThreadId": before})), + ) + .await?; + read_response_for_id(&mut writer, /*id*/ 5).await?; + let changed = read_notification_for_method(&mut observer, "thread/section/changed").await?; + assert_eq!( + changed.params, + Some(json!({"threadId": thread, "sectionId": destination})) + ); + } + server.kill().await?; + Ok(()) +} + async fn section_request_error( server: &mut TestAppServer, method: &str, diff --git a/codex-rs/tui/src/app/app_server_event_targets.rs b/codex-rs/tui/src/app/app_server_event_targets.rs index bf2112f50d..8e7b3f7b8a 100644 --- a/codex-rs/tui/src/app/app_server_event_targets.rs +++ b/codex-rs/tui/src/app/app_server_event_targets.rs @@ -205,6 +205,7 @@ pub(super) fn server_notification_thread_target( ServerNotification::ProjectChanged(_) | ServerNotification::SkillsChanged(_) | ServerNotification::AccountUpdated(_) + | ServerNotification::ThreadSectionChanged(_) | ServerNotification::GatewayOAuthChanged(_) | ServerNotification::AccountRateLimitsUpdated(_) | ServerNotification::AppListUpdated(_) diff --git a/codex-rs/tui/src/chatwidget/protocol.rs b/codex-rs/tui/src/chatwidget/protocol.rs index be7da50c03..7a08496373 100644 --- a/codex-rs/tui/src/chatwidget/protocol.rs +++ b/codex-rs/tui/src/chatwidget/protocol.rs @@ -379,6 +379,7 @@ impl ChatWidget { | ServerNotification::ThreadStarted(_) | ServerNotification::ThreadStatusChanged(_) | ServerNotification::ThreadReadStateChanged(_) + | ServerNotification::ThreadSectionChanged(_) | ServerNotification::ThreadReverted(_) | ServerNotification::ThreadQueueChanged(_) | ServerNotification::ThreadPredictionUpdated(_) diff --git a/sdk/python/src/openai_codex/generated/notification_registry.py b/sdk/python/src/openai_codex/generated/notification_registry.py index 2c1212bd8a..e11b3604ef 100644 --- a/sdk/python/src/openai_codex/generated/notification_registry.py +++ b/sdk/python/src/openai_codex/generated/notification_registry.py @@ -77,6 +77,7 @@ from .v2_all import ThreadRealtimeStartedNotification from .v2_all import ThreadRealtimeTranscriptDeltaNotification from .v2_all import ThreadRealtimeTranscriptDoneNotification from .v2_all import ThreadRevertedNotification +from .v2_all import ThreadSectionChangedNotification from .v2_all import ThreadSettingsUpdatedNotification from .v2_all import ThreadStartedNotification from .v2_all import ThreadStatusChangedNotification @@ -162,6 +163,7 @@ KnownNotificationPayload: TypeAlias = ( | ThreadRealtimeTranscriptDeltaNotification | ThreadRealtimeTranscriptDoneNotification | ThreadRevertedNotification + | ThreadSectionChangedNotification | ThreadSettingsUpdatedNotification | ThreadStartedNotification | ThreadStatusChangedNotification @@ -250,6 +252,7 @@ NOTIFICATION_MODELS: dict[str, type[KnownNotificationPayload]] = { "thread/realtime/transcript/delta": ThreadRealtimeTranscriptDeltaNotification, "thread/realtime/transcript/done": ThreadRealtimeTranscriptDoneNotification, "thread/reverted": ThreadRevertedNotification, + "thread/section/changed": ThreadSectionChangedNotification, "thread/settings/updated": ThreadSettingsUpdatedNotification, "thread/started": ThreadStartedNotification, "thread/status/changed": ThreadStatusChangedNotification, diff --git a/sdk/python/src/openai_codex/generated/v2_all.py b/sdk/python/src/openai_codex/generated/v2_all.py index cd74114fe1..531fed7eb7 100644 --- a/sdk/python/src/openai_codex/generated/v2_all.py +++ b/sdk/python/src/openai_codex/generated/v2_all.py @@ -6308,6 +6308,20 @@ class ThreadSectionAppearance(BaseModel): icon: str | None = None +class ThreadSectionChangedNotification(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + section_id: Annotated[ + str | None, + Field( + alias="sectionId", + description="Destination section, or `null` when the thread was removed from its section.", + ), + ] + thread_id: Annotated[str, Field(alias="threadId")] + + class ThreadSectionCreateParams(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -9697,6 +9711,23 @@ class ThreadNameUpdatedServerNotification(BaseModel): params: ThreadNameUpdatedNotification +class ThreadSectionChangedServerNotification(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + emitted_at_ms: Annotated[ + int | None, + Field( + alias="emittedAtMs", + description="Unix timestamp (in milliseconds) when app-server emitted this notification.", + ), + ] = None + method: Annotated[ + Literal["thread/section/changed"], Field(title="Thread/section/changedNotificationMethod") + ] + params: ThreadSectionChangedNotification + + class ThreadAttachmentUpdatedServerNotification(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -13634,6 +13665,7 @@ class ServerNotification( | ThreadRevertedServerNotification | SkillsChangedServerNotification | ThreadNameUpdatedServerNotification + | ThreadSectionChangedServerNotification | ThreadAttachmentUpdatedServerNotification | ThreadGoalUpdatedServerNotification | ThreadPredictionUpdatedServerNotification @@ -13722,6 +13754,7 @@ class ServerNotification( | ThreadRevertedServerNotification | SkillsChangedServerNotification | ThreadNameUpdatedServerNotification + | ThreadSectionChangedServerNotification | ThreadAttachmentUpdatedServerNotification | ThreadGoalUpdatedServerNotification | ThreadPredictionUpdatedServerNotification