feat(codex): archive native Codex thread when archiving agent (#827)

When a Codex-backed agent is archived from Paseo, call Codex's
thread/archive API so the session is also marked archived in the
Codex app. This keeps both UIs in sync.

- Add optional archiveNativeSession() to AgentClient interface
- Implement for Codex provider via thread/archive JSON-RPC call
- Call best-effort in both archiveAgent() and archiveSnapshot() paths
- Failures are logged as warnings and do not block the archive flow

Closes #822
This commit is contained in:
ezra
2026-05-09 12:37:09 +08:00
committed by GitHub
parent c40e1f03db
commit 0be9764194
3 changed files with 45 additions and 0 deletions

View File

@@ -975,6 +975,9 @@ export class AgentManager {
attentionReason: null,
attentionTimestamp: null,
});
await this.archiveNativeSessionBestEffort(agent.provider, stored.persistence);
this.notifyAgentState(agentId);
await this.closeAgent(agentId);
@@ -1118,6 +1121,9 @@ export class AgentManager {
attentionTimestamp: null,
};
await registry.upsert(nextRecord);
await this.archiveNativeSessionBestEffort(record.provider, record.persistence);
return nextRecord;
}
@@ -3136,6 +3142,23 @@ export class AgentManager {
return client;
}
async archiveNativeSessionBestEffort(
provider: AgentProvider,
persistence: AgentPersistenceHandle | null | undefined,
): Promise<void> {
if (!persistence) return;
const client = this.clients.get(provider);
if (!client?.archiveNativeSession) return;
try {
await client.archiveNativeSession(persistence);
} catch (error) {
this.logger.warn(
{ error, provider, sessionId: persistence.sessionId },
"Failed to archive native session (best-effort)",
);
}
}
private requireAgent(id: string): LiveManagedAgent {
const normalizedId = validateAgentId(id, "requireAgent");
const agent = this.agents.get(normalizedId);

View File

@@ -558,4 +558,9 @@ export interface AgentClient {
*/
isAvailable(): Promise<boolean>;
getDiagnostic?(): Promise<{ diagnostic: string }>;
/**
* Archive a persisted session in the native provider (best-effort).
* Called when Paseo archives an agent so the provider's own UI reflects the same state.
*/
archiveNativeSession?(handle: AgentPersistenceHandle): Promise<void>;
}

View File

@@ -8,6 +8,7 @@ import type {
AgentMode,
AgentModelDefinition,
McpServerConfig,
AgentPersistenceHandle,
AgentPermissionRequest,
AgentPermissionResponse,
AgentPermissionResult,
@@ -4904,6 +4905,22 @@ export class CodexAppServerAgentClient implements AgentClient {
}
}
async archiveNativeSession(handle: AgentPersistenceHandle): Promise<void> {
const threadId = handle.nativeHandle ?? handle.sessionId;
if (!threadId) return;
const child = await this.spawnAppServer();
const client = new CodexAppServerClient(child, this.logger);
try {
await client.request("initialize", buildCodexAppServerInitializeParams());
client.notify("initialized", {});
await client.request("thread/archive", { threadId });
} finally {
await client.dispose();
}
}
async isAvailable(): Promise<boolean> {
const command = this.runtimeSettings?.command;
if (command?.mode === "replace") {