fix(coding): bound missing Pi settlement

This commit is contained in:
inman
2026-09-01 12:40:08 +08:00
parent 8062b45103
commit f1fd13a70f
6 changed files with 478 additions and 52 deletions

View File

@@ -8,6 +8,7 @@ import { afterEach, describe, expect, it } from 'vitest';
import { PiAgentServerProcess } from '../../electron/coding-runtime/pi/agent-server-process';
import { materializeMakelorePiExtension } from '../../electron/coding-runtime/pi/extensions/makelore-runtime';
import { MAKELORE_DEFAULT_LANGUAGE_PROMPT } from '../../electron/coding-runtime/pi/resource-loader';
import type { PiRpcEvent } from '../../electron/coding-runtime/pi/rpc-client';
import type { PiWorkerProcessOptions } from '../../electron/coding-runtime/pi/worker-process';
const roots: string[] = [];
@@ -124,6 +125,16 @@ describe('Pi Agent Server real process', () => {
writeFile(languagePromptPath, MAKELORE_DEFAULT_LANGUAGE_PROMPT),
]);
const extensionPath = await materializeMakelorePiExtension(extensionDir);
const invalidJsonExtensionPath = path.join(extensionDir, 'invalid-json-extension.mjs');
await writeFile(invalidJsonExtensionPath, `
export function createMakeloreRuntime() {
return async function invalidJsonRuntime(pi) {
pi.on('message_end', async (event) => ({
message: { ...event.message, makeloreInvalidJson: 1n },
}));
};
}
`);
const runtimeRoot = path.resolve('node_modules/@earendil-works/pi-coding-agent');
const server = new PiAgentServerProcess({
executablePath: process.execPath,
@@ -132,7 +143,11 @@ describe('Pi Agent Server real process', () => {
configDir,
});
const workerOptions = (conversationId: string, generation: number): PiWorkerProcessOptions => {
const workerOptions = (
conversationId: string,
generation: number,
selectedExtensionPath = extensionPath,
): PiWorkerProcessOptions => {
const contextFile = path.join(root, `${conversationId}.json`);
return {
executablePath: process.execPath,
@@ -148,7 +163,7 @@ describe('Pi Agent Server real process', () => {
'--thinking', 'medium',
'--system-prompt', promptPath,
'--append-system-prompt', languagePromptPath,
'--extension', extensionPath,
'--extension', selectedExtensionPath,
'--session-id', `session-${conversationId}`,
],
env: {
@@ -163,7 +178,7 @@ describe('Pi Agent Server real process', () => {
};
};
await Promise.all(['left', 'right'].map(async (conversationId) => {
await Promise.all(['left', 'right', 'broken'].map(async (conversationId) => {
await writeFile(path.join(root, `${conversationId}.json`), JSON.stringify({
conversationId,
workerGeneration: 1,
@@ -216,6 +231,25 @@ describe('Pi Agent Server real process', () => {
provider.release();
await Promise.all([leftSettled, rightSettled]);
const broken = server.createWorker(workerOptions('broken', 1, invalidJsonExtensionPath));
await broken.start();
const postAcceptanceFailure = new Promise<PiRpcEvent>((resolve) => {
const unsubscribe = broken.subscribe((event) => {
if (event.type !== 'makelore_thread_error') return;
unsubscribe();
resolve(event);
});
});
await expect(broken.request({ type: 'prompt', message: 'BREAK_AFTER_ACCEPTANCE' }))
.resolves.toMatchObject({ success: true });
await expect(postAcceptanceFailure).resolves.toMatchObject({
type: 'makelore_thread_error',
code: 'PROMPT_FAILED_AFTER_ACCEPTANCE',
});
await expect(broken.request<{ isStreaming: boolean }>({ type: 'get_state' }))
.resolves.toMatchObject({ data: { isStreaming: false } });
await broken.stop('test_injection');
await left.stop('test_injection');
expect(server.processId).toBe(processId);
expect(server.activeThreadCount).toBe(1);