mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 23:44:41 +00:00
config.title is now strictly the caller's creation intent and is never mutated. The prompt-derived placeholder lives only in record.title at creation, so the metadata generator's upfront gate (hasExplicitTitle) is the only one and writes unconditionally when it runs. Drops the two projection fallbacks to record.config.title that were the second hidden path for the prompt to surface as a title.
136 lines
3.5 KiB
TypeScript
136 lines
3.5 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import type { StoredAgentRecord } from "./agent/agent-storage.js";
|
|
import {
|
|
buildConfigOverrides,
|
|
buildSessionConfig,
|
|
toAgentPersistenceHandle,
|
|
} from "./persistence-hooks.js";
|
|
|
|
function createRecord(overrides?: Partial<StoredAgentRecord>): StoredAgentRecord {
|
|
const now = new Date().toISOString();
|
|
return {
|
|
id: "agent-record",
|
|
provider: "claude",
|
|
cwd: "/tmp/project",
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
title: null,
|
|
lastStatus: "idle",
|
|
lastModeId: "plan",
|
|
config: { modeId: "plan", model: "claude-3.5-sonnet" },
|
|
persistence: {
|
|
provider: "claude",
|
|
sessionId: "session-123",
|
|
},
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("persistence hooks", () => {
|
|
test("buildConfigOverrides carries systemPrompt and mcpServers", () => {
|
|
const record = createRecord({
|
|
title: "Voice agent (current)",
|
|
config: {
|
|
modeId: "default",
|
|
model: "gpt-5.4-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.4-mini",
|
|
thinkingOptionId: "minimal",
|
|
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",
|
|
title: "Renamed title",
|
|
config: {
|
|
modeId: "default",
|
|
model: "gpt-5.4-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.4-mini",
|
|
systemPrompt: "Confirm and speak first.",
|
|
mcpServers: {
|
|
paseo: {
|
|
type: "stdio",
|
|
command: "node",
|
|
args: ["/tmp/bridge.mjs", "--socket", "/tmp/agent.sock"],
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
test("buildSessionConfig accepts providers from the canonical manifest", () => {
|
|
const record = createRecord({
|
|
provider: "claude",
|
|
persistence: {
|
|
provider: "claude",
|
|
sessionId: "session-123",
|
|
},
|
|
config: {},
|
|
});
|
|
|
|
expect(buildSessionConfig(record)).toMatchObject({
|
|
provider: "claude",
|
|
cwd: "/tmp/project",
|
|
});
|
|
});
|
|
|
|
test("buildSessionConfig skips records whose provider is missing from the registry", () => {
|
|
const record = createRecord({
|
|
id: "agent-missing-provider",
|
|
provider: "zai",
|
|
});
|
|
|
|
expect(
|
|
buildSessionConfig(record, {
|
|
validProviders: ["claude", "codex"],
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
|
|
test("toAgentPersistenceHandle rejects handles for unavailable providers", () => {
|
|
const handle = toAgentPersistenceHandle(["claude", "codex"], {
|
|
provider: "gemini",
|
|
sessionId: "session-123",
|
|
});
|
|
|
|
expect(handle).toBeNull();
|
|
});
|
|
});
|