feat(coding-agent): introduced fine grained per agent advisor configuration

- Replaced blanket subagent advisor global settings with fine-grained per-agent configuration and frontmatter support.
- Added dashboard keybindings and inline override editors for managing agent advisor patterns.
- Implemented settings migration logic to convert legacy global options into per-agent settings.
- Updated session persistence and execution layers to restore and enforce per-agent advisor behaviors.
This commit is contained in:
can1357
2026-08-13 04:59:50 +02:00
parent 1132c3e31c
commit e8eed95130
27 changed files with 586 additions and 91 deletions
@@ -62,7 +62,12 @@ function createRevivedSession(activeToolNames: string[][]): RevivedSessionHandle
return { session, observer: () => observer };
}
async function createPersistedSession(cwd: string, restrictToolNames?: boolean, modelRole?: string): Promise<string> {
async function createPersistedSession(
cwd: string,
restrictToolNames?: boolean,
modelRole?: string,
advisor?: string,
): Promise<string> {
const manager = SessionManager.create(cwd, path.join(cwd, "sessions"));
const sessionFile = manager.getSessionFile();
if (!sessionFile) throw new Error("Expected a persisted session file");
@@ -73,6 +78,7 @@ async function createPersistedSession(cwd: string, restrictToolNames?: boolean,
restrictToolNames,
modelRole,
resolvedModel: modelRole ? "anthropic/claude-sonnet-4-5" : undefined,
advisor,
});
manager.appendMessage({
role: "assistant",
@@ -180,6 +186,32 @@ describe("persisted subagent revival", () => {
expect(capturedOptions?.mcpManager).toBe(hostileMcp);
expect(capturedOptions?.customTools?.map(tool => tool.name)).toEqual(["mcp__server_read"]);
});
it("restores the persisted per-agent advisor opt-in on cold revival", async () => {
const cwd = makeTempDir("@pi-advisor-revive-");
const advisedFile = await createPersistedSession(cwd, undefined, undefined, "moonshot/k3");
const roleAdvisedFile = await createPersistedSession(cwd, undefined, undefined, "on");
const unadvisedFile = await createPersistedSession(cwd);
const captured: Settings[] = [];
vi.spyOn(sdkModule, "createAgentSession").mockImplementation(async options => {
if (options?.settings) captured.push(options.settings);
return { session: createRevivedSession([]).session } as CreateAgentSessionResult;
});
const factory = createFactory(cwd);
for (const sessionFile of [advisedFile, roleAdvisedFile, unadvisedFile]) {
const ref = createRef(sessionFile);
const reviver = await factory(ref);
if (!reviver) throw new Error("Expected a persisted reviver");
await reviver(ref);
}
const [advised, roleAdvised, unadvised] = captured;
expect(advised.get("advisor.enabled")).toBe(true);
expect(advised.getModelRole("advisor")).toBe("moonshot/k3");
expect(roleAdvised.get("advisor.enabled")).toBe(true);
expect(roleAdvised.getModelRole("advisor")).toBeUndefined();
expect(unadvised.get("advisor.enabled")).toBe(false);
});
it("restores the persisted custom model role before reopening the session", async () => {
const cwd = makeTempDir("@pi-custom-role-revive-");