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:
@@ -975,6 +975,9 @@ export class AgentManager {
|
|||||||
attentionReason: null,
|
attentionReason: null,
|
||||||
attentionTimestamp: null,
|
attentionTimestamp: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await this.archiveNativeSessionBestEffort(agent.provider, stored.persistence);
|
||||||
|
|
||||||
this.notifyAgentState(agentId);
|
this.notifyAgentState(agentId);
|
||||||
await this.closeAgent(agentId);
|
await this.closeAgent(agentId);
|
||||||
|
|
||||||
@@ -1118,6 +1121,9 @@ export class AgentManager {
|
|||||||
attentionTimestamp: null,
|
attentionTimestamp: null,
|
||||||
};
|
};
|
||||||
await registry.upsert(nextRecord);
|
await registry.upsert(nextRecord);
|
||||||
|
|
||||||
|
await this.archiveNativeSessionBestEffort(record.provider, record.persistence);
|
||||||
|
|
||||||
return nextRecord;
|
return nextRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3136,6 +3142,23 @@ export class AgentManager {
|
|||||||
return client;
|
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 {
|
private requireAgent(id: string): LiveManagedAgent {
|
||||||
const normalizedId = validateAgentId(id, "requireAgent");
|
const normalizedId = validateAgentId(id, "requireAgent");
|
||||||
const agent = this.agents.get(normalizedId);
|
const agent = this.agents.get(normalizedId);
|
||||||
|
|||||||
@@ -558,4 +558,9 @@ export interface AgentClient {
|
|||||||
*/
|
*/
|
||||||
isAvailable(): Promise<boolean>;
|
isAvailable(): Promise<boolean>;
|
||||||
getDiagnostic?(): Promise<{ diagnostic: string }>;
|
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>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
AgentMode,
|
AgentMode,
|
||||||
AgentModelDefinition,
|
AgentModelDefinition,
|
||||||
McpServerConfig,
|
McpServerConfig,
|
||||||
|
AgentPersistenceHandle,
|
||||||
AgentPermissionRequest,
|
AgentPermissionRequest,
|
||||||
AgentPermissionResponse,
|
AgentPermissionResponse,
|
||||||
AgentPermissionResult,
|
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> {
|
async isAvailable(): Promise<boolean> {
|
||||||
const command = this.runtimeSettings?.command;
|
const command = this.runtimeSettings?.command;
|
||||||
if (command?.mode === "replace") {
|
if (command?.mode === "replace") {
|
||||||
|
|||||||
Reference in New Issue
Block a user