aicodeswitch 5.0.0 → 5.1.0

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.
@@ -272,6 +272,11 @@ function buildTargetBody(options) {
272
272
  result = (0, providers_js_2.applyReasoningConfig)(result, providerConfig, effort);
273
273
  }
274
274
  }
275
+ // --- Safety net for Claude upstream: ensure thinking blocks alongside tool_use ---
276
+ // When thinking mode is enabled, Claude requires thinking blocks in assistant messages with tool_use
277
+ if (toFormat === 'claude' && result.thinking && result.messages) {
278
+ result.messages = (0, mapper_js_1.fixThinkingHistory)(result.messages, 'claude');
279
+ }
275
280
  return result;
276
281
  }
277
282
  /** Identity converter that passes events through unchanged */
@@ -22,6 +22,8 @@ function responsesToClaude(body) {
22
22
  : undefined;
23
23
  }
24
24
  // --- Input -> messages ---
25
+ // Track pending thinking blocks from reasoning items to merge into next assistant message
26
+ let pendingThinking = [];
25
27
  if (body.input) {
26
28
  for (const item of body.input) {
27
29
  if (item.type === 'message') {
@@ -33,6 +35,11 @@ function responsesToClaude(body) {
33
35
  }
34
36
  else if (item.role === 'assistant' || item.role === 'developer') {
35
37
  const content = extractMessageContent(item, 'output_text');
38
+ // Prepend pending thinking blocks from preceding reasoning items
39
+ if (pendingThinking.length > 0) {
40
+ content.unshift(...pendingThinking);
41
+ pendingThinking = [];
42
+ }
36
43
  if (content.length > 0) {
37
44
  messages.push({ role: item.role === 'developer' ? 'user' : 'assistant', content });
38
45
  }
@@ -46,15 +53,19 @@ function responsesToClaude(body) {
46
53
  catch (_c) {
47
54
  parsedInput = item.arguments;
48
55
  }
49
- messages.push({
50
- role: 'assistant',
51
- content: [{
52
- type: 'tool_use',
53
- id: item.call_id,
54
- name: item.name,
55
- input: parsedInput,
56
- }],
56
+ const content = [];
57
+ // Prepend pending thinking blocks from preceding reasoning items
58
+ if (pendingThinking.length > 0) {
59
+ content.push(...pendingThinking);
60
+ pendingThinking = [];
61
+ }
62
+ content.push({
63
+ type: 'tool_use',
64
+ id: item.call_id,
65
+ name: item.name,
66
+ input: parsedInput,
57
67
  });
68
+ messages.push({ role: 'assistant', content });
58
69
  }
59
70
  else if (item.type === 'function_call_output') {
60
71
  messages.push({
@@ -67,11 +78,25 @@ function responsesToClaude(body) {
67
78
  });
68
79
  }
69
80
  else if (item.type === 'reasoning') {
70
- // Skip reasoning items in messages (effort is extracted for thinking config below)
81
+ // Convert reasoning summary to Claude thinking block and attach to next assistant message
82
+ if (item.summary && Array.isArray(item.summary)) {
83
+ const thinkingText = item.summary
84
+ .filter((s) => s.type === 'summary_text')
85
+ .map((s) => s.text || '')
86
+ .join('');
87
+ if (thinkingText) {
88
+ pendingThinking.push({ type: 'thinking', thinking: thinkingText });
89
+ }
90
+ }
71
91
  continue;
72
92
  }
73
93
  }
74
94
  }
95
+ // If there are orphaned thinking blocks (reasoning at end with no following assistant message),
96
+ // create a standalone assistant message to hold them
97
+ if (pendingThinking.length > 0) {
98
+ messages.push({ role: 'assistant', content: pendingThinking });
99
+ }
75
100
  // --- Build result ---
76
101
  const result = {
77
102
  model: body.model,
@@ -16,6 +16,7 @@ const PROVIDER_CONFIGS = [
16
16
  { patterns: ['openrouter'], config: { supportsThinking: false, supportsEffort: true, thinkingParam: 'none', effortParam: 'reasoning.effort', effortValueMode: 'openrouter', outputFormat: 'reasoning' } },
17
17
  { patterns: ['siliconflow'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'enable_thinking', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
18
18
  { patterns: ['stepfun', 'step'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'none', effortParam: 'reasoning_effort', effortValueMode: 'low_high', outputFormat: 'reasoning' } },
19
+ { patterns: ['agnes'], config: { supportsThinking: true, supportsEffort: false, thinkingParam: 'chat_template_kwargs', effortParam: 'none', effortValueMode: 'passthrough', outputFormat: 'reasoning_content' } },
19
20
  ];
20
21
  const DEFAULT_CONFIG = {
21
22
  supportsThinking: false,
@@ -52,6 +53,9 @@ function applyReasoningConfig(body, config, effort) {
52
53
  case 'reasoning_split':
53
54
  result.reasoning_split = true;
54
55
  break;
56
+ case 'chat_template_kwargs':
57
+ result.chat_template_kwargs = Object.assign(Object.assign({}, result.chat_template_kwargs), { enable_thinking: true });
58
+ break;
55
59
  }
56
60
  }
57
61
  if (config.supportsEffort && config.effortParam !== 'none' && effort) {