Skip to content

feat(core): add stream object api #12841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: canary
Choose a base branch
from
Open

Conversation

akumatus
Copy link
Member

@akumatus akumatus commented Jun 17, 2025

Close AI-193

Summary by CodeRabbit

  • New Features

    • Added support for streaming structured AI chat responses as objects, enabling richer and more interactive chat experiences.
    • Chat messages now include a new field displaying structured stream objects, such as reasoning steps, text deltas, tool calls, and tool results.
    • GraphQL APIs and queries updated to expose these structured streaming objects in chat histories.
    • Introduced a new streaming chat endpoint for object-based responses.
  • Bug Fixes

    • Improved error handling for streaming responses to ensure more robust and informative error reporting.
  • Refactor

    • Centralized and streamlined session preparation and streaming logic for AI chat providers.
    • Unified streaming setup across multiple AI model providers.
  • Tests

    • Extended test coverage for streaming object responses to ensure reliability and correctness.
  • Documentation

    • Updated type definitions and schemas to reflect new streaming object capabilities in both backend and frontend code.

@akumatus akumatus requested a review from a team as a code owner June 17, 2025 09:08
Copy link

coderabbitai bot commented Jun 17, 2025

## Walkthrough

This change introduces support for streaming structured objects ("stream objects") in the backend AI chat system. It adds a new database column, updates the Prisma schema, extends provider interfaces and implementations, introduces new GraphQL types and fields, and adds comprehensive test coverage for the new streaming object functionality.

## Changes

| File(s) / Group                                                                                  | Change Summary |
|--------------------------------------------------------------------------------------------------|---------------|
| migrations/20250617004240_ai_stream_objects_message/migration.sql, schema.prisma                  | Add `streamObjects` JSON column to `ai_sessions_messages` table and Prisma model. |
| .../src/plugins/copilot/providers/types.ts, .../type.ts                                          | Define `StreamObjectSchema` and `StreamObject` type; extend message schemas to support `streamObjects`. |
| .../src/plugins/copilot/providers/provider.ts                                                    | Add abstract `streamObject` method to provider interface. |
| .../src/plugins/copilot/providers/utils.ts                                                       | Add `parseUnknownError` and `StreamObjectParser` for error handling and parsing stream objects. |
| .../src/plugins/copilot/providers/anthropic/anthropic.ts, .../gemini/gemini.ts, .../openai.ts    | Implement `streamObject` method and shared streaming logic in providers. |
| .../src/plugins/copilot/providers/anthropic/official.ts, .../anthropic/vertex.ts, .../gemini/generative.ts, .../gemini/vertex.ts, .../openai.ts, .../mocks/copilot.mock.ts | Update model capabilities to include `ModelOutputType.Object`. |
| .../src/plugins/copilot/controller.ts                                                            | Refactor session preparation logic; add new SSE endpoint for streaming objects. |
| .../src/plugins/copilot/session.ts                                                               | Persist and retrieve `streamObjects` in chat session messages. |
| .../src/plugins/copilot/resolver.ts, .../src/schema.gql, .../graphql/src/schema.ts               | Add `StreamObject` GraphQL type and integrate with `ChatMessage`. |
| .../graphql/src/graphql/copilot-history-list.gql, .../graphql/src/graphql/index.ts               | Extend queries to retrieve `streamObjects` in histories. |
| .../src/__tests__/copilot-provider.spec.ts, .../copilot.e2e.ts, .../mocks/copilot.mock.ts, .../utils/copilot.ts | Add/extend tests for streaming object functionality. |
| .../frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts                          | Add frontend schema and type for `StreamObject` and extend chat message schema. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant Controller
    participant Provider
    participant SessionService
    participant Database

    Client->>Controller: Request /stream-object (SSE)
    Controller->>SessionService: Prepare session, get provider/model
    Controller->>Provider: streamObject(model, messages, options)
    loop Stream chunks
        Provider-->>Controller: StreamObject
        Controller-->>Client: StreamObject (SSE)
        Controller->>SessionService: Save StreamObjects and content
        SessionService->>Database: Store message with streamObjects
    end

Assessment against linked issues

Objective Addressed Explanation
服务端支持 stream objects (AI-193)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Suggested reviewers

  • yoyoyohamapi

Poem

A rabbit hopped through code one night,
Bringing stream objects to the light.
Now messages flow, both text and more,
With structured streams from backend’s core.
Testers cheer, the schema grows—
In fields of JSON, the data flows!
🐇✨


<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=toeverything/AFFiNE&utm_content=12841):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@github-actions github-actions bot added app:server test Related to test cases app:core labels Jun 17, 2025
@akumatus akumatus requested review from a team and removed request for a team June 17, 2025 09:08
@akumatus akumatus changed the title feat(core): support stream objects in ai chat messages feat(core): add stream object api Jun 17, 2025
Copy link

codecov bot commented Jun 17, 2025

Codecov Report

Attention: Patch coverage is 76.50177% with 133 lines in your changes missing coverage. Please review.

Project coverage is 56.01%. Comparing base (899ffd1) to head (ccb026b).

Files with missing lines Patch % Lines
...ver/src/plugins/copilot/providers/gemini/gemini.ts 17.74% 51 Missing ⚠️
...end/server/src/plugins/copilot/providers/openai.ts 67.02% 31 Missing ⚠️
...kend/server/src/plugins/copilot/providers/utils.ts 75.71% 17 Missing ⚠️
...s/backend/server/src/plugins/copilot/controller.ts 91.85% 11 Missing ⚠️
...c/plugins/copilot/providers/anthropic/anthropic.ts 82.25% 11 Missing ⚠️
...d/server/src/plugins/copilot/providers/provider.ts 25.00% 9 Missing ⚠️
...backend/server/src/__tests__/mocks/copilot.mock.ts 91.66% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           canary   #12841      +/-   ##
==========================================
+ Coverage   55.93%   56.01%   +0.07%     
==========================================
  Files        2658     2658              
  Lines      125982   126408     +426     
  Branches    20031    20065      +34     
==========================================
+ Hits        70474    70804     +330     
- Misses      53172    53254      +82     
- Partials     2336     2350      +14     
Flag Coverage Δ
server-test 79.65% <76.50%> (-0.02%) ⬇️
unittest 31.67% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (13)
packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1)

