Skip to content

Commit d1aeaf1

Browse files
committed
experimental: Show model + prompt name over the message
1 parent 35219c7 commit d1aeaf1

File tree

8 files changed

+77
-56
lines changed

8 files changed

+77
-56
lines changed

e2e/prompts.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ test.describe('Prompts', () => {
4848
await expect(page.getByTestId('assistant-instructions-input')).toContainText('mocktest testi onnistui')
4949
})
5050

51-
test('Course prompt creation, chat link with prompt, and deletion', async ({ page }) => {
51+
test.only('Course prompt creation, chat link with prompt, and deletion', async ({ page }) => {
5252
await page.goto('/courses/test-course/prompts')
5353

5454
const newPromptName = `testausprompti-${test.info().workerIndex}`
@@ -98,7 +98,7 @@ test.describe('Prompts', () => {
9898
await page.getByTestId('prompt-selector-button').click()
9999

100100
// Prompt is not visible anymore in student view.
101-
expect(page.getByText(newPromptName)).not.toBeVisible()
101+
expect(page.getByText(newPromptName, { exact: true })).not.toBeVisible()
102102
})
103103

104104
test('Own prompts work in course chat and normal chat', async ({ page }) => {

src/client/components/ChatV2/ChatV2.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
88
import { useTranslation } from 'react-i18next'
99
import { useParams, useSearchParams } from 'react-router-dom'
1010
import { DEFAULT_ASSISTANT_INSTRUCTIONS, DEFAULT_MODEL, DEFAULT_MODEL_TEMPERATURE, FREE_MODEL, inProduction, validModels } from '../../../config'
11-
import type { ChatMessage, ToolCallResultEvent } from '../../../shared/chat'
11+
import type { ChatMessage, MessageGenerationInfo, ToolCallResultEvent } from '../../../shared/chat'
1212
import type { RagIndexAttributes } from '../../../shared/types'
1313
import { getLanguageValue } from '../../../shared/utils'
1414
import { useIsEmbedded } from '../../contexts/EmbeddedContext'
@@ -127,7 +127,7 @@ export const ChatV2 = () => {
127127

128128
const disclaimerInfo = infoTexts?.find((infoText) => infoText.name === 'disclaimer')?.text[i18n.language] ?? null
129129

130-
const { processStream, completion, isStreaming, setIsStreaming, toolCalls, streamController } = useChatStream({
130+
const { processStream, completion, isStreaming, setIsStreaming, toolCalls, streamController, generationInfo } = useChatStream({
131131
onComplete: ({ message }) => {
132132
if (message.content.length > 0) {
133133
setMessages((prev: ChatMessage[]) => prev.concat(message))
@@ -188,12 +188,18 @@ export const ChatV2 = () => {
188188
setIsStreaming(true)
189189
chatScroll.beginAutoscroll()
190190

191+
const generationInfo: MessageGenerationInfo = {
192+
model: activeModel,
193+
promptInfo: activePrompt
194+
? { id: activePrompt.id, name: activePrompt.name, type: 'saved', systemMessage: activePrompt.systemMessage }
195+
: { type: 'custom', systemMessage: customSystemMessage },
196+
}
197+
191198
try {
192199
const { tokenUsageAnalysis, stream } = await getCompletionStreamV3({
193-
systemMessage: activePrompt?.systemMessage || customSystemMessage,
200+
generationInfo,
194201
messages: newMessages,
195202
ragIndexId,
196-
model: activeModel,
197203
formData,
198204
modelTemperature: parseFloat(modelTemperature),
199205
courseId,
@@ -219,7 +225,7 @@ export const ChatV2 = () => {
219225

220226
clearRetryTimeout()
221227
if (stream) {
222-
await processStream(stream)
228+
await processStream(stream, generationInfo)
223229
}
224230
} catch (err: any) {
225231
console.error(err)
@@ -475,6 +481,7 @@ export const ChatV2 = () => {
475481
initial={<ConversationSplash courseName={course && getLanguageValue(course.name, i18n.language)} courseDate={course?.activityPeriod} />}
476482
messages={messages}
477483
completion={completion}
484+
generationInfo={generationInfo}
478485
isStreaming={isStreaming}
479486
toolCalls={toolCalls}
480487
setActiveToolResult={setActiveToolResult}

src/client/components/ChatV2/Conversation.tsx

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ import { t } from 'i18next'
1515
import FormatQuoteIcon from '@mui/icons-material/FormatQuote'
1616
import useLocalStorageState from '../../hooks/useLocalStorageState'
1717
import { BlueButton } from './general/Buttons'
18-
import type { ChatMessage, ToolCallResultEvent, ToolCallStatusEvent } from '../../../shared/chat'
18+
import type { AssistantMessage, ChatMessage, MessageGenerationInfo, ToolCallResultEvent, ToolCallStatusEvent, UserMessage } from '../../../shared/chat'
1919
import { useId, useMemo } from 'react'
20+
import { ArrowRight } from '@mui/icons-material'
2021

21-
const UserMessage = ({ content, attachments }: { content: string; attachments?: string }) => (
22+
const UserMessageItem = ({ message }: { message: UserMessage }) => (
2223
<Box
2324
sx={{
2425
backgroundColor: '#efefef',
@@ -33,9 +34,9 @@ const UserMessage = ({ content, attachments }: { content: string; attachments?:
3334
width: 'fit-content',
3435
}}
3536
>
36-
{content}
37+
{message.content}
3738

38-
{attachments && (
39+
{message.attachments && (
3940
<Typography
4041
variant="body2"
4142
sx={{
@@ -47,7 +48,7 @@ const UserMessage = ({ content, attachments }: { content: string; attachments?:
4748
}}
4849
>
4950
<AttachFileIcon fontSize="small" />
50-
{attachments}
51+
{message.attachments}
5152
</Typography>
5253
)}
5354
</Box>
@@ -102,18 +103,24 @@ const ToolResult = ({ toolResult, handleToolResult }: { toolResult: ToolCallResu
102103
)
103104
}
104105

105-
const AssistantMessage = ({
106-
content,
107-
error,
108-
toolResults,
109-
setActiveToolResult,
110-
}: {
111-
content: string
112-
error?: string
113-
toolResults?: Record<string, ToolCallResultEvent>
114-
setActiveToolResult: (data: ToolCallResultEvent) => void
115-
}) => {
116-
const processedContent = preprocessMath(content)
106+
const AssistantMessageInfo = ({ message }: { message: AssistantMessage }) => {
107+
if (!message.generationInfo) return null
108+
109+
const title =
110+
message.generationInfo.promptInfo.type === 'saved'
111+
? `${message.generationInfo.promptInfo.name} (${message.generationInfo.model})`
112+
: `${message.generationInfo.model}`
113+
114+
return (
115+
<Box sx={{ display: 'flex', opacity: 0.7, alignItems: 'center' }}>
116+
<ArrowRight fontSize="small" />
117+
<Typography fontSize="small">{title}</Typography>
118+
</Box>
119+
)
120+
}
121+
122+
const AssistantMessageItem = ({ message, setActiveToolResult }: { message: AssistantMessage; setActiveToolResult: (data: ToolCallResultEvent) => void }) => {
123+
const processedContent = preprocessMath(message.content)
117124
const katexOptions = {
118125
macros: {
119126
'\\abs': '\\left|#1\\right|',
@@ -185,8 +192,9 @@ const AssistantMessage = ({
185192
borderRadius: 4,
186193
}}
187194
>
188-
<CopyToClipboardButton id={msgId} copied={content} />
195+
<CopyToClipboardButton id={msgId} copied={message.content} />
189196
</Box>
197+
<AssistantMessageInfo message={message} />
190198
<ReactMarkdown
191199
remarkPlugins={[remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
192200
rehypePlugins={[[rehypeKatex, katexOptions]]}
@@ -255,12 +263,12 @@ const AssistantMessage = ({
255263
>
256264
{processedContent}
257265
</ReactMarkdown>
258-
{error && (
266+
{message.error && (
259267
<Box>
260-
<Typography variant="body1" fontStyle="italic" color="#cc0000">{`\n\n ${error}`}</Typography>
268+
<Typography variant="body1" fontStyle="italic" color="#cc0000">{`\n\n ${message.error}`}</Typography>
261269
</Box>
262270
)}
263-
{Object.values(toolResults ?? {}).map((toolResult) => (
271+
{Object.values(message.toolCalls ?? {}).map((toolResult) => (
264272
<ToolResult key={toolResult.callId} toolResult={toolResult} handleToolResult={handleToolResult} />
265273
))}
266274
</Box>
@@ -276,13 +284,13 @@ export const MessageItem = ({ message, setActiveToolResult }: { message: ChatMes
276284
height: 'auto',
277285
}}
278286
>
279-
<AssistantMessage content={message.content} error={message.error} toolResults={message.toolCalls} setActiveToolResult={setActiveToolResult} />
287+
<AssistantMessageItem message={message} setActiveToolResult={setActiveToolResult} />
280288
</Box>
281289
)
282290
} else {
283291
return (
284292
<Box data-sentry-mask data-testid="user-message" sx={{ alignSelf: 'flex-end' }}>
285-
<UserMessage content={message.content} attachments={message.attachments ?? ''} />
293+
<UserMessageItem message={message} />
286294
</Box>
287295
)
288296
}
@@ -291,13 +299,15 @@ export const MessageItem = ({ message, setActiveToolResult }: { message: ChatMes
291299
export const Conversation = ({
292300
messages,
293301
completion,
302+
generationInfo,
294303
toolCalls,
295304
isStreaming,
296305
setActiveToolResult,
297306
initial,
298307
}: {
299308
messages: ChatMessage[]
300309
completion: string
310+
generationInfo?: MessageGenerationInfo
301311
toolCalls: { [callId: string]: ToolCallStatusEvent }
302312
isStreaming: boolean
303313
setActiveToolResult: (data: ToolCallResultEvent) => void
@@ -326,7 +336,7 @@ export const Conversation = ({
326336
{isStreaming &&
327337
messages.length > 0 &&
328338
(completion.length > 0 ? (
329-
<MessageItem message={{ role: 'assistant', content: completion }} setActiveToolResult={setActiveToolResult} />
339+
<MessageItem message={{ role: 'assistant', content: completion, generationInfo }} setActiveToolResult={setActiveToolResult} />
330340
) : (
331341
<LoadingMessage toolCalls={toolCalls} />
332342
))}

src/client/components/ChatV2/useChatStream.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react'
2-
import type { AssistantMessage, ChatEvent, ToolCallResultEvent, ToolCallStatusEvent } from '../../../shared/chat'
2+
import type { AssistantMessage, ChatEvent, MessageGenerationInfo, ToolCallResultEvent, ToolCallStatusEvent } from '../../../shared/chat'
33

44
type ToolCallState = ToolCallStatusEvent
55

@@ -15,16 +15,18 @@ export const useChatStream = ({
1515
onText: () => void
1616
}) => {
1717
const [completion, setCompletion] = useState('')
18+
const [generationInfo, setGenerationInfo] = useState<MessageGenerationInfo | undefined>()
1819
const [isStreaming, setIsStreaming] = useState(false)
1920
const [toolCalls, setToolCalls] = useState<Record<string, ToolCallState>>({})
2021
const [streamController, setStreamController] = useState<AbortController>()
2122

2223
const decoder = new TextDecoder()
2324

24-
const processStream = async (stream: ReadableStream) => {
25+
const processStream = async (stream: ReadableStream, baseGenerationInfo: MessageGenerationInfo) => {
2526
let content = ''
2627
let error = ''
2728
const toolCallResultsAccum: Record<string, ToolCallResultEvent> = {}
29+
setGenerationInfo(baseGenerationInfo)
2830

2931
try {
3032
const reader = stream.getReader()
@@ -90,13 +92,15 @@ export const useChatStream = ({
9092
setCompletion('')
9193
setToolCalls({})
9294
setIsStreaming(false)
95+
setGenerationInfo(undefined)
9396

9497
onComplete({
9598
message: {
9699
role: 'assistant',
97100
content,
98101
error: error.length > 0 ? error : undefined,
99102
toolCalls: toolCallResultsAccum,
103+
generationInfo: baseGenerationInfo,
100104
},
101105
})
102106
}
@@ -105,6 +109,7 @@ export const useChatStream = ({
105109
return {
106110
processStream,
107111
completion,
112+
generationInfo,
108113
isStreaming,
109114
setIsStreaming,
110115
toolCalls,

src/client/components/ChatV2/util.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import type { ChatMessage } from '../../../shared/chat'
1+
import type { ChatMessage, MessageGenerationInfo } from '../../../shared/chat'
22
import { postAbortableStream } from '../../util/apiClient'
33

44
interface GetCompletionStreamProps {
5+
generationInfo: MessageGenerationInfo
56
courseId?: string
6-
systemMessage: string
77
messages: ChatMessage[]
8-
model: string
98
formData: FormData
109
ragIndexId?: number
1110
userConsent?: boolean
@@ -15,10 +14,9 @@ interface GetCompletionStreamProps {
1514
saveConsent: boolean
1615
}
1716
export const getCompletionStreamV3 = async ({
17+
generationInfo,
1818
courseId,
19-
systemMessage,
2019
messages,
21-
model,
2220
formData,
2321
ragIndexId,
2422
userConsent,
@@ -31,9 +29,9 @@ export const getCompletionStreamV3 = async ({
3129
courseId,
3230
options: {
3331
chatMessages: messages,
34-
systemMessage,
32+
systemMessage: generationInfo.promptInfo.systemMessage,
33+
model: generationInfo.model,
3534
ragIndexId,
36-
model,
3735
userConsent,
3836
modelTemperature,
3937
saveConsent,

src/server/routes/ai/v3.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,6 @@ router.post('/stream', upload.single('file'), async (r, res) => {
187187
tokensPerSecond: result.tokensPerSecond,
188188
}
189189

190-
logger.info(`Stream ended. Total tokens: ${tokenCount}`, chatCompletionMeta)
191-
192190
res.locals.chatCompletionMeta = chatCompletionMeta
193191

194192
// If course has saveDiscussion turned on and user has consented to saving the discussion, save the discussion

src/server/util/pate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ const sendEmail = async (targets: string[], text: string, subject: string) => {
2929

3030
logger.info(`Sending email with payload size ${payloadSizeKb.toFixed(2)} KB`)
3131

32-
if (inCI) {
33-
logger.info('Skipping email sending in CI')
32+
if (inCI || inDevelopment) {
33+
logger.info('Skipping email sending in CI or development')
3434
return
3535
}
3636

src/shared/chat.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export type AssistantMessage = {
4444
content: string
4545
error?: string
4646
toolCalls?: Record<string, ToolCallResultEvent>
47-
promptInfo?: MessagePromptInfo
47+
generationInfo?: MessageGenerationInfo
4848
}
4949

5050
export type Message = SystemMessage | UserMessage | AssistantMessage
@@ -55,14 +55,17 @@ export type ChatMessage = UserMessage | AssistantMessage
5555

5656
export type ChatRole = ChatMessage['role']
5757

58-
export type MessagePromptInfo =
59-
| {
60-
type: 'saved'
61-
id: string
62-
name: string
63-
systemMessage?: string
64-
}
65-
| {
66-
type: 'custom'
67-
systemMessage: string
68-
}
58+
export type MessageGenerationInfo = {
59+
model: string
60+
promptInfo:
61+
| {
62+
type: 'saved'
63+
id: string
64+
name: string
65+
systemMessage: string
66+
}
67+
| {
68+
type: 'custom'
69+
systemMessage: string
70+
}
71+
}

0 commit comments

Comments
 (0)