fix(pi): load installed device extensions
This commit is contained in:
@@ -177,11 +177,12 @@ async function createThreadRuntime(channel, rawOptions) {
|
|||||||
const appendSystemPrompts = optionValues(args, '--append-system-prompt');
|
const appendSystemPrompts = optionValues(args, '--append-system-prompt');
|
||||||
const sessionId = requiredString(optionValue(args, '--session-id'), 'Thread session id');
|
const sessionId = requiredString(optionValue(args, '--session-id'), 'Thread session id');
|
||||||
const forkSessionId = optionValue(args, '--fork');
|
const forkSessionId = optionValue(args, '--fork');
|
||||||
const extensionPaths = optionValues(args, '--extension').map((value) => path.resolve(value));
|
const [makeloreExtensionPath, ...additionalExtensionPaths] = optionValues(args, '--extension')
|
||||||
|
.map((value) => path.resolve(value));
|
||||||
const skillPaths = optionValues(args, '--skill').map((value) => path.resolve(value));
|
const skillPaths = optionValues(args, '--skill').map((value) => path.resolve(value));
|
||||||
if (extensionPaths.length !== 1) throw new Error('Thread requires exactly one Makelore extension');
|
if (!makeloreExtensionPath) throw new Error('Thread requires a Makelore extension');
|
||||||
if (appendSystemPrompts.length !== 1) throw new Error('Thread requires exactly one Makelore language prompt');
|
if (appendSystemPrompts.length !== 1) throw new Error('Thread requires exactly one Makelore language prompt');
|
||||||
const extensionModule = await import(pathToFileURL(extensionPaths[0]).href);
|
const extensionModule = await import(pathToFileURL(makeloreExtensionPath).href);
|
||||||
if (typeof extensionModule.createMakeloreRuntime !== 'function') {
|
if (typeof extensionModule.createMakeloreRuntime !== 'function') {
|
||||||
throw new Error('Makelore runtime extension factory is unavailable');
|
throw new Error('Makelore runtime extension factory is unavailable');
|
||||||
}
|
}
|
||||||
@@ -215,6 +216,7 @@ async function createThreadRuntime(channel, rawOptions) {
|
|||||||
cwd: runtimeCwd,
|
cwd: runtimeCwd,
|
||||||
})),
|
})),
|
||||||
}],
|
}],
|
||||||
|
additionalExtensionPaths,
|
||||||
additionalSkillPaths: skillPaths,
|
additionalSkillPaths: skillPaths,
|
||||||
noExtensions: true,
|
noExtensions: true,
|
||||||
noSkills: true,
|
noSkills: true,
|
||||||
|
|||||||
@@ -196,6 +196,22 @@ describe('Pi Agent Server real process', () => {
|
|||||||
writeFile(languagePromptPath, MAKELORE_DEFAULT_LANGUAGE_PROMPT),
|
writeFile(languagePromptPath, MAKELORE_DEFAULT_LANGUAGE_PROMPT),
|
||||||
]);
|
]);
|
||||||
const extensionPath = await materializeMakelorePiExtension(extensionDir);
|
const extensionPath = await materializeMakelorePiExtension(extensionDir);
|
||||||
|
const firstDeviceExtensionPath = path.join(extensionDir, 'first-device-extension.mjs');
|
||||||
|
const secondDeviceExtensionPath = path.join(extensionDir, 'second-device-extension.mjs');
|
||||||
|
await Promise.all([
|
||||||
|
writeFile(firstDeviceExtensionPath, [
|
||||||
|
'export default function (pi) {',
|
||||||
|
" pi.registerCommand('first-device-ping', { description: 'First device ping', handler: async () => {} });",
|
||||||
|
'}',
|
||||||
|
'',
|
||||||
|
].join('\n')),
|
||||||
|
writeFile(secondDeviceExtensionPath, [
|
||||||
|
'export default function (pi) {',
|
||||||
|
" pi.registerCommand('second-device-ping', { description: 'Second device ping', handler: async () => {} });",
|
||||||
|
'}',
|
||||||
|
'',
|
||||||
|
].join('\n')),
|
||||||
|
]);
|
||||||
const runtimeRoot = path.resolve('node_modules/@earendil-works/pi-coding-agent');
|
const runtimeRoot = path.resolve('node_modules/@earendil-works/pi-coding-agent');
|
||||||
const server = new PiAgentServerProcess({
|
const server = new PiAgentServerProcess({
|
||||||
executablePath: process.execPath,
|
executablePath: process.execPath,
|
||||||
@@ -221,6 +237,8 @@ describe('Pi Agent Server real process', () => {
|
|||||||
'--system-prompt', promptPath,
|
'--system-prompt', promptPath,
|
||||||
'--append-system-prompt', languagePromptPath,
|
'--append-system-prompt', languagePromptPath,
|
||||||
'--extension', extensionPath,
|
'--extension', extensionPath,
|
||||||
|
'--extension', firstDeviceExtensionPath,
|
||||||
|
'--extension', secondDeviceExtensionPath,
|
||||||
'--session-id', `session-${conversationId}`,
|
'--session-id', `session-${conversationId}`,
|
||||||
],
|
],
|
||||||
env: {
|
env: {
|
||||||
@@ -261,6 +279,15 @@ describe('Pi Agent Server real process', () => {
|
|||||||
.resolves.toMatchObject({
|
.resolves.toMatchObject({
|
||||||
data: { models: expect.arrayContaining([expect.objectContaining({ id: 'test-model' })]) },
|
data: { models: expect.arrayContaining([expect.objectContaining({ id: 'test-model' })]) },
|
||||||
});
|
});
|
||||||
|
await expect(left.request<{ commands: Array<{ name: string; source: string }> }>({ type: 'get_commands' }))
|
||||||
|
.resolves.toMatchObject({
|
||||||
|
data: {
|
||||||
|
commands: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ name: 'first-device-ping', source: 'extension' }),
|
||||||
|
expect.objectContaining({ name: 'second-device-ping', source: 'extension' }),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const settled = (worker: typeof left) => new Promise<void>((resolve) => {
|
const settled = (worker: typeof left) => new Promise<void>((resolve) => {
|
||||||
const unsubscribe = worker.subscribe((event) => {
|
const unsubscribe = worker.subscribe((event) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user