1-2: Validate JSON vs JSONB usage for performance
Consider using JSONB instead of JSON for the streamObjects column to gain indexing and performance benefits in Postgres, and think about whether a default empty array (DEFAULT '[]') or NOT NULL constraint is desirable.

packages/backend/server/src/__tests__/utils/copilot.ts (1)

585-592: Align return type with other chat helpers
The new chatWithStreamObject helper mirrors chatWithTextStream; consider adding a return type annotation (: Promise<string>) for consistency and clarity.

packages/backend/server/src/schema.gql (1)

1632-1639: Add basic description blocks to the newly introduced StreamObject type

SDL generated docs are empty; a short description clarifies its intent for GraphQL-first consumers and tooling such as GraphiQL.

packages/backend/server/src/__tests__/copilot.e2e.ts (1)

516-536: Tests pass but duplicate generator logic – consider a small helper
Array.from('generate text to object stream').map(...) is now repeated in three places for the different stream tests (text, text-stream, object-stream). A tiny helper such as buildTextDeltaStream(content: string) would remove duplication and make intent clearer.

-const objects = Array.from('generate text to object stream').map(data =>
-  JSON.stringify({ type: 'text-delta', textDelta: data })
-);
+const objects = buildTextDeltaStream('generate text to object stream');

Nice-to-have only – feel free to skip if you think the duplication is acceptable.

packages/backend/server/src/plugins/copilot/session.ts (1)

283-289: Duplicate property spread may silently mask bugs
...m already contains streamObjects/attachments/params. Re-adding them on the next lines is redundant and makes the effective precedence non-obvious.

-            data: state.messages.map(m => ({
-              ...m,
-              streamObjects: m.streamObjects || undefined,
-              attachments: m.attachments || undefined,
-              params: omit(m.params, ['docs']) || undefined,
-              sessionId,
-            })),
+            data: state.messages.map(m => ({
+              ...omit(m, ['params']),          // avoid double assignment
+              streamObjects: m.streamObjects || undefined,
+              attachments: m.attachments || undefined,
+              params: omit(m.params, ['docs']) || undefined,
+              sessionId,
+            })),

Removing the first spread or the explicit overrides would be cleaner.

packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1)

3-25: Schema duplication – export or share from a common package
StreamObjectSchema is now defined here and in backend/providers/types.ts. Divergence between the two copies is a maintainability risk.

Suggestion: move the schema to packages/common/graphql (or similar) and import it in both places, or at least export the constant so consumers can reference a single source.

No immediate functional bug – purely a maintainability note.

packages/backend/server/src/plugins/copilot/resolver.ts (1)

204-206: Type import is unused at runtime – safe, but ESLint may complain
StreamObject is referenced only as a TS type. If your linter flags unused values, add import type { … } or // eslint-disable-next-line @typescript-eslint/consistent-type-imports to avoid false positives.

packages/backend/server/src/plugins/copilot/providers/types.ts (2)

145-150: Make content truly optional when streamObjects are present

content is required even for pure streaming-object messages. Call-sites will have to pass an empty string, which is easy to forget and clutters data. Making it optional simplifies usage and enforces exactly one source of truth per message.

-  content: z.string(),
+  content: z.string().optional(),

NB: If you still need at least one of content or streamObjects, wrap the whole schema in a refine for mutual exclusivity.


157-157: Duplicate type alias – consider a single, central export

StreamObject now exists both here and in packages/frontend/core/.../type.ts. Divergence risks creep in quickly. Re-export the type from one place (e.g. @affine/copilot-types) and import it everywhere else.

packages/backend/server/src/__tests__/mocks/copilot.mock.ts (2)

20-114: Model capability list is highly repetitive – extract a helper

The same capability object (input: [Text, Image] / output: [Text, Object]) is duplicated many times, which is error-prone when the enum evolves. A tiny factory or shared constant keeps things DRY:

const textObjectCap = {
  input: [ModelInputType.Text, ModelInputType.Image],
  output: [ModelOutputType.Text, ModelOutputType.Object],
};

this.models = [
  { id: 'test', capabilities: [{ ...textObjectCap, input: [ModelInputType.Text], defaultForOutputType: true }] },
  { id: 'gpt-4o', capabilities: [textObjectCap] },
  
];

Not critical for a mock, but tidier and easier to maintain.


208-226: streamObject yields one character per delta – adequate for tests but maybe misleading

The generator currently does:

for (const data of result /* plain string */) {
  yield { type: 'text-delta', textDelta: data };
}

So "foo" streams three separate deltas "f","o","o". Real providers usually chunk by token or sentence, not single UTF-16 code unit. If the tests rely on more realistic behaviour, consider:

- for (const data of result) {
-   yield { type: 'text-delta', textDelta: data } as const;
+ for (const token of result.split(' ')) {   // or your tokeniser
+   yield { type: 'text-delta', textDelta: token };
 }

This keeps the mock closer to production behaviour without extra complexity.

packages/common/graphql/src/schema.ts (1)

132-141: streamObjects should probably be non-nullable and default to an empty list

In practice a consumer usually has to branch on three cases (null | [] | [...data]).
If the resolver always returns an array (possibly empty) and you define the field as streamObjects: [StreamObject!]!, the caller’s logic and generated types are simpler, and it avoids the common “cannot read property ‘length’ of null” foot-gun.

If there is a hard reason to expose null, please document the difference between “missing” and “present but empty”.

packages/backend/server/src/__tests__/copilot-provider.spec.ts (1)

188-201: Consider logging validation errors for easier debugging.

The validation logic is correct, but consider logging the error before returning false to help with debugging test failures.

 const checkStreamObjects = (result: string) => {
   try {
     const streamObjects = JSON.parse(result);
     if (!Array.isArray(streamObjects)) {
       return false;
     }
     for (const streamObject of streamObjects) {
       StreamObjectSchema.parse(streamObject);
     }
     return true;
-  } catch {
+  } catch (error) {
+    console.error('Stream object validation failed:', error);
     return false;
   }
 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4c2005 and 92571c7.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (4 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/backend/server/src/__tests__/utils/copilot.ts (1)
packages/backend/server/src/__tests__/e2e/test.ts (1)
  • app (8-8)
packages/backend/server/src/plugins/copilot/providers/provider.ts (3)
packages/backend/server/src/plugins/copilot/providers/types.ts (4)
  • ModelConditions (233-236)
  • PromptMessage (155-155)
  • CopilotChatOptions (176-176)
  • StreamObject (157-157)
packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1)
  • StreamObject (27-27)
packages/common/graphql/src/schema.ts (1)
  • StreamObject (2199-2207)
packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (2)
packages/backend/server/src/plugins/copilot/providers/types.ts (2)
  • StreamObjectSchema (121-143)
  • StreamObject (157-157)
packages/common/graphql/src/schema.ts (1)
  • StreamObject (2199-2207)
packages/backend/server/src/plugins/copilot/providers/types.ts (2)
packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1)
  • StreamObject (27-27)
packages/common/graphql/src/schema.ts (1)
  • StreamObject (2199-2207)
packages/backend/server/src/__tests__/copilot-provider.spec.ts (4)
packages/backend/server/src/__tests__/mocks/copilot.mock.ts (1)
  • streamObject (208-226)
packages/backend/server/src/plugins/copilot/providers/openai.ts (1)
  • streamObject (370-401)
packages/backend/server/src/plugins/copilot/providers/types.ts (2)
  • StreamObjectSchema (121-143)
  • StreamObject (157-157)
packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1)
  • StreamObject (27-27)
