fix: isolate concurrent OpenCode chat runs

This commit is contained in:
2026-08-17 22:03:37 +08:00
parent 7e8d9e3811
commit 65040730ec
29 changed files with 5207 additions and 427 deletions

View File

@@ -113,6 +113,62 @@ describe('opencode client', () => {
);
});
it('lists the live Agent registry scoped to the selected folder', async () => {
const agents = [{ name: 'game-design', description: '游戏设计伙伴' }];
const fetchImpl = vi.fn(async () => {
return new Response(JSON.stringify(agents), {
headers: { 'Content-Type': 'application/json' },
});
});
const client = createOpencodeClient({
baseUrl: 'http://127.0.0.1:4096',
directory: 'D:/work/app',
fetchImpl,
});
await expect(client.listAgents()).resolves.toEqual(agents);
expect(fetchImpl).toHaveBeenCalledWith(
'http://127.0.0.1:4096/agent?directory=D%3A%2Fwork%2Fapp',
expect.objectContaining({
headers: expect.objectContaining({
'Content-Type': 'application/json',
'x-opencode-directory': encodeURIComponent('D:/work/app'),
}),
}),
);
});
it('forwards AbortSignal to bounded runtime config, Agent, prompt, command, and summarize requests', async () => {
const fetchImpl = vi.fn(async (url: string | URL | Request) => {
const pathname = new URL(String(url)).pathname;
if (pathname === '/agent') return new Response('[]');
if (pathname === '/config') return new Response('{}');
if (pathname.endsWith('/prompt_async')) return new Response(null, { status: 204 });
return new Response('{}');
});
const client = createOpencodeClient({
baseUrl: 'http://127.0.0.1:4096',
directory: 'D:/work/app',
fetchImpl,
});
const controller = new AbortController();
const request = { signal: controller.signal };
await client.getConfig(request);
await client.listAgents(request);
await client.promptSessionAsync('ses_1', { text: 'Ship it' }, request);
await client.executeSessionCommand('ses_1', { command: 'review', arguments: '' }, request);
await client.summarizeSession('ses_1', {
providerID: 'niancode-user-models',
modelID: 'qwen3.7-plus',
}, request);
expect(fetchImpl).toHaveBeenCalledTimes(5);
for (const [, init] of fetchImpl.mock.calls) {
expect(init?.signal).toBe(controller.signal);
}
});
it('posts a text message to a session scoped to the selected folder', async () => {
const fetchImpl = vi.fn(async () => {
return new Response(JSON.stringify({ id: 'msg_1', role: 'user' }), {