mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Update files
This commit is contained in:
@@ -9,6 +9,7 @@ import { AgentManager } from "./agent-manager.js";
|
||||
import { AgentStorage } from "./agent-storage.js";
|
||||
import type {
|
||||
AgentClient,
|
||||
AgentPersistenceHandle,
|
||||
AgentRunResult,
|
||||
AgentSession,
|
||||
AgentSessionConfig,
|
||||
@@ -149,6 +150,99 @@ describe("AgentManager", () => {
|
||||
).rejects.toThrow("Working directory does not exist");
|
||||
});
|
||||
|
||||
test("resumeAgent keeps metadata config and applies systemPrompt/mcpServers overrides", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-resume-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
const storage = new AgentStorage(storagePath, logger);
|
||||
|
||||
class ResumeCaptureClient implements AgentClient {
|
||||
readonly provider = "codex" as const;
|
||||
readonly capabilities = TEST_CAPABILITIES;
|
||||
lastResumeOverrides: Partial<AgentSessionConfig> | undefined;
|
||||
|
||||
async isAvailable(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
async createSession(config: AgentSessionConfig): Promise<AgentSession> {
|
||||
return new TestAgentSession(config);
|
||||
}
|
||||
|
||||
async resumeSession(
|
||||
handle: AgentPersistenceHandle,
|
||||
overrides?: Partial<AgentSessionConfig>
|
||||
): Promise<AgentSession> {
|
||||
this.lastResumeOverrides = overrides;
|
||||
const metadata = (handle.metadata ?? {}) as Partial<AgentSessionConfig>;
|
||||
const merged: AgentSessionConfig = {
|
||||
...metadata,
|
||||
...overrides,
|
||||
provider: "codex",
|
||||
cwd: overrides?.cwd ?? metadata.cwd ?? process.cwd(),
|
||||
};
|
||||
return new TestAgentSession(merged);
|
||||
}
|
||||
}
|
||||
|
||||
const client = new ResumeCaptureClient();
|
||||
const manager = new AgentManager({
|
||||
clients: {
|
||||
codex: client,
|
||||
},
|
||||
registry: storage,
|
||||
logger,
|
||||
idFactory: () => "00000000-0000-4000-8000-000000000106",
|
||||
});
|
||||
|
||||
const handle: AgentPersistenceHandle = {
|
||||
provider: "codex",
|
||||
sessionId: "resume-session-1",
|
||||
metadata: {
|
||||
provider: "codex",
|
||||
cwd: workdir,
|
||||
systemPrompt: "old prompt",
|
||||
mcpServers: {
|
||||
legacy: {
|
||||
type: "stdio",
|
||||
command: "legacy-bridge",
|
||||
args: ["/tmp/legacy.sock"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const resumed = await manager.resumeAgent(handle, {
|
||||
cwd: workdir,
|
||||
systemPrompt: "new prompt",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/mcp-bridge.mjs", "--socket", "/tmp/paseo.sock"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(resumed.config.systemPrompt).toBe("new prompt");
|
||||
expect(resumed.config.mcpServers).toEqual({
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/mcp-bridge.mjs", "--socket", "/tmp/paseo.sock"],
|
||||
},
|
||||
});
|
||||
expect(client.lastResumeOverrides).toMatchObject({
|
||||
systemPrompt: "new prompt",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/mcp-bridge.mjs", "--socket", "/tmp/paseo.sock"],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("createAgent fails when generated agent ID is not a UUID", async () => {
|
||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-test-"));
|
||||
const storagePath = join(workdir, "agents");
|
||||
|
||||
@@ -129,6 +129,9 @@ function buildSerializableConfig(
|
||||
if (extra !== undefined) {
|
||||
serializable.extra = extra;
|
||||
}
|
||||
if (config.systemPrompt) {
|
||||
serializable.systemPrompt = config.systemPrompt;
|
||||
}
|
||||
if (config.mcpServers) {
|
||||
serializable.mcpServers = config.mcpServers;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ function createManagedAgent(
|
||||
modeId: configOverrides.modeId ?? "plan",
|
||||
model: configOverrides.model ?? "gpt-5.1",
|
||||
extra: configOverrides.extra ?? { claude: { maxThinkingTokens: 1024 } },
|
||||
systemPrompt: configOverrides.systemPrompt,
|
||||
mcpServers: configOverrides.mcpServers,
|
||||
};
|
||||
const session =
|
||||
@@ -119,6 +120,7 @@ describe("AgentStorage", () => {
|
||||
config: {
|
||||
modeId: "coding",
|
||||
model: "gpt-5.1",
|
||||
systemPrompt: "Be terse and explicit.",
|
||||
extra: { claude: { maxThinkingTokens: 1024 } },
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
@@ -137,6 +139,7 @@ describe("AgentStorage", () => {
|
||||
expect(record.provider).toBe("claude");
|
||||
expect(record.config?.modeId).toBe("coding");
|
||||
expect(record.config?.model).toBe("gpt-5.1");
|
||||
expect(record.config?.systemPrompt).toBe("Be terse and explicit.");
|
||||
expect(record.config?.mcpServers).toEqual({
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
|
||||
@@ -15,6 +15,7 @@ const SERIALIZABLE_CONFIG_SCHEMA = z
|
||||
model: z.string().nullable().optional(),
|
||||
thinkingOptionId: z.string().nullable().optional(),
|
||||
extra: z.record(z.any()).nullable().optional(),
|
||||
systemPrompt: z.string().nullable().optional(),
|
||||
mcpServers: z.record(z.any()).nullable().optional(),
|
||||
})
|
||||
.nullable()
|
||||
@@ -62,7 +63,7 @@ const STORED_AGENT_SCHEMA = z.object({
|
||||
|
||||
export type SerializableAgentConfig = Pick<
|
||||
AgentSessionConfig,
|
||||
"modeId" | "model" | "thinkingOptionId" | "extra" | "mcpServers"
|
||||
"modeId" | "model" | "thinkingOptionId" | "extra" | "systemPrompt" | "mcpServers"
|
||||
>;
|
||||
|
||||
export type StoredAgentRecord = z.infer<typeof STORED_AGENT_SCHEMA>;
|
||||
|
||||
@@ -270,6 +270,9 @@ function coerceSessionMetadata(metadata: AgentMetadata | undefined): Partial<Age
|
||||
result.extra = extra;
|
||||
}
|
||||
}
|
||||
if (typeof metadata.systemPrompt === "string") {
|
||||
result.systemPrompt = metadata.systemPrompt;
|
||||
}
|
||||
if (isMcpServersRecord(metadata.mcpServers)) {
|
||||
result.mcpServers = metadata.mcpServers;
|
||||
}
|
||||
|
||||
@@ -1597,6 +1597,9 @@ class CodexAppServerAgentSession implements AgentSession {
|
||||
modeId: this.currentMode,
|
||||
model: this.config.model ?? null,
|
||||
thinkingOptionId,
|
||||
extra: this.config.extra,
|
||||
systemPrompt: this.config.systemPrompt,
|
||||
mcpServers: this.config.mcpServers,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1961,6 +1961,7 @@ const AgentSessionConfigSchema = z
|
||||
networkAccess: z.boolean().optional(),
|
||||
webSearch: z.boolean().optional(),
|
||||
extra: AgentSessionExtraSchema.optional(),
|
||||
systemPrompt: z.string().optional(),
|
||||
mcpServers: z.record(McpServerConfigSchema).optional(),
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
@@ -4,6 +4,8 @@ import type { ManagedAgent } from "./agent/agent-manager.js";
|
||||
import type { StoredAgentRecord } from "./agent/agent-storage.js";
|
||||
import {
|
||||
attachAgentStoragePersistence,
|
||||
buildConfigOverrides,
|
||||
buildSessionConfig,
|
||||
} from "./persistence-hooks.js";
|
||||
import type {
|
||||
AgentPermissionRequest,
|
||||
@@ -140,4 +142,72 @@ describe("persistence hooks", () => {
|
||||
});
|
||||
expect(applySnapshot).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("buildConfigOverrides carries systemPrompt and mcpServers", () => {
|
||||
const record = createRecord({
|
||||
title: "Voice agent",
|
||||
config: {
|
||||
modeId: "default",
|
||||
model: "gpt-5.1-codex-mini",
|
||||
thinkingOptionId: "minimal",
|
||||
systemPrompt: "Use speak first.",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/bridge.mjs", "--socket", "/tmp/agent.sock"],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(buildConfigOverrides(record)).toMatchObject({
|
||||
cwd: "/tmp/project",
|
||||
modeId: "plan",
|
||||
model: "gpt-5.1-codex-mini",
|
||||
thinkingOptionId: "minimal",
|
||||
title: "Voice agent",
|
||||
systemPrompt: "Use speak first.",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/bridge.mjs", "--socket", "/tmp/agent.sock"],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test("buildSessionConfig includes persisted systemPrompt and mcpServers", () => {
|
||||
const record = createRecord({
|
||||
provider: "codex",
|
||||
config: {
|
||||
modeId: "default",
|
||||
model: "gpt-5.1-codex-mini",
|
||||
systemPrompt: "Confirm and speak first.",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/bridge.mjs", "--socket", "/tmp/agent.sock"],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(buildSessionConfig(record)).toMatchObject({
|
||||
provider: "codex",
|
||||
cwd: "/tmp/project",
|
||||
modeId: "plan",
|
||||
model: "gpt-5.1-codex-mini",
|
||||
systemPrompt: "Confirm and speak first.",
|
||||
mcpServers: {
|
||||
paseo: {
|
||||
type: "stdio",
|
||||
command: "node",
|
||||
args: ["/tmp/bridge.mjs", "--socket", "/tmp/agent.sock"],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,6 +56,7 @@ export function buildConfigOverrides(
|
||||
thinkingOptionId: record.config?.thinkingOptionId ?? undefined,
|
||||
title: record.title ?? undefined,
|
||||
extra: record.config?.extra ?? undefined,
|
||||
systemPrompt: record.config?.systemPrompt ?? undefined,
|
||||
mcpServers: record.config?.mcpServers ?? undefined,
|
||||
};
|
||||
}
|
||||
@@ -75,6 +76,7 @@ export function buildSessionConfig(
|
||||
thinkingOptionId: overrides.thinkingOptionId,
|
||||
title: overrides.title,
|
||||
extra: overrides.extra,
|
||||
systemPrompt: overrides.systemPrompt,
|
||||
mcpServers: overrides.mcpServers,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ const AgentSessionConfigSchema = z.object({
|
||||
})
|
||||
.partial()
|
||||
.optional(),
|
||||
systemPrompt: z.string().optional(),
|
||||
mcpServers: z.record(McpServerConfigSchema).optional(),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user