[codex] Record external agent import results (#28396)

## Summary
- restore `externalAgentConfig/import/progress` notifications while
keeping `externalAgentConfig/import/completed` as the must-deliver event
- persist completed external-agent config imports in state DB by
`importId`, including concrete success/failure details for config,
AGENTS.md, skills, plugins, MCP servers, subagents, hooks, commands, and
sessions
- add `externalAgentConfig/import/readHistories` so clients can recover
persisted import results after missing the live completion notification
- include `errorType` on import failures in protocol
responses/notifications and persisted DB JSON so future code can
classify failures without another wire/storage shape change

## Validation
- `git diff --check`
- `just test -p codex-state external_agent_config_imports`
- `just test -p codex-app-server-protocol`
- `CODEX_SQLITE_HOME=/private/tmp/codex-app-server-sqlite-read-details
just test -p codex-app-server
external_agent_config_import_sends_completion_notification_for_sync_only_import`

Also ran earlier broader checks before publishing:
- `just test -p codex-state`
-
`CODEX_SQLITE_HOME=/private/tmp/codex-app-server-external-agent-test-sqlite
just test -p codex-app-server external_agent_config`
- `just test -p codex-external-agent-migration`
This commit is contained in:
charlesgong-openai
2026-06-15 23:17:24 -07:00
committed by GitHub
parent 1e015884c5
commit 314fa3d25b
30 changed files with 1370 additions and 101 deletions
@@ -6620,6 +6620,29 @@
"title": "ExternalAgentConfig/importRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/readHistories"
],
"title": "ExternalAgentConfig/import/readHistoriesRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "ExternalAgentConfig/import/readHistoriesRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -1167,6 +1167,12 @@
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
@@ -1219,6 +1225,24 @@
],
"type": "object"
},
"ExternalAgentConfigImportProgressNotification": {
"properties": {
"importId": {
"type": "string"
},
"itemTypeResults": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
}
},
"required": [
"importId",
"itemTypeResults"
],
"type": "object"
},
"ExternalAgentConfigImportTypeResult": {
"properties": {
"failures": {
@@ -6333,6 +6357,26 @@
"title": "RemoteControl/status/changedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"externalAgentConfig/import/progress"
],
"title": "ExternalAgentConfig/import/progressNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ExternalAgentConfigImportProgressNotification"
}
},
"required": [
"method",
"params"
],
"title": "ExternalAgentConfig/import/progressNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -2124,6 +2124,29 @@
"title": "ExternalAgentConfig/importRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/v2/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/readHistories"
],
"title": "ExternalAgentConfig/import/readHistoriesRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "ExternalAgentConfig/import/readHistoriesRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -4834,6 +4857,26 @@
"title": "RemoteControl/status/changedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"externalAgentConfig/import/progress"
],
"title": "ExternalAgentConfig/import/progressNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportProgressNotification"
}
},
"required": [
"method",
"params"
],
"title": "ExternalAgentConfig/import/progressNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -9089,6 +9132,52 @@
"title": "ExternalAgentConfigImportCompletedNotification",
"type": "object"
},
"ExternalAgentConfigImportHistoriesReadResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"data": {
"items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportHistory"
},
"type": "array"
}
},
"required": [
"data"
],
"title": "ExternalAgentConfigImportHistoriesReadResponse",
"type": "object"
},
"ExternalAgentConfigImportHistory": {
"properties": {
"completedAtMs": {
"format": "int64",
"type": "integer"
},
"failures": {
"items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"importId": {
"type": "string"
},
"successes": {
"items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"completedAtMs",
"failures",
"importId",
"successes"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
@@ -9097,6 +9186,12 @@
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
@@ -9165,6 +9260,26 @@
"title": "ExternalAgentConfigImportParams",
"type": "object"
},
"ExternalAgentConfigImportProgressNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"importId": {
"type": "string"
},
"itemTypeResults": {
"items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportTypeResult"
},
"type": "array"
}
},
"required": [
"importId",
"itemTypeResults"
],
"title": "ExternalAgentConfigImportProgressNotification",
"type": "object"
},
"ExternalAgentConfigImportResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -3111,6 +3111,29 @@
"title": "ExternalAgentConfig/importRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/readHistories"
],
"title": "ExternalAgentConfig/import/readHistoriesRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "ExternalAgentConfig/import/readHistoriesRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -5402,6 +5425,52 @@
"title": "ExternalAgentConfigImportCompletedNotification",
"type": "object"
},
"ExternalAgentConfigImportHistoriesReadResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"data": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportHistory"
},
"type": "array"
}
},
"required": [
"data"
],
"title": "ExternalAgentConfigImportHistoriesReadResponse",
"type": "object"
},
"ExternalAgentConfigImportHistory": {
"properties": {
"completedAtMs": {
"format": "int64",
"type": "integer"
},
"failures": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"importId": {
"type": "string"
},
"successes": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"completedAtMs",
"failures",
"importId",
"successes"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
@@ -5410,6 +5479,12 @@
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
@@ -5478,6 +5553,26 @@
"title": "ExternalAgentConfigImportParams",
"type": "object"
},
"ExternalAgentConfigImportProgressNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"importId": {
"type": "string"
},
"itemTypeResults": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
}
},
"required": [
"importId",
"itemTypeResults"
],
"title": "ExternalAgentConfigImportProgressNotification",
"type": "object"
},
"ExternalAgentConfigImportResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -13011,6 +13106,26 @@
"title": "RemoteControl/status/changedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"externalAgentConfig/import/progress"
],
"title": "ExternalAgentConfig/import/progressNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ExternalAgentConfigImportProgressNotification"
}
},
"required": [
"method",
"params"
],
"title": "ExternalAgentConfig/import/progressNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -9,6 +9,12 @@
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
@@ -0,0 +1,128 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ExternalAgentConfigImportHistory": {
"properties": {
"completedAtMs": {
"format": "int64",
"type": "integer"
},
"failures": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"importId": {
"type": "string"
},
"successes": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"completedAtMs",
"failures",
"importId",
"successes"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"message": {
"type": "string"
},
"source": {
"type": [
"string",
"null"
]
}
},
"required": [
"failureStage",
"itemType",
"message"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeSuccess": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"source": {
"type": [
"string",
"null"
]
},
"target": {
"type": [
"string",
"null"
]
}
},
"required": [
"itemType"
],
"type": "object"
},
"ExternalAgentConfigMigrationItemType": {
"enum": [
"AGENTS_MD",
"CONFIG",
"SKILLS",
"PLUGINS",
"MCP_SERVER_CONFIG",
"SUBAGENTS",
"HOOKS",
"COMMANDS",
"SESSIONS"
],
"type": "string"
}
},
"properties": {
"data": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportHistory"
},
"type": "array"
}
},
"required": [
"data"
],
"title": "ExternalAgentConfigImportHistoriesReadResponse",
"type": "object"
}
@@ -0,0 +1,127 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"message": {
"type": "string"
},
"source": {
"type": [
"string",
"null"
]
}
},
"required": [
"failureStage",
"itemType",
"message"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeSuccess": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"source": {
"type": [
"string",
"null"
]
},
"target": {
"type": [
"string",
"null"
]
}
},
"required": [
"itemType"
],
"type": "object"
},
"ExternalAgentConfigImportTypeResult": {
"properties": {
"failures": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"successes": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"failures",
"itemType",
"successes"
],
"type": "object"
},
"ExternalAgentConfigMigrationItemType": {
"enum": [
"AGENTS_MD",
"CONFIG",
"SKILLS",
"PLUGINS",
"MCP_SERVER_CONFIG",
"SUBAGENTS",
"HOOKS",
"COMMANDS",
"SESSIONS"
],
"type": "string"
}
},
"properties": {
"importId": {
"type": "string"
},
"itemTypeResults": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
}
},
"required": [
"importId",
"itemTypeResults"
],
"title": "ExternalAgentConfigImportProgressNotification",
"type": "object"
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,6 @@
// 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.
import type { ExternalAgentConfigImportHistory } from "./ExternalAgentConfigImportHistory";
export type ExternalAgentConfigImportHistoriesReadResponse = { data: Array<ExternalAgentConfigImportHistory>, };
@@ -0,0 +1,7 @@
// 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.
import type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure";
import type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess";
export type ExternalAgentConfigImportHistory = { importId: string, completedAtMs: bigint, successes: Array<ExternalAgentConfigImportItemTypeSuccess>, failures: Array<ExternalAgentConfigImportItemTypeFailure>, };
@@ -3,4 +3,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ExternalAgentConfigMigrationItemType } from "./ExternalAgentConfigMigrationItemType";
export type ExternalAgentConfigImportItemTypeFailure = { itemType: ExternalAgentConfigMigrationItemType, failureStage: string, message: string, cwd: string | null, source: string | null, };
export type ExternalAgentConfigImportItemTypeFailure = { itemType: ExternalAgentConfigMigrationItemType, errorType: string | null, failureStage: string, message: string, cwd: string | null, source: string | null, };
@@ -0,0 +1,6 @@
// 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.
import type { ExternalAgentConfigImportTypeResult } from "./ExternalAgentConfigImportTypeResult";
export type ExternalAgentConfigImportProgressNotification = { importId: string, itemTypeResults: Array<ExternalAgentConfigImportTypeResult>, };
@@ -110,9 +110,12 @@ export type { ExperimentalFeatureStage } from "./ExperimentalFeatureStage";
export type { ExternalAgentConfigDetectParams } from "./ExternalAgentConfigDetectParams";
export type { ExternalAgentConfigDetectResponse } from "./ExternalAgentConfigDetectResponse";
export type { ExternalAgentConfigImportCompletedNotification } from "./ExternalAgentConfigImportCompletedNotification";
export type { ExternalAgentConfigImportHistoriesReadResponse } from "./ExternalAgentConfigImportHistoriesReadResponse";
export type { ExternalAgentConfigImportHistory } from "./ExternalAgentConfigImportHistory";
export type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure";
export type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess";
export type { ExternalAgentConfigImportParams } from "./ExternalAgentConfigImportParams";
export type { ExternalAgentConfigImportProgressNotification } from "./ExternalAgentConfigImportProgressNotification";
export type { ExternalAgentConfigImportResponse } from "./ExternalAgentConfigImportResponse";
export type { ExternalAgentConfigImportTypeResult } from "./ExternalAgentConfigImportTypeResult";
export type { ExternalAgentConfigMigrationItem } from "./ExternalAgentConfigMigrationItem";
@@ -1103,6 +1103,11 @@ client_request_definitions! {
serialization: global("config"),
response: v2::ExternalAgentConfigImportResponse,
},
ExternalAgentConfigImportHistoriesRead => "externalAgentConfig/import/readHistories" {
params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>,
serialization: global_shared_read("config"),
response: v2::ExternalAgentConfigImportHistoriesReadResponse,
},
ConfigValueWrite => "config/value/write" {
params: v2::ConfigValueWriteParams,
serialization: global("config"),
@@ -1614,6 +1619,7 @@ server_notification_definitions! {
AccountRateLimitsUpdated => "account/rateLimits/updated" (v2::AccountRateLimitsUpdatedNotification),
AppListUpdated => "app/list/updated" (v2::AppListUpdatedNotification),
RemoteControlStatusChanged => "remoteControl/status/changed" (v2::RemoteControlStatusChangedNotification),
ExternalAgentConfigImportProgress => "externalAgentConfig/import/progress" (v2::ExternalAgentConfigImportProgressNotification),
ExternalAgentConfigImportCompleted => "externalAgentConfig/import/completed" (v2::ExternalAgentConfigImportCompletedNotification),
FsChanged => "fs/changed" (v2::FsChangedNotification),
ReasoningSummaryTextDelta => "item/reasoning/summaryTextDelta" (v2::ReasoningSummaryTextDeltaNotification),
@@ -677,6 +677,7 @@ pub struct ExternalAgentConfigImportResponse {
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportItemTypeFailure {
pub item_type: ExternalAgentConfigMigrationItemType,
pub error_type: Option<String>,
pub failure_stage: String,
pub message: String,
pub cwd: Option<PathBuf>,
@@ -702,6 +703,31 @@ pub struct ExternalAgentConfigImportTypeResult {
pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportHistory {
pub import_id: String,
pub completed_at_ms: i64,
pub successes: Vec<ExternalAgentConfigImportItemTypeSuccess>,
pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportHistoriesReadResponse {
pub data: Vec<ExternalAgentConfigImportHistory>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportProgressNotification {
pub import_id: String,
pub item_type_results: Vec<ExternalAgentConfigImportTypeResult>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]