Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ function assertOk<T>(res: Response, data: ApiEnvelope<T>, fallback: string) {
}
}

export async function apiFetchSessions(params?: { mode?: ChatMode; errorMessage?: string }) {
const type = params?.mode ?? 'global';
const res = await authFetch(`/api/chat/sessions?type=${encodeURIComponent(type)}`, {
export async function apiFetchSessions(params: { mode?: ChatMode; connectionId: string; errorMessage?: string }) {
const type = params.mode ?? 'global';
const url = new URL('/api/chat/sessions', window.location.origin);
url.searchParams.set('type', type);
url.searchParams.set('connectionId', params.connectionId);
const res = await authFetch(url.toString(), {
method: 'GET',
cache: 'no-store',
});
Expand All @@ -54,7 +57,7 @@ export async function apiFetchSessionDetail(sessionId: string, options?: { error
return { detail, messages };
}

export async function apiCreateSession(params: { mode: ChatMode; errorMessage?: string; copilotNotSupportedMessage?: string }) {
export async function apiCreateSession(params: { mode: ChatMode; connectionId: string; errorMessage?: string; copilotNotSupportedMessage?: string }) {
if (params.mode === 'copilot') {
throw new Error(params.copilotNotSupportedMessage ?? 'Copilot sessions cannot be created manually.');
}
Expand All @@ -65,6 +68,7 @@ export async function apiCreateSession(params: { mode: ChatMode; errorMessage?:
cache: 'no-store',
body: JSON.stringify({
type: 'global',
connectionId: params.connectionId,
}),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { toast } from 'sonner';
import type { UIMessage } from 'ai';
import { useTranslations } from 'next-intl';
import { useParams } from 'next/navigation';
import posthog from 'posthog-js';

import type { ChatSessionItem, ChatMode } from './types';
Expand All @@ -23,6 +24,8 @@ export function useChatSessions(params: { mode: ChatMode; copilotEnvelope?: Copi
const { mode, copilotEnvelope } = params;
const copilotTabId = copilotEnvelope?.meta?.tabId ?? null;
const t = useTranslations('Chatbot');
const routeParams = useParams<{ connectionId: string }>();
const connectionId = routeParams.connectionId;

const [sessions, setSessions] = useState<ChatSessionItem[]>([]);
const [selectedSessionId, setSelectedSessionId] = useState<string | null>(null);
Expand Down Expand Up @@ -55,7 +58,7 @@ export function useChatSessions(params: { mode: ChatMode; copilotEnvelope?: Copi

setLoadingSessions(true);
try {
const list = await apiFetchSessions({ mode: 'global', errorMessage: t('Errors.FetchSessions') });
const list = await apiFetchSessions({ mode: 'global', connectionId, errorMessage: t('Errors.FetchSessions') });
setSessions(list);

const currentPreferred = preferredId ?? selectedSessionRef.current;
Expand All @@ -74,7 +77,7 @@ export function useChatSessions(params: { mode: ChatMode; copilotEnvelope?: Copi
setLoadingSessions(false);
}
},
[mode, t],
[mode, connectionId, t],
);

const fetchSessionDetail = useCallback(async (sessionId: string) => {
Expand Down Expand Up @@ -178,7 +181,7 @@ export function useChatSessions(params: { mode: ChatMode; copilotEnvelope?: Copi
if (creatingSession) return;
setCreatingSession(true);
try {
const created = await apiCreateSession({ mode: 'global', errorMessage: t('Errors.CreateSession') });
const created = await apiCreateSession({ mode: 'global', connectionId, errorMessage: t('Errors.CreateSession') });
if (created?.id) {
posthog.capture('chat_session_created', { session_id: created.id });
}
Expand Down
27 changes: 26 additions & 1 deletion apps/web/app/api/chat/sessions/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const GET = withUserAndOrganizationHandler(async ({ req, db, userId, orga
const locale = await getApiLocale();
const { searchParams } = new URL(req.url);
const type = (searchParams.get('type') as ChatSessionType | null) ?? 'global';
const connectionId = searchParams.get('connectionId');

if (type !== 'global' && type !== 'copilot') {
return NextResponse.json(
Expand All @@ -47,6 +48,16 @@ export const GET = withUserAndOrganizationHandler(async ({ req, db, userId, orga
);
}

if (!connectionId) {
return NextResponse.json(
ResponseUtil.error({
code: ErrorCodes.INVALID_PARAMS,
message: translateApi('Api.Chat.Errors.ConnectionIdRequired', undefined, locale),
}),
{ status: 400 },
);
}

try {
if (!db?.chat) throw new Error('Chat repository not available');

Expand All @@ -55,6 +66,7 @@ export const GET = withUserAndOrganizationHandler(async ({ req, db, userId, orga
userId,
type,
includeArchived: false,
connectionId,
});

return NextResponse.json(
Expand All @@ -81,14 +93,16 @@ export const POST = withUserAndOrganizationHandler(async ({ req, db, userId, org
const locale = await getApiLocale();
console.log('POST /api/chat/sessions called', userId, organizationId);

let payload: { type?: string } | null = null;
let payload: { type?: string; connectionId?: string } | null = null;
try {
payload = await req.json();
} catch {
payload = null;
}

const type = payload?.type ?? 'global';
const connectionId = payload?.connectionId ?? null;

if (type !== 'global') {
return NextResponse.json(
ResponseUtil.error({
Expand All @@ -99,12 +113,23 @@ export const POST = withUserAndOrganizationHandler(async ({ req, db, userId, org
);
}

if (!connectionId) {
return NextResponse.json(
ResponseUtil.error({
code: ErrorCodes.INVALID_PARAMS,
message: translateApi('Api.Chat.Errors.ConnectionIdRequired', undefined, locale),
}),
{ status: 400 },
);
}

try {
if (!db?.chat) throw new Error('Chat repository not available');

const created = await db.chat.createGlobalSession({
organizationId,
userId,
connectionId,
title: null,
metadata: null,
});
Expand Down
3 changes: 2 additions & 1 deletion apps/web/lib/database/postgres/impl/chat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,13 @@ export class PostgresChatRepository implements ChatRepository {
async listSessions(params: {
organizationId: string;
userId: string;
connectionId: string;
includeArchived?: boolean;
type?: ChatSessionType;
}) {
this.assertInited();

const conds = [eq(chatSessions.organizationId, params.organizationId), eq(chatSessions.userId, params.userId)];
const conds = [eq(chatSessions.organizationId, params.organizationId), eq(chatSessions.userId, params.userId), eq(chatSessions.connectionId, params.connectionId)];
if (!params.includeArchived) conds.push(isNull(chatSessions.archivedAt));
if (params.type) conds.push(eq(chatSessions.type, params.type));

Expand Down
1 change: 1 addition & 0 deletions apps/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1736,6 +1736,7 @@
"MissingTabId": "Missing tabId",
"FetchCopilotSessionFailed": "Failed to fetch Copilot session",
"InvalidSessionType": "Invalid session type",
"ConnectionIdRequired": "Connection ID is required",
"ListSessionsFailed": "Failed to fetch sessions",
"CopilotCreationNotAllowed": "Copilot sessions cannot be created via this endpoint",
"CreateSessionFailed": "Failed to create session"
Expand Down
1 change: 1 addition & 0 deletions apps/web/public/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,7 @@
"MissingTabId": "Falta tabId",
"FetchCopilotSessionFailed": "No se pudo obtener la sesión de Copilot",
"InvalidSessionType": "Tipo de sesión no válido",
"ConnectionIdRequired": "Se requiere el ID de conexión",
"ListSessionsFailed": "No se pudieron obtener las sesiones",
"CopilotCreationNotAllowed": "Las sesiones de Copilot no se pueden crear desde este endpoint",
"CreateSessionFailed": "No se pudo crear la sesión"
Expand Down
1 change: 1 addition & 0 deletions apps/web/public/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,7 @@
"MissingTabId": "tabId がありません",
"FetchCopilotSessionFailed": "Copilot セッションの取得に失敗しました",
"InvalidSessionType": "無効なセッション種別です",
"ConnectionIdRequired": "接続IDが必要です",
"ListSessionsFailed": "セッションの取得に失敗しました",
"CopilotCreationNotAllowed": "このエンドポイントでは Copilot セッションを作成できません",
"CreateSessionFailed": "セッションの作成に失敗しました"
Expand Down
1 change: 1 addition & 0 deletions apps/web/public/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,7 @@
"MissingTabId": "缺少 tabId",
"FetchCopilotSessionFailed": "获取 Copilot 会话失败",
"InvalidSessionType": "非法的 session type",
"ConnectionIdRequired": "缺少 Connection ID 参数",
"ListSessionsFailed": "获取会话列表失败",
"CopilotCreationNotAllowed": "Copilot 会话不能通过该接口创建",
"CreateSessionFailed": "创建会话失败"
Expand Down
2 changes: 1 addition & 1 deletion apps/web/types/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export interface ChatRepository {

createGlobalSession(input: ChatSessionCreateGlobal): Promise<ChatSessionRecord>;

listSessions(params: { organizationId: string; userId: string; includeArchived?: boolean; type?: ChatSessionType }): Promise<ChatSessionRecord[]>;
listSessions(params: { organizationId: string; userId: string; connectionId: string; includeArchived?: boolean; type?: ChatSessionType }): Promise<ChatSessionRecord[]>;

readSession(params: { organizationId: string; sessionId: string; userId: string }): Promise<ChatSessionRecord | null>;

Expand Down
Loading