Skip to content

Commit 6280e64

Browse files
committed
feat: add model info to the response msg
Resolves #39
1 parent 08c2fd9 commit 6280e64

File tree

23 files changed

+266
-181
lines changed

23 files changed

+266
-181
lines changed

_build/js/src/chatHistory.ts

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ToolResponseContent, ToolCalls } from './executor/types';
1+
import type { ToolResponseContent, ToolCalls, ServiceResponse, Metadata } from './executor/types';
22

33
export type AssistantMessageContentType = 'text' | 'image';
44

@@ -34,14 +34,15 @@ export type ToolResponseMessage = BaseMessage & {
3434
el?: UpdatableHTMLElement<ToolResponseMessage>;
3535
};
3636

37-
export type AssistantMessage = Omit<BaseMessage, 'toolCalls'> & {
38-
__type: 'AssistantMessage';
39-
role: 'assistant';
40-
content: string | undefined;
41-
contentType: AssistantMessageContentType;
42-
toolCalls?: ToolCalls;
43-
el?: UpdatableHTMLElement<AssistantMessage>;
44-
};
37+
export type AssistantMessage = Metadata &
38+
Omit<BaseMessage, 'toolCalls'> & {
39+
__type: 'AssistantMessage';
40+
role: 'assistant';
41+
content: string | undefined;
42+
contentType: AssistantMessageContentType;
43+
toolCalls?: ToolCalls;
44+
el?: UpdatableHTMLElement<AssistantMessage>;
45+
};
4546

