feat(rpc): add validated desktop Pi RPC command palette
This commit is contained in:
@@ -20,10 +20,12 @@ function createAdapterFactory() {
|
||||
startAdapter: (options) => {
|
||||
const adapter = {
|
||||
sent: [],
|
||||
sentWithOptions: [],
|
||||
extensionResponses: [],
|
||||
stopped: false,
|
||||
send(command) {
|
||||
send(command, options) {
|
||||
this.sent.push(command);
|
||||
this.sentWithOptions.push({ command, options });
|
||||
return Promise.resolve({
|
||||
type: "response",
|
||||
command: command.type,
|
||||
@@ -53,6 +55,10 @@ test("starts only the home agent and creates other worktree agents on explicit s
|
||||
});
|
||||
|
||||
const home = await registry.start();
|
||||
assert.deepEqual(fixture.calls[0].adapter.sentWithOptions[0], {
|
||||
command: { type: "get_state" },
|
||||
options: { timeoutMs: 90_000 },
|
||||
});
|
||||
assert.equal(registry.listAgents().length, 1);
|
||||
assert.equal(home.worktreePath, worktrees.home);
|
||||
|
||||
@@ -72,6 +78,58 @@ test("starts only the home agent and creates other worktree agents on explicit s
|
||||
assert.ok(fixture.calls.every(({ adapter }) => adapter.stopped));
|
||||
});
|
||||
|
||||
test("sends abort without waiting behind a blocked prompt", async () => {
|
||||
const worktrees = await createWorktrees();
|
||||
const fixture = createAdapterFactory();
|
||||
const registry = createAgentRegistry({
|
||||
homeWorktree: worktrees.home,
|
||||
sessionRoot: worktrees.sessionRoot,
|
||||
startAdapter: fixture.startAdapter,
|
||||
});
|
||||
const agent = await registry.start();
|
||||
const adapter = fixture.calls[0].adapter;
|
||||
const send = adapter.send.bind(adapter);
|
||||
let releasePrompt;
|
||||
adapter.send = (command) => {
|
||||
if (command.type !== "prompt") return send(command);
|
||||
adapter.sent.push(command);
|
||||
return new Promise((resolve) => {
|
||||
releasePrompt = () =>
|
||||
resolve({ type: "response", command: "prompt", success: true });
|
||||
});
|
||||
};
|
||||
const prompt = registry.route(agent.id, "prompt", { message: "Work" });
|
||||
while (!releasePrompt) await new Promise((resolve) => setImmediate(resolve));
|
||||
const abort = registry.route(agent.id, "abort");
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
assert.equal(adapter.sent.at(-1).type, "abort");
|
||||
releasePrompt();
|
||||
await Promise.all([prompt, abort]);
|
||||
await registry.stop();
|
||||
});
|
||||
|
||||
test("keeps a runtime healthy after a non-terminal adapter diagnostic", async () => {
|
||||
const worktrees = await createWorktrees();
|
||||
const fixture = createAdapterFactory();
|
||||
const registry = createAgentRegistry({
|
||||
homeWorktree: worktrees.home,
|
||||
sessionRoot: worktrees.sessionRoot,
|
||||
startAdapter: fixture.startAdapter,
|
||||
});
|
||||
await registry.start();
|
||||
|
||||
fixture.calls[0].options.onError(
|
||||
{ code: "frame_too_large", message: "Pi RPC frame exceeds 32 bytes" },
|
||||
{ terminal: false },
|
||||
);
|
||||
|
||||
const runtime = registry.getWorkspace().directories[0].runtimes[0];
|
||||
assert.equal(runtime.state, "idle");
|
||||
assert.equal(runtime.attention, false);
|
||||
assert.equal(runtime.error, undefined);
|
||||
await registry.stop();
|
||||
});
|
||||
|
||||
test("stops agents created during shutdown and rejects new selections", async () => {
|
||||
const worktrees = await createWorktrees();
|
||||
const fixture = createAdapterFactory();
|
||||
@@ -270,8 +328,9 @@ test("coordinates forgetting with directory creation and active commands", async
|
||||
/runtimes are open/,
|
||||
);
|
||||
const closing = registry.closeSessionRuntime(
|
||||
registry.listAgents().find((agent) => agent.worktreePath === worktrees.feature)
|
||||
.runtimeId,
|
||||
registry
|
||||
.listAgents()
|
||||
.find((agent) => agent.worktreePath === worktrees.feature).runtimeId,
|
||||
);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
releaseStop();
|
||||
@@ -483,9 +542,10 @@ test("routes commands by explicit agent ID and replays only events after the cur
|
||||
type: "agent_state",
|
||||
data: { state: "streaming" },
|
||||
});
|
||||
await registry.route(agent.id, "submit_prompt", {
|
||||
const followUp = await registry.route(agent.id, "submit_prompt", {
|
||||
message: "After this turn",
|
||||
});
|
||||
assert.equal(followUp.delivery, "follow_up");
|
||||
assert.deepEqual(adapter.sent.at(-1), {
|
||||
type: "follow_up",
|
||||
message: "After this turn",
|
||||
|
||||
Reference in New Issue
Block a user