Skip to content

Commit c63eede

Browse files
committed
Add type definition in message store
1 parent 0b7ffae commit c63eede

File tree

7 files changed

+99
-67
lines changed

7 files changed

+99
-67
lines changed

src/renderer/components/common/SamplingCard.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { ref, computed, watch } from 'vue'
33
import { listenSampling, sendResponse } from '@/renderer/utils'
44
import { useSnackbarStore } from '@/renderer/store/snackbar'
55
import { useChatbotStore } from '@/renderer/store/chatbot'
6-
import { MessageEntry } from '@/renderer/store/history'
76
import { createCompletion } from '@/renderer/composables/chatCompletions'
7+
import type { ChatCompletionResponseMessage } from '@/renderer/types/message'
88
99
const snackbarStore = useSnackbarStore()
1010
@@ -16,7 +16,7 @@ const samplingDialog = ref(false)
1616
1717
const samplingParams = ref({})
1818
19-
const samplingResults = ref<MessageEntry[]>([])
19+
const samplingResults = ref<ChatCompletionResponseMessage[]>([])
2020
2121
const samplingChannel = ref('')
2222
@@ -79,7 +79,10 @@ const finishSampling = (index: number) => {
7979
role: bestResponse?.role || 'assistant',
8080
content: {
8181
type: 'text',
82-
text: bestResponse?.content || `No response from model ${chatbotStore.model}`
82+
text:
83+
bestResponse?.content ||
84+
bestResponse?.reasoning_content ||
85+
`No response from model ${chatbotStore.model}`
8386
}
8487
}
8588
sendResponse(samplingChannel.value, response)

