Преглед изворни кода

more interleaved thinking fixes (#5334)

Aiden Cline пре 2 месеци
родитељ
комит
18d3c054a3

+ 18 - 31
packages/opencode/src/provider/transform.ts

@@ -74,23 +74,23 @@ export namespace ProviderTransform {
       return result
     }
 
-    // DeepSeek: Handle reasoning_content for tool call continuations
-    // - With tool calls: Include reasoning_content in providerOptions so model can continue reasoning
-    // - Without tool calls: Strip reasoning (new turn doesn't need previous reasoning)
-    // See: https://api-docs.deepseek.com/guides/thinking_mode
-    if (model.providerID === "deepseek" || model.api.id.toLowerCase().includes("deepseek")) {
+    if (
+      model.providerID === "deepseek" ||
+      model.api.id.toLowerCase().includes("deepseek") ||
+      (model.capabilities.interleaved &&
+        typeof model.capabilities.interleaved === "object" &&
+        model.capabilities.interleaved.field === "reasoning_content")
+    ) {
       return msgs.map((msg) => {
         if (msg.role === "assistant" && Array.isArray(msg.content)) {
           const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
-          const hasToolCalls = msg.content.some((part: any) => part.type === "tool-call")
           const reasoningText = reasoningParts.map((part: any) => part.text).join("")
 
           // Filter out reasoning parts from content
           const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
 
-          // If this message has tool calls and reasoning, include reasoning_content
-          // so DeepSeek can continue reasoning after tool execution
-          if (hasToolCalls && reasoningText) {
+          // Include reasoning_content directly on the message for all assistant messages
+          if (reasoningText) {
             return {
               ...msg,
               content: filteredContent,
@@ -104,12 +104,12 @@ export namespace ProviderTransform {
             }
           }
 
-          // For final answers (no tool calls), just strip reasoning
           return {
             ...msg,
             content: filteredContent,
           }
         }
+
         return msg
       })
     }
@@ -212,20 +212,23 @@ export namespace ProviderTransform {
   ): Record<string, any> {
     const result: Record<string, any> = {}
 
-    // switch to providerID later, for now use this
     if (model.api.npm === "@openrouter/ai-sdk-provider") {
       result["usage"] = {
         include: true,
       }
+      if (model.api.id.includes("gemini-3")) {
+        result["reasoning"] = { effort: "high" }
+      }
+    }
+
+    if (model.providerID === "baseten") {
+      result["chat_template_args"] = { enable_thinking: true }
     }
 
     if (model.providerID === "openai" || providerOptions?.setCacheKey) {
       result["promptCacheKey"] = sessionID
     }
 
-    if (model.api.npm === "@openrouter/ai-sdk-provider" && model.api.id.includes("gemini-3")) {
-      result["reasoning"] = { effort: "high" }
-    }
     if (model.api.npm === "@ai-sdk/google" || model.api.npm === "@ai-sdk/google-vertex") {
       result["thinkingConfig"] = {
         thinkingLevel: "high",
@@ -274,23 +277,7 @@ export namespace ProviderTransform {
     return options
   }
 
-  export function providerOptions(model: Provider.Model, options: { [x: string]: any }, messages: ModelMessage[]) {
-    if (model.capabilities.interleaved && typeof model.capabilities.interleaved === "object") {
-      const cot = []
-      const assistantMessages = messages.filter((msg) => msg.role === "assistant")
-      for (const msg of assistantMessages) {
-        for (const part of msg.content) {
-          if (typeof part === "string") {
-            continue
-          }
-          if (part.type === "reasoning") {
-            cot.push(part)
-          }
-        }
-      }
-      options[model.capabilities.interleaved.field] = cot
-    }
-
+  export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
     switch (model.api.npm) {
       case "@ai-sdk/openai":
       case "@ai-sdk/azure":

+ 0 - 1
packages/opencode/src/session/compaction.ts

@@ -143,7 +143,6 @@ export namespace SessionCompaction {
       providerOptions: ProviderTransform.providerOptions(
         model,
         pipe({}, mergeDeep(ProviderTransform.options(model, input.sessionID)), mergeDeep(model.options)),
-        [],
       ),
       headers: model.headers,
       abortSignal: input.abort,

+ 2 - 2
packages/opencode/src/session/prompt.ts

@@ -593,7 +593,7 @@ export namespace SessionPrompt {
           OUTPUT_TOKEN_MAX,
         ),
         abortSignal: abort,
-        providerOptions: ProviderTransform.providerOptions(model, params.options, messages),
+        providerOptions: ProviderTransform.providerOptions(model, params.options),
         stopWhen: stepCountIs(1),
         temperature: params.temperature,
         topP: params.topP,
@@ -1473,7 +1473,7 @@ export namespace SessionPrompt {
     await generateText({
       // use higher # for reasoning models since reasoning tokens eat up a lot of the budget
       maxOutputTokens: small.capabilities.reasoning ? 3000 : 20,
-      providerOptions: ProviderTransform.providerOptions(small, options, []),
+      providerOptions: ProviderTransform.providerOptions(small, options),
       messages: [
         ...SystemPrompt.title(small.providerID).map(
           (x): ModelMessage => ({

+ 2 - 2
packages/opencode/src/session/summary.ts

@@ -91,7 +91,7 @@ export namespace SessionSummary {
     if (textPart && !userMsg.summary?.title) {
       const result = await generateText({
         maxOutputTokens: small.capabilities.reasoning ? 1500 : 20,
-        providerOptions: ProviderTransform.providerOptions(small, options, []),
+        providerOptions: ProviderTransform.providerOptions(small, options),
         messages: [
           ...SystemPrompt.title(small.providerID).map(
             (x): ModelMessage => ({
@@ -144,7 +144,7 @@ export namespace SessionSummary {
         const result = await generateText({
           model: language,
           maxOutputTokens: 100,
-          providerOptions: ProviderTransform.providerOptions(small, options, []),
+          providerOptions: ProviderTransform.providerOptions(small, options),
           messages: [
             ...SystemPrompt.summarize(small.providerID).map(
               (x): ModelMessage => ({