packages/backend/server/src/__tests__/copilot.e2e.ts (2)
packages/backend/server/src/__tests__/utils/copilot.ts (4)
  • createCopilotSession (20-36)
  • createCopilotMessage (490-542)
  • chatWithStreamObject (585-591)
  • textToEventStream (628-638)
packages/backend/server/src/__tests__/e2e/test.ts (1)
  • app (8-8)
⏰ Context from checks skipped due to timeout of 90000ms (51)
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: test-build-mobile-app / build-ios-web
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, webkit)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, firefox)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E Test (5)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, chromium)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, webkit)
  • GitHub Check: Build @affine/electron renderer
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, chromium)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, firefox)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: Build Server native
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: Build AFFiNE native (aarch64-pc-windows-msvc)
  • GitHub Check: y-octo binding test on x86_64-apple-darwin
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: Build AFFiNE native (x86_64-pc-windows-msvc)
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: Build AFFiNE native (x86_64-apple-darwin)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: Run native tests
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: loom thread test
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Build AFFiNE native (aarch64-apple-darwin)
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
🔇 Additional comments (31)
packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2)

26-30: Approve adding Object output capability
Including ModelOutputType.Object in the first model’s outputs aligns this provider with others and enables structured object streaming.


44-48: Approve adding Object output capability
The same update for the "Gemini 2.5 Pro" model is correct—ModelOutputType.Object support is now in place.

packages/backend/server/schema.prisma (1)

416-423: Prisma schema updated to store stream objects
The optional streamObjects JSON field on AiSessionMessage is correctly added between content and attachments. Ensure client code generation is rerun.

packages/common/graphql/src/graphql/copilot-history-list.gql (1)

17-24: Expose new streamObjects field in query
The GraphQL query now retrieves all relevant properties of streamObjects. Confirm that the server schema and client typings include this new field.

packages/common/graphql/src/graphql/index.ts (1)

620-627: Consider factoring streamObjects selection into a fragment

streamObjects is now projected inline in every history query. Since it is a stable, reusable field set, extracting it into a small fragment (e.g. StreamObjectFields) would keep the generated file shorter and make future field-level changes less error-prone.

-          streamObjects {
-            type
-            textDelta
-            toolCallId
-            toolName
-            args
-            result
-          }
+          ...StreamObjectFields
...
+fragment StreamObjectFields on StreamObject {
+  type
+  textDelta
+  toolCallId
+  toolName
+  args
+  result
+}

[ suggest_optional_refactor ]

packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (1)

21-22: Verify a default “object” model is really selected

Only the last capability marks defaultForOutputType: true.
If callers request outputType = ModelOutputType.Object without an explicit modelId, every other model will be skipped even when it supports object output, and Sonnet-v2 is always chosen.
Please confirm this is intentional; otherwise mark one capability per model, or move the flag to the capability that is actually intended to be the fallback.

[ request_verification ]

Also applies to: 30-31, 39-40, 48-50

packages/backend/server/src/schema.gql (1)

93-100: content should be nullable now that messages may contain only streamObjects

With object streaming a message can legitimately have no text.
Keeping content: String! forces producers to emit an empty string, breaking semantic validation elsewhere (e.g. min(1) checks in PromptMessageSchema). Recommend relaxing the field:

-  content: String!
+  content: String

This change ripples to generated typings and the Zod schema, but avoids inconsistent data and simplifies validation.

[ raise_critical_issue ]

packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (1)

23-24: Same default-model caveat as Vertex provider

See the comment on AnthropicVertexProvider: only claude-3-5-sonnet-20241022 is marked defaultForOutputType. A generic “object” request will bypass Opus/Sonnet-4 even if they are superior. Double-check this selection logic.

[ request_verification ]

Also applies to: 32-33, 41-42, 50-52

packages/backend/server/src/plugins/copilot/providers/provider.ts (1)

36-37: Abstract method name bikeshedding – plural vs. singular

The new API is streamObject but returns an AsyncIterable<StreamObject> (plural). To stay parallel with streamText, consider streamObjects to avoid confusion.

Not blocking, but aligning the naming now is cheaper than later API churn.

[ suggest_nitpick ]

Also applies to: 229-234

packages/backend/server/src/__tests__/copilot.e2e.ts (1)

42-44: Import looks good – no action required
Nothing to flag regarding the added chatWithStreamObject import.

packages/backend/server/src/plugins/copilot/session.ts (1)

512-520: Good – streamObjects now fetched for history queries
Including streamObjects in the messages.select list is essential for the new UI. Nice catch.

packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (1)

28-33: Capability update is correct
Adding ModelOutputType.Object aligns Gemini models with the new streaming-object feature. No further changes required here.

Also applies to: 47-52, 65-69

packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1)

34-35: Minor type mismatch with backend attachment union (outside this PR)
Frontend still restricts attachments to string[], whereas backend allows mixed string / { attachment, mimeType }. Not introduced by this PR, but worth aligning in the future to avoid runtime casting.

packages/backend/server/src/plugins/copilot/resolver.ts (1)

