Skip to content

Commit 8c348b2

Browse files
committed
Refine the interaction and type definitions for the elicitation
1 parent c25af6c commit 8c348b2

File tree

9 files changed

+80
-65
lines changed

9 files changed

+80
-65
lines changed

src/main/IPCs.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { closeCommandPicker } from './aid/commands'
2626

2727
import { commandSelectionInvoke, mcpServersCallback } from './index'
2828
import { getCachedText } from './aid/utils'
29-
import { SamplingResponse } from './types'
29+
import { McpClientResponse } from './types'
3030

3131
const handlerRegistry = new Map<string, Function>()
3232

@@ -290,11 +290,11 @@ export default class IPCs {
290290
}
291291
}
292292

293-
export function listenOnceForSamplingResponse(
293+
export function listenOnceForRendererResponse(
294294
responseChannel: string,
295-
resolve: (_value: SamplingResponse) => void
295+
resolve: (_value: McpClientResponse) => void
296296
) {
297-
ipcMain.once(responseChannel, (_event, response: SamplingResponse) => {
297+
ipcMain.once(responseChannel, (_event, response: McpClientResponse) => {
298298
resolve(response)
299299
})
300300
}

src/main/index.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,22 @@ import { createErrorWindow, createMainWindow } from './MainRunner'
55

66
import {
77
SamplingRequest,
8-
IpcElicitationEvents,
8+
SamplingResponse,
9+
ElicitRequest,
10+
ElicitResponse,
911
IpcCommandEvents,
10-
IpcMcpEvents,
11-
SamplingResponse
12+
IpcMcpEvents
1213
} from './types'
1314

14-
import { listenOnceForSamplingResponse } from './IPCs'
15+
import { IpcSamplingRequest, IpcElicitRequest } from '@/types/ipc'
16+
17+
import { listenOnceForRendererResponse } from './IPCs'
1518

1619
import * as shortcuts from './aid/shortcuts'
1720
import Commander from './aid/commander'
1821

1922
import { showWindow } from './tray'
2023

21-
import { McpClientResult, IpcSamplingRequest } from '@/types/ipc'
22-
2324
let mainWindow: BrowserWindow
2425
let errorWindow: BrowserWindow
2526

@@ -117,7 +118,7 @@ process.on('uncaughtException', async () => {
117118

118119
const msgSamplingTransferResultChannel = 'msgSamplingTransferResult'
119120

120-
export function samplingTransferInvoke(request: SamplingRequest): Promise<McpClientResult> {
121+
export function samplingTransferInvoke(request: SamplingRequest): Promise<SamplingResponse> {
121122
return new Promise<SamplingResponse>((resolve) => {
122123
if (!mainWindow || mainWindow.isDestroyed()) {
123124
resolve(null)
@@ -126,7 +127,7 @@ export function samplingTransferInvoke(request: SamplingRequest): Promise<McpCli
126127

127128
const responseChannel = `${msgSamplingTransferResultChannel}-${uuidv4()}`
128129

129-
listenOnceForSamplingResponse(responseChannel, resolve)
130+
listenOnceForRendererResponse(responseChannel, resolve)
130131

131132
mainWindow.webContents.send('msgSamplingTransferInvoke', {
132133
request,
@@ -137,9 +138,7 @@ export function samplingTransferInvoke(request: SamplingRequest): Promise<McpCli
137138

138139
const msgElicitationTransferResultChannel = 'msgElicitationTransferResult'
139140

140-
export function elicitationTransferInvoke<T extends keyof IpcElicitationEvents>(
141-
...args: Parameters<IpcElicitationEvents[T]>
142-
): Promise<any> {
141+
export function elicitationTransferInvoke(request: ElicitRequest): Promise<ElicitResponse> {
143142
return new Promise((resolve) => {
144143
if (!mainWindow || mainWindow.isDestroyed()) {
145144
resolve(null)
@@ -148,12 +147,12 @@ export function elicitationTransferInvoke<T extends keyof IpcElicitationEvents>(
148147

149148
const responseChannel = `${msgElicitationTransferResultChannel}-${uuidv4()}`
150149

151-
listenOnceForSamplingResponse(responseChannel, resolve)
150+
listenOnceForRendererResponse(responseChannel, resolve)
152151

153152
mainWindow.webContents.send('msgElicitationTransferInvoke', {
154-
args,
153+
request,
155154
responseChannel
156-
})
155+
} as IpcElicitRequest)
157156
})
158157
}
159158

src/main/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {
2+
ClientResult as McpClientResponse,
23
CreateMessageRequest as SamplingRequest,
34
CreateMessageResult as SamplingResponse,
4-
ElicitRequest
5+
ElicitRequest,
6+
ElicitResult as ElicitResponse
57
} from '@modelcontextprotocol/sdk/types.js'
68

79
import { McpCallback } from './mcp/types'
810

9-
export { SamplingRequest, SamplingResponse }
11+
export { McpClientResponse, SamplingRequest, SamplingResponse, ElicitRequest, ElicitResponse }
1012

1113
type CommandRequest = {
1214
prompt: string

src/renderer/components/common/ElicitationCard.vue

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts">
2-
import { ref, toRaw } from 'vue'
2+
import { ref, toRaw, computed } from 'vue'
33
import { ElicitationTransfer } from '@/renderer/utils'
4-
import type { ElicitRequest, ElicitResult } from '@modelcontextprotocol/sdk/types'
4+
import { IpcElicitRequestCallback, ElicitRequest, ElicitResponse } from '@/types/ipc'
55
import { validateNumberRange } from '@/renderer/store/dxt'
66
import { useI18n } from 'vue-i18n'
77
const { t } = useI18n()
@@ -20,6 +20,14 @@ const elicitationParams = ref<ElicitRequestParams | {}>({})
2020
2121
const elicitationChannel = ref('')
2222
23+
const normalizedProperties = computed(() => {
24+
const props = (elicitationParams.value as ElicitRequestParams).requestedSchema.properties
25+
return Object.keys(props).map((key) => ({
26+
key,
27+
para: props[key]
28+
}))
29+
})
30+
2331
const getConfigAttribute = (name: string) => {
2432
return elicitationResults.value[name] ?? null
2533
}
@@ -34,7 +42,7 @@ const dynamicModel = (name: string) => ({
3442
})
3543
3644
const declineElicitation = () => {
37-
const response: ElicitResult = {
45+
const response: ElicitResponse = {
3846
action: 'decline'
3947
}
4048
ElicitationTransfer.response(elicitationChannel.value, response)
@@ -43,7 +51,7 @@ const declineElicitation = () => {
4351
}
4452
4553
// const cancelElicitation = () => {
46-
// const response: ElicitResult = {
54+
// const response: ElicitResponse = {
4755
// "action": "cancel"
4856
// }
4957
// ElicitationTransfer.response(elicitationChannel.value, response)
@@ -52,7 +60,7 @@ const declineElicitation = () => {
5260
// }
5361
5462
const acceptElicitation = () => {
55-
const response: ElicitResult = {
63+
const response: ElicitResponse = {
5664
action: 'accept',
5765
content: toRaw(elicitationResults.value)
5866
}
@@ -110,10 +118,10 @@ const validateStringLength = (
110118
}
111119
}
112120
113-
const handleProgress = (_event, progress) => {
121+
const handleProgress: IpcElicitRequestCallback = (_event, progress) => {
114122
console.log('Elicitation', progress)
115123
elicitationDialog.value = true
116-
elicitationParams.value = progress.args[0].params
124+
elicitationParams.value = progress.request.params as ElicitRequestParams
117125
elicitationChannel.value = progress.responseChannel
118126
}
119127
@@ -137,11 +145,7 @@ ElicitationTransfer.request(handleProgress)
137145
'properties' in elicitationParams.requestedSchema
138146
"
139147
>
140-
<v-row
141-
v-for="(para, key) in elicitationParams.requestedSchema.properties"
142-
:key="key"
143-
class="mx-3 mb-3"
144-
>
148+
<v-row v-for="{ para, key } in normalizedProperties" :key="key" class="mx-3 mb-3">
145149
<v-select
146150
v-if="para.enum"
147151
prepend-icon="mdi-list-box-outline"

src/renderer/components/common/SamplingCard.vue

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ import { useMessageStore } from '@/renderer/store/message'
88
import { createCompletion } from '@/renderer/composables/chatCompletions'
99
import ConfigJsonCard from './ConfigJsonCard.vue'
1010
11-
import type {
12-
ChatCompletionResponseMessage,
13-
McpSamplingResponseMessage
14-
} from '@/renderer/types/message'
11+
import type { ChatCompletionResponseMessage } from '@/renderer/types/message'
1512
16-
import { IpcSamplingRequestCallback, SamplingRequest } from '@/types/ipc'
13+
import { IpcSamplingRequestCallback, SamplingRequest, SamplingResponse } from '@/types/ipc'
1714
1815
type SamplingRequestParams = SamplingRequest['params']
1916
@@ -64,7 +61,7 @@ const clearSampling = () => {
6461
6562
const finishSampling = (index: number) => {
6663
const bestResponse: ChatCompletionResponseMessage = samplingResults.value[index]
67-
const response: McpSamplingResponseMessage = {
64+
const response: SamplingResponse = {
6865
model: chatbotStore.model,
6966
role: bestResponse?.role || 'assistant',
7067
content: {
@@ -81,7 +78,7 @@ const finishSampling = (index: number) => {
8178
}
8279
8380
const rejectSampling = () => {
84-
const response: McpSamplingResponseMessage = {
81+
const response: SamplingResponse = {
8582
model: 'N/A',
8683
role: 'assistant',
8784
stopReason: 'Reject by user',

src/renderer/components/pages/ChatPage.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import 'katex/dist/katex.min.css'
1515
1616
import mermaid from 'mermaid'
1717
18-
import * as echarts from 'echarts';
18+
import * as echarts from 'echarts'
1919
2020
import highlight from 'highlight.js'
2121
import 'highlight.js/styles/atom-one-dark.css'

src/renderer/composables/chatCompletions.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,6 @@ export const createCompletion = async (
128128

129129
console.log(chatbotConfig)
130130

131-
const conversation = rawconversation.reduce((newConversation, item) => {
132-
if (item.role === 'assistant') {
133-
const { reasoning_content, ...rest } = item
134-
void reasoning_content
135-
newConversation.push(rest)
136-
}
137-
// (item.role === "user" && item.content[0].type === "image_url") {
138-
// // Image is too large, only latest query could be kept
139-
// newConversation = [item];
140-
// }
141-
else {
142-
newConversation.push(item)
143-
}
144-
return newConversation
145-
}, [] as RequestMessageType[])
146-
// const conversation = rawconversation
147131
try {
148132
// Create a completion (axios is not used here because it does not support streaming)
149133

@@ -186,6 +170,22 @@ export const createCompletion = async (
186170
let target: ChatConversationMessage[]
187171

188172
if (!sampling) {
173+
const conversation = rawconversation.reduce((newConversation, item) => {
174+
if (item.role === 'assistant') {
175+
const { reasoning_content, ...rest } = item
176+
void reasoning_content
177+
newConversation.push(rest)
178+
}
179+
// (item.role === "user" && item.content[0].type === "image_url") {
180+
// // Image is too large, only latest query could be kept
181+
// newConversation = [item];
182+
// }
183+
else {
184+
newConversation.push(item)
185+
}
186+
return newConversation
187+
}, [] as RequestMessageType[])
188+
189189
target = messageStore.conversation
190190

191191
body.messages = promptMessage(

src/renderer/utils/index.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { McpServerApi } from '@/renderer/store/mcp'
22
import { useDxtStore } from '@/renderer/store/dxt'
33

4-
import { IpcSamplingRequestCallback } from '@/types/ipc'
4+
import { IpcSamplingRequestCallback, IpcElicitRequestCallback } from '@/types/ipc'
5+
import { SamplingResponse, ElicitResponse } from '@/types/ipc'
56

67
function isValidValue(value: any): boolean {
78
if (value === null || value === undefined) return false
@@ -76,7 +77,11 @@ class Sampling {
7677
}
7778

7879
// Channel format: "msgSamplingTransferResult-uuid4()"
79-
static async msgSamplingTransferResult(channel: string, response: any): Promise<void> {
80+
static async msgSamplingTransferResult(
81+
channel: string,
82+
response: SamplingResponse
83+
): Promise<void> {
84+
console.log(response)
8085
await window.mainApi.send(channel, response)
8186
}
8287
}
@@ -87,12 +92,15 @@ export const SamplingTransfer = {
8792
}
8893

8994
class Elicitation {
90-
static async msgElicitationTransferInvoke(callback: any): Promise<any> {
95+
static async msgElicitationTransferInvoke(callback: IpcElicitRequestCallback): Promise<void> {
9196
return window.mainApi.on('msgElicitationTransferInvoke', callback)
9297
}
9398

9499
// Channel format: "msgElicitationTransferResult-uuid4()"
95-
static async msgElicitationTransferResult(channel: string, response: any): Promise<void> {
100+
static async msgElicitationTransferResult(
101+
channel: string,
102+
response: ElicitResponse
103+
): Promise<void> {
96104
await window.mainApi.send(channel, response)
97105
}
98106
}

src/types/ipc.d.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import type { ClientResult as McpClientResult } from '@modelcontextprotocol/sdk/types'
1+
import type { SamplingRequest, SamplingResponse, ElicitRequest, ElicitResponse } from '@/main/types'
22

3-
import type { SamplingRequest } from '@/main/types'
4-
5-
export type { McpClientResult, SamplingRequest }
3+
export type { SamplingRequest, SamplingResponse, ElicitRequest, ElicitResponse }
64

75
export type IpcSamplingRequest = {
86
request: SamplingRequest
97
responseChannel: string
108
}
119

12-
export type IpcSamplingRequestCallback = (_event: Event, _progress: IpcSamplingProgress) => void
10+
export type IpcSamplingRequestCallback = (_event: Event, _progress: IpcSamplingRequest) => void
11+
12+
export type IpcElicitRequest = {
13+
request: ElicitRequest
14+
responseChannel: string
15+
}
16+
17+
export type IpcElicitRequestCallback = (_event: Event, _progress: IpcElicitRequest) => void

0 commit comments

Comments
 (0)