@animalabs/membrane 0.5.27 → 0.5.29

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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * OpenAI Responses API provider adapter
3
+ *
4
+ * Adapter for OpenAI's `/v1/responses` endpoint, required for image generation
5
+ * models like `gpt-image-1`. The Responses API differs from Chat Completions:
6
+ *
7
+ * - Uses `input` array instead of `messages`
8
+ * - Content types: `input_text` / `input_image` (not `text` / `image_url`)
9
+ * - Image generation is a tool: `{"type": "image_generation"}`
10
+ * - Generated images come back as `image_generation_call` output items
11
+ * - Streaming uses different event types
12
+ *
13
+ * This adapter converts membrane's ProviderRequest into the Responses API format,
14
+ * sends the request, and converts the response back into membrane ContentBlocks.
15
+ */
16
+ import type { ProviderAdapter, ProviderRequest, ProviderRequestOptions, ProviderResponse, StreamCallbacks } from '../types/index.js';
17
+ export interface OpenAIResponsesAdapterConfig {
18
+ /** API key (defaults to OPENAI_API_KEY env var) */
19
+ apiKey?: string;
20
+ /** Base URL (default: https://api.openai.com/v1) */
21
+ baseURL?: string;
22
+ /** Organization ID (optional) */
23
+ organization?: string;
24
+ /** Default max output tokens */
25
+ defaultMaxTokens?: number;
26
+ }
27
+ export declare class OpenAIResponsesAdapter implements ProviderAdapter {
28
+ readonly name = "openai-responses";
29
+ private apiKey;
30
+ private baseURL;
31
+ private organization?;
32
+ private defaultMaxTokens;
33
+ constructor(config?: OpenAIResponsesAdapterConfig);
34
+ supportsModel(modelId: string): boolean;
35
+ complete(request: ProviderRequest, options?: ProviderRequestOptions): Promise<ProviderResponse>;
36
+ stream(request: ProviderRequest, callbacks: StreamCallbacks, options?: ProviderRequestOptions): Promise<ProviderResponse>;
37
+ private getHeaders;
38
+ private buildRequest;
39
+ private convertMessages;
40
+ private mapRole;
41
+ private parseResponse;
42
+ private buildContentBlocks;
43
+ private handleError;
44
+ }
45
+ //# sourceMappingURL=openai-responses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-responses.d.ts","sourceRoot":"","sources":["../../src/providers/openai-responses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAyF3B,MAAM,WAAW,4BAA4B;IAC3C,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,iCAAiC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,gCAAgC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,qBAAa,sBAAuB,YAAW,eAAe;IAC5D,QAAQ,CAAC,IAAI,sBAAsB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,GAAE,4BAAiC;IAWrD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC,QAAQ,CACZ,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;IA6BtB,MAAM,CACV,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;IAwI5B,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,YAAY;IA+CpB,OAAO,CAAC,eAAe;IAmDvB,OAAO,CAAC,OAAO;IAiBf,OAAO,CAAC,aAAa;IA6CrB,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,WAAW;CA0DpB"}
@@ -0,0 +1,394 @@
1
+ /**
2
+ * OpenAI Responses API provider adapter
3
+ *
4
+ * Adapter for OpenAI's `/v1/responses` endpoint, required for image generation
5
+ * models like `gpt-image-1`. The Responses API differs from Chat Completions:
6
+ *
7
+ * - Uses `input` array instead of `messages`
8
+ * - Content types: `input_text` / `input_image` (not `text` / `image_url`)
9
+ * - Image generation is a tool: `{"type": "image_generation"}`
10
+ * - Generated images come back as `image_generation_call` output items
11
+ * - Streaming uses different event types
12
+ *
13
+ * This adapter converts membrane's ProviderRequest into the Responses API format,
14
+ * sends the request, and converts the response back into membrane ContentBlocks.
15
+ */
16
+ import { MembraneError, rateLimitError, contextLengthError, authError, serverError, abortError, networkError, } from '../types/index.js';
17
+ // ============================================================================
18
+ // OpenAI Responses Adapter
19
+ // ============================================================================
20
+ export class OpenAIResponsesAdapter {
21
+ name = 'openai-responses';
22
+ apiKey;
23
+ baseURL;
24
+ organization;
25
+ defaultMaxTokens;
26
+ constructor(config = {}) {
27
+ this.apiKey = config.apiKey ?? process.env.OPENAI_API_KEY ?? '';
28
+ this.baseURL = (config.baseURL ?? 'https://api.openai.com/v1').replace(/\/$/, '');
29
+ this.organization = config.organization;
30
+ this.defaultMaxTokens = config.defaultMaxTokens ?? 4096;
31
+ if (!this.apiKey) {
32
+ throw new Error('OpenAI API key not provided');
33
+ }
34
+ }
35
+ supportsModel(modelId) {
36
+ return modelId.startsWith('gpt-image');
37
+ }
38
+ async complete(request, options) {
39
+ const responsesRequest = this.buildRequest(request);
40
+ options?.onRequest?.(responsesRequest);
41
+ try {
42
+ const response = await fetch(`${this.baseURL}/responses`, {
43
+ method: 'POST',
44
+ headers: this.getHeaders(),
45
+ body: JSON.stringify(responsesRequest),
46
+ signal: options?.signal,
47
+ });
48
+ if (!response.ok) {
49
+ const errorText = await response.text();
50
+ throw new Error(`OpenAI Responses API error: ${response.status} ${errorText}`);
51
+ }
52
+ const data = (await response.json());
53
+ if (data.error) {
54
+ throw new Error(`OpenAI Responses API error: ${data.error.code} ${data.error.message}`);
55
+ }
56
+ return this.parseResponse(data, request.model, responsesRequest);
57
+ }
58
+ catch (error) {
59
+ throw this.handleError(error, responsesRequest);
60
+ }
61
+ }
62
+ async stream(request, callbacks, options) {
63
+ const responsesRequest = this.buildRequest(request);
64
+ responsesRequest.stream = true;
65
+ options?.onRequest?.(responsesRequest);
66
+ try {
67
+ const response = await fetch(`${this.baseURL}/responses`, {
68
+ method: 'POST',
69
+ headers: this.getHeaders(),
70
+ body: JSON.stringify(responsesRequest),
71
+ signal: options?.signal,
72
+ });
73
+ if (!response.ok) {
74
+ const errorText = await response.text();
75
+ throw new Error(`OpenAI Responses API error: ${response.status} ${errorText}`);
76
+ }
77
+ const reader = response.body?.getReader();
78
+ if (!reader) {
79
+ throw new Error('No response body');
80
+ }
81
+ const decoder = new TextDecoder();
82
+ let accumulated = '';
83
+ let images = [];
84
+ let lastUsage;
85
+ let buffer = '';
86
+ while (true) {
87
+ const { done, value } = await reader.read();
88
+ if (done)
89
+ break;
90
+ buffer += decoder.decode(value, { stream: true });
91
+ const lines = buffer.split('\n');
92
+ buffer = lines.pop() ?? '';
93
+ for (const line of lines) {
94
+ if (!line.startsWith('data: '))
95
+ continue;
96
+ const data = line.slice(6).trim();
97
+ if (!data || data === '[DONE]')
98
+ continue;
99
+ try {
100
+ const parsed = JSON.parse(data);
101
+ // Handle text deltas
102
+ if (parsed.type === 'response.output_text.delta') {
103
+ const delta = parsed.delta ?? '';
104
+ accumulated += delta;
105
+ callbacks.onChunk(delta);
106
+ }
107
+ // Handle completed text
108
+ if (parsed.type === 'response.output_text.done') {
109
+ // Text already accumulated via deltas
110
+ }
111
+ // Handle image generation results
112
+ if (parsed.type === 'response.image_generation_call.done') {
113
+ if (parsed.result) {
114
+ images.push({
115
+ data: parsed.result,
116
+ mimeType: 'image/png',
117
+ });
118
+ }
119
+ }
120
+ // Handle completed response (has usage)
121
+ if (parsed.type === 'response.completed' || parsed.type === 'response.done') {
122
+ const resp = parsed.response ?? parsed;
123
+ if (resp.usage) {
124
+ lastUsage = resp.usage;
125
+ }
126
+ // Extract any images from the completed response output
127
+ if (resp.output) {
128
+ for (const item of resp.output) {
129
+ if (item.type === 'image_generation_call' && item.result) {
130
+ // Only add if not already captured via streaming events
131
+ const alreadyCaptured = images.some(img => img.data === item.result);
132
+ if (!alreadyCaptured) {
133
+ images.push({
134
+ data: item.result,
135
+ mimeType: 'image/png',
136
+ });
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ catch {
144
+ // Ignore parse errors in stream chunks
145
+ }
146
+ }
147
+ }
148
+ // Process remaining buffer
149
+ if (buffer.trim()) {
150
+ const remaining = buffer.trim();
151
+ const dataLine = remaining.startsWith('data: ') ? remaining.slice(6).trim() : remaining;
152
+ if (dataLine && dataLine !== '[DONE]') {
153
+ try {
154
+ const parsed = JSON.parse(dataLine);
155
+ if (parsed.type === 'response.completed' || parsed.type === 'response.done') {
156
+ const resp = parsed.response ?? parsed;
157
+ if (resp.usage)
158
+ lastUsage = resp.usage;
159
+ }
160
+ }
161
+ catch {
162
+ // Final buffer wasn't valid JSON
163
+ }
164
+ }
165
+ }
166
+ const cachedTokens = lastUsage?.input_tokens_details?.cached_tokens ?? 0;
167
+ return {
168
+ content: this.buildContentBlocks(accumulated, images),
169
+ stopReason: 'end_turn',
170
+ stopSequence: undefined,
171
+ usage: {
172
+ inputTokens: lastUsage?.input_tokens ?? 0,
173
+ outputTokens: lastUsage?.output_tokens ?? 0,
174
+ cacheReadTokens: cachedTokens > 0 ? cachedTokens : undefined,
175
+ },
176
+ model: request.model,
177
+ rawRequest: responsesRequest,
178
+ raw: { usage: lastUsage },
179
+ };
180
+ }
181
+ catch (error) {
182
+ throw this.handleError(error, responsesRequest);
183
+ }
184
+ }
185
+ // --------------------------------------------------------------------------
186
+ // Request Building
187
+ // --------------------------------------------------------------------------
188
+ getHeaders() {
189
+ const headers = {
190
+ Authorization: `Bearer ${this.apiKey}`,
191
+ 'Content-Type': 'application/json',
192
+ };
193
+ if (this.organization) {
194
+ headers['OpenAI-Organization'] = this.organization;
195
+ }
196
+ return headers;
197
+ }
198
+ buildRequest(request) {
199
+ const input = this.convertMessages(request.messages);
200
+ const maxTokens = request.maxTokens || this.defaultMaxTokens;
201
+ const responsesRequest = {
202
+ model: request.model,
203
+ input,
204
+ max_output_tokens: maxTokens,
205
+ };
206
+ // System prompt → instructions
207
+ if (request.system) {
208
+ const systemText = typeof request.system === 'string'
209
+ ? request.system
210
+ : request.system
211
+ .filter((b) => b.type === 'text')
212
+ .map((b) => b.text)
213
+ .join('\n');
214
+ if (systemText) {
215
+ responsesRequest.instructions = systemText;
216
+ }
217
+ }
218
+ if (request.temperature !== undefined) {
219
+ responsesRequest.temperature = request.temperature;
220
+ }
221
+ if (request.topP !== undefined) {
222
+ responsesRequest.top_p = request.topP;
223
+ }
224
+ // Auto-include image_generation tool for image models
225
+ if (request.model?.includes('image')) {
226
+ responsesRequest.tools = [{ type: 'image_generation' }];
227
+ }
228
+ // Apply extra params (filter out internal membrane fields)
229
+ if (request.extra) {
230
+ const { normalizedMessages, prompt, ...rest } = request.extra;
231
+ Object.assign(responsesRequest, rest);
232
+ }
233
+ return responsesRequest;
234
+ }
235
+ convertMessages(messages) {
236
+ const result = [];
237
+ for (const msg of messages) {
238
+ const role = this.mapRole(msg.role);
239
+ // Simple string content
240
+ if (typeof msg.content === 'string') {
241
+ result.push({ role, content: msg.content });
242
+ continue;
243
+ }
244
+ // Array content blocks (Anthropic-style)
245
+ if (Array.isArray(msg.content)) {
246
+ const parts = [];
247
+ for (const block of msg.content) {
248
+ if (block.type === 'text') {
249
+ if (block.text) {
250
+ parts.push({ type: 'input_text', text: block.text });
251
+ }
252
+ }
253
+ else if (block.type === 'image') {
254
+ const source = block.source;
255
+ if (source?.type === 'base64' && source.data) {
256
+ const mimeType = source.media_type ?? source.mediaType ?? 'image/jpeg';
257
+ parts.push({
258
+ type: 'input_image',
259
+ image_url: `data:${mimeType};base64,${source.data}`,
260
+ });
261
+ }
262
+ }
263
+ // tool_use and tool_result are not supported in the Responses API input
264
+ // for image models — skip them silently
265
+ }
266
+ if (parts.length > 0) {
267
+ result.push({ role, content: parts });
268
+ }
269
+ continue;
270
+ }
271
+ // Null/empty content — skip
272
+ if (msg.content === null || msg.content === undefined)
273
+ continue;
274
+ // Fallback
275
+ result.push({ role, content: String(msg.content) });
276
+ }
277
+ return result;
278
+ }
279
+ mapRole(role) {
280
+ switch (role) {
281
+ case 'user':
282
+ return 'user';
283
+ case 'assistant':
284
+ return 'assistant';
285
+ case 'system':
286
+ return 'developer';
287
+ default:
288
+ return 'user';
289
+ }
290
+ }
291
+ // --------------------------------------------------------------------------
292
+ // Response Parsing
293
+ // --------------------------------------------------------------------------
294
+ parseResponse(response, requestedModel, rawRequest) {
295
+ let text = '';
296
+ const images = [];
297
+ for (const item of response.output) {
298
+ if (item.type === 'message') {
299
+ for (const content of item.content) {
300
+ if (content.type === 'output_text') {
301
+ text += content.text;
302
+ }
303
+ else if (content.type === 'image_generation_call') {
304
+ images.push({
305
+ data: content.result,
306
+ mimeType: 'image/png',
307
+ });
308
+ }
309
+ }
310
+ }
311
+ else if (item.type === 'image_generation_call') {
312
+ images.push({
313
+ data: item.result,
314
+ mimeType: 'image/png',
315
+ });
316
+ }
317
+ }
318
+ const cachedTokens = response.usage?.input_tokens_details?.cached_tokens ?? 0;
319
+ return {
320
+ content: this.buildContentBlocks(text, images),
321
+ stopReason: 'end_turn',
322
+ stopSequence: undefined,
323
+ usage: {
324
+ inputTokens: response.usage?.input_tokens ?? 0,
325
+ outputTokens: response.usage?.output_tokens ?? 0,
326
+ cacheReadTokens: cachedTokens > 0 ? cachedTokens : undefined,
327
+ },
328
+ model: response.model ?? requestedModel,
329
+ rawRequest,
330
+ raw: response,
331
+ };
332
+ }
333
+ buildContentBlocks(text, images = []) {
334
+ const content = [];
335
+ if (text) {
336
+ content.push({ type: 'text', text });
337
+ }
338
+ for (const img of images) {
339
+ content.push({
340
+ type: 'generated_image',
341
+ data: img.data,
342
+ mimeType: img.mimeType,
343
+ });
344
+ }
345
+ return content;
346
+ }
347
+ // --------------------------------------------------------------------------
348
+ // Error Handling
349
+ // --------------------------------------------------------------------------
350
+ handleError(error, rawRequest) {
351
+ if (error instanceof MembraneError)
352
+ return error;
353
+ if (error instanceof Error) {
354
+ const message = error.message;
355
+ if (message.includes('429') || message.includes('rate_limit')) {
356
+ const retryMatch = message.match(/retry after (\d+)/i);
357
+ const retryAfter = retryMatch?.[1] ? parseInt(retryMatch[1], 10) * 1000 : undefined;
358
+ return rateLimitError(message, retryAfter, error, rawRequest);
359
+ }
360
+ if (message.includes('401') ||
361
+ message.includes('invalid_api_key') ||
362
+ message.includes('Incorrect API key')) {
363
+ return authError(message, error, rawRequest);
364
+ }
365
+ if (message.includes('context_length') ||
366
+ message.includes('maximum context') ||
367
+ message.includes('too long')) {
368
+ return contextLengthError(message, error, rawRequest);
369
+ }
370
+ if (message.includes('500') ||
371
+ message.includes('502') ||
372
+ message.includes('503') ||
373
+ message.includes('server_error')) {
374
+ return serverError(message, undefined, error, rawRequest);
375
+ }
376
+ if (error.name === 'AbortError') {
377
+ return abortError(undefined, rawRequest);
378
+ }
379
+ if (message.includes('network') ||
380
+ message.includes('fetch') ||
381
+ message.includes('ECONNREFUSED')) {
382
+ return networkError(message, error, rawRequest);
383
+ }
384
+ }
385
+ return new MembraneError({
386
+ type: 'unknown',
387
+ message: error instanceof Error ? error.message : String(error),
388
+ retryable: false,
389
+ rawError: error,
390
+ rawRequest,
391
+ });
392
+ }
393
+ }
394
+ //# sourceMappingURL=openai-responses.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-responses.js","sourceRoot":"","sources":["../../src/providers/openai-responses.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,10 @@ export interface ImageContent {
26
26
  type: 'image';
27
27
  source: MediaSource;
28
28
  tokenEstimate?: number;
29
+ /** Original URL of the image (e.g., Discord CDN). Used by providers that
30
+ * can auto-fetch URLs from text (like Gemini 3.x) when inlineData is
31
+ * not viable (e.g., missing thought_signature on model-role images). */
32
+ sourceUrl?: string;
29
33
  }
30
34
  export interface DocumentContent {
31
35
  type: 'document';
@@ -1 +1 @@
1
- {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/types/content.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/types/content.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/types/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoIH,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAmB;IACzD,OAAO,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,OAAO,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAmB;IAC3D,OAAO,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAmB;IAEnB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC"}
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/types/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAwIH,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAmB;IAChD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAmB;IACzD,OAAO,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAmB;IAClD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,OAAO,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAmB;IAC3D,OAAO,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,KAAmB;IAEnB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animalabs/membrane",
3
- "version": "0.5.27",
3
+ "version": "0.5.29",
4
4
  "description": "LLM middleware - a selective boundary that transforms what passes through",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -313,14 +313,19 @@ export class NativeFormatter implements PrefillFormatter {
313
313
  result.push(textBlock);
314
314
  } else if (block.type === 'image') {
315
315
  if (block.source.type === 'base64') {
316
- result.push({
316
+ const imageBlock: Record<string, unknown> = {
317
317
  type: 'image',
318
318
  source: {
319
319
  type: 'base64',
320
320
  media_type: block.source.mediaType,
321
321
  data: block.source.data,
322
322
  },
323
- });
323
+ };
324
+ // Preserve sourceUrl for providers that use URL-as-text (Gemini 3.x)
325
+ if (block.sourceUrl) {
326
+ imageBlock.sourceUrl = block.sourceUrl;
327
+ }
328
+ result.push(imageBlock);
324
329
  }
325
330
  } else if (block.type === 'tool_use') {
326
331
  result.push({
package/src/membrane.ts CHANGED
@@ -931,14 +931,19 @@ export class Membrane {
931
931
  });
932
932
  } else if (block.type === 'image') {
933
933
  if (block.source.type === 'base64') {
934
- content.push({
934
+ const imageBlock: Record<string, unknown> = {
935
935
  type: 'image',
936
936
  source: {
937
937
  type: 'base64',
938
938
  media_type: block.source.mediaType,
939
939
  data: block.source.data,
940
940
  },
941
- });
941
+ };
942
+ // Preserve sourceUrl for providers that use URL-as-text (Gemini 3.x)
943
+ if (block.sourceUrl) {
944
+ imageBlock.sourceUrl = block.sourceUrl;
945
+ }
946
+ content.push(imageBlock);
942
947
  }
943
948
  }
944
949
  }
@@ -122,10 +122,26 @@ export class AnthropicAdapter implements ProviderAdapter {
122
122
  }
123
123
 
124
124
  private buildRequest(request: ProviderRequest): Anthropic.MessageCreateParams {
125
+ // Strip provider-specific fields (e.g., sourceUrl for Gemini) from image blocks
126
+ // before sending to Anthropic, which rejects extra inputs
127
+ const sanitizedMessages = (request.messages as any[]).map((msg: any) => {
128
+ if (!Array.isArray(msg.content)) return msg;
129
+ return {
130
+ ...msg,
131
+ content: msg.content.map((block: any) => {
132
+ if (block.type === 'image' && block.sourceUrl !== undefined) {
133
+ const { sourceUrl, ...rest } = block;
134
+ return rest;
135
+ }
136
+ return block;
137
+ }),
138
+ };
139
+ });
140
+
125
141
  const params: Anthropic.MessageCreateParams = {
126
142
  model: request.model,
127
143
  max_tokens: request.maxTokens || this.defaultMaxTokens,
128
- messages: request.messages as Anthropic.MessageParam[],
144
+ messages: sanitizedMessages as Anthropic.MessageParam[],
129
145
  };
130
146
 
131
147
  // Handle system prompt - can be string or content blocks with cache_control
@@ -378,11 +378,13 @@ export class GeminiAdapter implements ProviderAdapter {
378
378
  private convertMessages(messages: any[], model?: string): GeminiContent[] {
379
379
  const contents: GeminiContent[] = [];
380
380
 
381
- // Gemini 3.x models require thought_signature on image parts in context.
382
- // Since images from other sources (user uploads, other models) don't carry
383
- // thought signatures, strip images from context for these models to avoid
384
- // 400 INVALID_ARGUMENT errors. They can still GENERATE images via responseModalities.
385
- const stripContextImages = model?.startsWith('gemini-3');
381
+ // Gemini 3.x requires thought_signature on image parts from model outputs.
382
+ // Images that round-trip through Discord lose their thought_signature metadata,
383
+ // causing 400 INVALID_ARGUMENT when sent back as inlineData. For gemini-3.x
384
+ // model-role images, we fall back to embedding the source URL as text — Gemini
385
+ // auto-fetches URLs from text content, enabling iterative editing without
386
+ // thought_signature. User images pass through as normal inlineData.
387
+ const useUrlForModelImages = model?.startsWith('gemini-3');
386
388
 
387
389
  for (const msg of messages) {
388
390
  const role: 'user' | 'model' = msg.role === 'assistant' ? 'model' : 'user';
@@ -402,8 +404,12 @@ export class GeminiAdapter implements ProviderAdapter {
402
404
  if (block.type === 'text') {
403
405
  if (block.text) parts.push({ text: block.text });
404
406
  } else if (block.type === 'image') {
405
- // Skip images in context for models that require thought_signature
406
- if (stripContextImages) continue;
407
+ // Gemini 3.x model-role images: use URL-as-text so Gemini auto-fetches
408
+ // the image without needing thought_signature metadata
409
+ if (useUrlForModelImages && role === 'model' && block.sourceUrl) {
410
+ parts.push({ text: block.sourceUrl });
411
+ continue;
412
+ }
407
413
 
408
414
  // Anthropic image format → Gemini inlineData
409
415
  const source = block.source;
@@ -53,3 +53,8 @@ export {
53
53
  fromGeminiParts,
54
54
  type GeminiAdapterConfig,
55
55
  } from './gemini.js';
56
+
57
+ export {
58
+ OpenAIResponsesAdapter,
59
+ type OpenAIResponsesAdapterConfig,
60
+ } from './openai-responses.js';