171-190: GraphQL type aligns with backend object – good
StreamObjectType mirrors the discriminated-union contract; nullable fields are correctly marked.

packages/backend/server/src/plugins/copilot/providers/types.ts (1)

214-220: Confirm semantic split between Object and Structured output types

ModelOutputType already contains Structured; introducing Object may confuse downstream filtering logic unless the semantics are crystal-clear. Please verify:

  1. Providers return distinct payloads for the two.
  2. Capability resolution and default selection handle them correctly.

If they are synonyms, prefer a single enum member to avoid branching.

packages/common/graphql/src/schema.ts (1)

3388-3396: Large nested selection may bloat the GetCopilotHistories payload

The query now pulls streamObjects (including JSON-typed args / result) for every message in every session.
For long histories this can explode response size and cause noticeable latency.

Consider adding a parameter to make streamObjects opt-in (e.g. includeStreamObjects boolean in QueryChatHistoriesInput) or slicing the message set.

Please benchmark the worst-case payload size with realistic sessions and check whether the current CDN / client cache limits are hit.

packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3)

159-159: Good refactoring to reduce code duplication.

The extraction of common streaming logic into the getFullStream helper method improves maintainability.


175-206: Well-implemented streaming object method.

The streamObject method correctly implements structured object streaming with proper error handling, metrics tracking, and cancellation support. The implementation is consistent with the existing streamText pattern.


208-227: Clean extraction of common streaming logic.

The getFullStream method effectively consolidates the streaming setup, properly handling system prompts, messages, and provider-specific options.

packages/backend/server/src/__tests__/copilot-provider.spec.ts (2)

407-420: Good test coverage for streaming objects.

The test case properly validates the new streaming object functionality.


714-734: Correct implementation of object streaming test runner.

The test runner properly collects stream objects and converts them to JSON for verification.

packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (1)

117-169: Consistent implementation across providers.

The Anthropic provider correctly implements the same streaming object pattern as other providers, with proper handling of Anthropic-specific options like tools and multi-step support.

packages/backend/server/src/plugins/copilot/providers/utils.ts (3)

390-404: Robust error parsing utility.

The parseUnknownError function properly handles various error types and ensures consistent Error instances are thrown.


465-466: Good use of centralized error handling.

Using parseUnknownError improves robustness compared to directly accessing chunk.error.message.


510-528: Clean implementation of StreamObjectParser.

The parser correctly handles the supported chunk types and maintains consistent error handling.

packages/backend/server/src/plugins/copilot/controller.ts (2)

193-229: Excellent refactoring to centralize session preparation.

The prepareChatSession method effectively reduces code duplication. Note that it currently hardcodes ModelOutputType.Text when choosing the provider, which is appropriate for the current usage but may need adjustment if used for other output types in the future.


346-440: Well-implemented streaming object endpoint.

The chatStreamObject endpoint correctly:

  • Merges consecutive chunks of the same type to reduce redundancy
  • Extracts content only from text-delta chunks
  • Persists both content and structured stream objects to the session
  • Maintains consistency with other streaming endpoints for error handling and metrics
packages/backend/server/src/plugins/copilot/providers/openai.ts (4)

75-76: LGTM! Consistent model capability updates.

The addition of ModelOutputType.Object to model capabilities is consistently applied across all relevant OpenAI models. The newer models (gpt-4.1 series) appropriately include both Object and Structured output types.

Also applies to: 85-85, 94-94, 104-104, 113-117, 127-131, 140-144, 153-157, 166-166, 175-175, 184-184


338-338: Good refactoring to reduce code duplication.

Extracting the stream setup logic to getFullStream improves maintainability and ensures consistency between streamText and streamObject methods.


370-401: Well-structured implementation of streamObject method.

The new method follows the established patterns in the codebase:

  • Proper parameter validation and model selection
  • Consistent error handling and metrics tracking
  • Correct handling of abort signals
  • Clean separation of concerns with StreamObjectParser

443-466: Clean extraction of stream setup logic.

The getFullStream method successfully consolidates the common streaming setup code, making it reusable between streamText and streamObject while maintaining all the necessary configuration options.

@akumatus akumatus force-pushed the feat/ai-stream-objects branch from 92571c7 to 640bfa3 Compare June 17, 2025 09:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/backend/server/src/plugins/copilot/controller.ts (1)

426-439: Metric name inconsistency – object stream errors counted as text stream

The outer catch block increments chat_stream_errors instead of chat_object_stream_errors, skewing dashboards and alerts.

-      metrics.ai.counter('chat_stream_errors').add(1, info);
+      metrics.ai.counter('chat_object_stream_errors').add(1, info);
packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (1)

150-169: getFullStream duplicated across providers – consider elevating to base class

Almost identical helper logic (chatToGPTMessage + streamText({...}).fullStream) now exists in Anthropic, OpenAI, Gemini, etc. Extracting it into CopilotProvider (or a small mix-in) would:

• eliminate copy-paste bugs,
• keep all provider-agnostic options (tools, maxSteps, continueSteps) in one place,
• make future tweaks (e.g. retry, logging) one-shot.

No functional blocker, but worthwhile to improve maintainability.

packages/backend/server/src/plugins/copilot/providers/openai.ts (1)

443-466: Same getFullStream boilerplate here – centralise or share

See similar comment in Anthropic provider: this block is nearly identical (aside from provider-specific option mapping). A shared utility would avoid drift between providers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92571c7 and 640bfa3.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (4 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (21)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql
  • packages/common/graphql/src/graphql/index.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts
  • packages/backend/server/schema.prisma
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts
  • packages/backend/server/src/tests/utils/copilot.ts
  • packages/backend/server/src/plugins/copilot/session.ts
  • packages/common/graphql/src/graphql/copilot-history-list.gql
  • packages/backend/server/src/plugins/copilot/providers/provider.ts
  • packages/backend/server/src/plugins/copilot/resolver.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts
  • packages/backend/server/src/schema.gql
  • packages/backend/server/src/plugins/copilot/providers/types.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts
  • packages/backend/server/src/tests/mocks/copilot.mock.ts
  • packages/backend/server/src/tests/copilot.e2e.ts
  • packages/backend/server/src/plugins/copilot/providers/utils.ts
  • packages/backend/server/src/tests/copilot-provider.spec.ts
  • packages/common/graphql/src/schema.ts
⏰ Context from checks skipped due to timeout of 90000ms (57)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (3)
  • GitHub Check: Native Unit Test
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: test-build-mobile-app / build-ios-web
  • GitHub Check: E2E Test (8)
  • GitHub Check: fuzzing
  • GitHub Check: y-octo binding test on aarch64-unknown-linux-gnu
  • GitHub Check: y-octo binding test on aarch64-apple-darwin
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, webkit)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E Test (5)
  • GitHub Check: y-octo binding test on x86_64-apple-darwin
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, firefox)
  • GitHub Check: Run native tests
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, chromium)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, webkit)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, chromium)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, firefox)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: Build @affine/electron renderer
  • GitHub Check: Build AFFiNE native (x86_64-pc-windows-msvc)
  • GitHub Check: loom thread test
  • GitHub Check: Build AFFiNE native (aarch64-pc-windows-msvc)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Build Server native
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: Lint
  • GitHub Check: Typecheck
