+
+
diff --git a/app/slices/setup/api/data/repositories/api/schemas.gen.ts b/app/slices/setup/api/data/repositories/api/schemas.gen.ts
index b860737..ff51c74 100644
--- a/app/slices/setup/api/data/repositories/api/schemas.gen.ts
+++ b/app/slices/setup/api/data/repositories/api/schemas.gen.ts
@@ -1252,6 +1252,255 @@ export const UpdateSkillDtoSchema = {
},
} as const;
+export const ChatSessionDtoSchema = {
+ type: "object",
+ properties: {
+ id: {
+ type: "string",
+ example: "chat-9f2c…",
+ },
+ agentId: {
+ type: "string",
+ },
+ channel: {
+ type: "string",
+ enum: ["bridle", "telegram", "slack", "internal"],
+ example: "bridle",
+ },
+ externalUserId: {
+ type: "string",
+ example: "admin",
+ },
+ sessionKey: {
+ type: "string",
+ example: "bridle:admin",
+ },
+ title: {
+ type: "object",
+ nullable: true,
+ },
+ preview: {
+ type: "object",
+ nullable: true,
+ description: "Last message text, truncated",
+ },
+ lastRole: {
+ type: "string",
+ enum: ["user", "assistant"],
+ nullable: true,
+ },
+ lastMessageAt: {
+ format: "date-time",
+ type: "string",
+ description: "Unix ms via ISO",
+ example: "2026-07-15T09:12:00.000Z",
+ },
+ messageCount: {
+ type: "number",
+ description: "Monotonic lifetime total",
+ },
+ userMessageCount: {
+ type: "number",
+ },
+ summary: {
+ type: "object",
+ nullable: true,
+ },
+ summaryAt: {
+ type: "object",
+ nullable: true,
+ },
+ insights: {
+ type: "object",
+ nullable: true,
+ description: "topics/sentiment/resolved/language",
+ },
+ archived: {
+ type: "boolean",
+ },
+ createdAt: {
+ format: "date-time",
+ type: "string",
+ },
+ updatedAt: {
+ format: "date-time",
+ type: "string",
+ },
+ },
+ required: [
+ "id",
+ "agentId",
+ "channel",
+ "externalUserId",
+ "sessionKey",
+ "lastMessageAt",
+ "messageCount",
+ "userMessageCount",
+ "archived",
+ "createdAt",
+ "updatedAt",
+ ],
+} as const;
+
+export const ChatListResponseDtoSchema = {
+ type: "object",
+ properties: {
+ items: {
+ type: "array",
+ items: {
+ $ref: "#/components/schemas/ChatSessionDto",
+ },
+ },
+ total: {
+ type: "number",
+ example: 128,
+ },
+ page: {
+ type: "number",
+ example: 1,
+ },
+ perPage: {
+ type: "number",
+ example: 50,
+ },
+ },
+ required: ["items", "total", "page", "perPage"],
+} as const;
+
+export const ChatMessageDtoSchema = {
+ type: "object",
+ properties: {
+ id: {
+ type: "string",
+ example: "c94dbcf2-…",
+ },
+ role: {
+ type: "string",
+ enum: [
+ "user",
+ "assistant",
+ "summary",
+ "tool_call",
+ "tool_result",
+ "system",
+ ],
+ example: "assistant",
+ },
+ text: {
+ type: "string",
+ example: "Hello, how can I help?",
+ },
+ ts: {
+ type: "number",
+ example: 1777562539964,
+ description: "Unix epoch ms",
+ },
+ },
+ required: ["id", "role", "text", "ts"],
+} as const;
+
+export const ChatMessagesResponseDtoSchema = {
+ type: "object",
+ properties: {
+ messages: {
+ type: "array",
+ items: {
+ $ref: "#/components/schemas/ChatMessageDto",
+ },
+ },
+ nextCursor: {
+ type: "object",
+ nullable: true,
+ description: "Pass to fetch the previous (older) page",
+ },
+ hasMore: {
+ type: "boolean",
+ },
+ },
+ required: ["messages", "hasMore"],
+} as const;
+
+export const SyncChatsDtoSchema = {
+ type: "object",
+ properties: {
+ agentId: {
+ type: "string",
+ description: "Reconcile only this agent; omit for all agents",
+ },
+ },
+} as const;
+
+export const SyncChatsResponseDtoSchema = {
+ type: "object",
+ properties: {
+ scannedAgents: {
+ type: "number",
+ },
+ scannedFiles: {
+ type: "number",
+ },
+ upserted: {
+ type: "number",
+ },
+ skipped: {
+ type: "number",
+ },
+ },
+ required: ["scannedAgents", "scannedFiles", "upserted", "skipped"],
+} as const;
+
+export const CreateChatFeedbackDtoSchema = {
+ type: "object",
+ properties: {
+ messageId: {
+ type: "string",
+ description: "Event.id of the rated assistant message",
+ },
+ rating: {
+ type: "number",
+ enum: [1, -1],
+ description: "1 = 👍, -1 = 👎",
+ },
+ comment: {
+ type: "string",
+ },
+ },
+ required: ["messageId", "rating"],
+} as const;
+
+export const ChatFeedbackDtoSchema = {
+ type: "object",
+ properties: {
+ id: {
+ type: "string",
+ },
+ messageId: {
+ type: "string",
+ },
+ rating: {
+ type: "number",
+ enum: [1, -1],
+ },
+ comment: {
+ type: "object",
+ nullable: true,
+ },
+ source: {
+ type: "string",
+ example: "admin",
+ },
+ authorId: {
+ type: "object",
+ nullable: true,
+ },
+ createdAt: {
+ format: "date-time",
+ type: "string",
+ },
+ },
+ required: ["id", "messageId", "rating", "source", "createdAt"],
+} as const;
+
export const TelegramChannelConfigDtoSchema = {
type: "object",
properties: {
diff --git a/app/slices/setup/api/data/repositories/api/sdk.gen.ts b/app/slices/setup/api/data/repositories/api/sdk.gen.ts
index dedbb3f..6630182 100644
--- a/app/slices/setup/api/data/repositories/api/sdk.gen.ts
+++ b/app/slices/setup/api/data/repositories/api/sdk.gen.ts
@@ -115,6 +115,38 @@ import type {
SkillControllerFindByIdData,
SkillControllerUpdateData,
FindDependentAgentsData,
+ GetChatsData,
+ GetChatsResponse,
+ GetChatData,
+ GetChatResponse,
+ GetChatMessagesData,
+ GetChatMessagesResponse,
+ SyncChatsData,
+ SyncChatsResponse,
+ SummarizeChatData,
+ SummarizeChatResponse,
+ GetMyChatFeedbackData,
+ GetMyChatFeedbackResponse,
+ CreateChatFeedbackData,
+ CreateChatFeedbackResponse,
+ DeleteChatFeedbackData,
+ DeleteChatFeedbackResponse,
+ ExportChatData,
+ GetMyChatsData,
+ GetMyChatsResponse,
+ GetMyChatData,
+ GetMyChatResponse,
+ GetMyChatMessagesData,
+ GetMyChatMessagesResponse,
+ SyncMyChatsData,
+ SyncMyChatsResponse,
+ ListMyChatFeedbackData,
+ ListMyChatFeedbackResponse,
+ CreateMyChatFeedbackData,
+ CreateMyChatFeedbackResponse,
+ DeleteMyChatFeedbackData,
+ DeleteMyChatFeedbackResponse,
+ ExportMyChatData,
GetAgentChannelsData,
GetAgentChannelsResponse,
SetAgentChannelsData,
@@ -1960,6 +1992,296 @@ export class SkillsService {
}
}
+export class ChatsService {
+ /**
+ * List chat sessions (index). Filter by agent, channel, search; paginated.
+ */
+ public static getChats
(
+ options?: Options,
+ ) {
+ return (options?.client ?? _heyApiClient).get<
+ GetChatsResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats",
+ ...options,
+ });
+ }
+
+ /**
+ * Get one chat session (index metadata).
+ */
+ public static getChat(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ GetChatResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}",
+ ...options,
+ });
+ }
+
+ /**
+ * Replay a chat session's transcript from S3, tail-first. `summary` markers are shown inline (compaction folds old turns into them); synthetic loop-control events are filtered. Admins may add tool_call,tool_result via `types`.
+ */
+ public static getChatMessages(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ GetChatMessagesResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/messages",
+ ...options,
+ });
+ }
+
+ /**
+ * Reconcile the chat index against S3 session files (all agents, or one).
+ */
+ public static syncChats(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).post<
+ SyncChatsResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/sync",
+ ...options,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ },
+ });
+ }
+
+ /**
+ * Generate (or refresh) an LLM summary + insights for one chat, on demand.
+ */
+ public static summarizeChat(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).post<
+ SummarizeChatResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/summarize",
+ ...options,
+ });
+ }
+
+ /**
+ * List the current user’s feedback for a chat session.
+ */
+ public static getMyChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ GetMyChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/feedback",
+ ...options,
+ });
+ }
+
+ /**
+ * Set the current user’s 👍/👎 on an assistant message.
+ */
+ public static createChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).post<
+ CreateChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/feedback",
+ ...options,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ },
+ });
+ }
+
+ /**
+ * Clear the current user’s feedback on a message (toggle-off).
+ */
+ public static deleteChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).delete<
+ DeleteChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/feedback/{messageId}",
+ ...options,
+ });
+ }
+
+ /**
+ * Download a chat transcript as json / markdown / csv.
+ */
+ public static exportChat(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ unknown,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/chats/{id}/export",
+ ...options,
+ });
+ }
+
+ /**
+ * List the current user's own chat sessions, newest first.
+ */
+ public static getMyChats(
+ options?: Options,
+ ) {
+ return (options?.client ?? _heyApiClient).get<
+ GetMyChatsResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats",
+ ...options,
+ });
+ }
+
+ /**
+ * Get one of the current user's own chat sessions.
+ */
+ public static getMyChat(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ GetMyChatResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}",
+ ...options,
+ });
+ }
+
+ /**
+ * Replay one of the current user's own chats, tail-first. `summary` markers are shown inline; tool events are never exposed to end users.
+ */
+ public static getMyChatMessages(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ GetMyChatMessagesResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}/messages",
+ ...options,
+ });
+ }
+
+ /**
+ * Reconcile the current user's OWN chats from S3 into the index (self-service, non-admin). Only sessions belonging to the caller are touched. A manual fallback when realtime indexing has not caught up.
+ */
+ public static syncMyChats(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).post<
+ SyncMyChatsResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/sync",
+ ...options,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ },
+ });
+ }
+
+ /**
+ * List the current user's own feedback for one of their chats.
+ */
+ public static listMyChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ ListMyChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}/feedback",
+ ...options,
+ });
+ }
+
+ /**
+ * Set the current user's 👍/👎 on a message in their own chat.
+ */
+ public static createMyChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).post<
+ CreateMyChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}/feedback",
+ ...options,
+ headers: {
+ "Content-Type": "application/json",
+ ...options?.headers,
+ },
+ });
+ }
+
+ /**
+ * Clear the current user's feedback on a message (toggle-off).
+ */
+ public static deleteMyChatFeedback(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).delete<
+ DeleteMyChatFeedbackResponse,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}/feedback/{messageId}",
+ ...options,
+ });
+ }
+
+ /**
+ * Download the current user's own chat as json / markdown / csv.
+ */
+ public static exportMyChat(
+ options: Options,
+ ) {
+ return (options.client ?? _heyApiClient).get<
+ unknown,
+ unknown,
+ ThrowOnError
+ >({
+ url: "/me/chats/{id}/export",
+ ...options,
+ });
+ }
+}
+
export class UsersService {
/**
* List all users
diff --git a/app/slices/setup/api/data/repositories/api/types.gen.ts b/app/slices/setup/api/data/repositories/api/types.gen.ts
index 12b0b7a..e4d193e 100644
--- a/app/slices/setup/api/data/repositories/api/types.gen.ts
+++ b/app/slices/setup/api/data/repositories/api/types.gen.ts
@@ -572,6 +572,122 @@ export type UpdateSkillDto = {
description?: string;
};
+export type ChatSessionDto = {
+ id: string;
+ agentId: string;
+ channel: "bridle" | "telegram" | "slack" | "internal";
+ externalUserId: string;
+ sessionKey: string;
+ title?: {
+ [key: string]: unknown;
+ } | null;
+ /**
+ * Last message text, truncated
+ */
+ preview?: {
+ [key: string]: unknown;
+ } | null;
+ lastRole?: "user" | "assistant";
+ /**
+ * Unix ms via ISO
+ */
+ lastMessageAt: string;
+ /**
+ * Monotonic lifetime total
+ */
+ messageCount: number;
+ userMessageCount: number;
+ summary?: {
+ [key: string]: unknown;
+ } | null;
+ summaryAt?: {
+ [key: string]: unknown;
+ } | null;
+ /**
+ * topics/sentiment/resolved/language
+ */
+ insights?: {
+ [key: string]: unknown;
+ } | null;
+ archived: boolean;
+ createdAt: string;
+ updatedAt: string;
+};
+
+export type ChatListResponseDto = {
+ items: Array;
+ total: number;
+ page: number;
+ perPage: number;
+};
+
+export type ChatMessageDto = {
+ id: string;
+ role:
+ | "user"
+ | "assistant"
+ | "summary"
+ | "tool_call"
+ | "tool_result"
+ | "system";
+ text: string;
+ /**
+ * Unix epoch ms
+ */
+ ts: number;
+};
+
+export type ChatMessagesResponseDto = {
+ messages: Array;
+ /**
+ * Pass to fetch the previous (older) page
+ */
+ nextCursor?: {
+ [key: string]: unknown;
+ } | null;
+ hasMore: boolean;
+};
+
+export type SyncChatsDto = {
+ /**
+ * Reconcile only this agent; omit for all agents
+ */
+ agentId?: string;
+};
+
+export type SyncChatsResponseDto = {
+ scannedAgents: number;
+ scannedFiles: number;
+ upserted: number;
+ skipped: number;
+};
+
+export type CreateChatFeedbackDto = {
+ /**
+ * Event.id of the rated assistant message
+ */
+ messageId: string;
+ /**
+ * 1 = 👍, -1 = 👎
+ */
+ rating: 1 | -1;
+ comment?: string;
+};
+
+export type ChatFeedbackDto = {
+ id: string;
+ messageId: string;
+ rating: 1 | -1;
+ comment?: {
+ [key: string]: unknown;
+ } | null;
+ source: string;
+ authorId?: {
+ [key: string]: unknown;
+ } | null;
+ createdAt: string;
+};
+
export type TelegramChannelConfigDto = {
/**
* Telegram bot HTTP API token (issued by @BotFather).
@@ -2393,6 +2509,318 @@ export type FindDependentAgentsResponses = {
200: unknown;
};
+export type GetChatsData = {
+ body?: never;
+ path?: never;
+ query?: {
+ /**
+ * Restrict to one agent
+ */
+ agentId?: string;
+ channel?: "bridle" | "telegram" | "slack" | "internal";
+ /**
+ * Matches title / preview / externalUserId
+ */
+ search?: string;
+ /**
+ * Show archived sessions
+ */
+ archived?: boolean;
+ /**
+ * Include internal (cron/heartbeat) sessions
+ */
+ includeInternal?: boolean;
+ page?: number;
+ perPage?: number;
+ };
+ url: "/chats";
+};
+
+export type GetChatsResponses = {
+ 200: ChatListResponseDto;
+};
+
+export type GetChatsResponse = GetChatsResponses[keyof GetChatsResponses];
+
+export type GetChatData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/chats/{id}";
+};
+
+export type GetChatResponses = {
+ 200: ChatSessionDto;
+};
+
+export type GetChatResponse = GetChatResponses[keyof GetChatResponses];
+
+export type GetChatMessagesData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: {
+ limit?: number;
+ /**
+ * Opaque cursor from a previous page
+ */
+ cursor?: string;
+ /**
+ * Comma-separated event types (debug toggle). Default user,assistant,summary. Admins may add tool_call,tool_result,system.
+ */
+ types?: string;
+ };
+ url: "/chats/{id}/messages";
+};
+
+export type GetChatMessagesResponses = {
+ 200: ChatMessagesResponseDto;
+};
+
+export type GetChatMessagesResponse =
+ GetChatMessagesResponses[keyof GetChatMessagesResponses];
+
+export type SyncChatsData = {
+ body: SyncChatsDto;
+ path?: never;
+ query?: never;
+ url: "/chats/sync";
+};
+
+export type SyncChatsResponses = {
+ 200: SyncChatsResponseDto;
+};
+
+export type SyncChatsResponse = SyncChatsResponses[keyof SyncChatsResponses];
+
+export type SummarizeChatData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/chats/{id}/summarize";
+};
+
+export type SummarizeChatResponses = {
+ 200: ChatSessionDto;
+};
+
+export type SummarizeChatResponse =
+ SummarizeChatResponses[keyof SummarizeChatResponses];
+
+export type GetMyChatFeedbackData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/chats/{id}/feedback";
+};
+
+export type GetMyChatFeedbackResponses = {
+ 200: Array;
+};
+
+export type GetMyChatFeedbackResponse =
+ GetMyChatFeedbackResponses[keyof GetMyChatFeedbackResponses];
+
+export type CreateChatFeedbackData = {
+ body: CreateChatFeedbackDto;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/chats/{id}/feedback";
+};
+
+export type CreateChatFeedbackResponses = {
+ 200: ChatFeedbackDto;
+};
+
+export type CreateChatFeedbackResponse =
+ CreateChatFeedbackResponses[keyof CreateChatFeedbackResponses];
+
+export type DeleteChatFeedbackData = {
+ body?: never;
+ path: {
+ id: string;
+ messageId: string;
+ };
+ query?: never;
+ url: "/chats/{id}/feedback/{messageId}";
+};
+
+export type DeleteChatFeedbackResponses = {
+ 204: void;
+};
+
+export type DeleteChatFeedbackResponse =
+ DeleteChatFeedbackResponses[keyof DeleteChatFeedbackResponses];
+
+export type ExportChatData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: {
+ /**
+ * Download format. json = raw messages, markdown/csv = transcript.
+ */
+ format?: "json" | "markdown" | "csv";
+ };
+ url: "/chats/{id}/export";
+};
+
+export type ExportChatResponses = {
+ 200: unknown;
+};
+
+export type GetMyChatsData = {
+ body?: never;
+ path?: never;
+ query?: {
+ /**
+ * Include archived chats
+ */
+ archived?: boolean;
+ page?: number;
+ perPage?: number;
+ };
+ url: "/me/chats";
+};
+
+export type GetMyChatsResponses = {
+ 200: ChatListResponseDto;
+};
+
+export type GetMyChatsResponse = GetMyChatsResponses[keyof GetMyChatsResponses];
+
+export type GetMyChatData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/me/chats/{id}";
+};
+
+export type GetMyChatResponses = {
+ 200: ChatSessionDto;
+};
+
+export type GetMyChatResponse = GetMyChatResponses[keyof GetMyChatResponses];
+
+export type GetMyChatMessagesData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: {
+ limit?: number;
+ /**
+ * Opaque cursor from a previous page
+ */
+ cursor?: string;
+ /**
+ * Comma-separated event types (debug toggle). Default user,assistant,summary. Admins may add tool_call,tool_result,system.
+ */
+ types?: string;
+ };
+ url: "/me/chats/{id}/messages";
+};
+
+export type GetMyChatMessagesResponses = {
+ 200: ChatMessagesResponseDto;
+};
+
+export type GetMyChatMessagesResponse =
+ GetMyChatMessagesResponses[keyof GetMyChatMessagesResponses];
+
+export type SyncMyChatsData = {
+ body: SyncChatsDto;
+ path?: never;
+ query?: never;
+ url: "/me/chats/sync";
+};
+
+export type SyncMyChatsResponses = {
+ 200: SyncChatsResponseDto;
+};
+
+export type SyncMyChatsResponse =
+ SyncMyChatsResponses[keyof SyncMyChatsResponses];
+
+export type ListMyChatFeedbackData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/me/chats/{id}/feedback";
+};
+
+export type ListMyChatFeedbackResponses = {
+ 200: Array;
+};
+
+export type ListMyChatFeedbackResponse =
+ ListMyChatFeedbackResponses[keyof ListMyChatFeedbackResponses];
+
+export type CreateMyChatFeedbackData = {
+ body: CreateChatFeedbackDto;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: "/me/chats/{id}/feedback";
+};
+
+export type CreateMyChatFeedbackResponses = {
+ 200: ChatFeedbackDto;
+};
+
+export type CreateMyChatFeedbackResponse =
+ CreateMyChatFeedbackResponses[keyof CreateMyChatFeedbackResponses];
+
+export type DeleteMyChatFeedbackData = {
+ body?: never;
+ path: {
+ id: string;
+ messageId: string;
+ };
+ query?: never;
+ url: "/me/chats/{id}/feedback/{messageId}";
+};
+
+export type DeleteMyChatFeedbackResponses = {
+ 204: void;
+};
+
+export type DeleteMyChatFeedbackResponse =
+ DeleteMyChatFeedbackResponses[keyof DeleteMyChatFeedbackResponses];
+
+export type ExportMyChatData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: {
+ /**
+ * Download format. json = raw messages, markdown/csv = transcript.
+ */
+ format?: "json" | "markdown" | "csv";
+ };
+ url: "/me/chats/{id}/export";
+};
+
+export type ExportMyChatResponses = {
+ 200: unknown;
+};
+
export type GetAgentChannelsData = {
body?: never;
path: {
diff --git a/app/slices/setup/theme/assets/css/tailwind.css b/app/slices/setup/theme/assets/css/tailwind.css
index a364b31..3f9dd39 100644
--- a/app/slices/setup/theme/assets/css/tailwind.css
+++ b/app/slices/setup/theme/assets/css/tailwind.css
@@ -3,6 +3,13 @@
@custom-variant dark (&:is(.dark *));
+@layer base {
+ button:not(:disabled),
+ [role="button"]:not(:disabled) {
+ cursor: pointer;
+ }
+}
+
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
diff --git a/app/slices/setup/theme/components/badge/Badge.vue b/app/slices/setup/theme/components/badge/Badge.vue
new file mode 100644
index 0000000..ba4cc9b
--- /dev/null
+++ b/app/slices/setup/theme/components/badge/Badge.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
diff --git a/app/slices/setup/theme/components/badge/index.ts b/app/slices/setup/theme/components/badge/index.ts
new file mode 100644
index 0000000..0cc92cc
--- /dev/null
+++ b/app/slices/setup/theme/components/badge/index.ts
@@ -0,0 +1,24 @@
+import type { VariantProps } from "class-variance-authority"
+import { cva } from "class-variance-authority"
+
+export const badgeVariants = cva(
+ "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
+ secondary:
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
+ destructive:
+ "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
+ outline:
+ "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ },
+)
+export type BadgeVariants = VariantProps
diff --git a/app/slices/user/auth/middleware/auth.global.ts b/app/slices/user/auth/middleware/auth.global.ts
index 6517a2a..5b99a74 100644
--- a/app/slices/user/auth/middleware/auth.global.ts
+++ b/app/slices/user/auth/middleware/auth.global.ts
@@ -4,10 +4,10 @@
* - /login self
* - /register self (gated by setting on the server side)
*
- * Anything under /agents/** requires login. The auth plugin awaits init()
- * before navigation kicks in, so isHydrated is always true when this runs.
+ * Anything under /agents/** or /chats/** requires login. The auth plugin awaits
+ * init() before navigation kicks in, so isHydrated is always true when this runs.
*/
-const PROTECTED_PREFIXES = ['/agents'];
+const PROTECTED_PREFIXES = ['/agents', '/chats'];
const AUTH_PAGES = new Set(['/login', '/register']);
export default defineNuxtRouteMiddleware((to) => {
diff --git a/k8s/deploy/30-api.yaml b/k8s/deploy/30-api.yaml
index 076ff70..9a5347f 100644
--- a/k8s/deploy/30-api.yaml
+++ b/k8s/deploy/30-api.yaml
@@ -86,6 +86,11 @@ spec:
value: /usr/src/app/rancher/.agent
- name: RANCHER_PADDOCK_DIR
value: /usr/src/app/rancher/.paddock/scenarios
+ # Chat insight cron-batch: LLM-summarize settled chats every N seconds
+ # (unset / <= 0 disables it; on-demand POST /chats/:id/summarize still
+ # works either way — see ChatInsightService).
+ - name: CHAT_INSIGHT_INTERVAL_SEC
+ value: "900"
# Browser-pool — shared headless Chromium for runtime tools.
# Internal URL is reached over the in-cluster Service; public URL
# is the user-facing host for VNC live views during 2FA logins.
diff --git a/k8s/platform/api/deployment.yaml b/k8s/platform/api/deployment.yaml
index c5c740c..26dca02 100644
--- a/k8s/platform/api/deployment.yaml
+++ b/k8s/platform/api/deployment.yaml
@@ -45,6 +45,11 @@ spec:
value: /usr/src/app/rancher/.agent
- name: RANCHER_PADDOCK_DIR
value: /usr/src/app/rancher/.paddock/scenarios
+ # Chat insight cron-batch: LLM-summarize settled chats every N seconds
+ # (unset / <= 0 disables it; on-demand POST /chats/:id/summarize still
+ # works either way — see ChatInsightService).
+ - name: CHAT_INSIGHT_INTERVAL_SEC
+ value: "900"
volumeMounts:
- name: paddock-work
mountPath: /usr/src/app/runtime/.paddock