feat(coding): add core host api composition

This commit is contained in:
2026-08-23 20:00:35 +08:00
parent 98bac20639
commit 22b4a9f9c4
23 changed files with 2258 additions and 59 deletions

View File

@@ -39,6 +39,7 @@ class RuntimeFakeWorker implements PiConversationWorker {
contextUsage: { tokens: 0, contextWindow: 100_000, percent: 0 },
tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
};
private commandsData: unknown = { commands: [] };
private failType: string | null = null;
private readonly responseGates = new Map<string, Promise<void>>();
private readonly events = new Set<(event: PiRpcEvent) => void>();
@@ -69,7 +70,11 @@ class RuntimeFakeWorker implements PiConversationWorker {
? this.stateData
: command.type === 'get_entries'
? this.entriesData
: command.type === 'get_session_stats' ? this.statsData : undefined;
: command.type === 'get_session_stats'
? this.statsData
: command.type === 'get_commands'
? this.commandsData
: undefined;
return {
type: 'response',
id: `${this.id}-${this.requests.length}`,
@@ -82,10 +87,11 @@ class RuntimeFakeWorker implements PiConversationWorker {
this.requests.push(structuredClone(command));
}
setSessionData(input: { state?: unknown; entries?: unknown; stats?: unknown }): void {
setSessionData(input: { state?: unknown; entries?: unknown; stats?: unknown; commands?: unknown }): void {
if (input.state !== undefined) this.stateData = structuredClone(input.state);
if (input.entries !== undefined) this.entriesData = structuredClone(input.entries);
if (input.stats !== undefined) this.statsData = structuredClone(input.stats);
if (input.commands !== undefined) this.commandsData = structuredClone(input.commands);
}
failNext(type: string): void { this.failType = type; }
@@ -222,6 +228,16 @@ describe('Pi Conversation runtime', () => {
},
});
await Promise.all(inputs.slice(0, 2).map((input) => runtime.prepare(input)));
workers.get(left.id)!.setSessionData({
commands: {
commands: [{ name: 'custom', description: 'Custom command', provider: 'raw-provider' }],
apiKey: 'raw-secret',
},
});
expect(await runtime.listCommands(left.id)).toEqual([
{ name: 'custom', description: 'Custom command' },
]);
expect(await runtime.listCommands('00000000-0000-4000-8000-000000000000')).toEqual([]);
const leftGenerationOneSeqs: number[] = [];
const unsubscribe = runtime.subscribe((envelope) => {
if (envelope.conversationId === left.id && envelope.workerGeneration === 1) {
@@ -242,7 +258,7 @@ describe('Pi Conversation runtime', () => {
return value;
});
await expect.poll(() => workers.get(left.id)!.requests.at(-1)?.type).toBe('prompt');
expect(workers.get(left.id)!.requests).toHaveLength(4);
expect(workers.get(left.id)!.requests).toHaveLength(5);
expect(acceptanceResolved).toBe(false);
releasePromptAcceptance();
const accepted = await acceptance;