[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
Unverified
parent 1e015884c5
commit 314fa3d25b
30 changed files with 1370 additions and 101 deletions
+8 -8
View File
@@ -155,13 +155,13 @@ pub fn missing_subagent_names(
Ok(names)
}
pub fn import_subagents(source_agents: &Path, target_agents: &Path) -> io::Result<usize> {
pub fn import_subagents(source_agents: &Path, target_agents: &Path) -> io::Result<Vec<String>> {
if !source_agents.is_dir() {
return Ok(0);
return Ok(Vec::new());
}
fs::create_dir_all(target_agents)?;
let mut imported = 0usize;
let mut imported = Vec::new();
for source_file in agent_source_files(source_agents)? {
let Some(target) = subagent_target_file(&source_file, target_agents) else {
continue;
@@ -174,7 +174,7 @@ pub fn import_subagents(source_agents: &Path, target_agents: &Path) -> io::Resul
continue;
};
fs::write(&target, render_agent_toml(&document.body, &metadata)?)?;
imported += 1;
imported.push(metadata.name);
}
Ok(imported)
@@ -195,13 +195,13 @@ pub fn missing_command_names(
.collect())
}
pub fn import_commands(source_commands: &Path, target_skills: &Path) -> io::Result<usize> {
pub fn import_commands(source_commands: &Path, target_skills: &Path) -> io::Result<Vec<String>> {
if !source_commands.is_dir() {
return Ok(0);
return Ok(Vec::new());
}
fs::create_dir_all(target_skills)?;
let mut imported = 0usize;
let mut imported = Vec::new();
for (source_file, name) in unique_supported_command_sources(source_commands)? {
let document = parse_document(&source_file)?;
let target_dir = target_skills.join(&name);
@@ -217,7 +217,7 @@ pub fn import_commands(source_commands: &Path, target_skills: &Path) -> io::Resu
target_dir.join("SKILL.md"),
render_command_skill(&document.body, &name, &description, &source_name),
)?;
imported += 1;
imported.push(name);
}
Ok(imported)