🔇 Additional comments (1)
packages/backend/server/src/plugins/copilot/providers/openai.ts (1)

370-401: Guard against undefined yields from StreamObjectParser

parser.parse(chunk) may return undefined for non-boundary chunks, but the current loop already filters with if (result). Good.
However, when chunk.type === 'finish', StreamObjectParser can emit any remaining buffered object(s). Ensure the parser implementation returns all pending objects; otherwise the terminal piece may be lost.
If the parser returns an array on finish, adapt the yield logic accordingly.

Just flagging for verification – no change required if the utility already handles this.

@akumatus akumatus force-pushed the feat/ai-stream-objects branch 3 times, most recently from 37f9b85 to 3e1de13 Compare June 17, 2025 12:48
@akumatus akumatus requested review from darkskygit and a team June 17, 2025 12:48
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
packages/backend/server/src/plugins/copilot/controller.ts (2)

399-411: Collecting the whole stream into memory may hurt large responses

shared$.pipe(toArray(), …) buffers every StreamObject chunk before persisting the message.
For lengthy object streams this can explode memory and delay DB writes.

Consider incremental persistence instead:

-shared$.pipe(
-  toArray(),
-  concatMap(values => {
-
-  })
+shared$.pipe(
+  bufferTime(500),   // or bufferCount(N)
+  filter(buf => buf.length),
+  mergeMap(buf => {
+    const parser = new StreamObjectParser();
+    const objects = parser.mergeTextDelta(buf);
+
+  })

This keeps memory bounded and makes partial results visible sooner.


255-257: Minor duplication – query is parsed three times

ChatQuerySchema.parse(query) is invoked in prepareChatSession, then again in each endpoint to extract reasoning, webSearch, etc.
Returning these flags from prepareChatSession would avoid redundant schema validation.

Also applies to: 308-310, 381-383

packages/backend/server/src/plugins/copilot/providers/utils.ts (1)

390-404: Declare parseUnknownError as never

The helper always throws, so its signature should reflect that.
This lets TypeScript flag unreachable code and prevents “falls through but returns void” confusion.

-export function parseUnknownError(error: unknown) {
+export function parseUnknownError(error: unknown): never {
   …
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37f9b85 and 3e1de13.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (5 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (22)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql
  • packages/backend/server/src/tests/copilot.e2e.ts
  • packages/backend/server/schema.prisma
  • packages/backend/server/src/tests/utils/copilot.ts
  • packages/common/graphql/src/graphql/copilot-history-list.gql
  • packages/common/graphql/src/graphql/index.ts
  • packages/backend/server/src/plugins/copilot/session.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts
  • packages/backend/server/src/plugins/copilot/providers/provider.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts
  • packages/backend/server/src/tests/mocks/copilot.mock.ts
  • packages/backend/server/src/schema.gql
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts
  • packages/backend/server/src/plugins/copilot/providers/types.ts
  • packages/backend/server/src/plugins/copilot/resolver.ts
  • packages/backend/server/src/tests/copilot-provider.spec.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts
  • packages/backend/server/src/plugins/copilot/providers/openai.ts
  • packages/common/graphql/src/schema.ts
⏰ Context from checks skipped due to timeout of 90000ms (703)
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Lint
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: test-build-mobile-app / android
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: test-build-mobile-app / android
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: test-build-mobile-app / android
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: test-build-mobile-app / android
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: test-build-mobile-app / android
  • GitHub Check: Cloud E2E Test 4/6
  • GitHub Check: Frontend Copilot E2E Test (6, 8)
  • GitHub Check: Cloud E2E Test 3/6
  • GitHub Check: Cloud E2E Test 6/6
  • GitHub Check: Cloud E2E Test 1/6
  • GitHub Check: Cloud Desktop E2E Test
  • GitHub Check: Cloud E2E Test 5/6
  • GitHub Check: Server Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (8, 8)
  • GitHub Check: Cloud E2E Test 2/6
  • GitHub Check: Check Git Status
  • GitHub Check: Frontend Copilot E2E Test (7, 8)
  • GitHub Check: Frontend Copilot E2E Test (2, 8)
  • GitHub Check: Server E2E Test
  • GitHub Check: Frontend Copilot E2E Test (5, 8)
  • GitHub Check: Frontend Copilot E2E Test (3, 8)
  • GitHub Check: Frontend Copilot E2E Test (1, 8)
  • GitHub Check: Server Test (6, 8)
  • GitHub Check: Frontend Copilot E2E Test (4, 8)
  • GitHub Check: Server Test (5, 8)
  • GitHub Check: Server Test with Elasticsearch
  • GitHub Check: Server Test (7, 8)
  • GitHub Check: Server Test (4, 8)
  • GitHub Check: Server Test (0, 8)
  • GitHub Check: Server Copilot Api Test
  • GitHub Check: Server Test (1, 8)
  • GitHub Check: Server Test (2, 8)
  • GitHub Check: Desktop Test (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Desktop Test (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop bundle check (ubuntu-latest, linux, x64, x86_64-unknown-linux-gnu, true)
  • GitHub Check: Desktop bundle check (macos-latest, macos, arm64, aarch64-apple-darwin, true)
  • GitHub Check: Desktop Test (windows-latest, windows, x64, x86_64-pc-windows-msvc, true)
  • GitHub Check: Unit Test (4)
  • GitHub Check: Unit Test (5)
  • GitHub Check: Unit Test (2)
  • GitHub Check: Unit Test (1)
  • GitHub Check: Unit Test (3)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: fuzzing
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
🔇 Additional comments (1)
packages/backend/server/src/plugins/copilot/controller.ts (1)

193-230: 👍 Well-factored prepareChatSession helper

Pulling the common boilerplate (provider selection, message stashing, param merging) into a single method noticeably cuts duplication and makes the three endpoints easier to reason about.

@akumatus akumatus force-pushed the feat/ai-stream-objects branch from 3e1de13 to 28bfa95 Compare June 18, 2025 08:40
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
packages/backend/server/src/plugins/copilot/controller.ts (4)

193-230: Consider returning the parsed query to avoid triple-parsing

prepareChatSession is a valuable extraction, but every call-site still has to call ChatQuerySchema.parse again for reasoning, webSearch, and messageId.
Returning the parse result (or at least those three fields) from this helper would:

  • remove duplicate parsing logic in chat, chatStream, and chatStreamObject;
  • avoid the extra Zod validation cost on every request;
  • keep the controller code a bit tidier.
-  private async prepareChatSession(
+  private async prepareChatSession(-  ) {
-    let { messageId, retry, modelId, params } = ChatQuerySchema.parse(query);
+  ): Promise<{
+      provider: CopilotProvider;
+      model: string;
+      session: ChatSession;
+      finalMessage: ChatMessage[];
+      parsed: ReturnType<typeof ChatQuerySchema.parse>;   // <─ new
+  }> {
+    const parsed = ChatQuerySchema.parse(query);
+    let { messageId, retry, modelId, params } = parsed;-    return {
-      provider,
-      model,
-      session,
-      finalMessage,
-    };
+    return { provider, model, session, finalMessage, parsed };
   }

Call-sites can then use parsed.reasoning etc. without a second Zod round-trip.
Not critical, but worth the small refactor.


243-256: Duplicate parsing immediately after helper call

Right after invoking prepareChatSession, the code re-parses query to extract reasoning / webSearch. If the previous comment is applied this block can simply use the already-returned data and drop the redundant ChatQuerySchema.parse.


295-308: Same duplicate parsing pattern here

chatStream repeats the same extra parse; once prepareChatSession exposes the parsed result this duplication disappears.


399-414: Possible memory bloat when buffering the full object stream

shared$.pipe(toArray()) buffers every streamed object chunk until the stream completes before persisting the message. For very long object streams this can grow unbounded and delay persistence until the end.

A lighter approach:

  • accumulate StreamObjects in a local array and persist every N chunks or on a throttle window; or
  • use reduce to build the merged objects incrementally without keeping all raw chunks.

Not a blocker (the text endpoint already behaves similarly), but worth revisiting if large object streams are expected.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e1de13 and 28bfa95.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (5 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (23)
  • packages/backend/server/schema.prisma
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts
  • packages/common/graphql/src/graphql/copilot-history-list.gql
  • packages/backend/server/src/tests/utils/copilot.ts
  • packages/backend/server/src/plugins/copilot/session.ts
  • packages/common/graphql/src/graphql/index.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts
  • packages/backend/server/src/schema.gql
  • packages/backend/server/src/plugins/copilot/providers/provider.ts
  • packages/backend/server/src/plugins/copilot/resolver.ts
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts
  • packages/backend/server/src/tests/copilot.e2e.ts
  • packages/backend/server/src/plugins/copilot/providers/types.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts
  • packages/backend/server/src/tests/mocks/copilot.mock.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts
  • packages/backend/server/src/tests/copilot-provider.spec.ts
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql
  • packages/backend/server/src/plugins/copilot/providers/openai.ts
  • packages/backend/server/src/plugins/copilot/providers/utils.ts
  • packages/common/graphql/src/schema.ts
🧰 Additional context used
🪛 ESLint
packages/backend/server/src/plugins/copilot/controller.ts

[error] 382-382: Finnish notation should not be used here.

(rxjs/finnish)


[error] 392-392: Finnish notation should not be used here.

(rxjs/finnish)

⏰ Context from checks skipped due to timeout of 90000ms (54)
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: test-build-mobile-app / build-ios-web
  • GitHub Check: loom thread test
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: y-octo binding test on x86_64-apple-darwin
  • GitHub Check: y-octo binding test on aarch64-unknown-linux-gnu
  • GitHub Check: E2E Test (6)
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: y-octo binding test on x86_64-unknown-linux-gnu
  • GitHub Check: Run native tests
  • GitHub Check: fuzzing
  • GitHub Check: y-octo binding test on aarch64-apple-darwin
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, chromium)
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (5)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, firefox)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, webkit)
  • GitHub Check: Build AFFiNE native (x86_64-unknown-linux-gnu)
  • GitHub Check: Build AFFiNE native (x86_64-apple-darwin)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, chromium)
  • GitHub Check: Build AFFiNE native (aarch64-pc-windows-msvc)
  • GitHub Check: Build AFFiNE native (x86_64-pc-windows-msvc)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, firefox)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, webkit)
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Build @affine/electron renderer
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: Lint
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Build Server native
  • GitHub Check: Typecheck
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Analyze (javascript, affine)
🔇 Additional comments (1)
packages/backend/server/src/plugins/copilot/controller.ts (1)

384-390: Workspace context now forwarded – good catch

The provider options for streamObject now include workspace: session.config.workspaceId, fixing the tenant-scoping issue flagged in the previous review.

@akumatus akumatus force-pushed the feat/ai-stream-objects branch from 28bfa95 to 1bc9e60 Compare June 18, 2025 09:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/backend/server/src/plugins/copilot/providers/utils.ts (2)

465-466: Unreachable break after a guaranteed throw

parseUnknownError never returns, so the break can’t execute.

-        parseUnknownError(chunk.error);
-        break;
+        parseUnknownError(chunk.error);

520-522: Same unreachable path in StreamObjectParser.parse

-        parseUnknownError(chunk.error);
-        return null;
+        parseUnknownError(chunk.error);
🧹 Nitpick comments (2)
packages/backend/server/src/plugins/copilot/controller.ts (1)

381-390: Nit: avoid double-parsing the query

ChatQuerySchema.parse(query) is executed once in prepareChatSession (line 199) and then repeated here just to pluck reasoning / webSearch. Consider returning those flags from prepareChatSession (or caching the parsed result) to avoid the redundant validation pass.

packages/backend/server/src/plugins/copilot/providers/utils.ts (1)

510-527: Add explicit return type to StreamObjectParser.parse

Declaring the intent helps TypeScript catch future regressions.

-public parse(chunk: TextStreamPart<CustomAITools>) {
+public parse(chunk: TextStreamPart<CustomAITools>): StreamObject | null {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28bfa95 and 1bc9e60.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (5 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (21)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql
  • packages/backend/server/schema.prisma
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts
  • packages/backend/server/src/tests/utils/copilot.ts
  • packages/backend/server/src/plugins/copilot/session.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts
  • packages/common/graphql/src/graphql/copilot-history-list.gql
  • packages/backend/server/src/plugins/copilot/providers/provider.ts
  • packages/common/graphql/src/graphql/index.ts
  • packages/backend/server/src/tests/copilot.e2e.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts
  • packages/backend/server/src/schema.gql
  • packages/backend/server/src/tests/mocks/copilot.mock.ts
  • packages/backend/server/src/plugins/copilot/resolver.ts
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts
  • packages/backend/server/src/plugins/copilot/providers/types.ts
  • packages/common/graphql/src/schema.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts
  • packages/backend/server/src/tests/copilot-provider.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (48)
  • GitHub Check: test-build-mobile-app / build-ios-web
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: y-octo binding test on aarch64-unknown-linux-gnu
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: y-octo binding test on x86_64-apple-darwin
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, webkit)
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: fuzzing
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, firefox)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, chromium)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, firefox)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, chromium)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, webkit)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E Test (9)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E Test (5)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: Build Server native
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: Build @affine/electron renderer
  • GitHub Check: Typecheck
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Build AFFiNE native (aarch64-pc-windows-msvc)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: Build AFFiNE native (x86_64-pc-windows-msvc)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Lint
🔇 Additional comments (2)
packages/backend/server/src/plugins/copilot/controller.ts (1)

