feat(server): improve context management (#15448)

#### PR Dependency Tree


* **PR #15448** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added workspace artifact upload, browsing, removal, deduplication, and
library ownership support.
* Copilot now supports scoped document and artifact search, canvas
reading, live editor context, and frontend tools.
* Added scope and focus selectors with source-resolution receipts in
chat.
* Added embedding health, progress, synchronization, and retrieval
capabilities.
* Added BYOK policy visibility, provider restrictions, endpoint dialect
selection, and validation.
* Added delegated editor interactions and userdata document
authorization.

* **Bug Fixes**
* Improved attachment handling, cancellation, access control, retrieval
fallbacks, workspace synchronization, and configuration validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-08-10 09:27:58 +08:00
committed by GitHub
parent 42322d13fe
commit ee899a267b
311 changed files with 20468 additions and 14806 deletions
@@ -6,7 +6,7 @@ test.describe.configure({ mode: 'serial' });
test.describe('AIChatWith/Attachments', () => {
test.beforeEach(async ({ loggedInPage: page, utils }) => {
await utils.testUtils.setupTestEnvironment(page, 'claude-sonnet-4-6');
await utils.testUtils.setupTestEnvironment(page);
await utils.chatPanel.openChatPanel(page);
});
@@ -26,13 +26,13 @@ test.describe('AIChatWith/Attachments', () => {
buffer: buffer,
},
],
'What is AttachmentEEee?'
'What is AttachmentEEee? Answer with a citation.'
);
await utils.chatPanel.waitForHistory(page, [
{
role: 'user',
content: 'What is AttachmentEEee?',
content: 'What is AttachmentEEee? Answer with a citation.',
},
{
role: 'assistant',
@@ -41,8 +41,29 @@ test.describe('AIChatWith/Attachments', () => {
]);
await expect(async () => {
const { content } = await utils.chatPanel.getLatestAssistantMessage(page);
const { content, message } =
await utils.chatPanel.getLatestAssistantMessage(page);
expect(content).toMatch(/EEee/);
const references = await message
.locator('affine-footnote-node')
.evaluateAll(nodes =>
nodes.map(
node =>
(
node as HTMLElement & {
footnote?: { reference?: Record<string, unknown> };
}
).footnote?.reference
)
);
expect(references).toEqual(
expect.arrayContaining([
expect.objectContaining({
type: 'attachment',
artifactId: expect.any(String),
}),
])
);
}).toPass({ timeout: 10000 });
});
@@ -6,7 +6,7 @@ test.describe.configure({ mode: 'serial' });
test.describe('AIChatWith/Collections', () => {
test.beforeEach(async ({ loggedInPage: page, utils }) => {
await utils.testUtils.setupTestEnvironment(page, 'claude-sonnet-4-6');
await utils.testUtils.setupTestEnvironment(page);
await utils.chatPanel.openChatPanel(page);
await utils.editor.clearAllCollections(page);
@@ -31,14 +31,31 @@ test.describe('AIChatWith/Collections', () => {
);
await utils.chatPanel.chatWithCollections(page, ['Collection 1']);
await utils.settings.openSettingsPanel(page);
await utils.settings.disableWorkspaceEmbedding(page);
await utils.settings.closeSettingsPanel(page);
await utils.chatPanel.makeChat(
page,
`What is Collection${randomStr}(Use English)`
`What is Collection${randomStr}? Use English and answer with a citation.`
);
await expect(
page.getByText(
'One or more selected sources are unavailable. Check the sources or workspace AI indexing settings, then retry.'
)
).toBeVisible();
expect(
(await utils.chatPanel.collectHistory(page)).filter(
message => message.role === 'user'
)
).toHaveLength(1);
await utils.settings.openSettingsPanel(page);
await utils.settings.enableWorkspaceEmbedding(page);
await utils.settings.closeSettingsPanel(page);
await page.getByTestId('ai-error-action-button').click();
await utils.chatPanel.waitForHistory(page, [
{
role: 'user',
content: `What is Collection${randomStr}(Use English)`,
content: `What is Collection${randomStr}? Use English and answer with a citation.`,
},
{
role: 'assistant',
@@ -50,7 +67,9 @@ test.describe('AIChatWith/Collections', () => {
const { content, message } =
await utils.chatPanel.getLatestAssistantMessage(page);
expect(content).toMatch(new RegExp(`Collection${randomStr}.*dog`));
expect(await message.locator('affine-footnote-node').count()).toBe(1);
expect(
await message.locator('affine-footnote-node').count()
).toBeGreaterThanOrEqual(1);
}).toPass();
});
@@ -79,12 +98,12 @@ test.describe('AIChatWith/Collections', () => {
]);
await utils.chatPanel.makeChat(
page,
`What is Collection${randomStr1}? What is Collection${randomStr2}?(Use English)`
`What is Collection${randomStr1}? What is Collection${randomStr2}? Use English and cite both sources.`
);
await utils.chatPanel.waitForHistory(page, [
{
role: 'user',
content: `What is Collection${randomStr1}? What is Collection${randomStr2}?(Use English)`,
content: `What is Collection${randomStr1}? What is Collection${randomStr2}? Use English and cite both sources.`,
},
{
role: 'assistant',
@@ -97,7 +116,9 @@ test.describe('AIChatWith/Collections', () => {
await utils.chatPanel.getLatestAssistantMessage(page);
expect(content).toMatch(new RegExp(`Collection${randomStr1}.*cat`));
expect(content).toMatch(new RegExp(`Collection${randomStr2}.*dog`));
expect(await message.locator('affine-footnote-node').count()).toBe(2);
expect(
await message.locator('affine-footnote-node').count()
).toBeGreaterThanOrEqual(2);
}).toPass();
});
});
@@ -22,6 +22,7 @@ test.describe('AIChatWith/Doc', () => {
await page.keyboard.insertText('Test Doc');
await page.keyboard.press('Enter');
await page.keyboard.insertText('DocEEee is a cute cat');
await utils.editor.waitForCurrentDocSynced(page);
await utils.chatPanel.chatWithDoc(page, 'Test Doc');
@@ -53,6 +54,7 @@ test.describe('AIChatWith/Doc', () => {
await page.keyboard.insertText('Test Doc1');
await page.keyboard.press('Enter');
await page.keyboard.insertText('DocEEee is a cute cat');
await utils.editor.waitForCurrentDocSynced(page);
// Initialize the doc 2
await clickNewPageButton(page);
@@ -61,6 +63,7 @@ test.describe('AIChatWith/Doc', () => {
await page.keyboard.insertText('Test Doc2');
await page.keyboard.press('Enter');
await page.keyboard.insertText('DocFFff is a cute dog');
await utils.editor.waitForCurrentDocSynced(page);
await utils.chatPanel.chatWithDoc(page, 'Test Doc1');
await utils.chatPanel.chatWithDoc(page, 'Test Doc2');