Skip to content

Commit 00cba71

Browse files
authored
🐛 fix: fix mistral can not chat (#6828)
* ♻️ refactor: refactor the implement * fix mistral issue * improve log * refactor to the getXXXStoreState * fix tests
1 parent 86544a8 commit 00cba71

File tree

24 files changed

+157
-133
lines changed

24 files changed

+157
-133
lines changed

packages/web-crawler/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"@mozilla/readability": "^0.5.0",
99
"happy-dom": "^17.0.0",
1010
"node-html-markdown": "^1.3.0",
11-
"query-string": "^9.1.1"
11+
"query-string": "^9.1.1",
12+
"url-join": "^5"
1213
}
1314
}

packages/web-crawler/src/crawImpl/browserless.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import qs from 'query-string';
2+
import urlJoin from 'url-join';
23

34
import { CrawlImpl, CrawlSuccessResult } from '../type';
45
import { htmlToMarkdown } from '../utils/htmlToMarkdown';
@@ -25,7 +26,7 @@ export const browserless: CrawlImpl = async (url, { filterOptions }) => {
2526

2627
try {
2728
const res = await fetch(
28-
qs.stringifyUrl({ query: { token: BROWSERLESS_TOKEN }, url: `${BASE_URL}/content` }),
29+
qs.stringifyUrl({ query: { token: BROWSERLESS_TOKEN }, url: urlJoin(BASE_URL, '/content') }),
2930
{
3031
body: JSON.stringify(input),
3132
headers: {

packages/web-crawler/src/urlRules.ts

+6
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,10 @@ export const crawUrlRules: CrawlUrlRule[] = [
6161
},
6262
urlPattern: 'https://www.qiumiwu.com/standings/(.*)',
6363
},
64+
65+
// mozilla use jina
66+
{
67+
impls: ['jina'],
68+
urlPattern: 'https://developer.mozilla.org(.*)',
69+
},
6470
];

src/features/Conversation/Extras/Usage/UsageDetail/ModelCard.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,6 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
112112
</Flexbox>
113113
</Tooltip>
114114
)}
115-
<Tooltip title={t('messages.modelCard.pricing.inputTokens', { amount: inputPrice })}>
116-
<Flexbox gap={2} horizontal>
117-
<Icon icon={ArrowUpFromDot} />
118-
{inputPrice}
119-
</Flexbox>
120-
</Tooltip>
121115
{pricing?.writeCacheInput && (
122116
<Tooltip
123117
title={t('messages.modelCard.pricing.writeCacheInputTokens', {
@@ -130,6 +124,12 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
130124
</Flexbox>
131125
</Tooltip>
132126
)}
127+
<Tooltip title={t('messages.modelCard.pricing.inputTokens', { amount: inputPrice })}>
128+
<Flexbox gap={2} horizontal>
129+
<Icon icon={ArrowUpFromDot} />
130+
{inputPrice}
131+
</Flexbox>
132+
</Tooltip>
133133
<Tooltip title={t('messages.modelCard.pricing.outputTokens', { amount: outputPrice })}>
134134
<Flexbox gap={2} horizontal>
135135
<Icon icon={ArrowDownToDot} />

src/features/Conversation/Extras/Usage/UsageDetail/index.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -138,20 +138,20 @@ const TokenDetail = memo<TokenDetailProps>(({ usage, model, provider }) => {
138138
</Flexbox>
139139
)}
140140
{outputDetails.length > 1 && (
141-
<>
141+
<Flexbox gap={4}>
142142
<Flexbox
143143
align={'center'}
144144
gap={4}
145145
horizontal
146146
justify={'space-between'}
147147
width={'100%'}
148148
>
149-
<div style={{ color: theme.colorTextDescription }}>
149+
<div style={{ color: theme.colorTextDescription, fontSize: 12 }}>
150150
{t('messages.tokenDetails.outputTitle')}
151151
</div>
152152
</Flexbox>
153153
<TokenProgress data={outputDetails} showIcon />
154-
</>
154+
</Flexbox>
155155
)}
156156
<Flexbox>
157157
<TokenProgress data={totalDetail} showIcon />

src/libs/agent-runtime/mistral/index.test.ts

-3
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,6 @@ describe('specific LobeMistralAI tests', () => {
5757
messages: [{ content: 'Hello', role: 'user' }],
5858
model: 'open-mistral-7b',
5959
stream: true,
60-
stream_options: {
61-
include_usage: true,
62-
},
6360
temperature: 0.35,
6461
top_p: 1,
6562
},

src/libs/agent-runtime/mistral/index.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import type { ChatModelCard } from '@/types/llm';
2+
13
import { ModelProvider } from '../types';
24
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
35

4-
import type { ChatModelCard } from '@/types/llm';
5-
66
export interface MistralModelCard {
77
capabilities: {
88
function_calling: boolean;
@@ -16,6 +16,9 @@ export interface MistralModelCard {
1616
export const LobeMistralAI = LobeOpenAICompatibleFactory({
1717
baseURL: 'https://api.mistral.ai/v1',
1818
chatCompletion: {
19+
// Mistral API does not support stream_options: { include_usage: true }
20+
// refs: https://github.com/lobehub/lobe-chat/issues/6825
21+
excludeUsage: true,
1922
handlePayload: (payload) => ({
2023
...(payload.max_tokens !== undefined && { max_tokens: payload.max_tokens }),
2124
messages: payload.messages as any,
@@ -33,12 +36,14 @@ export const LobeMistralAI = LobeOpenAICompatibleFactory({
3336
models: async ({ client }) => {
3437
const { LOBE_DEFAULT_MODEL_LIST } = await import('@/config/aiModels');
3538

36-
const modelsPage = await client.models.list() as any;
39+
const modelsPage = (await client.models.list()) as any;
3740
const modelList: MistralModelCard[] = modelsPage.data;
3841

3942
return modelList
4043
.map((model) => {
41-
const knownModel = LOBE_DEFAULT_MODEL_LIST.find((m) => model.id.toLowerCase() === m.id.toLowerCase());
44+
const knownModel = LOBE_DEFAULT_MODEL_LIST.find(
45+
(m) => model.id.toLowerCase() === m.id.toLowerCase(),
46+
);
4247

4348
return {
4449
contextWindowTokens: model.max_context_length,
@@ -47,9 +52,7 @@ export const LobeMistralAI = LobeOpenAICompatibleFactory({
4752
enabled: knownModel?.enabled || false,
4853
functionCall: model.capabilities.function_calling,
4954
id: model.id,
50-
reasoning:
51-
knownModel?.abilities?.reasoning
52-
|| false,
55+
reasoning: knownModel?.abilities?.reasoning || false,
5356
vision: model.capabilities.vision,
5457
};
5558
})

src/libs/agent-runtime/utils/debugStream.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const debugStream = async (stream: ReadableStream) => {
3535

3636
console.log(`[chunk ${chunk}] ${getTime()}`);
3737
console.log(chunkValue);
38-
console.log(`\n`);
38+
console.log('');
3939

4040
finished = done;
4141
chunk++;

src/libs/agent-runtime/utils/openaiCompatibleFactory/index.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ interface OpenAICompatibleFactoryOptions<T extends Record<string, any> = any> {
5757
apiKey?: string;
5858
baseURL?: string;
5959
chatCompletion?: {
60+
excludeUsage?: boolean;
6061
handleError?: (
6162
error: any,
6263
options: ConstructorOptions<T>,
@@ -224,12 +225,17 @@ export const LobeOpenAICompatibleFactory = <T extends Record<string, any> = any>
224225
...postPayload,
225226
messages,
226227
...(chatCompletion?.noUserId ? {} : { user: options?.user }),
227-
stream_options: postPayload.stream ? { include_usage: true } : undefined,
228+
stream_options:
229+
postPayload.stream && !chatCompletion?.excludeUsage
230+
? { include_usage: true }
231+
: undefined,
228232
};
229233

230234
if (debug?.chatCompletion?.()) {
231-
console.log('[requestPayload]:', JSON.stringify(finalPayload, null, 2));
235+
console.log('[requestPayload]');
236+
console.log(JSON.stringify(finalPayload), '\n');
232237
}
238+
233239
response = await this.client.chat.completions.create(finalPayload, {
234240
// https://github.com/lobehub/lobe-chat/pull/318
235241
headers: { Accept: '*/*', ...options?.requestHeaders },

src/services/chat.ts

+19-13
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ import {
1717
} from '@/libs/agent-runtime';
1818
import { filesPrompts } from '@/prompts/files';
1919
import { BuiltinSystemRolePrompts } from '@/prompts/systemRole';
20-
import { aiModelSelectors, aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
21-
import { getAgentChatConfig } from '@/store/chat/slices/aiChat/actions/helpers';
22-
import { useSessionStore } from '@/store/session';
20+
import { getAgentStoreState } from '@/store/agent';
21+
import { agentChatConfigSelectors } from '@/store/agent/selectors';
22+
import {
23+
aiModelSelectors,
24+
aiProviderSelectors,
25+
getAiInfraStoreState,
26+
useAiInfraStore,
27+
} from '@/store/aiInfra';
28+
import { getSessionStoreState } from '@/store/session';
2329
import { sessionMetaSelectors } from '@/store/session/selectors';
24-
import { useToolStore } from '@/store/tool';
30+
import { getToolStoreState } from '@/store/tool';
2531
import { pluginSelectors, toolSelectors } from '@/store/tool/selectors';
26-
import { useUserStore } from '@/store/user';
32+
import { getUserStoreState, useUserStore } from '@/store/user';
2733
import {
2834
modelConfigSelectors,
2935
modelProviderSelectors,
@@ -46,10 +52,10 @@ import { API_ENDPOINTS } from './_url';
4652
const isCanUseFC = (model: string, provider: string) => {
4753
// TODO: remove isDeprecatedEdition condition in V2.0
4854
if (isDeprecatedEdition) {
49-
return modelProviderSelectors.isModelEnabledFunctionCall(model)(useUserStore.getState());
55+
return modelProviderSelectors.isModelEnabledFunctionCall(model)(getUserStoreState());
5056
}
5157

52-
return aiModelSelectors.isModelSupportToolUse(model, provider)(useAiInfraStore.getState());
58+
return aiModelSelectors.isModelSupportToolUse(model, provider)(getAiInfraStoreState());
5359
};
5460

5561
/**
@@ -169,7 +175,7 @@ class ChatService {
169175
);
170176

171177
// =================== 0. process search =================== //
172-
const chatConfig = getAgentChatConfig();
178+
const chatConfig = agentChatConfigSelectors.currentChatConfig(getAgentStoreState());
173179

174180
const enabledSearch = chatConfig.searchMode !== 'off';
175181
const isModelHasBuiltinSearch = aiModelSelectors.isModelHasBuiltinSearch(
@@ -200,7 +206,7 @@ class ChatService {
200206

201207
// ============ 2. preprocess tools ============ //
202208

203-
let filterTools = toolSelectors.enabledSchema(pluginIds)(useToolStore.getState());
209+
let filterTools = toolSelectors.enabledSchema(pluginIds)(getToolStoreState());
204210

205211
// check this model can use function call
206212
const canUseFC = isCanUseFC(payload.model, payload.provider!);
@@ -378,7 +384,7 @@ class ChatService {
378384
* @param options
379385
*/
380386
runPluginApi = async (params: PluginRequestPayload, options?: FetchOptions) => {
381-
const s = useToolStore.getState();
387+
const s = getToolStoreState();
382388

383389
const settings = pluginSelectors.getPluginSettingsById(params.identifier)(s);
384390
const manifest = pluginSelectors.getToolManifestById(params.identifier)(s);
@@ -537,7 +543,7 @@ class ChatService {
537543
const hasTools = tools && tools?.length > 0;
538544
const hasFC = hasTools && isCanUseFC(model, provider);
539545
const toolsSystemRoles =
540-
hasFC && toolSelectors.enabledSystemRoles(tools)(useToolStore.getState());
546+
hasFC && toolSelectors.enabledSystemRoles(tools)(getToolStoreState());
541547

542548
const injectSystemRoles = BuiltinSystemRolePrompts({
543549
historySummary: options?.historySummary,
@@ -565,9 +571,9 @@ class ChatService {
565571
};
566572

567573
private mapTrace = (trace?: TracePayload, tag?: TraceTagMap): TracePayload => {
568-
const tags = sessionMetaSelectors.currentAgentMeta(useSessionStore.getState()).tags || [];
574+
const tags = sessionMetaSelectors.currentAgentMeta(getSessionStoreState()).tags || [];
569575

570-
const enabled = preferenceSelectors.userAllowTrace(useUserStore.getState());
576+
const enabled = preferenceSelectors.userAllowTrace(getUserStoreState());
571577

572578
if (!enabled) return { ...trace, enabled: false };
573579

src/store/agent/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export type { AgentStore } from './store';
2-
export { useAgentStore } from './store';
2+
export { getAgentStoreState, useAgentStore } from './store';

src/store/agent/slices/chat/selectors/chatConfig.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { contextCachingModels, thinkingWithToolClaudeModels } from '@/const/models';
2+
import { DEFAULT_AGENT_CHAT_CONFIG } from '@/const/settings';
23
import { AgentStoreState } from '@/store/agent/initialState';
34
import { LobeAgentChatConfig } from '@/types/agent';
45

@@ -30,10 +31,10 @@ const enableHistoryCount = (s: AgentStoreState) => {
3031
return chatConfig.enableHistoryCount;
3132
};
3233

33-
const historyCount = (s: AgentStoreState) => {
34+
const historyCount = (s: AgentStoreState): number => {
3435
const chatConfig = currentAgentChatConfig(s);
3536

36-
return chatConfig.historyCount;
37+
return chatConfig.historyCount || (DEFAULT_AGENT_CHAT_CONFIG.historyCount as number);
3738
};
3839

3940
const displayMode = (s: AgentStoreState) => {

src/store/agent/store.ts

+2
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ const createStore: StateCreator<AgentStore, [['zustand/devtools', never]]> = (..
2020
const devtools = createDevtools('agent');
2121

2222
export const useAgentStore = createWithEqualityFn<AgentStore>()(devtools(createStore), shallow);
23+
24+
export const getAgentStoreState = () => useAgentStore.getState();

src/store/aiInfra/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './selectors';
2-
export { useAiInfraStore } from './store';
2+
export { getAiInfraStoreState,useAiInfraStore } from './store';

src/store/aiInfra/store.ts

+2
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,5 @@ const createStore: StateCreator<AiInfraStore, [['zustand/devtools', never]]> = (
2323
const devtools = createDevtools('aiInfra');
2424

2525
export const useAiInfraStore = createWithEqualityFn<AiInfraStore>()(devtools(createStore), shallow);
26+
27+
export const getAiInfraStoreState = () => useAiInfraStore.getState();

0 commit comments

Comments
 (0)