193-230: prepareChatSession abstraction looks solid

The new helper eliminates the duplicated boilerplate around provider selection, message rewinding and session.finish(). The extra outputType parameter also solves the previous hard-coding issue.
No further concerns here.

packages/backend/server/src/plugins/copilot/providers/openai.ts (1)

370-401: streamObject implementation reuses getFullStream nicely

Logic mirrors streamText and keeps the parser concerns separated – looks good.
No blocking issues detected.

@akumatus akumatus force-pushed the feat/ai-stream-objects branch from 1bc9e60 to ccb026b Compare June 18, 2025 09:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
packages/backend/server/src/plugins/copilot/providers/openai.ts (1)

359-363: Cancel stream in finally to avoid leaks on happy-path completion

fullStream.cancel() is called only when options.signal.aborted fires.
If the consumer simply stops iterating early (e.g. client disconnect), the generator exits without cancelling, leaving the upstream request alive.

Add a finally block:

- for await (const chunk of fullStream) {
-
- }
+ try {
+   for await (const chunk of fullStream) { … }
+ } finally {
+   await fullStream.cancel?.();
+ }

Same pattern applies to streamObject.

🧹 Nitpick comments (1)
packages/backend/server/src/plugins/copilot/controller.ts (1)

193-230: Consider exposing reasoning, webSearch, & messageId from prepareChatSession to avoid repeated schema parsing