4647
export type UserMessage = Omit<BaseMessage, 'contexts' | 'attachments'> & {
4748
__type: 'UserMessage';
@@ -124,51 +125,57 @@ const addToolResponseMessage = (
124125
msgObject.el = namespace.onAddMessage(msgObject);
125126
};
126127

127-
const addAssistantMessage = (
128-
key: string,
129-
id: string,
130-
content: string | undefined,
131-
toolCalls: ToolCalls | undefined,
132-
contentType: AssistantMessageContentType,
133-
hidden: boolean = false,
134-
) => {
128+
const addAssistantMessage = (key: string, data: ServiceResponse, hidden: boolean = false) => {
135129
const namespace = _namespace[key];
136130
if (!namespace) {
137131
return;
138132
}
139133

140134
const msgObject: AssistantMessage = {
141135
__type: 'AssistantMessage',
142-
content,
143-
toolCalls,
144-
contentType,
136+
content: undefined,
137+
toolCalls: undefined,
138+
contentType: 'text',
145139
role: 'assistant',
146-
id,
140+
id: data.id,
141+
metadata: data.metadata,
147142
hidden,
148143
ctx: {},
149144
};
145+
if (data.__type === 'ImageData') {
146+
msgObject.content = data.url;
147+
msgObject.contentType = 'image';
148+
} else {
149+
msgObject.content = data.content;
150+
msgObject.toolCalls = data.toolCalls;
151+
}
150152

151153
const index = namespace.history.push(msgObject) - 1;
152-
if (id) {
153-
namespace.idRef[id] = namespace.history[index];
154+
if (data.id) {
155+
namespace.idRef[data.id] = namespace.history[index];
154156
}
155157

156158
msgObject.el = namespace.onAddMessage(msgObject);
157159
};
158160

159-
const updateAssistantMessage = (key: string, id: string, content: string) => {
161+
const updateAssistantMessage = (key: string, data: ServiceResponse) => {
160162
const namespace = _namespace[key];
161163
if (!namespace) {
162164
return;
163165
}
164166

165-
if (!namespace.idRef[id]) {
166-
addAssistantMessage(key, id, content, undefined, 'text', false);
167+
if (!namespace.idRef[data.id]) {
168+
addAssistantMessage(key, data, false);
167169
return;
168170
}
169171

170-
const msg = namespace.idRef[id];
171-
msg.content = content;
172+
const msg = namespace.idRef[data.id];
173+
174+
if (data.__type === 'ImageData') {
175+
msg.content = data.url;
176+
} else {
177+
msg.content = data.content;
178+
}
172179

173180
if (msg.__type === 'AssistantMessage' && msg.el && msg.el.update) {
174181
msg.el.update(msg);
@@ -191,19 +198,14 @@ export type ChatHistory = {
191198
| { content: string; contexts?: UserMessageContext[]; attachments?: UserAttachment[] },
192199
hidden?: boolean,
193200
) => void;
194-
addAssistantMessage: (
195-
id: string,
196-
content: string | undefined,
197-
toolCalls: ToolCalls | undefined,
198-
contentType: AssistantMessageContentType,
199-
hidden?: boolean,
200-
) => void;
201+
addAssistantMessage: (data: ServiceResponse, hidden?: boolean) => void;
202+
addToolCallsMessage: (toolCalls: ToolCalls, hidden?: boolean) => void;
201203
addToolResponseMessage: (
202204
id: string,
203205
content: ToolResponseMessage['content'],
204206
hidden?: boolean,
205207
) => void;
206-
updateAssistantMessage: (id: string, content: string) => void;
208+
updateAssistantMessage: (data: ServiceResponse) => void;
207209
getAssistantMessage: (id: string) => Message | undefined;
208210
getMessages: () => Message[];
209211
getMessagesHistory: () => Pick<
@@ -233,14 +235,31 @@ export const chatHistory = {
233235
const id = 'user-msg-' + Date.now() + Math.round(Math.random() * 1000);
234236
addUserMessage(key, id, content, hidden);
235237
},
236-
addAssistantMessage: (id, content, toolCalls, contentType, hidden = false) => {
237-
addAssistantMessage(key, id, content, toolCalls, contentType, hidden);
238+
addAssistantMessage: (data, hidden = false) => {
239+
addAssistantMessage(key, data, hidden);
240+
},
241+
242+
addToolCallsMessage: (toolCalls, hidden = false) => {
243+
addAssistantMessage(
244+
key,
245+
{
246+
__type: 'ToolsData',
247+
id: crypto.randomUUID(),
248+
content: undefined,
249+
toolCalls,
250+
usage: {
251+
completionTokens: 0,
252+
promptTokens: 0,
253+
},
254+
},
255+
hidden,
256+
);
238257
},
239258
addToolResponseMessage: (id, content, hidden = false) => {
240259
addToolResponseMessage(key, id, content, hidden);
241260
},
242-
updateAssistantMessage: (id, content) => {
243-
updateAssistantMessage(key, id, content);
261+
updateAssistantMessage: (data) => {
262+
updateAssistantMessage(key, data);
244263
},
245264
getAssistantMessage: (id) => {
246265
return getMessage(key, id);

_build/js/src/executor/apiClient.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,18 @@ export const aiFetch = async <D extends ServiceResponse>(
6969
return serviceExecutor<D>(data, onChunkStream, controller);
7070
}
7171

72-
const service = res.headers.get('x-modai-service') ?? 'openai';
73-
const parser = res.headers.get('x-modai-parser') ?? 'content';
72+
const service = res.headers.get('x-modai-service') ?? undefined;
73+
const parser = res.headers.get('x-modai-parser') ?? undefined;
74+
const model = res.headers.get('x-modai-model') ?? undefined;
7475

7576
try {
7677
if (stream) {
77-
const streamHandler = getStreamHandler(service, parser);
78+
const streamHandler = getStreamHandler(service, parser, model);
7879

7980
return (await streamHandler(res, onChunkStream as ChunkStream<TextData>, signal)) as D;
8081
}
8182

82-
const serviceParser = getServiceParser(service, parser);
83+
const serviceParser = getServiceParser(service, parser, model);
8384

8485
const data = await res.json();
8586

_build/js/src/executor/serviceExecutor.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ const callStreamService = async <D extends ServiceResponse>(
3838
onChunkStream?: ChunkStream<D>,
3939
signal?: AbortSignal,
4040
) => {
41-
const streamHandler = getStreamHandler(executorDetails.service, executorDetails.parser);
41+
const streamHandler = getStreamHandler(
42+
executorDetails.service,
43+
executorDetails.parser,
44+
executorDetails.model,
45+
);
4246

4347
const res = await fetch(executorDetails.url, {
4448
signal,
@@ -70,7 +74,11 @@ export const serviceExecutor = async <D extends ServiceResponse>(
7074
return (await callStreamService(executorDetails, onChunkStream, signal)) as D;
7175
}
7276

73-
const serviceParser = getServiceParser(executorDetails.service, executorDetails.parser);
77+
const serviceParser = getServiceParser(
78+
executorDetails.service,
79+
executorDetails.parser,
80+
executorDetails.model,
81+
);
7482

7583
const data = await callService(executorDetails, signal);
7684

_build/js/src/executor/services/index.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,31 @@ const services = {
1313
openrouter,
1414
};
1515

16-
export const getServiceParser = (service: string | undefined, parser: string | undefined) => {
17-
if (!service || !parser) {
16+
export const getServiceParser = (
17+
service: string | undefined,
18+
parser: string | undefined,
19+
model: string | undefined,
20+
) => {
21+
if (!service || !parser || !model) {
1822
throw new Error(lng('modai.error.service_required'));
1923
}
2024

2125
const serviceType = service as keyof typeof services;
2226
const parserType = parser as keyof ServiceHandler<unknown, unknown>;
2327

24-
if (!services[serviceType]?.[parserType]) {
28+
const serviceParser = services[serviceType]?.[parserType];
29+
30+
if (!serviceParser) {
2531
throw new Error(lng('modai.error.service_unsupported'));
2632
}
2733

28-
return services[serviceType]?.[parserType];
34+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35+
return (data: any) => {
36+
return {
37+
...serviceParser(data),
38+
metadata: {
39+
model,
40+
},
41+
};
42+
};
2943
};

_build/js/src/executor/streamHandlers/handlers/anthropic.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type StreamData =
3333
| { type: 'message_start'; message: { id: string; usage: { input_tokens: number } } }
3434
| { type: 'message_delta'; usage: { output_tokens: number } };
3535

36-
export const anthropic: StreamHandler = (chunk, buffer, currentData, onChunkStream) => {
36+
export const anthropic: StreamHandler = (chunk, buffer, currentData) => {
3737
buffer += chunk;
3838
let lastNewlineIndex = 0;
3939
let newlineIndex;
@@ -111,10 +111,6 @@ export const anthropic: StreamHandler = (chunk, buffer, currentData, onChunkStre
111111
promptTokens: currentData.usage.promptTokens || 0,
112112
},
113113
};
114-
115-
if (onChunkStream && currentData.content) {
116-
onChunkStream(currentData);
117-
}
118114
} catch {
119115
/* empty */
120116
}

_build/js/src/executor/streamHandlers/handlers/google.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type StreamData = {
1818
};
1919
};
2020

21-
export const google: StreamHandler = (chunk, buffer, currentData, onChunkStream) => {
21+
export const google: StreamHandler = (chunk, buffer, currentData) => {
2222
const jsonLines = chunk
2323
.trim()
2424
.split(',\r\n')
@@ -63,10 +63,6 @@ export const google: StreamHandler = (chunk, buffer, currentData, onChunkStream)
6363
promptTokens: parsedData?.usageMetadata.promptTokenCount,
6464
},
6565
};
66-
67-
if (onChunkStream && currentData.content) {
68-
onChunkStream(currentData);
69-
}
7066
} catch {
7167
/* empty */
7268
}

_build/js/src/executor/streamHandlers/handlers/openai.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type StreamData = {
2222
};
2323
};
2424

25-
export const openai: StreamHandler = (chunk, buffer, currentData, onChunkStream) => {
25+
export const openai: StreamHandler = (chunk, buffer, currentData) => {
2626
buffer += chunk;
2727
let lastNewlineIndex = 0;
2828
let newlineIndex;
@@ -52,10 +52,6 @@ export const openai: StreamHandler = (chunk, buffer, currentData, onChunkStream)
5252
!parsedData?.choices?.[0]?.delta?.tool_calls &&
5353
!parsedData?.choices?.[0]?.delta?.content
5454
) {
55-
if (onChunkStream && currentData?.content) {
56-
onChunkStream(currentData);
57-
}
58-
5955
continue;
6056
}
6157

@@ -96,18 +92,14 @@ export const openai: StreamHandler = (chunk, buffer, currentData, onChunkStream)
9692

9793
currentData = {
9894
__type: 'TextDataMaybeTools',
99-
id: currentData.id,
95+
id: parsedData.id,
10096
content: (currentData.content ?? '') + content,
10197
toolCalls,
10298
usage: {
10399
completionTokens: currentData.usage.completionTokens ?? 0,
104100
promptTokens: currentData.usage.promptTokens ?? 0,
105101
},
106102
};
107-
108-
if (onChunkStream && currentData?.content) {
109-
onChunkStream(currentData);
110-
}
111103
} catch {
112104
/* empty */
113105
}

_build/js/src/executor/streamHandlers/handlers/openrouter.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type StreamData = {
2222
};
2323
};
2424

25-
export const openrouter: StreamHandler = (chunk, buffer, currentData, onChunkStream) => {
25+
export const openrouter: StreamHandler = (chunk, buffer, currentData) => {
2626
buffer += chunk;
2727
let lastNewlineIndex = 0;
2828
let newlineIndex;
@@ -52,10 +52,6 @@ export const openrouter: StreamHandler = (chunk, buffer, currentData, onChunkStr
5252
!parsedData?.choices?.[0]?.delta?.tool_calls &&
5353
!parsedData?.choices?.[0]?.delta?.content
5454
) {
55-
if (onChunkStream && currentData?.content) {
56-
onChunkStream(currentData);
57-
}
58-
5955
continue;
6056
}
6157

@@ -96,18 +92,14 @@ export const openrouter: StreamHandler = (chunk, buffer, currentData, onChunkStr
9692

9793
currentData = {
9894
__type: 'TextDataMaybeTools',
99-
id: currentData.id,
95+
id: parsedData.id,
10096
content: (currentData.content ?? '') + content,
10197
toolCalls,
10298
usage: {
10399
completionTokens: currentData.usage.completionTokens ?? 0,
104100
promptTokens: currentData.usage.promptTokens ?? 0,
105101
},
106102
};
107-
108-
if (onChunkStream && currentData?.content) {
109-
onChunkStream(currentData);
110-
}
111103
} catch {
112104
/* empty */
113105
}

0 commit comments

Comments
 (0)