src/renderer/components/pages/ChatPage.vue

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ config({
3737
})
3838
3939
interface Message {
40-
index: number
4140
role: 'user' | 'assistant' | 'tool'
4241
content: any
4342
tool_calls?: any[]
@@ -221,15 +220,11 @@ const groupMessages = computed<Group[]>(() => {
221220
:show-copy="false"
222221
:index="group.index"
223222
:range="group.messages!.length"
223+
@delete-messages="handleDeleteMessages"
224224
>
225-
<v-tabs
226-
v-model="dialogs[group.tab!]"
227-
:items="group.messages"
228-
show-arrows
229-
@delete-messages="handleDeleteMessages"
230-
>
225+
<v-tabs v-model="dialogs[group.tab!]" :items="group.messages" show-arrows>
231226
<template #tab="{ item }">
232-
<v-tab :text="item.index" :value="item.index">
227+
<v-tab :text="item.role" :value="item">
233228
<v-icon
234229
v-if="item.role === 'tool'"
235230
icon="mdi-arrow-left-bold-circle"
@@ -243,7 +238,7 @@ const groupMessages = computed<Group[]>(() => {
243238
</v-tab>
244239
</template>
245240
<template #item="{ item }">
246-
<v-tabs-window-item :value="item.index">
241+
<v-tabs-window-item :value="item">
247242
<v-card v-if="item.role === 'tool'" class="mt-1" variant="flat">
248243
<v-card-item prepend-icon="mdi-chevron-left">
249244
<v-card-subtitle>

src/renderer/components/pages/McpResourcePage.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,16 @@ const resourceStore = useResourceStore()
4444
<v-expansion-panel
4545
v-for="item in items as any"
4646
:key="item.raw.uri + ':' + item.raw.name"
47-
:text="JSON.stringify(item.raw)"
4847
:title="item.raw.name + ' - ' + item.raw.uri"
4948
>
49+
<v-expansion-panel-text>
50+
<v-textarea
51+
:model-value="JSON.stringify(item.raw, null, 2)"
52+
variant="plain"
53+
auto-grow
54+
readonly
55+
></v-textarea>
56+
</v-expansion-panel-text>
5057
</v-expansion-panel>
5158
</v-expansion-panels>
5259
</v-container>

src/renderer/composables/chatCompletions.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import type {
99
ToolCall,
1010
McpSamplingMessage,
1111
ChatCompletionRequestMessage,
12-
ChatCompletionResponseMessage
12+
ChatCompletionMessage,
13+
ChatConversationMessage
1314
} from '@/renderer/types/message'
1415

15-
type ChatCompletionMessage = ChatCompletionRequestMessage | McpSamplingMessage
16+
type RequestMessageType = ChatCompletionRequestMessage | McpSamplingMessage
1617

1718
const isObjectEmpty = (obj?: Record<string, unknown>): boolean => {
1819
return !!obj && Object.keys(obj).length === 0
@@ -35,7 +36,7 @@ export const isEmptyTools = (tools: any): boolean => {
3536
const promptMessage = (
3637
conversation: ChatCompletionRequestMessage[],
3738
systemPrompt: string | null
38-
): ChatCompletionRequestMessage[] => {
39+
): ChatCompletionMessage[] => {
3940
if (systemPrompt) {
4041
return [{ content: systemPrompt, role: 'system' }, ...conversation]
4142
} else {
@@ -44,7 +45,7 @@ const promptMessage = (
4445
}
4546

4647
export const createCompletion = async (
47-
rawconversation: ChatCompletionMessage[],
48+
rawconversation: RequestMessageType[],
4849
sampling: any = null
4950
) => {
5051
const snackbarStore = useSnackbarStore()
@@ -73,7 +74,7 @@ export const createCompletion = async (
7374
newConversation.push(item)
7475
}
7576
return newConversation
76-
}, [] as ChatCompletionMessage[])
77+
}, [] as RequestMessageType[])
7778
// const conversation = rawconversation
7879
try {
7980
messageStore.generating = true
@@ -91,7 +92,7 @@ export const createCompletion = async (
9192
stream: chatbotStore.stream
9293
}
9394

94-
let target: ChatCompletionResponseMessage[]
95+
let target: ChatConversationMessage[]
9596

9697
if (!sampling) {
9798
target = messageStore.conversation

src/renderer/store/history.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@ import localForage from 'localforage'
33
import { v4 as uuidv4 } from 'uuid'
44
import { useMessageStore } from '@/renderer/store/message'
55

6-
type ConversationID = string
6+
import type { ChatConversationMessage } from '@/renderer/types/message'
77

8-
export type MessageEntry = {
9-
role: string
10-
content: any
11-
reasoning_content?: string
12-
[key: string]: any
13-
}
8+
type ConversationID = string
149

1510
type ConversationEntry = {
1611
id: ConversationID
17-
messages: MessageEntry[]
12+
messages: ChatConversationMessage[]
13+
}
14+
15+
interface HistoryStoreState {
16+
selected: ConversationID[] | undefined
17+
conversation: ConversationEntry[]
1818
}
1919

2020
export const useHistoryStore = defineStore('historyStore', {
21-
state: () => ({
21+
state: (): HistoryStoreState => ({
2222
selected: undefined as ConversationID[] | undefined,
2323
conversation: [] as ConversationEntry[]
2424
}),
@@ -38,7 +38,7 @@ export const useHistoryStore = defineStore('historyStore', {
3838
deleteById(index: number) {
3939
this.conversation.splice(index, 1)
4040
},
41-
init(conversation: MessageEntry[]) {
41+
init(conversation: ChatConversationMessage[]) {
4242
const newId = this.getDate()
4343
this.conversation.unshift({
4444
id: newId,
@@ -76,7 +76,7 @@ export const useHistoryStore = defineStore('historyStore', {
7676
downloadHistory() {
7777
this.download(this.conversation, 'history.json')
7878
},
79-
download(json, filename) {
79+
download(json: ChatConversationMessage[] | ConversationEntry[], filename: string) {
8080
const blob = new Blob([JSON.stringify(json, null, 2)], { type: 'application/json' })
8181
const url = URL.createObjectURL(blob)
8282
const a = document.createElement('a')

src/renderer/store/message.ts

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,26 @@ import { useMcpStore } from '@/renderer/store/mcp'
44
import { useHistoryStore } from '@/renderer/store/history'
55
import { createCompletion, isEmptyTools } from '@/renderer/composables/chatCompletions'
66

7+
import type {
8+
ToolCall,
9+
ToolMessage,
10+
UserMessage,
11+
ChatConversationMessage
12+
} from '@/renderer/types/message'
13+
14+
interface MessageStoreState {
15+
userMessage: string
16+
conversation: ChatConversationMessage[]
17+
historyId: string
18+
base64: string
19+
generating: boolean
20+
}
21+
722
export const useMessageStore = defineStore('messageStore', {
8-
// TODO: fix any to type
9-
state: (): any => ({
23+
state: (): MessageStoreState => ({
1024
userMessage: '',
1125
conversation: [],
1226
historyId: '',
13-
images: [],
1427
base64: '',
1528
generating: false
1629
}),
@@ -35,7 +48,6 @@ export const useMessageStore = defineStore('messageStore', {
3548
},
3649
clear() {
3750
this.userMessage = ''
38-
this.images = []
3951
},
4052
handleKeydown(e) {
4153
if (e.key === 'Enter' && e.shiftKey) {
@@ -105,48 +117,50 @@ export const useMessageStore = defineStore('messageStore', {
105117
postToolCall: async function () {
106118
const mcpStore = useMcpStore()
107119
const last = this.conversation.at(-1)
108-
if (!last || !last.tool_calls) {
120+
121+
if (!last || !('tool_calls' in last) || !last.tool_calls) {
109122
return
110123
}
124+
111125
if (isEmptyTools(last.tool_calls)) {
112126
delete last.tool_calls
113-
// return
114-
} else {
115-
let toolCalled = false
116-
console.log(last.tool_calls)
127+
return
128+
}
117129

118-
const callNextTool = async (toolCalls, index) => {
119-
if (index >= toolCalls.length) {
120-
return
121-
}
130+
let toolCalled = false
131+
console.log(last.tool_calls)
122132

123-
const toolCall = toolCalls[index]
133+
const callNextTool = async (toolCalls: ToolCall[], index: number) => {
134+
if (index >= toolCalls.length) {
135+
return
136+
}
124137

125-
let result
138+
const toolCall = toolCalls[index]
126139

127-
try {
128-
result = await mcpStore.callTool(toolCall.function.name, toolCall.function.arguments)
129-
console.log(result)
130-
} catch (error) {
131-
result = mcpStore.packReturn(`Error calling tool: ${error}`)
132-
}
140+
let result
133141

134-
if (result.content) {
135-
this.contentConvert(result.content, toolCall.id).forEach((item) => {
136-
this.conversation.push(item)
137-
})
138-
toolCalled = true
139-
}
142+
try {
143+
result = await mcpStore.callTool(toolCall.function.name, toolCall.function.arguments)
144+
console.log(result)
145+
} catch (error) {
146+
result = mcpStore.packReturn(`Error calling tool: ${error}`)
140147
}
141148

142-
await callNextTool(last.tool_calls, 0)
143-
144-
if (toolCalled) {
145-
this.startInference()
149+
if (result.content) {
150+
this.contentConvert(result.content, toolCall.id).forEach((item) => {
151+
this.conversation.push(item)
152+
})
153+
toolCalled = true
146154
}
147155
}
156+
157+
await callNextTool(last.tool_calls, 0)
158+
159+
if (toolCalled) {
160+
this.startInference()
161+
}
148162
},
149-
contentConvert: function (content, toolCallId) {
163+
contentConvert: function (content, toolCallId): Array<UserMessage | ToolMessage> {
150164
const mcpStore = useMcpStore()
151165
const msg = content.map((item) => mcpStore.convertItem(item))
152166
console.log(msg)

src/renderer/types/message.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,18 @@ const SystemMessageSchema = z.object({
6060
})
6161

6262
const UserMessageSchema = z.object({
63-
content: z.union([TextContent, z.array(TextContentPartSchema), z.array(ImageContentPartSchema)]),
63+
content: z.union([
64+
TextContent,
65+
z.array(z.union([TextContentPartSchema, ImageContentPartSchema]))
66+
]),
6467
role: z.literal('user'),
6568
name: z.string().optional()
6669
})
6770

6871
const AssistantMessageSchema = z.object({
6972
content: z.union([
7073
TextContent,
71-
z.array(TextContentPartSchema),
72-
z.array(RefusalContentPartSchema)
74+
z.array(z.union([TextContentPartSchema, RefusalContentPartSchema]))
7375
]),
7476
reasoning_content: z.string().optional(),
7577
tool_calls: z.array(ToolCallSchema).optional(),
@@ -84,6 +86,12 @@ const ToolMessageSchema = z.object({
8486
})
8587

8688
const ChatCompletionRequestMessageSchema = z.union([
89+
UserMessageSchema,
90+
AssistantMessageSchema,
91+
ToolMessageSchema
92+
])
93+
94+
const ChatCompletionMessageSchema = z.union([
8795
SystemMessageSchema,
8896
UserMessageSchema,
8997
AssistantMessageSchema,
@@ -101,9 +109,9 @@ const ChatCompletionResponseMessageSchema = z.object({
101109

102110
export type ToolCall = Infer<typeof ToolCallSchema>
103111
// type SystemMessage = Infer<typeof SystemMessageSchema>
104-
// type UserMessage = Infer<typeof UserMessageSchema>
112+
export type UserMessage = Infer<typeof UserMessageSchema>
105113
export type AssistantMessage = Infer<typeof AssistantMessageSchema>
106-
// type ToolMessage = Infer<typeof ToolMessageSchema>
114+
export type ToolMessage = Infer<typeof ToolMessageSchema>
107115

108116
type TextContentPart = Infer<typeof TextContentPartSchema>
109117
// type RefusalContentPart = Infer<typeof RefusalContentPartSchema>
@@ -128,3 +136,7 @@ export type ChatCompletionRequestMessage = Infer<typeof ChatCompletionRequestMes
128136
export type ChatCompletionPromptMessage = PromptMessage
129137

130138
export type ChatCompletionResponseMessage = Infer<typeof ChatCompletionResponseMessageSchema>
139+
140+
export type ChatCompletionMessage = Infer<typeof ChatCompletionMessageSchema>
141+
142+
export type ChatConversationMessage = ChatCompletionRequestMessage | ChatCompletionResponseMessage

0 commit comments

Comments
 (0)