Compare commits

...

2 Commits

Author SHA1 Message Date
suyao
229a8f60b2 fix: ci 2025-08-14 21:15:40 +08:00
suyao
aa635eba88 fix/magistral-2507 2025-08-14 21:09:00 +08:00
5 changed files with 62 additions and 21 deletions

View File

@@ -270,7 +270,7 @@
"winston-daily-rotate-file": "^5.0.0",
"word-extractor": "^1.0.4",
"zipread": "^1.3.3",
"zod": "^3.25.74"
"zod": "^4.0.0"
},
"resolutions": {
"pdf-parse@npm:1.1.1": "patch:pdf-parse@npm%3A1.1.1#~/.yarn/patches/pdf-parse-npm-1.1.1-04a6109b2a.patch",

View File

@@ -4,7 +4,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
import { JSDOM } from 'jsdom'
import TurndownService from 'turndown'
import { z } from 'zod'
import { z } from 'zod/v3'
export const RequestPayloadSchema = z.object({
url: z.string().url(),

View File

@@ -52,6 +52,7 @@ import {
import { ChunkType, TextStartChunk, ThinkingStartChunk } from '@renderer/types/chunk'
import { Message } from '@renderer/types/newMessage'
import {
MistralDeltaSchema,
OpenAISdkMessageParam,
OpenAISdkParams,
OpenAISdkRawChunk,
@@ -804,7 +805,8 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
(typeof choice.delta.content === 'string' && choice.delta.content !== '') ||
(typeof (choice.delta as any).reasoning_content === 'string' &&
(choice.delta as any).reasoning_content !== '') ||
(typeof (choice.delta as any).reasoning === 'string' && (choice.delta as any).reasoning !== ''))
(typeof (choice.delta as any).reasoning === 'string' && (choice.delta as any).reasoning !== '') ||
Array.isArray(choice.delta.content))
) {
contentSource = choice.delta
} else if ('message' in choice) {
@@ -815,8 +817,15 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
if (!contentSource?.content) {
accumulatingText = false
}
// @ts-ignore - reasoning_content is not in standard OpenAI types but some providers use it
if (!contentSource?.reasoning_content && !contentSource?.reasoning) {
const mistralDelta = MistralDeltaSchema.safeParse(contentSource?.content)
if (
// @ts-ignore - reasoning_content is not in standard OpenAI types but some providers use it
!contentSource?.reasoning_content &&
// @ts-ignore - reasoning is not in standard OpenAI types but some providers use it
!contentSource?.reasoning &&
(mistralDelta.data?.[0]?.type !== 'thinking' || !mistralDelta.success)
) {
isThinking = false
}
@@ -850,12 +859,14 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
}
// 处理推理内容 (e.g. from OpenRouter DeepSeek-R1)
// @ts-ignore - reasoning_content is not in standard OpenAI types but some providers use it
const reasoningText = contentSource.reasoning_content || contentSource.reasoning
const reasoningText =
// @ts-ignore - reasoning_content is not in standard OpenAI types but some providers use it
contentSource.reasoning_content ||
// @ts-ignore - reasoning_content is not in standard OpenAI types but some providers use it
contentSource.reasoning ||
(mistralDelta.data?.[0]?.type === 'thinking' ? mistralDelta.data?.[0]?.thinking[0]?.text : undefined)
if (reasoningText) {
// logger.silly('since reasoningText is trusy, try to enqueue THINKING_START AND THINKING_DELTA')
if (!isThinking) {
// logger.silly('since isThinking is falsy, try to enqueue THINKING_START')
controller.enqueue({
type: ChunkType.THINKING_START
} as ThinkingStartChunk)
@@ -872,22 +883,35 @@ export class OpenAIAPIClient extends OpenAIBaseClient<
}
// 处理文本内容
if (contentSource.content) {
// logger.silly('since contentSource.content is trusy, try to enqueue TEXT_START and TEXT_DELTA')
if (mistralDelta.success && mistralDelta.data?.[0]?.type === 'text') {
if (!accumulatingText) {
// logger.silly('enqueue TEXT_START')
controller.enqueue({
type: ChunkType.TEXT_START
} as TextStartChunk)
accumulatingText = true
}
// logger.silly('enqueue TEXT_DELTA')
controller.enqueue({
type: ChunkType.TEXT_DELTA,
text: contentSource.content
text: mistralDelta.data?.[0]?.text
})
} else {
accumulatingText = false
} else if (!mistralDelta.success) {
if (contentSource.content) {
// logger.silly('since contentSource.content is trusy, try to enqueue TEXT_START and TEXT_DELTA')
if (!accumulatingText) {
// logger.silly('enqueue TEXT_START')
controller.enqueue({
type: ChunkType.TEXT_START
} as TextStartChunk)
accumulatingText = true
}
// logger.silly('enqueue TEXT_DELTA')
controller.enqueue({
type: ChunkType.TEXT_DELTA,
text: contentSource.content
})
} else {
accumulatingText = false
}
}
// 处理工具调用

View File

@@ -23,6 +23,7 @@ import {
} from '@google/genai'
import OpenAI, { AzureOpenAI } from 'openai'
import { Stream } from 'openai/streaming'
import * as z from 'zod'
import { EndpointType } from './index'
@@ -260,3 +261,19 @@ export interface AwsBedrockSdkToolCall {
input: any
toolUseId: string
}
export const MistralDeltaTextSchema = z.object({
type: z.literal('text'),
text: z.string()
})
export const MistralDeltaThinkingSchema = z.object({
type: z.literal('thinking'),
thinking: z.array(MistralDeltaTextSchema)
})
export const MistralDeltaSchema = z.array(
z.discriminatedUnion('type', [MistralDeltaTextSchema, MistralDeltaThinkingSchema])
)
export type MistralDelta = z.infer<typeof MistralDeltaSchema>

View File

@@ -8650,7 +8650,7 @@ __metadata:
winston-daily-rotate-file: "npm:^5.0.0"
word-extractor: "npm:^1.0.4"
zipread: "npm:^1.3.3"
zod: "npm:^3.25.74"
zod: "npm:^4.0.0"
languageName: unknown
linkType: soft
@@ -22669,10 +22669,10 @@ __metadata:
languageName: node
linkType: hard
"zod@npm:^3.25.74":
version: 3.25.74
resolution: "zod@npm:3.25.74"
checksum: 10c0/59e38b046ac333b5bd1ba325a83b6798721227cbfb1e69dfc7159bd7824b904241ab923026edb714fafefec3624265ae374a70aee9a5a45b365bd31781ffa105
"zod@npm:^4.0.0":
version: 4.0.17
resolution: "zod@npm:4.0.17"
checksum: 10c0/c56ef4cc02f8f52be8724c5a8b338266202d68477c7606bee9b7299818b75c9adc27f16f4b6704a372f3e7578bd016f389de19bfec766564b7c39d0d327c540a
languageName: node
linkType: hard