Each endpoint still calls ChatQuerySchema.parse(query) after invoking prepareChatSession, duplicating work already done on line 199.
Returning these fields (or the whole parsed object) from prepareChatSession would:

  • remove three extra parses per request
  • guarantee the same canonical values are used everywhere
  • marginally simplify each handler’s body

Not urgent, but worth a small follow-up refactor.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1bc9e60 and ccb026b.

📒 Files selected for processing (24)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql (1 hunks)
  • packages/backend/server/schema.prisma (1 hunks)
  • packages/backend/server/src/__tests__/copilot-provider.spec.ts (5 hunks)
  • packages/backend/server/src/__tests__/copilot.e2e.ts (2 hunks)
  • packages/backend/server/src/__tests__/mocks/copilot.mock.ts (9 hunks)
  • packages/backend/server/src/__tests__/utils/copilot.ts (1 hunks)
  • packages/backend/server/src/plugins/copilot/controller.ts (5 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/openai.ts (15 hunks)
  • packages/backend/server/src/plugins/copilot/providers/provider.ts (2 hunks)
  • packages/backend/server/src/plugins/copilot/providers/types.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/providers/utils.ts (4 hunks)
  • packages/backend/server/src/plugins/copilot/resolver.ts (3 hunks)
  • packages/backend/server/src/plugins/copilot/session.ts (2 hunks)
  • packages/backend/server/src/schema.gql (2 hunks)
  • packages/common/graphql/src/graphql/copilot-history-list.gql (1 hunks)
  • packages/common/graphql/src/graphql/index.ts (1 hunks)
  • packages/common/graphql/src/schema.ts (3 hunks)
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (22)
  • packages/backend/server/migrations/20250617004240_ai_stream_objects_message/migration.sql
  • packages/backend/server/src/plugins/copilot/providers/gemini/vertex.ts
  • packages/backend/server/src/plugins/copilot/providers/provider.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/vertex.ts
  • packages/backend/server/src/plugins/copilot/session.ts
  • packages/common/graphql/src/graphql/copilot-history-list.gql
  • packages/backend/server/schema.prisma
  • packages/backend/server/src/tests/copilot.e2e.ts
  • packages/backend/server/src/tests/utils/copilot.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/generative.ts
  • packages/backend/server/src/schema.gql
  • packages/frontend/core/src/blocksuite/ai/components/ai-chat-messages/type.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/official.ts
  • packages/backend/server/src/plugins/copilot/resolver.ts
  • packages/backend/server/src/tests/mocks/copilot.mock.ts
  • packages/backend/server/src/plugins/copilot/providers/gemini/gemini.ts
  • packages/backend/server/src/plugins/copilot/providers/types.ts
  • packages/backend/server/src/plugins/copilot/providers/anthropic/anthropic.ts
  • packages/common/graphql/src/graphql/index.ts
  • packages/backend/server/src/tests/copilot-provider.spec.ts
  • packages/backend/server/src/plugins/copilot/providers/utils.ts
  • packages/common/graphql/src/schema.ts
🧰 Additional context used
🪛 ESLint
packages/backend/server/src/plugins/copilot/controller.ts

[error] 382-382: Finnish notation should not be used here.

(rxjs/finnish)


[error] 392-392: Finnish notation should not be used here.

(rxjs/finnish)

⏰ Context from checks skipped due to timeout of 90000ms (57)
  • GitHub Check: test-build-mobile-app / build-android-web
  • GitHub Check: test-build-mobile-app / build-ios-web
  • GitHub Check: Build Server native
  • GitHub Check: fuzzing
  • GitHub Check: y-octo binding test on x86_64-pc-windows-msvc
  • GitHub Check: y-octo binding test on aarch64-apple-darwin
  • GitHub Check: y-octo binding test on aarch64-pc-windows-msvc
  • GitHub Check: y-octo binding test on aarch64-unknown-linux-gnu
  • GitHub Check: loom thread test
  • GitHub Check: y-octo binding test on x86_64-unknown-linux-gnu
  • GitHub Check: miri code check
  • GitHub Check: Run native tests
  • GitHub Check: Build @affine/electron renderer
  • GitHub Check: E2E Test (9)
  • GitHub Check: y-octo binding test on x86_64-apple-darwin
  • GitHub Check: E2E Test (10)
  • GitHub Check: E2E Test (6)
  • GitHub Check: E2E Test (5)
  • GitHub Check: E2E Test (4)
  • GitHub Check: E2E Test (7)
  • GitHub Check: E2E Test (3)
  • GitHub Check: E2E Test (8)
  • GitHub Check: E2E Test (2)
  • GitHub Check: E2E BlockSuite Test (5)
  • GitHub Check: E2E Test (1)
  • GitHub Check: E2E BlockSuite Test (10)
  • GitHub Check: E2E BlockSuite Test (8)
  • GitHub Check: E2E BlockSuite Test (9)
  • GitHub Check: E2E BlockSuite Test (6)
  • GitHub Check: E2E BlockSuite Test (7)
  • GitHub Check: E2E BlockSuite Test (2)
  • GitHub Check: E2E BlockSuite Test (3)
  • GitHub Check: E2E BlockSuite Test (4)
  • GitHub Check: E2E BlockSuite Test (1)
  • GitHub Check: Build AFFiNE native (aarch64-pc-windows-msvc)
  • GitHub Check: Build AFFiNE native (x86_64-pc-windows-msvc)
  • GitHub Check: Analyze (javascript, blocksuite)
  • GitHub Check: E2E Mobile Test (3)
  • GitHub Check: Analyze (javascript, affine)
  • GitHub Check: Analyze (typescript, blocksuite)
  • GitHub Check: Lint Rust
  • GitHub Check: Build AFFiNE native (x86_64-unknown-linux-gnu)
  • GitHub Check: Analyze (typescript, affine)
  • GitHub Check: E2E Mobile Test (4)
  • GitHub Check: E2E Mobile Test (1)
  • GitHub Check: Build AFFiNE native (x86_64-apple-darwin)
  • GitHub Check: E2E Mobile Test (2)
  • GitHub Check: E2E Mobile Test (5)
  • GitHub Check: Typecheck
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, firefox)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, firefox)
  • GitHub Check: Build AFFiNE native (aarch64-apple-darwin)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, chromium)
  • GitHub Check: E2E BlockSuite Cross Browser Test (2, webkit)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, webkit)
  • GitHub Check: E2E BlockSuite Cross Browser Test (1, chromium)
  • GitHub Check: Lint
