@open-mercato/ai-assistant 0.6.2-develop.3461.1.605f31c2c9 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +2 -2
- package/dist/modules/ai_assistant/acl.js +1 -0
- package/dist/modules/ai_assistant/acl.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js +197 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/conversations/[conversationId]/route.js +272 -0
- package/dist/modules/ai_assistant/api/ai/conversations/[conversationId]/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/conversations/import/route.js +108 -0
- package/dist/modules/ai_assistant/api/ai/conversations/import/route.js.map +7 -0
- package/dist/modules/ai_assistant/api/ai/conversations/route.js +207 -0
- package/dist/modules/ai_assistant/api/ai/conversations/route.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiChatConversation.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiChatConversation.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiChatConversationParticipant.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiChatConversationParticipant.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities/AiChatMessage.js +5 -0
- package/dist/modules/ai_assistant/data/entities/AiChatMessage.js.map +7 -0
- package/dist/modules/ai_assistant/data/entities.js +200 -0
- package/dist/modules/ai_assistant/data/entities.js.map +2 -2
- package/dist/modules/ai_assistant/data/repositories/AiChatConversationRepository.js +448 -0
- package/dist/modules/ai_assistant/data/repositories/AiChatConversationRepository.js.map +7 -0
- package/dist/modules/ai_assistant/data/validators.js +72 -0
- package/dist/modules/ai_assistant/data/validators.js.map +7 -0
- package/dist/modules/ai_assistant/i18n/de.json +3 -0
- package/dist/modules/ai_assistant/i18n/en.json +3 -0
- package/dist/modules/ai_assistant/i18n/es.json +3 -0
- package/dist/modules/ai_assistant/i18n/pl.json +3 -0
- package/dist/modules/ai_assistant/lib/conversation-storage.js +43 -0
- package/dist/modules/ai_assistant/lib/conversation-storage.js.map +7 -0
- package/dist/modules/ai_assistant/migrations/Migration20260518092853_ai_assistant.js +28 -0
- package/dist/modules/ai_assistant/migrations/Migration20260518092853_ai_assistant.js.map +7 -0
- package/dist/modules/ai_assistant/setup.js +1 -0
- package/dist/modules/ai_assistant/setup.js.map +2 -2
- package/generated/entities/ai_chat_conversation/index.ts +15 -0
- package/generated/entities/ai_chat_conversation_participant/index.ts +9 -0
- package/generated/entities/ai_chat_message/index.ts +16 -0
- package/generated/entities.ids.generated.ts +4 -1
- package/generated/entity-fields-registry.ts +46 -0
- package/jest.config.cjs +3 -1
- package/package.json +14 -15
- package/src/modules/ai_assistant/acl.ts +1 -0
- package/src/modules/ai_assistant/api/ai/chat/__tests__/route.test.ts +107 -0
- package/src/modules/ai_assistant/api/ai/chat/route.ts +245 -1
- package/src/modules/ai_assistant/api/ai/conversations/[conversationId]/route.ts +320 -0
- package/src/modules/ai_assistant/api/ai/conversations/__tests__/route.test.ts +93 -0
- package/src/modules/ai_assistant/api/ai/conversations/import/route.ts +122 -0
- package/src/modules/ai_assistant/api/ai/conversations/route.ts +241 -0
- package/src/modules/ai_assistant/data/entities/AiChatConversation.ts +2 -0
- package/src/modules/ai_assistant/data/entities/AiChatConversationParticipant.ts +2 -0
- package/src/modules/ai_assistant/data/entities/AiChatMessage.ts +2 -0
- package/src/modules/ai_assistant/data/entities.ts +255 -0
- package/src/modules/ai_assistant/data/repositories/AiChatConversationRepository.ts +597 -0
- package/src/modules/ai_assistant/data/repositories/__tests__/AiChatConversationRepository.test.ts +592 -0
- package/src/modules/ai_assistant/data/validators.ts +134 -0
- package/src/modules/ai_assistant/i18n/de.json +3 -0
- package/src/modules/ai_assistant/i18n/en.json +3 -0
- package/src/modules/ai_assistant/i18n/es.json +3 -0
- package/src/modules/ai_assistant/i18n/pl.json +3 -0
- package/src/modules/ai_assistant/lib/conversation-storage.ts +93 -0
- package/src/modules/ai_assistant/migrations/.snapshot-open-mercato.json +822 -0
- package/src/modules/ai_assistant/migrations/Migration20260518092853_ai_assistant.ts +39 -0
- package/src/modules/ai_assistant/setup.ts +1 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod validators for the server-side AI chat conversation APIs.
|
|
5
|
+
*
|
|
6
|
+
* Spec: `2026-05-05-ai-chat-server-side-conversation-storage`. Used by the
|
|
7
|
+
* REST routes under `api/ai/conversations/...` and by the repository to keep
|
|
8
|
+
* input shapes aligned with the database constraints declared in
|
|
9
|
+
* `data/entities.ts`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Page-context snapshot persisted on a conversation row. */
|
|
13
|
+
export const aiChatPageContextSchema = z
|
|
14
|
+
.object({
|
|
15
|
+
pageId: z.string().min(1).max(256).optional(),
|
|
16
|
+
entityType: z.string().min(1).max(256).optional(),
|
|
17
|
+
recordId: z.string().min(1).max(256).optional(),
|
|
18
|
+
})
|
|
19
|
+
.passthrough()
|
|
20
|
+
|
|
21
|
+
export type AiChatPageContextInput = z.infer<typeof aiChatPageContextSchema>
|
|
22
|
+
|
|
23
|
+
const aiAgentIdSchema = z
|
|
24
|
+
.string()
|
|
25
|
+
.trim()
|
|
26
|
+
.min(1, 'agentId must be a non-empty string')
|
|
27
|
+
.max(256, 'agentId exceeds the maximum length of 256 characters')
|
|
28
|
+
|
|
29
|
+
const conversationIdSchema = z
|
|
30
|
+
.string()
|
|
31
|
+
.trim()
|
|
32
|
+
.min(1, 'conversationId must be a non-empty string')
|
|
33
|
+
.max(128, 'conversationId exceeds the maximum length of 128 characters')
|
|
34
|
+
|
|
35
|
+
const titleSchema = z.string().trim().min(1).max(200)
|
|
36
|
+
|
|
37
|
+
/** `POST /api/ai_assistant/ai/conversations` */
|
|
38
|
+
export const aiChatConversationCreateSchema = z.object({
|
|
39
|
+
agentId: aiAgentIdSchema,
|
|
40
|
+
conversationId: conversationIdSchema.optional(),
|
|
41
|
+
title: titleSchema.optional(),
|
|
42
|
+
pageContext: aiChatPageContextSchema.nullable().optional(),
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
export type AiChatConversationCreateInput = z.infer<typeof aiChatConversationCreateSchema>
|
|
46
|
+
|
|
47
|
+
/** `GET /api/ai_assistant/ai/conversations?agent=&status=&limit=&cursor=` */
|
|
48
|
+
export const aiChatConversationListQuerySchema = z.object({
|
|
49
|
+
agent: aiAgentIdSchema.optional(),
|
|
50
|
+
status: z.enum(['open', 'closed']).optional(),
|
|
51
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
52
|
+
cursor: z.string().trim().min(1).max(200).optional(),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
export type AiChatConversationListQuery = z.infer<typeof aiChatConversationListQuerySchema>
|
|
56
|
+
|
|
57
|
+
/** `PATCH /api/ai_assistant/ai/conversations/:conversationId` */
|
|
58
|
+
export const aiChatConversationUpdateSchema = z
|
|
59
|
+
.object({
|
|
60
|
+
title: titleSchema.nullable().optional(),
|
|
61
|
+
status: z.enum(['open', 'closed']).optional(),
|
|
62
|
+
pageContext: aiChatPageContextSchema.nullable().optional(),
|
|
63
|
+
})
|
|
64
|
+
.refine(
|
|
65
|
+
(value) =>
|
|
66
|
+
typeof value.title !== 'undefined' ||
|
|
67
|
+
typeof value.status !== 'undefined' ||
|
|
68
|
+
typeof value.pageContext !== 'undefined',
|
|
69
|
+
{ message: 'At least one of title, status, or pageContext is required.' },
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
export type AiChatConversationUpdateInput = z.infer<typeof aiChatConversationUpdateSchema>
|
|
73
|
+
|
|
74
|
+
const messageRoleSchema = z.enum(['user', 'assistant', 'system'])
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Shared message-body shape. `clientMessageId` is the idempotency key for
|
|
78
|
+
* retries and lazy imports; `content` is capped to keep transcript rows
|
|
79
|
+
* bounded; `uiParts` / `attachmentIds` / `files` accept the serializable
|
|
80
|
+
* subset the chat UI already produces. Attachment previews (`data:` URLs
|
|
81
|
+
* and transient blob URLs) MUST NOT pass through here — the UI strips them
|
|
82
|
+
* before upload.
|
|
83
|
+
*/
|
|
84
|
+
const messageBaseSchema = z.object({
|
|
85
|
+
clientMessageId: z.string().trim().min(1).max(128).optional(),
|
|
86
|
+
role: messageRoleSchema,
|
|
87
|
+
content: z.string().max(64_000),
|
|
88
|
+
uiParts: z.array(z.unknown()).max(64).optional(),
|
|
89
|
+
attachmentIds: z.array(z.string().trim().min(1).max(128)).max(32).optional(),
|
|
90
|
+
files: z
|
|
91
|
+
.array(
|
|
92
|
+
z
|
|
93
|
+
.object({
|
|
94
|
+
id: z.string().trim().min(1).max(128).optional(),
|
|
95
|
+
name: z.string().trim().min(1).max(256).optional(),
|
|
96
|
+
mimeType: z.string().trim().min(1).max(128).optional(),
|
|
97
|
+
size: z.number().int().nonnegative().optional(),
|
|
98
|
+
})
|
|
99
|
+
.passthrough(),
|
|
100
|
+
)
|
|
101
|
+
.max(32)
|
|
102
|
+
.optional(),
|
|
103
|
+
model: z.string().trim().min(1).max(128).optional(),
|
|
104
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
/** `POST /api/ai_assistant/ai/conversations/import` */
|
|
108
|
+
export const aiChatConversationImportSchema = z.object({
|
|
109
|
+
conversation: z.object({
|
|
110
|
+
conversationId: conversationIdSchema,
|
|
111
|
+
agentId: aiAgentIdSchema,
|
|
112
|
+
title: titleSchema.optional(),
|
|
113
|
+
status: z.enum(['open', 'closed']).optional(),
|
|
114
|
+
pageContext: aiChatPageContextSchema.nullable().optional(),
|
|
115
|
+
}),
|
|
116
|
+
messages: z.array(messageBaseSchema).max(100),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
export type AiChatConversationImportInput = z.infer<typeof aiChatConversationImportSchema>
|
|
120
|
+
|
|
121
|
+
/** Transcript GET query: `?limit=&before=` */
|
|
122
|
+
export const aiChatConversationTranscriptQuerySchema = z.object({
|
|
123
|
+
limit: z.coerce.number().int().min(1).max(200).optional(),
|
|
124
|
+
before: z.string().trim().min(1).max(200).optional(),
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
export type AiChatConversationTranscriptQuery = z.infer<
|
|
128
|
+
typeof aiChatConversationTranscriptQuerySchema
|
|
129
|
+
>
|
|
130
|
+
|
|
131
|
+
/** Internal payload accepted by the repository when appending a single message. */
|
|
132
|
+
export const aiChatMessageAppendSchema = messageBaseSchema
|
|
133
|
+
|
|
134
|
+
export type AiChatMessageAppendInput = z.infer<typeof aiChatMessageAppendSchema>
|
|
@@ -176,6 +176,7 @@
|
|
|
176
176
|
"ai_assistant.chat.dock.close": "KI-Dock schließen",
|
|
177
177
|
"ai_assistant.chat.dock.collapse": "KI-Dock einklappen",
|
|
178
178
|
"ai_assistant.chat.dock.expand": "KI-Dock erweitern",
|
|
179
|
+
"ai_assistant.chat.downloadFile": "{name} herunterladen",
|
|
179
180
|
"ai_assistant.chat.emptyTranscript": "Noch keine Nachrichten. Stellen Sie dem Agenten eine Frage, um zu beginnen.",
|
|
180
181
|
"ai_assistant.chat.errorTitle": "Agenten-Anfrage fehlgeschlagen",
|
|
181
182
|
"ai_assistant.chat.example.create": "Ein neues Produkt erstellen",
|
|
@@ -183,6 +184,7 @@
|
|
|
183
184
|
"ai_assistant.chat.example.show": "Aktuelle Bestellungen anzeigen",
|
|
184
185
|
"ai_assistant.chat.idleExamples": "Beispiele:",
|
|
185
186
|
"ai_assistant.chat.idleTitle": "Stellen Sie eine Frage oder beschreiben Sie, was Sie tun möchten.",
|
|
187
|
+
"ai_assistant.chat.imagePreviewDialogDescription": "Bildvorschau",
|
|
186
188
|
"ai_assistant.chat.mutation_cards.confirmation.cancel": "Abbrechen",
|
|
187
189
|
"ai_assistant.chat.mutation_cards.confirmation.defaultSummary": "Die angeforderten Änderungen werden ausgeführt...",
|
|
188
190
|
"ai_assistant.chat.mutation_cards.confirmation.errorTitle": "Bestätigung fehlgeschlagen",
|
|
@@ -273,6 +275,7 @@
|
|
|
273
275
|
"ai_assistant.chat.uiPartPending": "Ausstehendes UI-Element:",
|
|
274
276
|
"ai_assistant.chat.userRoleLabel": "Sie",
|
|
275
277
|
"ai_assistant.chat.welcomeTitle": "How can I help?",
|
|
278
|
+
"ai_assistant.chat.zoomImage": "Vorschau von {name} öffnen",
|
|
276
279
|
"ai_assistant.dock.bottom": "Unten andocken",
|
|
277
280
|
"ai_assistant.dock.close": "Schließen",
|
|
278
281
|
"ai_assistant.dock.floating": "Schwebend",
|
|
@@ -176,6 +176,7 @@
|
|
|
176
176
|
"ai_assistant.chat.dock.close": "Close AI dock",
|
|
177
177
|
"ai_assistant.chat.dock.collapse": "Collapse AI dock",
|
|
178
178
|
"ai_assistant.chat.dock.expand": "Expand AI dock",
|
|
179
|
+
"ai_assistant.chat.downloadFile": "Download {name}",
|
|
179
180
|
"ai_assistant.chat.emptyTranscript": "No messages yet. Ask the agent anything to get started.",
|
|
180
181
|
"ai_assistant.chat.errorTitle": "Agent dispatch failed",
|
|
181
182
|
"ai_assistant.chat.example.create": "Create a new product",
|
|
@@ -183,6 +184,7 @@
|
|
|
183
184
|
"ai_assistant.chat.example.show": "Show me recent orders",
|
|
184
185
|
"ai_assistant.chat.idleExamples": "Examples:",
|
|
185
186
|
"ai_assistant.chat.idleTitle": "Ask me anything or describe what you want to do.",
|
|
187
|
+
"ai_assistant.chat.imagePreviewDialogDescription": "Image preview",
|
|
186
188
|
"ai_assistant.chat.mutation_cards.confirmation.cancel": "Cancel",
|
|
187
189
|
"ai_assistant.chat.mutation_cards.confirmation.defaultSummary": "Applying the requested changes...",
|
|
188
190
|
"ai_assistant.chat.mutation_cards.confirmation.errorTitle": "Confirm failed",
|
|
@@ -273,6 +275,7 @@
|
|
|
273
275
|
"ai_assistant.chat.uiPartPending": "Pending UI part:",
|
|
274
276
|
"ai_assistant.chat.userRoleLabel": "You",
|
|
275
277
|
"ai_assistant.chat.welcomeTitle": "How can I help?",
|
|
278
|
+
"ai_assistant.chat.zoomImage": "Open {name} preview",
|
|
276
279
|
"ai_assistant.dock.bottom": "Dock Bottom",
|
|
277
280
|
"ai_assistant.dock.close": "Close",
|
|
278
281
|
"ai_assistant.dock.floating": "Floating",
|
|
@@ -176,6 +176,7 @@
|
|
|
176
176
|
"ai_assistant.chat.dock.close": "Cerrar el panel de IA",
|
|
177
177
|
"ai_assistant.chat.dock.collapse": "Contraer el panel de IA",
|
|
178
178
|
"ai_assistant.chat.dock.expand": "Ampliar el panel de IA",
|
|
179
|
+
"ai_assistant.chat.downloadFile": "Descargar {name}",
|
|
179
180
|
"ai_assistant.chat.emptyTranscript": "Aún no hay mensajes. Pregúntele al agente cualquier cosa para empezar.",
|
|
180
181
|
"ai_assistant.chat.errorTitle": "Error al enviar la solicitud al agente",
|
|
181
182
|
"ai_assistant.chat.example.create": "Crear un producto nuevo",
|
|
@@ -183,6 +184,7 @@
|
|
|
183
184
|
"ai_assistant.chat.example.show": "Mostrar pedidos recientes",
|
|
184
185
|
"ai_assistant.chat.idleExamples": "Ejemplos:",
|
|
185
186
|
"ai_assistant.chat.idleTitle": "Pregunte lo que necesite o describa lo que desea hacer.",
|
|
187
|
+
"ai_assistant.chat.imagePreviewDialogDescription": "Vista previa de imagen",
|
|
186
188
|
"ai_assistant.chat.mutation_cards.confirmation.cancel": "Cancelar",
|
|
187
189
|
"ai_assistant.chat.mutation_cards.confirmation.defaultSummary": "Aplicando los cambios solicitados...",
|
|
188
190
|
"ai_assistant.chat.mutation_cards.confirmation.errorTitle": "La confirmación falló",
|
|
@@ -273,6 +275,7 @@
|
|
|
273
275
|
"ai_assistant.chat.uiPartPending": "Parte de UI pendiente:",
|
|
274
276
|
"ai_assistant.chat.userRoleLabel": "Usted",
|
|
275
277
|
"ai_assistant.chat.welcomeTitle": "How can I help?",
|
|
278
|
+
"ai_assistant.chat.zoomImage": "Abrir vista previa de {name}",
|
|
276
279
|
"ai_assistant.dock.bottom": "Anclar abajo",
|
|
277
280
|
"ai_assistant.dock.close": "Cerrar",
|
|
278
281
|
"ai_assistant.dock.floating": "Flotante",
|
|
@@ -176,6 +176,7 @@
|
|
|
176
176
|
"ai_assistant.chat.dock.close": "Zamknij panel AI",
|
|
177
177
|
"ai_assistant.chat.dock.collapse": "Zwiń panel AI",
|
|
178
178
|
"ai_assistant.chat.dock.expand": "Rozwiń panel AI",
|
|
179
|
+
"ai_assistant.chat.downloadFile": "Pobierz {name}",
|
|
179
180
|
"ai_assistant.chat.emptyTranscript": "Brak wiadomości. Zadaj agentowi dowolne pytanie, aby rozpocząć.",
|
|
180
181
|
"ai_assistant.chat.errorTitle": "Nie udało się wysłać żądania do agenta",
|
|
181
182
|
"ai_assistant.chat.example.create": "Utwórz nowy produkt",
|
|
@@ -183,6 +184,7 @@
|
|
|
183
184
|
"ai_assistant.chat.example.show": "Pokaż ostatnie zamówienia",
|
|
184
185
|
"ai_assistant.chat.idleExamples": "Przykłady:",
|
|
185
186
|
"ai_assistant.chat.idleTitle": "Zapytaj mnie o cokolwiek lub opisz, co chcesz zrobić.",
|
|
187
|
+
"ai_assistant.chat.imagePreviewDialogDescription": "Podgląd obrazu",
|
|
186
188
|
"ai_assistant.chat.mutation_cards.confirmation.cancel": "Anuluj",
|
|
187
189
|
"ai_assistant.chat.mutation_cards.confirmation.defaultSummary": "Wdrażanie żądanych zmian...",
|
|
188
190
|
"ai_assistant.chat.mutation_cards.confirmation.errorTitle": "Potwierdzenie nie powiodło się",
|
|
@@ -273,6 +275,7 @@
|
|
|
273
275
|
"ai_assistant.chat.uiPartPending": "Oczekująca część UI:",
|
|
274
276
|
"ai_assistant.chat.userRoleLabel": "Ty",
|
|
275
277
|
"ai_assistant.chat.welcomeTitle": "How can I help?",
|
|
278
|
+
"ai_assistant.chat.zoomImage": "Otwórz podgląd {name}",
|
|
276
279
|
"ai_assistant.dock.bottom": "Dokuj na dole",
|
|
277
280
|
"ai_assistant.dock.close": "Zamknij",
|
|
278
281
|
"ai_assistant.dock.floating": "Pływające",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import type { AwilixContainer } from 'awilix'
|
|
3
|
+
import {
|
|
4
|
+
AiChatConversation,
|
|
5
|
+
AiChatMessage,
|
|
6
|
+
} from '../data/entities'
|
|
7
|
+
import {
|
|
8
|
+
AiChatConversationAccessError,
|
|
9
|
+
AiChatConversationRepository,
|
|
10
|
+
type AiChatConversationContext,
|
|
11
|
+
} from '../data/repositories/AiChatConversationRepository'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Thin service-layer wrapper that resolves the entity manager from the
|
|
15
|
+
* Awilix container and exposes a typed API on top of
|
|
16
|
+
* `AiChatConversationRepository`. The REST routes for the conversation APIs
|
|
17
|
+
* call into this surface; the future chat dispatcher write path will reuse
|
|
18
|
+
* the same helpers so persistence stays consistent across entry points.
|
|
19
|
+
*
|
|
20
|
+
* Spec: `2026-05-05-ai-chat-server-side-conversation-storage` §"Commands".
|
|
21
|
+
*
|
|
22
|
+
* Re-exports the access error so route handlers can map it to a 404 without
|
|
23
|
+
* importing the repository directly.
|
|
24
|
+
*/
|
|
25
|
+
export { AiChatConversationAccessError }
|
|
26
|
+
export type { AiChatConversationContext }
|
|
27
|
+
|
|
28
|
+
export function createConversationStorage(
|
|
29
|
+
container: AwilixContainer,
|
|
30
|
+
): AiChatConversationRepository {
|
|
31
|
+
const em = container.resolve<EntityManager>('em')
|
|
32
|
+
return new AiChatConversationRepository(em)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SerializedAiChatConversation {
|
|
36
|
+
conversationId: string
|
|
37
|
+
agentId: string
|
|
38
|
+
title: string | null
|
|
39
|
+
status: 'open' | 'closed'
|
|
40
|
+
visibility: 'private' | 'shared' | 'organization'
|
|
41
|
+
pageContext: Record<string, unknown> | null
|
|
42
|
+
createdAt: string
|
|
43
|
+
updatedAt: string
|
|
44
|
+
lastMessageAt: string | null
|
|
45
|
+
importedFromLocalAt: string | null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface SerializedAiChatMessage {
|
|
49
|
+
id: string
|
|
50
|
+
clientMessageId: string | null
|
|
51
|
+
role: 'user' | 'assistant' | 'system'
|
|
52
|
+
content: string
|
|
53
|
+
uiParts: unknown[]
|
|
54
|
+
attachmentIds: string[]
|
|
55
|
+
files: Array<Record<string, unknown>>
|
|
56
|
+
model: string | null
|
|
57
|
+
metadata: Record<string, unknown> | null
|
|
58
|
+
createdAt: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function serializeAiChatConversation(
|
|
62
|
+
row: AiChatConversation,
|
|
63
|
+
): SerializedAiChatConversation {
|
|
64
|
+
return {
|
|
65
|
+
conversationId: row.conversationId,
|
|
66
|
+
agentId: row.agentId,
|
|
67
|
+
title: row.title ?? null,
|
|
68
|
+
status: row.status,
|
|
69
|
+
visibility: row.visibility,
|
|
70
|
+
pageContext: row.pageContext ?? null,
|
|
71
|
+
createdAt: row.createdAt.toISOString(),
|
|
72
|
+
updatedAt: row.updatedAt.toISOString(),
|
|
73
|
+
lastMessageAt: row.lastMessageAt ? row.lastMessageAt.toISOString() : null,
|
|
74
|
+
importedFromLocalAt: row.importedFromLocalAt
|
|
75
|
+
? row.importedFromLocalAt.toISOString()
|
|
76
|
+
: null,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function serializeAiChatMessage(row: AiChatMessage): SerializedAiChatMessage {
|
|
81
|
+
return {
|
|
82
|
+
id: row.id,
|
|
83
|
+
clientMessageId: row.clientMessageId ?? null,
|
|
84
|
+
role: row.role,
|
|
85
|
+
content: row.content,
|
|
86
|
+
uiParts: Array.isArray(row.uiParts) ? row.uiParts : [],
|
|
87
|
+
attachmentIds: Array.isArray(row.attachmentIds) ? row.attachmentIds : [],
|
|
88
|
+
files: Array.isArray(row.filesMetadata) ? row.filesMetadata : [],
|
|
89
|
+
model: row.model ?? null,
|
|
90
|
+
metadata: row.metadata ?? null,
|
|
91
|
+
createdAt: row.createdAt.toISOString(),
|
|
92
|
+
}
|
|
93
|
+
}
|