feat(server): refactor copilot (#14892)

#### PR Dependency Tree


* **PR #14892** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
This commit is contained in:
DarkSky
2026-05-04 00:36:47 +08:00
committed by GitHub
parent fa8f1a096c
commit d64f368623
239 changed files with 35859 additions and 16777 deletions
@@ -12,6 +12,8 @@ const image = {
};
test.describe('AIAction/GenerateAnImageWithImage', () => {
test.describe.configure({ timeout: 4 * 60000 });
test.beforeEach(async ({ loggedInPage: page, utils }) => {
await utils.testUtils.setupTestEnvironment(page);
await utils.chatPanel.openChatPanel(page);
@@ -12,6 +12,8 @@ const image = {
};
test.describe('AIAction/ImageFilter', () => {
test.describe.configure({ timeout: 4 * 60000 });
test.beforeEach(async ({ loggedInPage: page, utils }) => {
await utils.testUtils.setupTestEnvironment(page);
await utils.chatPanel.openChatPanel(page);
@@ -12,6 +12,8 @@ const image = {
};
test.describe('AIAction/ImageProcessing', () => {
test.describe.configure({ timeout: 4 * 60000 });
test.beforeEach(async ({ loggedInPage: page, utils }) => {
await utils.testUtils.setupTestEnvironment(page);
await utils.chatPanel.openChatPanel(page);
@@ -81,12 +81,9 @@ export class EditorUtils {
return page.getByTestId('title-edit-button').innerText();
}
public static async waitForAiAnswer(page: Page) {
public static async waitForAiAnswer(page: Page, timeout = 2 * 60000) {
const answer = page.getByTestId('ai-penel-answer').last();
await answer.waitFor({
state: 'visible',
timeout: 2 * 60000,
});
await answer.waitFor({ state: 'visible', timeout });
return answer;
}
@@ -99,10 +96,10 @@ export class EditorUtils {
const responseTimeoutMs = options?.responseTimeoutMs ?? 60000;
await action();
await this.waitForAiAnswer(page);
await this.waitForAiAnswer(page, responseTimeoutMs);
await page.getByTestId('ai-generating').waitFor({
state: 'hidden',
timeout: 2 * 60000,
timeout: responseTimeoutMs,
});
const responses = new Set<string>();
@@ -573,31 +570,43 @@ export class EditorUtils {
explainImage: this.createAction(page, () =>
page.getByTestId('action-explain-image').click()
),
generateImage: this.createAction(page, async () => {
await page.getByTestId('action-generate-image').click();
const input = page.locator(
'affine-ai-panel-widget .ai-panel-container textarea'
);
await input.waitFor({ state: 'visible' });
await input.fill('generate an image');
await page.getByTestId('ai-panel-input-send').waitFor({
state: 'visible',
});
await page.getByTestId('ai-panel-input-send').click();
}),
generateImage: this.createAction(
page,
async () => {
await page.getByTestId('action-generate-image').click();
const input = page.locator(
'affine-ai-panel-widget .ai-panel-container textarea'
);
await input.waitFor({ state: 'visible' });
await input.fill('generate an image');
await page.getByTestId('ai-panel-input-send').waitFor({
state: 'visible',
});
await page.getByTestId('ai-panel-input-send').click();
},
{ responseTimeoutMs: 4 * 60000 }
),
generateCaption: this.createAction(page, () =>
page.getByTestId('action-generate-caption').click()
),
imageProcessing: (type: string) =>
this.createAction(page, async () => {
await page.getByTestId('action-image-processing').hover();
await page.getByTestId(`action-image-processing-${type}`).click();
})(),
this.createAction(
page,
async () => {
await page.getByTestId('action-image-processing').hover();
await page.getByTestId(`action-image-processing-${type}`).click();
},
{ responseTimeoutMs: 4 * 60000 }
)(),
imageFilter: (style: string) =>
this.createAction(page, async () => {
await page.getByTestId('action-ai-image-filter').hover();
await page.getByTestId(`action-image-filter-${style}`).click();
})(),
this.createAction(
page,
async () => {
await page.getByTestId('action-ai-image-filter').hover();
await page.getByTestId(`action-image-filter-${style}`).click();
},
{ responseTimeoutMs: 4 * 60000 }
)(),
};
}
@@ -61,13 +61,20 @@ export class TestUtils {
await waitForEditorLoad(page);
}
public async setupTestEnvironment(
page: Page,
defaultModel = 'gemini-2.5-flash'
) {
await switchDefaultChatModel(defaultModel);
public async setupTestEnvironment(page: Page, defaultModel?: string) {
const hasExplicitModel = defaultModel !== undefined;
const selectedModel = defaultModel ?? 'gemini-2.5-flash';
await switchDefaultChatModel(selectedModel);
await skipOnboarding(page.context());
if (hasExplicitModel) {
await page.context().addInitScript(model => {
window.localStorage.setItem(
'global-state:AIModelId',
JSON.stringify(model)
);
}, selectedModel);
}
await openHomePage(page);
await this.createNewPage(page);
}
+6 -7
View File
@@ -154,15 +154,14 @@ export async function cleanupWorkspace(workspaceId: string): Promise<void> {
export async function switchDefaultChatModel(model: string) {
await runPrisma(async client => {
const promptId = await client.aiPrompt
.findFirst({
where: { name: 'Chat With AFFiNE AI' },
select: { id: true },
})
.then(f => f!.id);
const prompt = await client.aiPrompt.findFirst({
where: { name: 'Chat With AFFiNE AI' },
select: { id: true },
});
if (!prompt) return;
await client.aiPrompt.update({
where: { id: promptId },
where: { id: prompt.id },
data: { model },
});
});