Skip to content

Commit 31f6455

Browse files
authored
Merge pull request #329 from Opencode-DCP/dev
merge dev into master
2 parents 76efa32 + 005730a commit 31f6455

File tree

4 files changed

+74
-54
lines changed

4 files changed

+74
-54
lines changed

lib/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,15 +450,15 @@ const defaultConfig: PluginConfig = {
450450
strategies: {
451451
deduplication: {
452452
enabled: true,
453-
protectedTools: [...DEFAULT_PROTECTED_TOOLS],
453+
protectedTools: [],
454454
},
455455
supersedeWrites: {
456456
enabled: false,
457457
},
458458
purgeErrors: {
459459
enabled: true,
460460
turns: 4,
461-
protectedTools: [...DEFAULT_PROTECTED_TOOLS],
461+
protectedTools: [],
462462
},
463463
},
464464
}

lib/messages/inject.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
buildToolIdList,
99
createSyntheticAssistantMessage,
1010
createSyntheticUserMessage,
11+
createSyntheticToolPart,
12+
isDeepSeekOrKimi,
1113
isIgnoredUserMessage,
1214
} from "./utils"
1315
import { getFilePathFromParameters, isProtectedFilePath } from "../protected-file-patterns"
@@ -142,15 +144,28 @@ export const insertPruneToolContext = (
142144
const userInfo = lastUserMessage.info as UserMessage
143145
const variant = state.variant ?? userInfo.variant
144146

145-
const lastMessage = messages[messages.length - 1]
146-
const isLastMessageUser =
147-
lastMessage?.info?.role === "user" && !isIgnoredUserMessage(lastMessage)
147+
let lastNonIgnoredMessage: WithParts | undefined
148+
for (let i = messages.length - 1; i >= 0; i--) {
149+
const msg = messages[i]
150+
if (!(msg.info.role === "user" && isIgnoredUserMessage(msg))) {
151+
lastNonIgnoredMessage = msg
152+
break
153+
}
154+
}
148155

149-
if (isLastMessageUser) {
156+
if (!lastNonIgnoredMessage || lastNonIgnoredMessage.info.role === "user") {
150157
messages.push(createSyntheticUserMessage(lastUserMessage, prunableToolsContent, variant))
151158
} else {
152-
messages.push(
153-
createSyntheticAssistantMessage(lastUserMessage, prunableToolsContent, variant),
154-
)
159+
const providerID = userInfo.model?.providerID || ""
160+
const modelID = userInfo.model?.modelID || ""
161+
162+
if (isDeepSeekOrKimi(providerID, modelID)) {
163+
const toolPart = createSyntheticToolPart(lastNonIgnoredMessage, prunableToolsContent)
164+
lastNonIgnoredMessage.parts.push(toolPart)
165+
} else {
166+
messages.push(
167+
createSyntheticAssistantMessage(lastUserMessage, prunableToolsContent, variant),
168+
)
169+
}
155170
}
156171
}

lib/messages/utils.ts

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ const SYNTHETIC_MESSAGE_ID = "msg_01234567890123456789012345"
77
const SYNTHETIC_PART_ID = "prt_01234567890123456789012345"
88
const SYNTHETIC_CALL_ID = "call_01234567890123456789012345"
99

10-
const isGeminiModel = (modelID: string): boolean => {
10+
export const isDeepSeekOrKimi = (providerID: string, modelID: string): boolean => {
11+
const lowerProviderID = providerID.toLowerCase()
1112
const lowerModelID = modelID.toLowerCase()
12-
return lowerModelID.includes("gemini")
13+
return (
14+
lowerProviderID.includes("deepseek") ||
15+
lowerProviderID.includes("kimi") ||
16+
lowerModelID.includes("deepseek") ||
17+
lowerModelID.includes("kimi")
18+
)
1319
}
1420

1521
export const createSyntheticUserMessage = (
@@ -50,54 +56,59 @@ export const createSyntheticAssistantMessage = (
5056
const userInfo = baseMessage.info as UserMessage
5157
const now = Date.now()
5258

53-
const baseInfo = {
54-
id: SYNTHETIC_MESSAGE_ID,
55-
sessionID: userInfo.sessionID,
56-
role: "assistant" as const,
57-
agent: userInfo.agent || "code",
58-
parentID: userInfo.id,
59-
modelID: userInfo.model.modelID,
60-
providerID: userInfo.model.providerID,
61-
mode: "default",
62-
path: {
63-
cwd: "/",
64-
root: "/",
65-
},
66-
time: { created: now, completed: now },
67-
cost: 0,
68-
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
69-
...(variant !== undefined && { variant }),
70-
}
71-
72-
// For Gemini models, add thoughtSignature bypass to avoid validation errors
73-
const toolPartMetadata = isGeminiModel(userInfo.model.modelID)
74-
? { google: { thoughtSignature: "skip_thought_signature_validator" } }
75-
: undefined
76-
7759
return {
78-
info: baseInfo,
60+
info: {
61+
id: SYNTHETIC_MESSAGE_ID,
62+
sessionID: userInfo.sessionID,
63+
role: "assistant" as const,
64+
agent: userInfo.agent || "code",
65+
parentID: userInfo.id,
66+
modelID: userInfo.model.modelID,
67+
providerID: userInfo.model.providerID,
68+
mode: "default",
69+
path: {
70+
cwd: "/",
71+
root: "/",
72+
},
73+
time: { created: now, completed: now },
74+
cost: 0,
75+
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
76+
...(variant !== undefined && { variant }),
77+
},
7978
parts: [
8079
{
8180
id: SYNTHETIC_PART_ID,
8281
sessionID: userInfo.sessionID,
8382
messageID: SYNTHETIC_MESSAGE_ID,
84-
type: "tool",
85-
callID: SYNTHETIC_CALL_ID,
86-
tool: "context_info",
87-
state: {
88-
status: "completed",
89-
input: {},
90-
output: content,
91-
title: "Context Info",
92-
metadata: {},
93-
time: { start: now, end: now },
94-
},
95-
...(toolPartMetadata && { metadata: toolPartMetadata }),
83+
type: "text",
84+
text: content,
9685
},
9786
],
9887
}
9988
}
10089

90+
export const createSyntheticToolPart = (baseMessage: WithParts, content: string) => {
91+
const userInfo = baseMessage.info as UserMessage
92+
const now = Date.now()
93+
94+
return {
95+
id: SYNTHETIC_PART_ID,
96+
sessionID: userInfo.sessionID,
97+
messageID: baseMessage.info.id,
98+
type: "tool" as const,
99+
callID: SYNTHETIC_CALL_ID,
100+
tool: "context_info",
101+
state: {
102+
status: "completed" as const,
103+
input: {},
104+
output: content,
105+
title: "Context Info",
106+
metadata: {},
107+
time: { start: now, end: now },
108+
},
109+
}
110+
}
111+
101112
/**
102113
* Extracts a human-readable key from tool metadata for display purposes.
103114
*/

lib/ui/utils.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ function shortenSinglePath(path: string, workingDirectory?: string): string {
6060
return path
6161
}
6262

63-
/**
64-
* Formats a list of pruned items in the style: "→ tool: parameter"
65-
*/
6663
export function formatPrunedItemsList(
6764
pruneToolIds: string[],
6865
toolMetadata: Map<string, ToolParameterEntry>,
@@ -95,9 +92,6 @@ export function formatPrunedItemsList(
9592
return lines
9693
}
9794

98-
/**
99-
* Formats a PruningResult into a human-readable string for the prune tool output.
100-
*/
10195
export function formatPruningResultForTool(
10296
prunedIds: string[],
10397
toolMetadata: Map<string, ToolParameterEntry>,

0 commit comments

Comments
 (0)