mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 12:55:00 +00:00
feat(server): add typed list session gql (#12979)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Introduced new API endpoints and GraphQL queries to retrieve Copilot chat sessions by workspace, document, and pinned status, with detailed session and message information. * Added support for filtering and querying Copilot chat histories with new options such as pinned status and message ordering. * **Bug Fixes** * Improved filtering logic for listing and retrieving chat sessions, ensuring accurate results for workspace, document, and pinned session queries. * **Tests** * Expanded and refactored test coverage for session listing, filtering, and new query options to ensure reliability and correctness of Copilot session retrieval. * Updated snapshot data to reflect new session types and filtering capabilities. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -16,6 +16,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
role: 'assistant',
|
||||
},
|
||||
],
|
||||
pinned: false,
|
||||
tokens: 8,
|
||||
},
|
||||
]
|
||||
@@ -30,6 +31,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
role: 'assistant',
|
||||
},
|
||||
],
|
||||
pinned: false,
|
||||
tokens: 8,
|
||||
},
|
||||
]
|
||||
|
||||
Binary file not shown.
@@ -53,7 +53,10 @@ import {
|
||||
createWorkspaceCopilotSession,
|
||||
forkCopilotSession,
|
||||
getCopilotSession,
|
||||
getDocSessions,
|
||||
getHistories,
|
||||
getPinnedSessions,
|
||||
getWorkspaceSessions,
|
||||
listContext,
|
||||
listContextDocAndFiles,
|
||||
matchFiles,
|
||||
@@ -1140,31 +1143,94 @@ test('should list histories for different session types correctly', async t => {
|
||||
]);
|
||||
|
||||
const testHistoryQuery = async (
|
||||
queryDocId: string | undefined,
|
||||
expectedSessionId: string,
|
||||
queryFn: () => Promise<any[]>,
|
||||
opts: {
|
||||
sessionIds?: string[];
|
||||
sessionId?: string;
|
||||
pinned?: boolean;
|
||||
isEmpty?: boolean;
|
||||
},
|
||||
description: string
|
||||
) => {
|
||||
const histories = await getHistories(app, {
|
||||
workspaceId,
|
||||
docId: queryDocId,
|
||||
});
|
||||
t.is(histories.length, 1, `should return ${description}`);
|
||||
t.is(
|
||||
histories[0].sessionId,
|
||||
expectedSessionId,
|
||||
`should return correct ${description}`
|
||||
);
|
||||
const s = await queryFn();
|
||||
|
||||
if (opts.isEmpty) {
|
||||
t.is(s.length, 0, `should return ${description}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (opts.sessionIds) {
|
||||
t.is(s.length, opts.sessionIds.length, `should return ${description}`);
|
||||
const ids = s.map(h => h.sessionId).sort((a, b) => a.localeCompare(b));
|
||||
const expectedIds = opts.sessionIds.sort((a, b) => a.localeCompare(b));
|
||||
t.deepEqual(ids, expectedIds, `should return correct ${description}`);
|
||||
} else if (opts.sessionId) {
|
||||
t.is(s.length, 1, `should return ${description}`);
|
||||
t.is(
|
||||
s[0].sessionId,
|
||||
opts.sessionId,
|
||||
`should return correct ${description}`
|
||||
);
|
||||
if (opts.pinned !== undefined) {
|
||||
t.is(s[0].pinned, opts.pinned, `pinned status for ${description}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// test for getHistories
|
||||
await testHistoryQuery(
|
||||
undefined,
|
||||
workspaceSessionId,
|
||||
() => getHistories(app, { workspaceId, docId: null }),
|
||||
{ sessionId: workspaceSessionId },
|
||||
'workspace session history'
|
||||
);
|
||||
await testHistoryQuery(
|
||||
pinnedDocId,
|
||||
pinnedSessionId,
|
||||
() => getHistories(app, { workspaceId, docId: pinnedDocId }),
|
||||
{ sessionId: pinnedSessionId },
|
||||
'pinned session history'
|
||||
);
|
||||
await testHistoryQuery(docId, docSessionId, 'doc session history');
|
||||
await testHistoryQuery(
|
||||
() => getHistories(app, { workspaceId, docId }),
|
||||
{ sessionId: docSessionId },
|
||||
'doc session history'
|
||||
);
|
||||
|
||||
// test for getWorkspaceSessions
|
||||
await testHistoryQuery(
|
||||
() => getWorkspaceSessions(app, { workspaceId }),
|
||||
{ sessionId: workspaceSessionId, pinned: false },
|
||||
'workspace-level sessions'
|
||||
);
|
||||
|
||||
// test for getDocSessions
|
||||
await testHistoryQuery(
|
||||
() =>
|
||||
getDocSessions(app, { workspaceId, docId, options: { pinned: false } }),
|
||||
{ sessionId: docSessionId, pinned: false },
|
||||
'doc sessions'
|
||||
);
|
||||
|
||||
await testHistoryQuery(
|
||||
() => getDocSessions(app, { workspaceId, docId: pinnedDocId }),
|
||||
{ sessionId: pinnedSessionId, pinned: true },
|
||||
'pinned doc sessions'
|
||||
);
|
||||
|
||||
// test for getPinnedSessions
|
||||
await testHistoryQuery(
|
||||
() => getPinnedSessions(app, { workspaceId }),
|
||||
{ sessionId: pinnedSessionId, pinned: true },
|
||||
'pinned sessions'
|
||||
);
|
||||
|
||||
await testHistoryQuery(
|
||||
() => getPinnedSessions(app, { workspaceId, docId: pinnedDocId }),
|
||||
{ sessionId: pinnedSessionId, pinned: true },
|
||||
'pinned session for specific doc'
|
||||
);
|
||||
|
||||
await testHistoryQuery(
|
||||
() => getPinnedSessions(app, { workspaceId, docId }),
|
||||
{ isEmpty: true },
|
||||
'no pinned sessions for non-pinned doc'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -262,16 +262,53 @@ Generated by [AVA](https://avajs.dev).
|
||||
|
||||
{
|
||||
all_workspace_sessions: {
|
||||
count: 2,
|
||||
count: 7,
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: true,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: true,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'pinned',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'workspace',
|
||||
@@ -283,30 +320,35 @@ Generated by [AVA](https://avajs.dev).
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: true,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: true,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 1,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: true,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 1,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: true,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: true,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 1,
|
||||
type: 'doc',
|
||||
@@ -318,6 +360,7 @@ Generated by [AVA](https://avajs.dev).
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
@@ -325,28 +368,39 @@ Generated by [AVA](https://avajs.dev).
|
||||
],
|
||||
},
|
||||
non_action_sessions: {
|
||||
count: 4,
|
||||
count: 5,
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: true,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: true,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
@@ -354,28 +408,25 @@ Generated by [AVA](https://avajs.dev).
|
||||
],
|
||||
},
|
||||
non_fork_sessions: {
|
||||
count: 4,
|
||||
count: 3,
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
@@ -383,16 +434,44 @@ Generated by [AVA](https://avajs.dev).
|
||||
],
|
||||
},
|
||||
recent_top3_sessions: {
|
||||
count: 3,
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: true,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'doc',
|
||||
},
|
||||
],
|
||||
},
|
||||
workspace_sessions_with_messages: {
|
||||
count: 2,
|
||||
sessionTypes: [
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'pinned',
|
||||
},
|
||||
{
|
||||
hasMessages: false,
|
||||
isAction: false,
|
||||
isFork: false,
|
||||
messageCount: 0,
|
||||
type: 'workspace',
|
||||
@@ -486,102 +565,3 @@ Generated by [AVA](https://avajs.dev).
|
||||
workspaceSessionExists: true,
|
||||
},
|
||||
}
|
||||
|
||||
## should handle session updates and validations
|
||||
|
||||
> should unpin existing when pinning new session
|
||||
|
||||
[
|
||||
{
|
||||
docId: null,
|
||||
id: 'session-update-id',
|
||||
pinned: true,
|
||||
},
|
||||
{
|
||||
docId: null,
|
||||
id: 'existing-pinned-session-id',
|
||||
pinned: false,
|
||||
},
|
||||
]
|
||||
|
||||
> session type conversion steps
|
||||
|
||||
[
|
||||
{
|
||||
session: {
|
||||
docId: 'doc-update-id',
|
||||
pinned: false,
|
||||
},
|
||||
step: 'workspace_to_doc',
|
||||
type: 'doc',
|
||||
},
|
||||
{
|
||||
session: {
|
||||
docId: null,
|
||||
pinned: false,
|
||||
},
|
||||
step: 'doc_to_workspace',
|
||||
type: 'workspace',
|
||||
},
|
||||
{
|
||||
session: {
|
||||
docId: null,
|
||||
pinned: true,
|
||||
},
|
||||
step: 'workspace_to_pinned',
|
||||
type: 'pinned',
|
||||
},
|
||||
]
|
||||
|
||||
## should create multiple doc sessions and query latest
|
||||
|
||||
> multiple doc sessions for same document with order verification
|
||||
|
||||
[
|
||||
{
|
||||
docId: 'multi-session-doc',
|
||||
hasMessages: true,
|
||||
isFirstSession: false,
|
||||
isSecondSession: false,
|
||||
isThirdSession: true,
|
||||
messageCount: 1,
|
||||
},
|
||||
{
|
||||
docId: 'multi-session-doc',
|
||||
hasMessages: true,
|
||||
isFirstSession: false,
|
||||
isSecondSession: true,
|
||||
isThirdSession: false,
|
||||
messageCount: 1,
|
||||
},
|
||||
{
|
||||
docId: 'multi-session-doc',
|
||||
hasMessages: true,
|
||||
isFirstSession: true,
|
||||
isSecondSession: false,
|
||||
isThirdSession: false,
|
||||
messageCount: 1,
|
||||
},
|
||||
]
|
||||
|
||||
## should query recent topK sessions of different types
|
||||
|
||||
> should include different session types in recent topK query
|
||||
|
||||
[
|
||||
{
|
||||
docId: null,
|
||||
pinned: false,
|
||||
type: 'workspace',
|
||||
},
|
||||
{
|
||||
docId: null,
|
||||
pinned: true,
|
||||
type: 'pinned',
|
||||
},
|
||||
{
|
||||
docId: null,
|
||||
pinned: false,
|
||||
type: 'workspace',
|
||||
},
|
||||
]
|
||||
|
||||
Binary file not shown.
@@ -169,6 +169,7 @@ test('should list and filter session type', async t => {
|
||||
const workspaceSessions = await copilotSession.list({
|
||||
userId: user.id,
|
||||
workspaceId: workspace.id,
|
||||
docId: null,
|
||||
});
|
||||
|
||||
t.snapshot(
|
||||
@@ -575,6 +576,10 @@ test('should handle session queries, ordering, and filtering', async t => {
|
||||
const docParams = { ...baseParams, docId };
|
||||
const queryTestCases = [
|
||||
{ name: 'all_workspace_sessions', params: baseParams },
|
||||
{
|
||||
name: 'workspace_sessions_with_messages',
|
||||
params: { ...baseParams, docId: null, withMessages: true },
|
||||
},
|
||||
{
|
||||
name: 'doc_sessions_with_messages',
|
||||
params: { ...docParams, withMessages: true },
|
||||
@@ -609,6 +614,7 @@ test('should handle session queries, ordering, and filtering', async t => {
|
||||
type: copilotSession.getSessionType(s),
|
||||
hasMessages: !!s.messages?.length,
|
||||
messageCount: s.messages?.length || 0,
|
||||
isAction: s.promptName === TEST_PROMPTS.ACTION,
|
||||
isFork: !!s.parentSessionId,
|
||||
})),
|
||||
};
|
||||
|
||||
@@ -709,26 +709,30 @@ type ChatMessage = {
|
||||
|
||||
type History = {
|
||||
sessionId: string;
|
||||
pinned: boolean;
|
||||
tokens: number;
|
||||
action: string | null;
|
||||
createdAt: string;
|
||||
messages: ChatMessage[];
|
||||
};
|
||||
|
||||
type HistoryOptions = {
|
||||
action?: boolean;
|
||||
fork?: boolean;
|
||||
pinned?: boolean;
|
||||
limit?: number;
|
||||
skip?: number;
|
||||
sessionOrder?: 'asc' | 'desc';
|
||||
messageOrder?: 'asc' | 'desc';
|
||||
sessionId?: string;
|
||||
};
|
||||
|
||||
export async function getHistories(
|
||||
app: TestingApp,
|
||||
variables: {
|
||||
workspaceId: string;
|
||||
docId?: string;
|
||||
options?: {
|
||||
action?: boolean;
|
||||
fork?: boolean;
|
||||
limit?: number;
|
||||
skip?: number;
|
||||
sessionOrder?: 'asc' | 'desc';
|
||||
messageOrder?: 'asc' | 'desc';
|
||||
sessionId?: string;
|
||||
};
|
||||
docId?: string | null;
|
||||
options?: HistoryOptions;
|
||||
}
|
||||
): Promise<History[]> {
|
||||
const res = await app.gql(
|
||||
@@ -742,6 +746,7 @@ export async function getHistories(
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: $docId, options: $options) {
|
||||
sessionId
|
||||
pinned
|
||||
tokens
|
||||
action
|
||||
createdAt
|
||||
@@ -763,6 +768,152 @@ export async function getHistories(
|
||||
return res.currentUser?.copilot?.histories || [];
|
||||
}
|
||||
|
||||
export async function getWorkspaceSessions(
|
||||
app: TestingApp,
|
||||
variables: {
|
||||
workspaceId: string;
|
||||
options?: HistoryOptions;
|
||||
}
|
||||
): Promise<History[]> {
|
||||
const res = await app.gql(
|
||||
`query getCopilotWorkspaceSessions(
|
||||
$workspaceId: String!
|
||||
$options: QueryChatHistoriesInput
|
||||
) {
|
||||
currentUser {
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: null, options: $options) {
|
||||
sessionId
|
||||
pinned
|
||||
tokens
|
||||
action
|
||||
createdAt
|
||||
messages {
|
||||
id
|
||||
role
|
||||
content
|
||||
streamObjects {
|
||||
type
|
||||
textDelta
|
||||
toolCallId
|
||||
toolName
|
||||
args
|
||||
result
|
||||
}
|
||||
attachments
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
variables
|
||||
);
|
||||
|
||||
return res.currentUser?.copilot?.histories || [];
|
||||
}
|
||||
|
||||
export async function getDocSessions(
|
||||
app: TestingApp,
|
||||
variables: {
|
||||
workspaceId: string;
|
||||
docId: string;
|
||||
options?: HistoryOptions;
|
||||
}
|
||||
): Promise<History[]> {
|
||||
const res = await app.gql(
|
||||
`query getCopilotDocSessions(
|
||||
$workspaceId: String!
|
||||
$docId: String!
|
||||
$options: QueryChatHistoriesInput
|
||||
) {
|
||||
currentUser {
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: $docId, options: $options) {
|
||||
sessionId
|
||||
pinned
|
||||
tokens
|
||||
action
|
||||
createdAt
|
||||
messages {
|
||||
id
|
||||
role
|
||||
content
|
||||
streamObjects {
|
||||
type
|
||||
textDelta
|
||||
toolCallId
|
||||
toolName
|
||||
args
|
||||
result
|
||||
}
|
||||
attachments
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
variables
|
||||
);
|
||||
|
||||
return res.currentUser?.copilot?.histories || [];
|
||||
}
|
||||
|
||||
export async function getPinnedSessions(
|
||||
app: TestingApp,
|
||||
variables: {
|
||||
workspaceId: string;
|
||||
docId?: string;
|
||||
messageOrder?: 'asc' | 'desc';
|
||||
withPrompt?: boolean;
|
||||
}
|
||||
): Promise<History[]> {
|
||||
const res = await app.gql(
|
||||
`query getCopilotPinnedSessions(
|
||||
$workspaceId: String!
|
||||
$docId: String
|
||||
$messageOrder: ChatHistoryOrder
|
||||
$withPrompt: Boolean
|
||||
) {
|
||||
currentUser {
|
||||
copilot(workspaceId: $workspaceId) {
|
||||
histories(docId: $docId, options: {
|
||||
limit: 1,
|
||||
pinned: true,
|
||||
messageOrder: $messageOrder,
|
||||
withPrompt: $withPrompt
|
||||
}) {
|
||||
sessionId
|
||||
pinned
|
||||
tokens
|
||||
action
|
||||
createdAt
|
||||
messages {
|
||||
id
|
||||
role
|
||||
content
|
||||
streamObjects {
|
||||
type
|
||||
textDelta
|
||||
toolCallId
|
||||
toolName
|
||||
args
|
||||
result
|
||||
}
|
||||
attachments
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`,
|
||||
variables
|
||||
);
|
||||
|
||||
return res.currentUser?.copilot?.histories || [];
|
||||
}
|
||||
|
||||
type Prompt = {
|
||||
name: string;
|
||||
model: string;
|
||||
|
||||
@@ -285,38 +285,44 @@ export class CopilotSessionModel extends BaseModel {
|
||||
}
|
||||
|
||||
async list(options: ListSessionOptions) {
|
||||
const { userId, sessionId, workspaceId, docId } = options;
|
||||
const { userId, sessionId, workspaceId, docId, action, fork } = options;
|
||||
|
||||
function getNullCond<T>(
|
||||
maybeBool: boolean | undefined,
|
||||
wrap: (ret: { not: null } | null) => T = ret => ret as T
|
||||
): T | undefined {
|
||||
return maybeBool === true
|
||||
? wrap({ not: null })
|
||||
: maybeBool === false
|
||||
? wrap(null)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function getEqCond<T>(maybeValue: T | undefined): T | undefined {
|
||||
return maybeValue !== undefined ? maybeValue : undefined;
|
||||
}
|
||||
|
||||
const conditions: Prisma.AiSessionWhereInput['OR'] = [
|
||||
{
|
||||
userId,
|
||||
workspaceId,
|
||||
docId: docId ?? null,
|
||||
id: sessionId ? { equals: sessionId } : undefined,
|
||||
docId: getEqCond(docId),
|
||||
id: getEqCond(sessionId),
|
||||
deletedAt: null,
|
||||
prompt:
|
||||
typeof options.action === 'boolean'
|
||||
? options.action
|
||||
? { action: { not: null } }
|
||||
: { action: null }
|
||||
: undefined,
|
||||
parentSessionId:
|
||||
typeof options.fork === 'boolean'
|
||||
? options.fork
|
||||
? { not: null }
|
||||
: null
|
||||
: undefined,
|
||||
pinned: getEqCond(options.pinned),
|
||||
prompt: getNullCond(fork, ret => ({ action: ret })),
|
||||
parentSessionId: getNullCond(fork),
|
||||
},
|
||||
];
|
||||
|
||||
if (!options?.action && options?.fork) {
|
||||
if (!action && fork) {
|
||||
// query forked sessions from other users
|
||||
// only query forked session if fork == true and action == false
|
||||
conditions.push({
|
||||
userId: { not: userId },
|
||||
workspaceId: workspaceId,
|
||||
docId: docId ?? null,
|
||||
id: sessionId ? { equals: sessionId } : undefined,
|
||||
id: getEqCond(sessionId),
|
||||
prompt: { action: null },
|
||||
// should only find forked session
|
||||
parentSessionId: { not: null },
|
||||
|
||||
Reference in New Issue
Block a user