@ai-sdk/alibaba 1.0.54 → 1.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,13 +22,26 @@ function formatImageUrl({
22
22
  export function convertToAlibabaChatMessages({
23
23
  prompt,
24
24
  cacheControlValidator,
25
+ preserveThinking = false,
25
26
  }: {
26
27
  prompt: LanguageModelV3Prompt;
27
28
  cacheControlValidator?: CacheControlValidator;
29
+ preserveThinking?: boolean;
28
30
  }): AlibabaChatPrompt {
29
31
  const messages: AlibabaChatPrompt = [];
30
32
 
33
+ // TODO use findLastIndex once we use ES2023
34
+ let lastUserMessageIndex = -1;
35
+ for (let i = prompt.length - 1; i >= 0; i--) {
36
+ if (prompt[i].role === 'user') {
37
+ lastUserMessageIndex = i;
38
+ break;
39
+ }
40
+ }
41
+
42
+ let index = -1;
31
43
  for (const { role, content, ...message } of prompt) {
44
+ index++;
32
45
  const messageCacheControl = cacheControlValidator?.getCacheControl(
33
46
  message.providerOptions,
34
47
  );
@@ -102,6 +115,7 @@ export function convertToAlibabaChatMessages({
102
115
 
103
116
  case 'assistant': {
104
117
  let text = '';
118
+ let reasoningContent = '';
105
119
  const toolCalls: Array<{
106
120
  id: string;
107
121
  type: 'function';
@@ -126,19 +140,38 @@ export function convertToAlibabaChatMessages({
126
140
  break;
127
141
  }
128
142
  case 'reasoning': {
129
- // Reasoning content is handled separately in the response
130
- // but may appear in assistant messages during multi-turn conversations
131
- text += part.text;
143
+ // Reasoning from the current round (after the last user
144
+ // message) always accompanies tool calls. Earlier rounds are
145
+ // replayed only when preserved thinking is enabled.
146
+ if (preserveThinking || index > lastUserMessageIndex) {
147
+ reasoningContent += part.text;
148
+ }
132
149
  break;
133
150
  }
134
151
  }
135
152
  }
136
153
 
154
+ if (
155
+ text.length === 0 &&
156
+ toolCalls.length === 0 &&
157
+ reasoningContent.length === 0
158
+ ) {
159
+ break;
160
+ }
161
+
137
162
  messages.push({
138
163
  role: 'assistant',
139
- content: messageCacheControl
140
- ? [{ type: 'text', text, cache_control: messageCacheControl }]
141
- : text || null,
164
+ content:
165
+ text.length === 0 &&
166
+ toolCalls.length === 0 &&
167
+ reasoningContent.length > 0
168
+ ? null
169
+ : messageCacheControl
170
+ ? [{ type: 'text', text, cache_control: messageCacheControl }]
171
+ : text || null,
172
+ ...(reasoningContent.length > 0
173
+ ? { reasoning_content: reasoningContent }
174
+ : {}),
142
175
  tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
143
176
  });
144
177
 
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Whether a model id supports Alibaba's preserved-thinking mode
3
+ * (`preserve_thinking`), which replays assistant `reasoning_content` from
4
+ * previous turns.
5
+ *
6
+ * Supported models per Alibaba's documentation:
7
+ * https://docs.qwencloud.com/developer-guides/text-generation/thinking#preserve-thinking-in-multi-turn
8
+ */
9
+ const preservedThinkingModelIds = new Set([
10
+ 'kimi-k2.7-code',
11
+ 'qwen3.6-max-preview',
12
+ 'qwen3.6-plus',
13
+ 'qwen3.6-plus-2026-04-02',
14
+ 'qwen3.7-flash',
15
+ 'qwen3.7-flash-2026-07-15',
16
+ 'qwen3.7-max',
17
+ 'qwen3.7-max-2026-05-17',
18
+ 'qwen3.7-max-2026-05-20',
19
+ 'qwen3.7-max-2026-06-08',
20
+ 'qwen3.7-max-preview',
21
+ 'qwen3.7-plus',
22
+ 'qwen3.7-plus-2026-05-26',
23
+ 'qwen3.8-flash',
24
+ 'qwen3.8-max',
25
+ 'qwen3.8-max-0902',
26
+ ]);
27
+
28
+ export function supportsPreservedThinking(modelId: string): boolean {
29
+ return preservedThinkingModelIds.has(modelId);
30
+ }