opencode-pollinations-plugin 6.1.0-beta.5 → 6.1.0-beta.7

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.
@@ -112,6 +112,75 @@ function truncateTools(tools, limit = 120) {
112
112
  return tools;
113
113
  return tools.slice(0, limit);
114
114
  }
115
+ // --- BEDROCK COMPATIBILITY SHIM ---
116
+ // Bedrock requires:
117
+ // 1. toolUseId matching [a-zA-Z0-9_-]+ (no dots, spaces, special chars)
118
+ // 2. toolConfig present when toolUse/toolResult in messages
119
+ function sanitizeToolUseId(id) {
120
+ // Replace any char not in [a-zA-Z0-9_-] with underscore
121
+ return id.replace(/[^a-zA-Z0-9_-]/g, '_');
122
+ }
123
+ function sanitizeForBedrock(body) {
124
+ if (!body)
125
+ return body;
126
+ const sanitized = JSON.parse(JSON.stringify(body)); // Deep clone
127
+ // 1. Sanitize toolUseId in all messages
128
+ if (sanitized.messages && Array.isArray(sanitized.messages)) {
129
+ for (const msg of sanitized.messages) {
130
+ if (msg.content && Array.isArray(msg.content)) {
131
+ for (const block of msg.content) {
132
+ // Handle toolUse blocks
133
+ if (block.toolUse && block.toolUse.toolUseId) {
134
+ block.toolUse.toolUseId = sanitizeToolUseId(block.toolUse.toolUseId);
135
+ }
136
+ // Handle toolResult blocks
137
+ if (block.toolResult && block.toolResult.toolUseId) {
138
+ block.toolResult.toolUseId = sanitizeToolUseId(block.toolResult.toolUseId);
139
+ }
140
+ // Handle OpenAI-style tool_calls
141
+ if (block.type === 'tool_use' && block.id) {
142
+ block.id = sanitizeToolUseId(block.id);
143
+ }
144
+ }
145
+ }
146
+ // Handle assistant tool_calls array (OpenAI format)
147
+ if (msg.tool_calls && Array.isArray(msg.tool_calls)) {
148
+ for (const tc of msg.tool_calls) {
149
+ if (tc.id)
150
+ tc.id = sanitizeToolUseId(tc.id);
151
+ }
152
+ }
153
+ // Handle tool role message (OpenAI format)
154
+ if (msg.role === 'tool' && msg.tool_call_id) {
155
+ msg.tool_call_id = sanitizeToolUseId(msg.tool_call_id);
156
+ }
157
+ }
158
+ }
159
+ // 2. Add toolConfig if tools present but toolConfig missing
160
+ if (sanitized.tools && Array.isArray(sanitized.tools) && sanitized.tools.length > 0) {
161
+ if (!sanitized.tool_config && !sanitized.toolConfig) {
162
+ // Build toolConfig from tools array (Bedrock Converse format)
163
+ sanitized.tool_config = {
164
+ tools: sanitized.tools.map((t) => {
165
+ if (t.function) {
166
+ // OpenAI format -> Bedrock format
167
+ return {
168
+ toolSpec: {
169
+ name: t.function.name,
170
+ description: t.function.description || '',
171
+ inputSchema: {
172
+ json: t.function.parameters || { type: 'object', properties: {} }
173
+ }
174
+ }
175
+ };
176
+ }
177
+ return t; // Already in Bedrock format
178
+ })
179
+ };
180
+ }
181
+ }
182
+ return sanitized;
183
+ }
115
184
  const MAX_RETRIES = 3;
116
185
  const RETRY_DELAY_MS = 1000;
117
186
  function sleep(ms) {
@@ -587,10 +656,18 @@ export async function handleChatCompletion(req, res, bodyRaw) {
587
656
  if (authHeader)
588
657
  headers['Authorization'] = authHeader;
589
658
  // 5. Forward (Global Fetch with Retry)
659
+ // BEDROCK COMPATIBILITY: Apply transformation BEFORE first request
660
+ const isBedrockModel = actualModel.includes('nova') ||
661
+ actualModel.includes('amazon') ||
662
+ actualModel.includes('chickytutor');
663
+ const finalProxyBody = isBedrockModel ? sanitizeForBedrock(proxyBody) : proxyBody;
664
+ if (isBedrockModel) {
665
+ log(`[Proxy] Applied Bedrock shim for ${actualModel} (Initial Request)`);
666
+ }
590
667
  const fetchRes = await fetchWithRetry(targetUrl, {
591
668
  method: 'POST',
592
669
  headers: headers,
593
- body: JSON.stringify(proxyBody)
670
+ body: JSON.stringify(finalProxyBody)
594
671
  });
595
672
  res.statusCode = fetchRes.status;
596
673
  fetchRes.headers.forEach((val, key) => {
@@ -647,20 +724,20 @@ export async function handleChatCompletion(req, res, bodyRaw) {
647
724
  log(`[SafetyNet] Adjusted max_tokens to 4000 for ${actualModel}`);
648
725
  }
649
726
  }
650
- // BEDROCK COMPATIBILITY FIX (BUG 1)
727
+ // BEDROCK COMPATIBILITY SHIM (BUG 1 - Proper Transform)
651
728
  const isBedrockModel = actualModel.includes('nova') ||
652
729
  actualModel.includes('amazon') ||
653
730
  actualModel.includes('chickytutor');
654
- if (isBedrockModel && retryBody.tools) {
655
- delete retryBody.tools;
656
- log(`[SafetyNet] Tools removed for Bedrock model: ${actualModel}`);
657
- emitStatusToast('warning', '⚠️ Tools désactivés (Bedrock incompatible)', 'Fallback');
731
+ let finalRetryBody = retryBody;
732
+ if (isBedrockModel) {
733
+ finalRetryBody = sanitizeForBedrock(retryBody);
734
+ log(`[SafetyNet] Applied Bedrock shim for ${actualModel}`);
658
735
  }
659
736
  // 4. Retry Fetch
660
737
  const retryRes = await fetchWithRetry(targetUrl, {
661
738
  method: 'POST',
662
739
  headers: retryHeaders,
663
- body: JSON.stringify(retryBody)
740
+ body: JSON.stringify(finalRetryBody)
664
741
  });
665
742
  if (retryRes.ok) {
666
743
  res.statusCode = retryRes.status;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-pollinations-plugin",
3
3
  "displayName": "Pollinations AI (V5.6)",
4
- "version": "6.1.0-beta.5",
4
+ "version": "6.1.0-beta.7",
5
5
  "description": "Native Pollinations.ai Provider Plugin for OpenCode",
6
6
  "publisher": "pollinations",
7
7
  "repository": {