feat(server): refactor provider interface (#11665)

fix AI-4
fix AI-18

better provider/model choose to allow fallback to similar models (e.g., self-hosted) when the provider is not fully configured
split functions of different output types
This commit is contained in:
darkskygit
2025-05-22 06:28:20 +00:00
parent a3b8aaff61
commit b388f92c96
36 changed files with 1465 additions and 903 deletions
@@ -121,6 +121,7 @@ test.before(async t => {
});
const textPromptName = 'prompt';
const imagePromptName = 'prompt-image';
test.beforeEach(async t => {
Sinon.restore();
const { app, prompt } = t.context;
@@ -131,6 +132,10 @@ test.beforeEach(async t => {
await prompt.set(textPromptName, 'test', [
{ role: 'system', content: 'hello {{word}}' },
]);
await prompt.set(imagePromptName, 'test-image', [
{ role: 'system', content: 'hello {{word}}' },
]);
});
test.after.always(async t => {
@@ -441,33 +446,44 @@ test('should be able to chat with api', async t => {
Sinon.stub(storage, 'handleRemoteLink').resolvesArg(2);
const { id } = await createWorkspace(app);
const sessionId = await createCopilotSession(
app,
id,
randomUUID(),
textPromptName
);
const messageId = await createCopilotMessage(app, sessionId);
const ret = await chatWithText(app, sessionId, messageId);
t.is(ret, 'generate text to text', 'should be able to chat with text');
{
const sessionId = await createCopilotSession(
app,
id,
randomUUID(),
textPromptName
);
const messageId = await createCopilotMessage(app, sessionId);
const ret = await chatWithText(app, sessionId, messageId);
t.is(ret, 'generate text to text', 'should be able to chat with text');
const ret2 = await chatWithTextStream(app, sessionId, messageId);
t.is(
ret2,
textToEventStream('generate text to text stream', messageId),
'should be able to chat with text stream'
);
const ret2 = await chatWithTextStream(app, sessionId, messageId);
t.is(
ret2,
textToEventStream('generate text to text stream', messageId),
'should be able to chat with text stream'
);
}
const ret3 = await chatWithImages(app, sessionId, messageId);
t.is(
array2sse(sse2array(ret3).filter(e => e.event !== 'event')),
textToEventStream(
['https://example.com/test.jpg', 'hello '],
messageId,
'attachment'
),
'should be able to chat with images'
);
{
const sessionId = await createCopilotSession(
app,
id,
randomUUID(),
imagePromptName
);
const messageId = await createCopilotMessage(app, sessionId);
const ret3 = await chatWithImages(app, sessionId, messageId);
t.is(
array2sse(sse2array(ret3).filter(e => e.event !== 'event')),
textToEventStream(
['https://example.com/test-image.jpg', 'hello '],
messageId,
'attachment'
),
'should be able to chat with images'
);
}
Sinon.restore();
});
@@ -918,7 +934,10 @@ test('should be able to transcript', async t => {
const { id: workspaceId } = await createWorkspace(app);
Sinon.stub(app.get(GeminiProvider), 'generateText').resolves(
Sinon.stub(app.get(GeminiProvider), 'structure').resolves(
'[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]'
);
Sinon.stub(app.get(GeminiProvider), 'text').resolves(
'[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]'
);