refactor(core): get copilot sessions api (#10168)

Fix issue [BS-2575](https://linear.app/affine-design/issue/BS-2575).

### What Changed?
- Refactor `getCopilotSessions` api.
  - Add `docId` parameter.
  - Add `action` parameter.
This commit is contained in:
akumatus
2025-02-14 06:57:57 +00:00
parent f20e3f6d8f
commit 1bf1832211
10 changed files with 82 additions and 96 deletions
@@ -129,6 +129,12 @@ enum ChatHistoryOrder {
registerEnumType(ChatHistoryOrder, { name: 'ChatHistoryOrder' }); registerEnumType(ChatHistoryOrder, { name: 'ChatHistoryOrder' });
@InputType()
class QueryChatSessionsInput {
@Field(() => Boolean, { nullable: true })
action: boolean | undefined;
}
@InputType() @InputType()
class QueryChatHistoriesInput implements Partial<ListHistoriesOptions> { class QueryChatHistoriesInput implements Partial<ListHistoriesOptions> {
@Field(() => Boolean, { nullable: true }) @Field(() => Boolean, { nullable: true })
@@ -274,6 +280,9 @@ class CopilotPromptType {
export class CopilotType { export class CopilotType {
@Field(() => ID, { nullable: true }) @Field(() => ID, { nullable: true })
workspaceId!: string | undefined; workspaceId!: string | undefined;
@Field(() => ID, { nullable: true })
docId!: string | undefined;
} }
@Throttle() @Throttle()
@@ -296,31 +305,23 @@ export class CopilotResolver {
} }
@ResolveField(() => [String], { @ResolveField(() => [String], {
description: 'Get the session list of chats in the workspace', description: 'Get the session list in the workspace',
complexity: 2, complexity: 2,
}) })
async chats( async sessionIds(
@Parent() copilot: CopilotType, @Parent() copilot: CopilotType,
@CurrentUser() user: CurrentUser @CurrentUser() user: CurrentUser,
@Args('docId', { nullable: true }) docId?: string,
@Args('options', { nullable: true }) options?: QueryChatSessionsInput
) { ) {
if (!copilot.workspaceId) return []; if (!copilot.workspaceId) return [];
await this.permissions.checkCloudWorkspace(copilot.workspaceId, user.id); await this.permissions.checkCloudWorkspace(copilot.workspaceId, user.id);
return await this.chatSession.listSessions(user.id, copilot.workspaceId); return await this.chatSession.listSessionIds(
} user.id,
copilot.workspaceId,
@ResolveField(() => [String], { docId,
description: 'Get the session list of actions in the workspace', options
complexity: 2, );
})
async actions(
@Parent() copilot: CopilotType,
@CurrentUser() user: CurrentUser
) {
if (!copilot.workspaceId) return [];
await this.permissions.checkCloudWorkspace(copilot.workspaceId, user.id);
return await this.chatSession.listSessions(user.id, copilot.workspaceId, {
action: true,
});
} }
@ResolveField(() => [CopilotHistoriesType], {}) @ResolveField(() => [CopilotHistoriesType], {})
@@ -391,17 +391,18 @@ export class ChatSessionService {
.reduce((prev, cost) => prev + cost, 0); .reduce((prev, cost) => prev + cost, 0);
} }
async listSessions( async listSessionIds(
userId: string, userId: string,
workspaceId: string, workspaceId: string,
options?: { docId?: string; action?: boolean } docId?: string,
options?: { action?: boolean }
): Promise<string[]> { ): Promise<string[]> {
return await this.db.aiSession return await this.db.aiSession
.findMany({ .findMany({
where: { where: {
userId, userId,
workspaceId, workspaceId,
docId: workspaceId === options?.docId ? undefined : options?.docId, docId,
prompt: { prompt: {
action: options?.action ? { not: null } : null, action: options?.action ? { not: null } : null,
}, },
+8 -6
View File
@@ -37,18 +37,16 @@ enum ContextFileStatus {
} }
type Copilot { type Copilot {
"""Get the session list of actions in the workspace"""
actions: [String!]!
"""Get the session list of chats in the workspace"""
chats: [String!]!
"""Get the context list of a session""" """Get the context list of a session"""
contexts(contextId: String, sessionId: String!): [CopilotContext!]! contexts(contextId: String, sessionId: String!): [CopilotContext!]!
docId: ID
histories(docId: String, options: QueryChatHistoriesInput): [CopilotHistories!]! histories(docId: String, options: QueryChatHistoriesInput): [CopilotHistories!]!
"""Get the quota of the user in the workspace""" """Get the quota of the user in the workspace"""
quota: CopilotQuota! quota: CopilotQuota!
"""Get the session list in the workspace"""
sessionIds(docId: String, options: QueryChatSessionsInput): [String!]!
workspaceId: ID workspaceId: ID
} }
@@ -884,6 +882,10 @@ input QueryChatHistoriesInput {
withPrompt: Boolean withPrompt: Boolean
} }
input QueryChatSessionsInput {
action: Boolean
}
type QueryTooLongDataType { type QueryTooLongDataType {
max: Int! max: Int!
} }
@@ -301,6 +301,11 @@ declare global {
docId: string, docId: string,
promptName?: string promptName?: string
) => Promise<string>; ) => Promise<string>;
getSessionIds: (
workspaceId: string,
docId?: string,
options?: { action?: boolean }
) => Promise<string[] | undefined>;
updateSession: (sessionId: string, promptName: string) => Promise<string>; updateSession: (sessionId: string, promptName: string) => Promise<string>;
} }
@@ -136,15 +136,23 @@ export class CopilotClient {
} }
} }
async getSessions(workspaceId: string) { async getSessionIds(
workspaceId: string,
docId?: string,
options?: RequestOptions<
typeof getCopilotSessionsQuery
>['variables']['options']
) {
try { try {
const res = await this.gql({ const res = await this.gql({
query: getCopilotSessionsQuery, query: getCopilotSessionsQuery,
variables: { variables: {
workspaceId, workspaceId,
docId,
options,
}, },
}); });
return res.currentUser?.copilot; return res.currentUser?.copilot?.sessionIds;
} catch (err) { } catch (err) {
throw resolveError(err); throw resolveError(err);
} }
@@ -1,5 +1,4 @@
import { AIProvider } from '@affine/core/blocksuite/presets/ai'; import { AIProvider } from '@affine/core/blocksuite/presets/ai';
import type { ForkChatSessionInput } from '@affine/graphql';
import { assertExists } from '@blocksuite/affine/global/utils'; import { assertExists } from '@blocksuite/affine/global/utils';
import { partition } from 'lodash-es'; import { partition } from 'lodash-es';
@@ -48,36 +47,13 @@ export async function createChatSession({
promptName, promptName,
}); });
// always update the prompt name // always update the prompt name
await updateChatSession({ await client.updateSession({
sessionId, sessionId,
client,
promptName, promptName,
}); });
return sessionId; return sessionId;
} }
export function updateChatSession({
client,
sessionId,
promptName,
}: {
client: CopilotClient;
sessionId: string;
promptName: string;
}) {
return client.updateSession({
sessionId,
promptName,
});
}
export function forkCopilotSession(
client: CopilotClient,
forkChatSessionInput: ForkChatSessionInput
) {
return client.forkSession(forkChatSessionInput);
}
async function resizeImage(blob: Blob | File): Promise<Blob | null> { async function resizeImage(blob: Blob | File): Promise<Blob | null> {
let src = ''; let src = '';
try { try {
@@ -360,17 +336,3 @@ export function toImage({
}, },
}; };
} }
export function cleanupSessions({
workspaceId,
docId,
sessionIds,
client,
}: {
workspaceId: string;
docId: string;
sessionIds: string[];
client: CopilotClient;
}) {
return client.cleanupSessions({ workspaceId, docId, sessionIds });
}
@@ -11,14 +11,7 @@ import { z } from 'zod';
import type { CopilotClient } from './copilot-client'; import type { CopilotClient } from './copilot-client';
import type { PromptKey } from './prompt'; import type { PromptKey } from './prompt';
import { import { createChatSession, textToText, toImage } from './request';
cleanupSessions,
createChatSession,
forkCopilotSession,
textToText,
toImage,
updateChatSession,
} from './request';
import { setupTracker } from './tracker'; import { setupTracker } from './tracker';
const filterStyleToPromptName = new Map( const filterStyleToPromptName = new Map(
@@ -424,9 +417,15 @@ Could you make a new website based on these notes and send back just the html fi
promptName, promptName,
}); });
}, },
getSessionIds: async (
workspaceId: string,
docId?: string,
options?: { action?: boolean }
) => {
return client.getSessionIds(workspaceId, docId, options);
},
updateSession: async (sessionId: string, promptName: string) => { updateSession: async (sessionId: string, promptName: string) => {
return updateChatSession({ return client.updateSession({
client,
sessionId, sessionId,
promptName, promptName,
}); });
@@ -490,7 +489,7 @@ Could you make a new website based on these notes and send back just the html fi
docId: string, docId: string,
sessionIds: string[] sessionIds: string[]
) => { ) => {
await cleanupSessions({ workspaceId, docId, sessionIds, client }); await client.cleanupSessions({ workspaceId, docId, sessionIds });
}, },
ids: async ( ids: async (
workspaceId: string, workspaceId: string,
@@ -533,7 +532,7 @@ Could you make a new website based on these notes and send back just the html fi
AIProvider.provide('onboarding', toggleGeneralAIOnboarding); AIProvider.provide('onboarding', toggleGeneralAIOnboarding);
AIProvider.provide('forkChat', options => { AIProvider.provide('forkChat', options => {
return forkCopilotSession(client, options); return client.forkSession(options);
}); });
const disposeRequestLoginHandler = AIProvider.slots.requestLogin.on(() => { const disposeRequestLoginHandler = AIProvider.slots.requestLogin.on(() => {
@@ -1,8 +1,11 @@
query getCopilotSessions($workspaceId: String!) { query getCopilotSessions(
$workspaceId: String!
$docId: String
$options: QueryChatSessionsInput
) {
currentUser { currentUser {
copilot(workspaceId: $workspaceId) { copilot(workspaceId: $workspaceId) {
actions sessionIds(docId: $docId, options: $options)
chats
} }
} }
} }
@@ -421,11 +421,10 @@ export const getCopilotSessionsQuery = {
definitionName: 'currentUser', definitionName: 'currentUser',
containsFile: false, containsFile: false,
query: ` query: `
query getCopilotSessions($workspaceId: String!) { query getCopilotSessions($workspaceId: String!, $docId: String, $options: QueryChatSessionsInput) {
currentUser { currentUser {
copilot(workspaceId: $workspaceId) { copilot(workspaceId: $workspaceId) {
actions sessionIds(docId: $docId, options: $options)
chats
} }
} }
}`, }`,
+15 -9
View File
@@ -76,15 +76,14 @@ export enum ContextFileStatus {
export interface Copilot { export interface Copilot {
__typename?: 'Copilot'; __typename?: 'Copilot';
/** Get the session list of actions in the workspace */
actions: Array<Scalars['String']['output']>;
/** Get the session list of chats in the workspace */
chats: Array<Scalars['String']['output']>;
/** Get the context list of a session */ /** Get the context list of a session */
contexts: Array<CopilotContext>; contexts: Array<CopilotContext>;
docId: Maybe<Scalars['ID']['output']>;
histories: Array<CopilotHistories>; histories: Array<CopilotHistories>;
/** Get the quota of the user in the workspace */ /** Get the quota of the user in the workspace */
quota: CopilotQuota; quota: CopilotQuota;
/** Get the session list in the workspace */
sessionIds: Array<Scalars['String']['output']>;
workspaceId: Maybe<Scalars['ID']['output']>; workspaceId: Maybe<Scalars['ID']['output']>;
} }
@@ -98,6 +97,11 @@ export interface CopilotHistoriesArgs {
options?: InputMaybe<QueryChatHistoriesInput>; options?: InputMaybe<QueryChatHistoriesInput>;
} }
export interface CopilotSessionIdsArgs {
docId?: InputMaybe<Scalars['String']['input']>;
options?: InputMaybe<QueryChatSessionsInput>;
}
export interface CopilotContext { export interface CopilotContext {
__typename?: 'CopilotContext'; __typename?: 'CopilotContext';
/** list files in context */ /** list files in context */
@@ -1301,6 +1305,10 @@ export interface QueryChatHistoriesInput {
withPrompt?: InputMaybe<Scalars['Boolean']['input']>; withPrompt?: InputMaybe<Scalars['Boolean']['input']>;
} }
export interface QueryChatSessionsInput {
action?: InputMaybe<Scalars['Boolean']['input']>;
}
export interface QueryTooLongDataType { export interface QueryTooLongDataType {
__typename?: 'QueryTooLongDataType'; __typename?: 'QueryTooLongDataType';
max: Scalars['Int']['output']; max: Scalars['Int']['output'];
@@ -2196,17 +2204,15 @@ export type UpdateCopilotSessionMutation = {
export type GetCopilotSessionsQueryVariables = Exact<{ export type GetCopilotSessionsQueryVariables = Exact<{
workspaceId: Scalars['String']['input']; workspaceId: Scalars['String']['input'];
docId?: InputMaybe<Scalars['String']['input']>;
options?: InputMaybe<QueryChatSessionsInput>;
}>; }>;
export type GetCopilotSessionsQuery = { export type GetCopilotSessionsQuery = {
__typename?: 'Query'; __typename?: 'Query';
currentUser: { currentUser: {
__typename?: 'UserType'; __typename?: 'UserType';
copilot: { copilot: { __typename?: 'Copilot'; sessionIds: Array<string> };
__typename?: 'Copilot';
actions: Array<string>;
chats: Array<string>;
};
} | null; } | null;
}; };