mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
refactor: derive session payloads from ManagedAgent
This commit is contained in:
@@ -9,7 +9,7 @@ import type {
|
||||
} from "./agent-sdk-types.js";
|
||||
import type {
|
||||
AgentManager,
|
||||
AgentSnapshot,
|
||||
ManagedAgent,
|
||||
WaitForAgentResult,
|
||||
} from "./agent-manager.js";
|
||||
import {
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
AgentSnapshotPayloadSchema,
|
||||
serializeAgentSnapshot,
|
||||
} from "../messages.js";
|
||||
import { toAgentPayload } from "./agent-projections.js";
|
||||
import { curateAgentActivity } from "./activity-curator.js";
|
||||
import { AGENT_PROVIDER_DEFINITIONS } from "./provider-manifest.js";
|
||||
import { AgentRegistry } from "./agent-registry.js";
|
||||
@@ -90,7 +91,7 @@ async function resolveAgentTitle(
|
||||
|
||||
async function serializeSnapshotWithMetadata(
|
||||
agentRegistry: AgentRegistry,
|
||||
snapshot: AgentSnapshot
|
||||
snapshot: ManagedAgent
|
||||
) {
|
||||
const title = await resolveAgentTitle(agentRegistry, snapshot.id);
|
||||
return serializeAgentSnapshot(snapshot, { title });
|
||||
@@ -232,7 +233,7 @@ export async function createAgentMcpServer(
|
||||
structuredContent: ensureValidJson({
|
||||
agentId: snapshot.id,
|
||||
type: provider,
|
||||
status: snapshot.status,
|
||||
status: snapshot.lifecycle,
|
||||
cwd: snapshot.cwd,
|
||||
currentModeId: snapshot.currentModeId,
|
||||
availableModes: snapshot.availableModes,
|
||||
@@ -394,7 +395,7 @@ export async function createAgentMcpServer(
|
||||
|
||||
const responseData = {
|
||||
success: true,
|
||||
status: snapshot?.status ?? "idle",
|
||||
status: snapshot?.lifecycle ?? "idle",
|
||||
lastMessage: null,
|
||||
permission: null,
|
||||
};
|
||||
@@ -435,7 +436,7 @@ export async function createAgentMcpServer(
|
||||
return {
|
||||
content: [],
|
||||
structuredContent: ensureValidJson({
|
||||
status: snapshot.status,
|
||||
status: snapshot.lifecycle,
|
||||
snapshot: structuredSnapshot,
|
||||
}),
|
||||
};
|
||||
@@ -616,13 +617,14 @@ export async function createAgentMcpServer(
|
||||
},
|
||||
},
|
||||
async () => {
|
||||
const permissions = agentManager.listAgents().flatMap((agent) =>
|
||||
agent.pendingPermissions.map((request) => ({
|
||||
const permissions = agentManager.listAgents().flatMap((agent) => {
|
||||
const payload = toAgentPayload(agent);
|
||||
return payload.pendingPermissions.map((request) => ({
|
||||
agentId: agent.id,
|
||||
status: agent.status,
|
||||
status: payload.status,
|
||||
request,
|
||||
}))
|
||||
);
|
||||
}));
|
||||
});
|
||||
|
||||
return {
|
||||
content: [],
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { z } from "zod";
|
||||
import {
|
||||
AGENT_LIFECYCLE_STATUSES,
|
||||
type AgentSnapshot,
|
||||
type ManagedAgent,
|
||||
} from "./agent/agent-manager.js";
|
||||
import { toAgentPayload } from "./agent/agent-projections.js";
|
||||
import type {
|
||||
AgentCapabilityFlags,
|
||||
AgentModelDefinition,
|
||||
@@ -16,16 +17,6 @@ import type {
|
||||
AgentUsage,
|
||||
} from "./agent/agent-sdk-types.js";
|
||||
|
||||
export type AgentSnapshotPayload = Omit<
|
||||
AgentSnapshot,
|
||||
"createdAt" | "updatedAt" | "lastUserMessageAt"
|
||||
> & {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastUserMessageAt: string | null;
|
||||
title: string | null;
|
||||
};
|
||||
|
||||
const AGENT_PROVIDERS: [AgentProvider, AgentProvider] = ["claude", "codex"];
|
||||
const AgentProviderSchema = z.enum(AGENT_PROVIDERS);
|
||||
|
||||
@@ -230,96 +221,17 @@ export const AgentSnapshotPayloadSchema = z.object({
|
||||
title: z.string().nullable(),
|
||||
});
|
||||
|
||||
function sanitizeOptionalJson(value: unknown): unknown {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
.map((item) => sanitizeOptionalJson(item))
|
||||
.filter((item) => item !== undefined);
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return value.toISOString();
|
||||
}
|
||||
if (typeof value === "object") {
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const [key, val] of Object.entries(value as Record<string, unknown>)) {
|
||||
const sanitized = sanitizeOptionalJson(val);
|
||||
if (sanitized !== undefined) {
|
||||
result[key] = sanitized;
|
||||
}
|
||||
}
|
||||
return Object.keys(result).length ? result : undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function sanitizeOptionalJsonValue<T>(value: T | undefined): T | undefined {
|
||||
const sanitized = sanitizeOptionalJson(value);
|
||||
return sanitized === undefined ? undefined : (sanitized as T);
|
||||
}
|
||||
|
||||
function sanitizePersistenceHandle(
|
||||
handle: AgentPersistenceHandle | null
|
||||
): AgentPersistenceHandle | null {
|
||||
if (!handle) {
|
||||
return null;
|
||||
}
|
||||
const sanitized: AgentPersistenceHandle = {
|
||||
provider: handle.provider,
|
||||
sessionId: handle.sessionId,
|
||||
};
|
||||
if (handle.nativeHandle !== undefined) {
|
||||
sanitized.nativeHandle = handle.nativeHandle;
|
||||
}
|
||||
const metadata = sanitizeOptionalJsonValue(handle.metadata);
|
||||
if (metadata !== undefined) {
|
||||
sanitized.metadata = metadata;
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
export type AgentSnapshotPayload = z.infer<typeof AgentSnapshotPayloadSchema>;
|
||||
|
||||
export type AgentStreamEventPayload = z.infer<
|
||||
typeof AgentStreamEventPayloadSchema
|
||||
>;
|
||||
|
||||
export function serializeAgentSnapshot(
|
||||
snapshot: AgentSnapshot,
|
||||
agent: ManagedAgent,
|
||||
options?: { title?: string | null }
|
||||
): AgentSnapshotPayload {
|
||||
const payload: AgentSnapshotPayload = {
|
||||
id: snapshot.id,
|
||||
provider: snapshot.provider,
|
||||
cwd: snapshot.cwd,
|
||||
model: snapshot.model,
|
||||
createdAt: snapshot.createdAt.toISOString(),
|
||||
updatedAt: snapshot.updatedAt.toISOString(),
|
||||
lastUserMessageAt: snapshot.lastUserMessageAt
|
||||
? snapshot.lastUserMessageAt.toISOString()
|
||||
: null,
|
||||
status: snapshot.status,
|
||||
sessionId: snapshot.sessionId,
|
||||
capabilities: snapshot.capabilities,
|
||||
currentModeId: snapshot.currentModeId,
|
||||
availableModes: snapshot.availableModes,
|
||||
pendingPermissions: snapshot.pendingPermissions,
|
||||
persistence: sanitizePersistenceHandle(snapshot.persistence),
|
||||
title: options?.title ?? null,
|
||||
};
|
||||
|
||||
const lastUsage = sanitizeOptionalJsonValue<AgentUsage>(snapshot.lastUsage);
|
||||
if (lastUsage !== undefined) {
|
||||
payload.lastUsage = lastUsage;
|
||||
}
|
||||
if (snapshot.lastError !== undefined) {
|
||||
payload.lastError = snapshot.lastError;
|
||||
}
|
||||
|
||||
return payload;
|
||||
return toAgentPayload(agent, options);
|
||||
}
|
||||
|
||||
export function serializeAgentStreamEvent(
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
OpenRouterProviderOptions,
|
||||
} from "@openrouter/ai-sdk-provider";
|
||||
import {
|
||||
serializeAgentSnapshot,
|
||||
serializeAgentStreamEvent,
|
||||
type AgentSnapshotPayload,
|
||||
type SessionInboundMessage,
|
||||
@@ -39,7 +38,8 @@ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
||||
import { createTerminalMcpServer } from "./terminal-mcp/index.js";
|
||||
import { fetchProviderModelCatalog } from "./agent/model-catalog.js";
|
||||
import { AgentManager } from "./agent/agent-manager.js";
|
||||
import type { AgentSnapshot } from "./agent/agent-manager.js";
|
||||
import type { ManagedAgent } from "./agent/agent-manager.js";
|
||||
import { toAgentPayload } from "./agent/agent-projections.js";
|
||||
import type {
|
||||
AgentPermissionResponse,
|
||||
AgentPromptInput,
|
||||
@@ -234,7 +234,7 @@ export class Session {
|
||||
private unsubscribeAgentEvents: (() => void) | null = null;
|
||||
private pendingAgentInitializations: Map<
|
||||
string,
|
||||
Promise<AgentSnapshot>
|
||||
Promise<ManagedAgent>
|
||||
> = new Map();
|
||||
|
||||
constructor(
|
||||
@@ -325,7 +325,7 @@ export class Session {
|
||||
throw new Error(`Agent ${agentId} not found`);
|
||||
}
|
||||
|
||||
if (snapshot.status !== "running") {
|
||||
if (snapshot.lifecycle !== "running") {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -532,10 +532,10 @@ export class Session {
|
||||
}
|
||||
|
||||
private async buildAgentPayload(
|
||||
agent: AgentSnapshot
|
||||
agent: ManagedAgent
|
||||
): Promise<AgentSnapshotPayload> {
|
||||
const title = await this.getStoredAgentTitle(agent.id);
|
||||
return serializeAgentSnapshot(agent, { title });
|
||||
return toAgentPayload(agent, { title });
|
||||
}
|
||||
|
||||
private buildStoredAgentPayload(record: StoredAgentRecord): AgentSnapshotPayload {
|
||||
@@ -576,7 +576,7 @@ export class Session {
|
||||
};
|
||||
}
|
||||
|
||||
private async ensureAgentLoaded(agentId: string): Promise<AgentSnapshot> {
|
||||
private async ensureAgentLoaded(agentId: string): Promise<ManagedAgent> {
|
||||
const existing = this.agentManager.getAgent(agentId);
|
||||
if (existing) {
|
||||
return existing;
|
||||
@@ -594,7 +594,7 @@ export class Session {
|
||||
}
|
||||
|
||||
const handle = toAgentPersistenceHandle(record.persistence);
|
||||
let snapshot: AgentSnapshot;
|
||||
let snapshot: ManagedAgent;
|
||||
if (handle) {
|
||||
snapshot = await this.agentManager.resumeAgent(
|
||||
handle,
|
||||
@@ -619,7 +619,7 @@ export class Session {
|
||||
}
|
||||
}
|
||||
|
||||
private async forwardAgentState(agent: AgentSnapshot): Promise<void> {
|
||||
private async forwardAgentState(agent: ManagedAgent): Promise<void> {
|
||||
try {
|
||||
const payload = await this.buildAgentPayload(agent);
|
||||
this.emit({
|
||||
@@ -1189,7 +1189,7 @@ export class Session {
|
||||
payload: {
|
||||
status: "agent_initialized",
|
||||
agentId,
|
||||
agentStatus: snapshot.status,
|
||||
agentStatus: snapshot.lifecycle,
|
||||
requestId,
|
||||
timelineSize,
|
||||
},
|
||||
@@ -1197,7 +1197,7 @@ export class Session {
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[Session ${this.clientId}] Agent ${agentId} initialized with ${timelineSize} timeline item(s); status=${snapshot.status}`
|
||||
`[Session ${this.clientId}] Agent ${agentId} initialized with ${timelineSize} timeline item(s); status=${snapshot.lifecycle}`
|
||||
);
|
||||
} catch (error: any) {
|
||||
console.error(
|
||||
@@ -1370,7 +1370,7 @@ export class Session {
|
||||
);
|
||||
|
||||
try {
|
||||
let snapshot: AgentSnapshot;
|
||||
let snapshot: ManagedAgent;
|
||||
const existing = this.agentManager.getAgent(agentId);
|
||||
if (existing) {
|
||||
await this.interruptAgentIfRunning(agentId);
|
||||
@@ -2048,7 +2048,7 @@ export class Session {
|
||||
}
|
||||
}
|
||||
|
||||
private emitAgentTimelineSnapshot(agent: AgentSnapshot): number {
|
||||
private emitAgentTimelineSnapshot(agent: ManagedAgent): number {
|
||||
const timeline = this.agentManager.getTimeline(agent.id);
|
||||
const events = timeline.map((item) => ({
|
||||
event: serializeAgentStreamEvent({
|
||||
|
||||
Reference in New Issue
Block a user