Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/presenter/configPresenter/providerDbLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ export class ProviderDbLoader {
return provider.models.find((m) => m.id === modelId)
}

getSourceUrl(): string {
return this.readMeta()?.sourceUrl?.trim() || this.getProviderDbUrl()
}

private loadFromCache(): ProviderAggregate | null {
try {
if (!fs.existsSync(this.cacheFilePath)) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export class CompactionService {
contextLength: number
reserveTokens: number
supportsVision: boolean
preserveInterleavedReasoning: boolean
newUserContent: string | SendMessageInput
}): CompactionIntent | null {
const settings = this.getCompactionSettings()
Expand Down Expand Up @@ -239,6 +240,7 @@ export class CompactionService {
contextLength: number
reserveTokens: number
supportsVision: boolean
preserveInterleavedReasoning: boolean
}): CompactionIntent | null {
const settings = this.getCompactionSettings()
if (!settings.enabled) {
Expand Down Expand Up @@ -322,6 +324,7 @@ export class CompactionService {
contextLength: number
reserveTokens: number
supportsVision: boolean
preserveInterleavedReasoning: boolean
records: ChatMessageRecord[]
protectedTurnCount: number
triggerThreshold: number
Expand All @@ -335,7 +338,11 @@ export class CompactionService {
return null
}

const turns = buildHistoryTurns(scopedRecords, params.supportsVision)
const turns = buildHistoryTurns(
scopedRecords,
params.supportsVision,
params.preserveInterleavedReasoning
)
Comment thread
zerob13 marked this conversation as resolved.
if (turns.length === 0) {
return null
}
Expand Down
40 changes: 32 additions & 8 deletions src/main/presenter/deepchatAgentPresenter/contextBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type ContextBuildOptions = {
summaryCursorOrderSeq?: number
historyRecords?: ChatMessageRecord[]
fallbackProtectedTurnCount?: number
preserveInterleavedReasoning?: boolean
}

type TokenizedTurn = {
Expand Down Expand Up @@ -216,7 +217,8 @@ export function estimateMessagesTokens(messages: ChatMessage[]): number {
*/
export function recordToChatMessages(
record: ChatMessageRecord,
supportsVision: boolean
supportsVision: boolean,
preserveInterleavedReasoning: boolean = false
): ChatMessage[] {
if (isCompactionRecord(record)) {
return []
Expand All @@ -228,10 +230,18 @@ export function recordToChatMessages(
}

const blocks = JSON.parse(record.content) as AssistantMessageBlock[]
const text = blocks
const combinedText = blocks
.filter((block) => block.type === 'content' || block.type === 'reasoning_content')
.map((block) => block.content)
.join('')
const text = blocks
.filter((block) => block.type === 'content')
.map((block) => block.content)
.join('')
const reasoning = blocks
.filter((block) => block.type === 'reasoning_content')
.map((block) => block.content)
.join('')

const toolCallBlocks = blocks.filter(
(block) =>
Expand All @@ -244,7 +254,7 @@ export function recordToChatMessages(
)

if (toolCallBlocks.length === 0) {
return [{ role: 'assistant', content: text }]
return [{ role: 'assistant', content: combinedText }]
Comment thread
zerob13 marked this conversation as resolved.
}

const toolCalls: NonNullable<ChatMessage['tool_calls']> = []
Expand All @@ -261,14 +271,17 @@ export function recordToChatMessages(
}

if (toolCalls.length === 0) {
return [{ role: 'assistant', content: text }]
return [{ role: 'assistant', content: combinedText }]
}

const assistantMessage: ChatMessage = {
role: 'assistant',
content: text,
tool_calls: toolCalls
}
if (preserveInterleavedReasoning && reasoning) {
assistantMessage.reasoning_content = reasoning
}

const result: ChatMessage[] = [assistantMessage]
for (const block of toolCallBlocks) {
Expand All @@ -284,7 +297,8 @@ export function recordToChatMessages(

export function buildHistoryTurns(
records: ChatMessageRecord[],
supportsVision: boolean
supportsVision: boolean,
preserveInterleavedReasoning: boolean = false
Comment thread
coderabbitai[bot] marked this conversation as resolved.
): HistoryTurn[] {
const sortedRecords = [...records].sort((a, b) => a.orderSeq - b.orderSeq)
const turns: ChatMessageRecord[][] = []
Expand All @@ -310,7 +324,9 @@ export function buildHistoryTurns(
}

return turns.map((turnRecords) => {
const messages = turnRecords.flatMap((record) => recordToChatMessages(record, supportsVision))
const messages = turnRecords.flatMap((record) =>
recordToChatMessages(record, supportsVision, preserveInterleavedReasoning)
)
return {
records: turnRecords,
messages,
Expand Down Expand Up @@ -440,7 +456,11 @@ export function buildContext(
options.historyRecords ??
messageStore.getMessages(sessionId).filter((message) => message.status === 'sent')
const historyRecords = filterRecordsFromCursor(sentRecords, options.summaryCursorOrderSeq ?? 1)
const historyTurns = buildHistoryTurns(historyRecords, supportsVision)
const historyTurns = buildHistoryTurns(
historyRecords,
supportsVision,
options.preserveInterleavedReasoning ?? false
)

const newUserMessage = createUserChatMessage(newUserContent, supportsVision)
const systemPromptTokens = systemPrompt ? approximateTokenSize(systemPrompt) : 0
Expand Down Expand Up @@ -530,7 +550,11 @@ export function buildResumeContext(
return message.orderSeq >= cursor
})

const historyTurns = buildHistoryTurns(historyRecords, supportsVision)
const historyTurns = buildHistoryTurns(
historyRecords,
supportsVision,
options.preserveInterleavedReasoning ?? false
)
const systemPromptTokens = systemPrompt ? approximateTokenSize(systemPrompt) : 0
const available = contextLength - systemPromptTokens - reserveTokens
const selectedHistory = selectTurnHistory(
Expand Down
41 changes: 27 additions & 14 deletions src/main/presenter/deepchatAgentPresenter/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import type { SearchResult } from '@shared/types/core/search'
import type { IToolPresenter } from '@shared/types/presenters/tool.presenter'
import type { AssistantMessageBlock, PermissionMode } from '@shared/types/agent-interface'
import { parseQuestionToolArgs, QUESTION_TOOL_NAME } from '../../lib/agentRuntime/questionTool'
import type { IoParams, PendingToolInteraction, ProcessHooks, StreamState } from './types'
import type {
InterleavedReasoningConfig,
IoParams,
PendingToolInteraction,
ProcessHooks,
StreamState
} from './types'
import type { ChatMessage } from '@shared/types/core/chat-message'
import { nanoid } from 'nanoid'
import type { ToolOutputGuard } from './toolOutputGuard'
Expand Down Expand Up @@ -48,15 +54,6 @@ function extractReasoningFromBlocks(blocks: AssistantMessageBlock[]): string {
.join('')
}

function requiresReasoningField(modelId: string): boolean {
const lower = modelId.toLowerCase()
return (
lower.includes('deepseek-reasoner') ||
lower.includes('kimi-k2-thinking') ||
lower.includes('glm-4.7')
)
}

function toolResponseToText(content: string | MCPContentItem[]): string {
if (typeof content === 'string') return content
return content
Expand Down Expand Up @@ -391,6 +388,7 @@ export async function executeTools(
tools: MCPToolDefinition[],
toolPresenter: IToolPresenter,
modelId: string,
interleavedReasoning: InterleavedReasoningConfig,
io: IoParams,
permissionMode: PermissionMode,
toolOutputGuard: ToolOutputGuard,
Expand Down Expand Up @@ -425,10 +423,25 @@ export async function executeTools(
}))
}

if (requiresReasoningField(modelId)) {
const reasoning = extractReasoningFromBlocks(iterationBlocks)
if (reasoning) {
assistantMessage.reasoning_content = reasoning
const reasoning = extractReasoningFromBlocks(iterationBlocks)
if (interleavedReasoning.preserveReasoningContent && reasoning) {
assistantMessage.reasoning_content = reasoning
} else if (
reasoning &&
interleavedReasoning.reasoningSupported &&
!interleavedReasoning.forcedBySessionSetting &&
!interleavedReasoning.portraitInterleaved
) {
const gapPayload = {
providerId: providerId?.trim() || 'unknown-provider',
modelId,
providerDbSourceUrl: interleavedReasoning.providerDbSourceUrl,
reasoningContentLength: reasoning.length,
toolCallCount: state.completedToolCalls.length
}
hooks?.onInterleavedReasoningGap?.(gapPayload)
if (!hooks?.onInterleavedReasoningGap) {
console.warn('[DeepChatDispatch] Missing interleaved reasoning portrait:', gapPayload)
}
}

Expand Down
Loading
Loading