feat: integrate automatic game resource delivery
This commit is contained in:
@@ -320,6 +320,115 @@ describe('Makelore Pi extension bundle', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('streams job-tool progress through the authenticated product bridge', async () => {
|
||||
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-product-stream-'));
|
||||
roots.push(root);
|
||||
const host = new PiManagedExtensionHost();
|
||||
hosts.push(host);
|
||||
const details = (phase: string) => ({
|
||||
schema: 'makelore-capability.v1' as const,
|
||||
plugin_id: 'makelore.game-resource',
|
||||
plugin_version: '1.0.0',
|
||||
capability_id: 'game-resource.generate',
|
||||
operation: 'generate',
|
||||
request_id: 'pi:stream-run:stream-tool',
|
||||
success: true,
|
||||
status: phase === 'saved' ? 200 : 202,
|
||||
code: null,
|
||||
error: null,
|
||||
retryable: false,
|
||||
billing: {
|
||||
mode: 'platform_metered' as const,
|
||||
status: phase === 'saved' ? 'settled' as const : 'dispatched' as const,
|
||||
reserved_points: '2.00',
|
||||
...(phase === 'saved' ? { actual_points: '2.00' } : {}),
|
||||
usage_amount: 1,
|
||||
unit: 'generation',
|
||||
},
|
||||
payload_schema: 'game-resource.v1',
|
||||
data: { phase, executionId: 'execution-a' },
|
||||
});
|
||||
const invoke = vi.fn(async (input: {
|
||||
onUpdate?: (result: { content: []; details: ReturnType<typeof details> }) => void;
|
||||
}) => {
|
||||
input.onUpdate?.({ content: [], details: details('generating') });
|
||||
input.onUpdate?.({ content: [], details: details('saving') });
|
||||
return { content: [], details: details('saved') };
|
||||
});
|
||||
host.configureProductTools(new PiProductTools({
|
||||
browser: {} as AgentBrowserModule,
|
||||
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
|
||||
bundledSkillsDir: path.resolve('resources/coding-skills'),
|
||||
capabilityRegistry: { invoke } as unknown as CodingCapabilityRegistryImpl,
|
||||
}));
|
||||
const jobTool: CodingPluginToolDefinition = {
|
||||
name: 'game_resource_generate',
|
||||
label: 'Generate game resource',
|
||||
description: 'Generate and save a game resource.',
|
||||
capabilityId: 'game-resource.generate',
|
||||
operation: 'generate',
|
||||
roles: ['parent'],
|
||||
mutation: 'write',
|
||||
projectWriteLease: false,
|
||||
permissions: ['hosted.game-resource.generate'],
|
||||
executionMode: 'job',
|
||||
inputSchema: { type: 'object', additionalProperties: false, properties: {} },
|
||||
};
|
||||
const registration = await host.registerWorker({
|
||||
conversationId: 'stream-conversation', generation: 1, projectId: 'stream-project',
|
||||
projectPath: root, extensionsDir: root, tools: [jobTool],
|
||||
});
|
||||
await host.bindRun('stream-conversation', 1, 'stream-run');
|
||||
const previous = {
|
||||
bridge: process.env.MAKELORE_PI_BRIDGE_URL,
|
||||
token: process.env.MAKELORE_PI_WORKER_TOKEN,
|
||||
context: process.env.MAKELORE_PI_CONTEXT_FILE,
|
||||
role: process.env.MAKELORE_PI_WORKER_ROLE,
|
||||
};
|
||||
Object.assign(process.env, registration.env);
|
||||
try {
|
||||
const module = await import(
|
||||
/* @vite-ignore */ `${pathToFileURL(registration.extensionPath).href}?stream=${Date.now()}`
|
||||
) as {
|
||||
default(factory: {
|
||||
registerTool(tool: ExtensionTool): void;
|
||||
on(event: string, handler: ExtensionHandler): void;
|
||||
}): void | Promise<void>;
|
||||
};
|
||||
const tools = new Map<string, ExtensionTool>();
|
||||
await module.default({
|
||||
registerTool: (tool) => tools.set(tool.name, tool),
|
||||
on: () => undefined,
|
||||
});
|
||||
const updates: unknown[] = [];
|
||||
const result = await tools.get('game_resource_generate')?.execute?.(
|
||||
'stream-tool',
|
||||
{},
|
||||
new AbortController().signal,
|
||||
(update: unknown) => updates.push(update),
|
||||
);
|
||||
|
||||
expect(updates).toEqual([
|
||||
{ content: [], details: details('generating') },
|
||||
{ content: [], details: details('saving') },
|
||||
]);
|
||||
expect(result).toEqual({ content: [], details: details('saved') });
|
||||
expect(invoke).toHaveBeenCalledWith(expect.objectContaining({
|
||||
toolName: 'game_resource_generate',
|
||||
onUpdate: expect.any(Function),
|
||||
}));
|
||||
} finally {
|
||||
for (const [key, value] of Object.entries(previous)) {
|
||||
const environmentKey = key === 'bridge' ? 'MAKELORE_PI_BRIDGE_URL'
|
||||
: key === 'token' ? 'MAKELORE_PI_WORKER_TOKEN'
|
||||
: key === 'context' ? 'MAKELORE_PI_CONTEXT_FILE'
|
||||
: 'MAKELORE_PI_WORKER_ROLE';
|
||||
if (value === undefined) delete process.env[environmentKey];
|
||||
else process.env[environmentKey] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('executes versioned product tools through the authenticated real bundle', async () => {
|
||||
const root = await mkdtemp(path.join(tmpdir(), 'makelore-pi-product-bundle-'));
|
||||
roots.push(root);
|
||||
|
||||
Reference in New Issue
Block a user