🔇 Additional comments (2)
packages/backend/server/src/plugins/copilot/providers/openai.ts (2)

70-77: Verify selectModel chooses an Object-capable model when outputType = Object

Models now advertise ModelOutputType.Object, but only one capability (gpt-4.1 lines 110-119) is flagged defaultForOutputType: true.
If selectModel falls back to the first capability marked as default for the requested output, all object requests may be routed to gpt-4.1 even when the caller asked for gpt-4o.

Please double-check the selection logic or explicitly mark the intended default for each series.


370-401: streamObject still relies on streamText API – verify chunk format

getFullStream() delegates to streamText() from ai, which streams text deltas.
If/when OpenAI ships a native object-stream API the chunk format may diverge, breaking StreamObjectParser.

Keep an eye on provider docs and gate this path behind feature detection so we don’t silently mis-parse future responses.

Comment on lines +399 to +414
shared$.pipe(
toArray(),
concatMap(values => {
const parser = new StreamObjectParser();
const streamObjects = parser.mergeTextDelta(values);
const content = parser.mergeContent(streamObjects);
session.push({
role: 'assistant',
content,
streamObjects,
createdAt: new Date(),
});
return from(session.save());
}),
mergeMap(() => EMPTY)
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

toArray() buffers the entire object stream – may balloon memory for long chats

shared$.pipe(toArray(), …) stores every StreamObject chunk until the provider finishes.
Large, multi-turn streams (or hallucinating models) could easily reach MBs in RAM before the session is flushed.

A light-weight alternative:

- shared$.pipe(
-   toArray(),
-   concatMap(values => {
-     const parser = new StreamObjectParser();
-     const streamObjects = parser.mergeTextDelta(values);
-     const content = parser.mergeContent(streamObjects);
-
-   }),
+ shared$.pipe(
+   bufferTime(1000),          // flush every second (or N chunks)
+   filter(batch => batch.length),
+   mergeMap(batch => {
+     parser.mergeTextDelta(batch);   // keep parser outside the pipeline
+     return EMPTY;
+   }),
+   finalize(async () => {
+     const streamObjects = parser.getObjects();  // expose accumulated result
+     const content = parser.mergeContent(streamObjects);
+
+   }),

This streams chunks through while still persisting the final merged result, keeping peak memory constant.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/backend/server/src/plugins/copilot/controller.ts around lines 399 to
414, the use of toArray() buffers the entire stream of StreamObject chunks,
which can cause high memory usage for long or large streams. To fix this,
refactor the code to process and persist chunks incrementally as they arrive
instead of collecting them all before saving. This approach will keep memory
usage constant by streaming chunks through and only merging and saving the final
result at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
app:core app:server test Related to test cases
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

2 participants