@amux.ai/adapter-qwen 0.1.1

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.
package/dist/index.js ADDED
@@ -0,0 +1,600 @@
1
+ import { contentToString, parseOpenAICompatibleError, mapFinishReason, parseOpenAIUsage } from '@amux.ai/llm-bridge';
2
+
3
+ // src/inbound/request-parser.ts
4
+ function parseRequest(request) {
5
+ const req = request;
6
+ let system;
7
+ const messages = [];
8
+ for (const msg of req.messages) {
9
+ if (msg.role === "system") {
10
+ if (typeof msg.content === "string") {
11
+ system = system ? `${system}
12
+ ${msg.content}` : msg.content;
13
+ }
14
+ } else {
15
+ messages.push(parseMessage(msg));
16
+ }
17
+ }
18
+ const tools = req.tools?.map((tool) => parseTool(tool));
19
+ const toolChoice = req.tool_choice ? parseToolChoice(req.tool_choice) : void 0;
20
+ return {
21
+ messages,
22
+ model: req.model,
23
+ tools,
24
+ toolChoice,
25
+ stream: req.stream,
26
+ system,
27
+ generation: {
28
+ temperature: req.temperature,
29
+ topP: req.top_p,
30
+ maxTokens: req.max_tokens,
31
+ stopSequences: req.stop ? Array.isArray(req.stop) ? req.stop : [req.stop] : void 0,
32
+ presencePenalty: req.presence_penalty,
33
+ frequencyPenalty: req.frequency_penalty,
34
+ seed: req.seed,
35
+ responseFormat: req.response_format ? { type: req.response_format.type } : void 0,
36
+ // Qwen-specific: thinking mode
37
+ thinking: req.enable_thinking !== void 0 ? { enabled: req.enable_thinking } : void 0,
38
+ // Qwen-specific: web search
39
+ enableSearch: req.enable_search
40
+ },
41
+ // Store Qwen-specific extensions
42
+ extensions: req.fps !== void 0 ? { qwen: { fps: req.fps } } : void 0,
43
+ raw: request
44
+ };
45
+ }
46
+ function parseMessage(msg) {
47
+ return {
48
+ role: msg.role,
49
+ content: parseContent(msg.content),
50
+ name: msg.name,
51
+ toolCalls: msg.tool_calls,
52
+ toolCallId: msg.tool_call_id,
53
+ // Qwen-specific: reasoning content
54
+ reasoningContent: msg.reasoning_content
55
+ };
56
+ }
57
+ function parseContent(content) {
58
+ if (content === null || content === void 0) {
59
+ return "";
60
+ }
61
+ if (typeof content === "string") {
62
+ return content;
63
+ }
64
+ return content.map((part) => {
65
+ if (part.type === "text") {
66
+ return {
67
+ type: "text",
68
+ text: part.text
69
+ };
70
+ }
71
+ if (part.type === "image_url") {
72
+ const url = part.image_url.url;
73
+ if (url.startsWith("data:")) {
74
+ const match = url.match(/^data:([^;]+);base64,(.+)$/);
75
+ if (match) {
76
+ return {
77
+ type: "image",
78
+ source: {
79
+ type: "base64",
80
+ mediaType: match[1],
81
+ data: match[2]
82
+ }
83
+ };
84
+ }
85
+ }
86
+ return {
87
+ type: "image",
88
+ source: {
89
+ type: "url",
90
+ url
91
+ }
92
+ };
93
+ }
94
+ return {
95
+ type: "text",
96
+ text: JSON.stringify(part)
97
+ };
98
+ });
99
+ }
100
+ function parseTool(tool) {
101
+ return {
102
+ type: "function",
103
+ function: {
104
+ name: tool.function.name,
105
+ description: tool.function.description,
106
+ parameters: tool.function.parameters,
107
+ strict: tool.function.strict
108
+ }
109
+ };
110
+ }
111
+ function parseToolChoice(choice) {
112
+ if (typeof choice === "string") {
113
+ return choice;
114
+ }
115
+ return {
116
+ type: "function",
117
+ function: {
118
+ name: choice.function.name
119
+ }
120
+ };
121
+ }
122
+ function parseResponse(response) {
123
+ const res = response;
124
+ const choices = res.choices.map((choice) => ({
125
+ index: choice.index,
126
+ message: {
127
+ role: choice.message.role,
128
+ content: choice.message.content ?? "",
129
+ toolCalls: choice.message.tool_calls,
130
+ // Qwen-specific: reasoning content
131
+ reasoningContent: choice.message.reasoning_content
132
+ },
133
+ finishReason: mapFinishReason(choice.finish_reason)
134
+ }));
135
+ return {
136
+ id: res.id,
137
+ model: res.model,
138
+ choices,
139
+ created: res.created,
140
+ systemFingerprint: res.system_fingerprint,
141
+ usage: parseOpenAIUsage(res.usage),
142
+ raw: response
143
+ };
144
+ }
145
+
146
+ // src/inbound/stream-parser.ts
147
+ function mapFinishReason2(reason) {
148
+ const reasonMap = {
149
+ stop: "stop",
150
+ length: "length",
151
+ tool_calls: "tool_calls",
152
+ content_filter: "content_filter"
153
+ };
154
+ return reasonMap[reason] ?? "stop";
155
+ }
156
+ function parseStream(chunk) {
157
+ const data = chunk;
158
+ if (!data.choices || data.choices.length === 0) {
159
+ if (data.usage) {
160
+ return {
161
+ type: "end",
162
+ id: data.id,
163
+ model: data.model,
164
+ usage: {
165
+ promptTokens: data.usage.prompt_tokens,
166
+ completionTokens: data.usage.completion_tokens,
167
+ totalTokens: data.usage.total_tokens
168
+ },
169
+ raw: chunk
170
+ };
171
+ }
172
+ return null;
173
+ }
174
+ const choice = data.choices[0];
175
+ if (!choice) return null;
176
+ const delta = choice.delta;
177
+ const events = [];
178
+ if (choice.index === 0 && !delta.content && !delta.tool_calls && !delta.reasoning_content && !choice.finish_reason) {
179
+ return {
180
+ type: "start",
181
+ id: data.id,
182
+ model: data.model,
183
+ raw: chunk
184
+ };
185
+ }
186
+ if (delta.reasoning_content) {
187
+ events.push({
188
+ type: "reasoning",
189
+ id: data.id,
190
+ model: data.model,
191
+ reasoning: {
192
+ type: "reasoning",
193
+ delta: delta.reasoning_content,
194
+ index: choice.index
195
+ },
196
+ raw: chunk
197
+ });
198
+ }
199
+ if (delta.content) {
200
+ events.push({
201
+ type: "content",
202
+ id: data.id,
203
+ model: data.model,
204
+ content: {
205
+ type: "content",
206
+ delta: delta.content,
207
+ index: choice.index
208
+ },
209
+ raw: chunk
210
+ });
211
+ }
212
+ if (delta.tool_calls && delta.tool_calls.length > 0) {
213
+ const toolCall = delta.tool_calls[0];
214
+ if (toolCall) {
215
+ events.push({
216
+ type: "tool_call",
217
+ id: data.id,
218
+ model: data.model,
219
+ toolCall: {
220
+ type: "tool_call",
221
+ id: toolCall.id,
222
+ name: toolCall.function?.name,
223
+ arguments: toolCall.function?.arguments,
224
+ index: toolCall.index
225
+ },
226
+ raw: chunk
227
+ });
228
+ }
229
+ }
230
+ if (choice.finish_reason) {
231
+ events.push({
232
+ type: "end",
233
+ id: data.id,
234
+ model: data.model,
235
+ finishReason: mapFinishReason2(choice.finish_reason),
236
+ usage: data.usage ? {
237
+ promptTokens: data.usage.prompt_tokens,
238
+ completionTokens: data.usage.completion_tokens,
239
+ totalTokens: data.usage.total_tokens
240
+ } : void 0,
241
+ raw: chunk
242
+ });
243
+ }
244
+ if (events.length === 0) {
245
+ return null;
246
+ }
247
+ const firstEvent = events[0];
248
+ return events.length === 1 && firstEvent ? firstEvent : events;
249
+ }
250
+ function parseError(error) {
251
+ return parseOpenAICompatibleError(error);
252
+ }
253
+
254
+ // src/outbound/request-builder.ts
255
+ function buildRequest(ir) {
256
+ const messages = [];
257
+ if (ir.system) {
258
+ messages.push({
259
+ role: "system",
260
+ content: ir.system
261
+ });
262
+ }
263
+ for (const msg of ir.messages) {
264
+ messages.push({
265
+ role: msg.role,
266
+ content: buildContent(msg.content),
267
+ name: msg.name,
268
+ tool_calls: msg.toolCalls,
269
+ tool_call_id: msg.toolCallId,
270
+ // Qwen-specific: reasoning content
271
+ reasoning_content: msg.reasoningContent
272
+ });
273
+ }
274
+ const request = {
275
+ model: ir.model ?? "qwen-plus",
276
+ messages,
277
+ stream: ir.stream
278
+ };
279
+ if (ir.tools && ir.tools.length > 0) {
280
+ request.tools = ir.tools.map((tool) => ({
281
+ type: "function",
282
+ function: {
283
+ name: tool.function.name,
284
+ description: tool.function.description,
285
+ parameters: tool.function.parameters,
286
+ strict: tool.function.strict
287
+ }
288
+ }));
289
+ }
290
+ if (ir.toolChoice) {
291
+ request.tool_choice = ir.toolChoice;
292
+ }
293
+ if (ir.generation) {
294
+ if (ir.generation.temperature !== void 0) {
295
+ request.temperature = ir.generation.temperature;
296
+ }
297
+ if (ir.generation.topP !== void 0) {
298
+ request.top_p = ir.generation.topP;
299
+ }
300
+ if (ir.generation.maxTokens !== void 0) {
301
+ request.max_tokens = ir.generation.maxTokens;
302
+ }
303
+ if (ir.generation.stopSequences && ir.generation.stopSequences.length > 0) {
304
+ request.stop = ir.generation.stopSequences;
305
+ }
306
+ if (ir.generation.presencePenalty !== void 0) {
307
+ request.presence_penalty = ir.generation.presencePenalty;
308
+ }
309
+ if (ir.generation.frequencyPenalty !== void 0) {
310
+ request.frequency_penalty = ir.generation.frequencyPenalty;
311
+ }
312
+ if (ir.generation.seed !== void 0) {
313
+ request.seed = ir.generation.seed;
314
+ }
315
+ if (ir.generation.responseFormat) {
316
+ if (ir.generation.responseFormat.type === "json_object") {
317
+ request.response_format = { type: "json_object" };
318
+ }
319
+ }
320
+ if (ir.generation.thinking) {
321
+ request.enable_thinking = ir.generation.thinking.enabled;
322
+ }
323
+ if (ir.generation.enableSearch !== void 0) {
324
+ request.enable_search = ir.generation.enableSearch;
325
+ }
326
+ }
327
+ const qwenExt = ir.extensions?.qwen;
328
+ if (qwenExt?.fps !== void 0) {
329
+ request.fps = qwenExt.fps;
330
+ }
331
+ if (ir.stream) {
332
+ request.stream_options = { include_usage: true };
333
+ }
334
+ return request;
335
+ }
336
+ function buildContent(content) {
337
+ if (typeof content === "string") {
338
+ return content || null;
339
+ }
340
+ if (!content || content.length === 0) {
341
+ return null;
342
+ }
343
+ const allText = content.every((part) => part.type === "text");
344
+ if (allText) {
345
+ return content.map((part) => part.type === "text" ? part.text : "").join("");
346
+ }
347
+ return content.map((part) => {
348
+ if (part.type === "text") {
349
+ return { type: "text", text: part.text };
350
+ }
351
+ if (part.type === "image") {
352
+ const imgPart = part;
353
+ if (imgPart.source.type === "url") {
354
+ return {
355
+ type: "image_url",
356
+ image_url: { url: imgPart.source.url }
357
+ };
358
+ }
359
+ return {
360
+ type: "image_url",
361
+ image_url: {
362
+ url: `data:${imgPart.source.mediaType};base64,${imgPart.source.data}`
363
+ }
364
+ };
365
+ }
366
+ return { type: "text", text: JSON.stringify(part) };
367
+ });
368
+ }
369
+ function buildResponse(ir) {
370
+ return {
371
+ id: ir.id,
372
+ object: "chat.completion",
373
+ created: ir.created ?? Math.floor(Date.now() / 1e3),
374
+ model: ir.model,
375
+ system_fingerprint: ir.systemFingerprint,
376
+ choices: ir.choices.map((choice) => ({
377
+ index: choice.index,
378
+ message: {
379
+ role: choice.message.role,
380
+ content: contentToString(choice.message.content),
381
+ tool_calls: choice.message.toolCalls,
382
+ // Qwen-specific: reasoning content
383
+ reasoning_content: choice.message.reasoningContent
384
+ },
385
+ finish_reason: choice.finishReason ?? "stop"
386
+ })),
387
+ usage: ir.usage ? {
388
+ prompt_tokens: ir.usage.promptTokens,
389
+ completion_tokens: ir.usage.completionTokens,
390
+ total_tokens: ir.usage.totalTokens
391
+ } : void 0
392
+ };
393
+ }
394
+
395
+ // src/outbound/stream-builder.ts
396
+ function createStreamBuilder() {
397
+ let chunkId = `chatcmpl-${Date.now()}`;
398
+ let model = "";
399
+ let created = Math.floor(Date.now() / 1e3);
400
+ const toolCallsState = /* @__PURE__ */ new Map();
401
+ return {
402
+ process(event) {
403
+ const events = [];
404
+ if (event.id) chunkId = event.id;
405
+ if (event.model) model = event.model;
406
+ if (event.type === "start") {
407
+ events.push({
408
+ event: "data",
409
+ data: {
410
+ id: chunkId,
411
+ object: "chat.completion.chunk",
412
+ created,
413
+ model,
414
+ choices: [{
415
+ index: 0,
416
+ delta: { role: "assistant", content: "" },
417
+ finish_reason: null
418
+ }]
419
+ }
420
+ });
421
+ }
422
+ if (event.type === "content" && event.content?.delta) {
423
+ events.push({
424
+ event: "data",
425
+ data: {
426
+ id: chunkId,
427
+ object: "chat.completion.chunk",
428
+ created,
429
+ model,
430
+ choices: [{
431
+ index: 0,
432
+ delta: { content: event.content.delta },
433
+ finish_reason: null
434
+ }]
435
+ }
436
+ });
437
+ }
438
+ if (event.type === "reasoning" && event.reasoning?.delta) {
439
+ events.push({
440
+ event: "data",
441
+ data: {
442
+ id: chunkId,
443
+ object: "chat.completion.chunk",
444
+ created,
445
+ model,
446
+ choices: [{
447
+ index: 0,
448
+ delta: { reasoning_content: event.reasoning.delta },
449
+ finish_reason: null
450
+ }]
451
+ }
452
+ });
453
+ }
454
+ if (event.type === "tool_call" && event.toolCall) {
455
+ const toolIndex = event.toolCall.index ?? 0;
456
+ const toolCallDelta = { index: toolIndex };
457
+ if (event.toolCall.name) {
458
+ toolCallDelta.id = event.toolCall.id || `call_${Date.now()}_${toolIndex}`;
459
+ toolCallDelta.type = "function";
460
+ toolCallDelta.function = { name: event.toolCall.name };
461
+ toolCallsState.set(toolIndex, {
462
+ id: toolCallDelta.id,
463
+ name: event.toolCall.name
464
+ });
465
+ }
466
+ if (event.toolCall.arguments) {
467
+ toolCallDelta.function = {
468
+ ...toolCallDelta.function,
469
+ arguments: event.toolCall.arguments
470
+ };
471
+ }
472
+ events.push({
473
+ event: "data",
474
+ data: {
475
+ id: chunkId,
476
+ object: "chat.completion.chunk",
477
+ created,
478
+ model,
479
+ choices: [{
480
+ index: 0,
481
+ delta: { tool_calls: [toolCallDelta] },
482
+ finish_reason: null
483
+ }]
484
+ }
485
+ });
486
+ }
487
+ if (event.type === "end") {
488
+ const finishReason = mapFinishReason3(event.finishReason);
489
+ const finalChunk = {
490
+ id: chunkId,
491
+ object: "chat.completion.chunk",
492
+ created,
493
+ model,
494
+ choices: [{
495
+ index: 0,
496
+ delta: {},
497
+ finish_reason: finishReason
498
+ }]
499
+ };
500
+ if (event.usage) {
501
+ finalChunk.usage = {
502
+ prompt_tokens: event.usage.promptTokens ?? 0,
503
+ completion_tokens: event.usage.completionTokens ?? 0,
504
+ total_tokens: event.usage.totalTokens ?? 0
505
+ };
506
+ }
507
+ events.push({ event: "data", data: finalChunk });
508
+ }
509
+ if (event.type === "error" && event.error) {
510
+ events.push({
511
+ event: "data",
512
+ data: {
513
+ error: {
514
+ message: event.error.message,
515
+ type: "server_error",
516
+ code: event.error.code
517
+ }
518
+ }
519
+ });
520
+ }
521
+ return events;
522
+ },
523
+ finalize() {
524
+ return [{ event: "data", data: "[DONE]" }];
525
+ }
526
+ };
527
+ }
528
+ function mapFinishReason3(reason) {
529
+ if (!reason) return "stop";
530
+ const reasonMap = {
531
+ stop: "stop",
532
+ length: "length",
533
+ tool_calls: "tool_calls",
534
+ content_filter: "content_filter",
535
+ end_turn: "stop",
536
+ max_tokens: "length"
537
+ };
538
+ return reasonMap[reason] ?? "stop";
539
+ }
540
+
541
+ // src/adapter.ts
542
+ var qwenAdapter = {
543
+ name: "qwen",
544
+ version: "1.0.0",
545
+ capabilities: {
546
+ streaming: true,
547
+ tools: true,
548
+ vision: true,
549
+ multimodal: true,
550
+ // Supports images, audio, video
551
+ systemPrompt: true,
552
+ toolChoice: true,
553
+ reasoning: true,
554
+ // QwQ model supports reasoning
555
+ webSearch: true,
556
+ // Qwen supports web search
557
+ jsonMode: true,
558
+ logprobs: false,
559
+ seed: true
560
+ },
561
+ inbound: {
562
+ parseRequest: (request) => {
563
+ return parseRequest(request);
564
+ },
565
+ parseResponse: (response) => {
566
+ return parseResponse(response);
567
+ },
568
+ parseStream: (chunk) => {
569
+ return parseStream(chunk);
570
+ },
571
+ parseError: (error) => {
572
+ return parseError(error);
573
+ }
574
+ },
575
+ outbound: {
576
+ buildRequest: (ir) => {
577
+ return buildRequest(ir);
578
+ },
579
+ buildResponse: (ir) => {
580
+ return buildResponse(ir);
581
+ },
582
+ createStreamBuilder
583
+ },
584
+ getInfo() {
585
+ return {
586
+ name: this.name,
587
+ version: this.version,
588
+ capabilities: this.capabilities,
589
+ endpoint: {
590
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode",
591
+ chatPath: "/v1/chat/completions",
592
+ modelsPath: "/v1/models"
593
+ }
594
+ };
595
+ }
596
+ };
597
+
598
+ export { qwenAdapter };
599
+ //# sourceMappingURL=index.js.map
600
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/inbound/request-parser.ts","../src/inbound/response-parser.ts","../src/inbound/stream-parser.ts","../src/inbound/error-parser.ts","../src/outbound/request-builder.ts","../src/outbound/response-builder.ts","../src/outbound/stream-builder.ts","../src/adapter.ts"],"names":["mapFinishReason"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n LLMRequestIR,\n Message,\n Tool,\n ToolChoice,\n ContentPart,\n TextContent,\n ImageContent,\n} from '@amux.ai/llm-bridge'\n\nimport type { QwenRequest, QwenMessage, QwenTool, QwenContentPart } from '../types'\n\n/**\n * Parse Qwen request to IR\n */\nexport function parseRequest(request: unknown): LLMRequestIR {\n const req = request as QwenRequest\n\n // Extract system message if present\n let system: string | undefined\n const messages: Message[] = []\n\n for (const msg of req.messages) {\n if (msg.role === 'system') {\n if (typeof msg.content === 'string') {\n system = system ? `${system}\\n${msg.content}` : msg.content\n }\n } else {\n messages.push(parseMessage(msg))\n }\n }\n\n // Parse tools\n const tools: Tool[] | undefined = req.tools?.map((tool) => parseTool(tool))\n\n // Parse tool choice\n const toolChoice: ToolChoice | undefined = req.tool_choice\n ? parseToolChoice(req.tool_choice)\n : undefined\n\n return {\n messages,\n model: req.model,\n tools,\n toolChoice,\n stream: req.stream,\n system,\n generation: {\n temperature: req.temperature,\n topP: req.top_p,\n maxTokens: req.max_tokens,\n stopSequences: req.stop\n ? Array.isArray(req.stop)\n ? req.stop\n : [req.stop]\n : undefined,\n presencePenalty: req.presence_penalty,\n frequencyPenalty: req.frequency_penalty,\n seed: req.seed,\n responseFormat: req.response_format\n ? { type: req.response_format.type }\n : undefined,\n // Qwen-specific: thinking mode\n thinking: req.enable_thinking !== undefined\n ? { enabled: req.enable_thinking }\n : undefined,\n // Qwen-specific: web search\n enableSearch: req.enable_search,\n },\n // Store Qwen-specific extensions\n extensions: req.fps !== undefined\n ? { qwen: { fps: req.fps } }\n : undefined,\n raw: request,\n }\n}\n\nfunction parseMessage(msg: QwenMessage): Message {\n return {\n role: msg.role,\n content: parseContent(msg.content),\n name: msg.name,\n toolCalls: msg.tool_calls,\n toolCallId: msg.tool_call_id,\n // Qwen-specific: reasoning content\n reasoningContent: msg.reasoning_content,\n }\n}\n\nfunction parseContent(\n content: string | QwenContentPart[] | null | undefined\n): string | ContentPart[] {\n if (content === null || content === undefined) {\n return ''\n }\n\n if (typeof content === 'string') {\n return content\n }\n\n return content.map((part): ContentPart => {\n if (part.type === 'text') {\n return {\n type: 'text',\n text: part.text,\n } as TextContent\n }\n\n if (part.type === 'image_url') {\n const url = part.image_url.url\n\n if (url.startsWith('data:')) {\n const match = url.match(/^data:([^;]+);base64,(.+)$/)\n if (match) {\n return {\n type: 'image',\n source: {\n type: 'base64',\n mediaType: match[1],\n data: match[2],\n },\n } as ImageContent\n }\n }\n\n return {\n type: 'image',\n source: {\n type: 'url',\n url: url,\n },\n } as ImageContent\n }\n\n // For audio, video, etc., store as text for now\n return {\n type: 'text',\n text: JSON.stringify(part),\n } as TextContent\n })\n}\n\nfunction parseTool(tool: QwenTool): Tool {\n return {\n type: 'function',\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n strict: tool.function.strict,\n },\n }\n}\n\nfunction parseToolChoice(\n choice: 'auto' | 'none' | 'required' | { type: 'function'; function: { name: string } }\n): ToolChoice {\n if (typeof choice === 'string') {\n return choice as ToolChoice\n }\n return {\n type: 'function',\n function: {\n name: choice.function.name,\n },\n }\n}\n","import type { LLMResponseIR, Choice, Role } from '@amux.ai/llm-bridge'\nimport { mapFinishReason, parseOpenAIUsage } from '@amux.ai/llm-bridge'\n\nimport type { QwenResponse } from '../types'\n\n/**\n * Parse Qwen response to IR\n */\nexport function parseResponse(response: unknown): LLMResponseIR {\n const res = response as QwenResponse\n\n const choices: Choice[] = res.choices.map((choice) => ({\n index: choice.index,\n message: {\n role: choice.message.role as Role,\n content: choice.message.content ?? '',\n toolCalls: choice.message.tool_calls,\n // Qwen-specific: reasoning content\n reasoningContent: choice.message.reasoning_content,\n },\n finishReason: mapFinishReason(choice.finish_reason),\n }))\n\n return {\n id: res.id,\n model: res.model,\n choices,\n created: res.created,\n systemFingerprint: res.system_fingerprint,\n usage: parseOpenAIUsage(res.usage),\n raw: response,\n }\n}\n","import type { LLMStreamEvent, FinishReason } from '@amux.ai/llm-bridge'\n\nimport type { QwenStreamChunk } from '../types'\n\n/**\n * Map Qwen finish reason to IR finish reason\n */\nfunction mapFinishReason(reason: string): FinishReason {\n const reasonMap: Record<string, FinishReason> = {\n stop: 'stop',\n length: 'length',\n tool_calls: 'tool_calls',\n content_filter: 'content_filter',\n }\n return reasonMap[reason] ?? 'stop'\n}\n\n/**\n * Parse Qwen stream chunk to IR stream event\n */\nexport function parseStream(\n chunk: unknown\n): LLMStreamEvent | LLMStreamEvent[] | null {\n const data = chunk as QwenStreamChunk\n\n if (!data.choices || data.choices.length === 0) {\n // Check for usage-only chunk\n if (data.usage) {\n return {\n type: 'end',\n id: data.id,\n model: data.model,\n usage: {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n },\n raw: chunk,\n }\n }\n return null\n }\n\n const choice = data.choices[0]\n if (!choice) return null\n\n const delta = choice.delta\n const events: LLMStreamEvent[] = []\n\n // Start event (first chunk with role or empty delta at index 0)\n if (choice.index === 0 && !delta.content && !delta.tool_calls && !delta.reasoning_content && !choice.finish_reason) {\n return {\n type: 'start',\n id: data.id,\n model: data.model,\n raw: chunk,\n }\n }\n\n // Qwen-specific: Reasoning content delta\n if (delta.reasoning_content) {\n events.push({\n type: 'reasoning',\n id: data.id,\n model: data.model,\n reasoning: {\n type: 'reasoning',\n delta: delta.reasoning_content,\n index: choice.index,\n },\n raw: chunk,\n })\n }\n\n // Content delta\n if (delta.content) {\n events.push({\n type: 'content',\n id: data.id,\n model: data.model,\n content: {\n type: 'content',\n delta: delta.content,\n index: choice.index,\n },\n raw: chunk,\n })\n }\n\n // Tool call delta\n if (delta.tool_calls && delta.tool_calls.length > 0) {\n const toolCall = delta.tool_calls[0]\n if (toolCall) {\n events.push({\n type: 'tool_call',\n id: data.id,\n model: data.model,\n toolCall: {\n type: 'tool_call',\n id: toolCall.id,\n name: toolCall.function?.name,\n arguments: toolCall.function?.arguments,\n index: toolCall.index,\n },\n raw: chunk,\n })\n }\n }\n\n // End event\n if (choice.finish_reason) {\n events.push({\n type: 'end',\n id: data.id,\n model: data.model,\n finishReason: mapFinishReason(choice.finish_reason),\n usage: data.usage\n ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n raw: chunk,\n })\n }\n\n if (events.length === 0) {\n return null\n }\n\n const firstEvent = events[0]\n return events.length === 1 && firstEvent ? firstEvent : events\n}\n","import { parseOpenAICompatibleError } from '@amux.ai/llm-bridge'\nimport type { LLMErrorIR } from '@amux.ai/llm-bridge'\n\n/**\n * Parse Qwen error to IR\n */\nexport function parseError(error: unknown): LLMErrorIR {\n return parseOpenAICompatibleError(error)\n}\n","import type { LLMRequestIR, ContentPart, ImageContent } from '@amux.ai/llm-bridge'\n\nimport type { QwenRequest, QwenMessage, QwenContentPart } from '../types'\n\n/**\n * Build Qwen request from IR\n */\nexport function buildRequest(ir: LLMRequestIR): QwenRequest {\n const messages: QwenMessage[] = []\n\n // Add system message if present\n if (ir.system) {\n messages.push({\n role: 'system',\n content: ir.system,\n })\n }\n\n // Add conversation messages\n for (const msg of ir.messages) {\n messages.push({\n role: msg.role,\n content: buildContent(msg.content),\n name: msg.name,\n tool_calls: msg.toolCalls,\n tool_call_id: msg.toolCallId,\n // Qwen-specific: reasoning content\n reasoning_content: msg.reasoningContent,\n })\n }\n\n const request: QwenRequest = {\n model: ir.model ?? 'qwen-plus',\n messages,\n stream: ir.stream,\n }\n\n // Add tools if present\n if (ir.tools && ir.tools.length > 0) {\n request.tools = ir.tools.map((tool) => ({\n type: 'function',\n function: {\n name: tool.function.name,\n description: tool.function.description,\n parameters: tool.function.parameters,\n strict: tool.function.strict,\n },\n }))\n }\n\n // Add tool choice if present\n if (ir.toolChoice) {\n request.tool_choice = ir.toolChoice\n }\n\n // Add generation parameters\n if (ir.generation) {\n if (ir.generation.temperature !== undefined) {\n request.temperature = ir.generation.temperature\n }\n if (ir.generation.topP !== undefined) {\n request.top_p = ir.generation.topP\n }\n if (ir.generation.maxTokens !== undefined) {\n request.max_tokens = ir.generation.maxTokens\n }\n if (ir.generation.stopSequences && ir.generation.stopSequences.length > 0) {\n request.stop = ir.generation.stopSequences\n }\n if (ir.generation.presencePenalty !== undefined) {\n request.presence_penalty = ir.generation.presencePenalty\n }\n if (ir.generation.frequencyPenalty !== undefined) {\n request.frequency_penalty = ir.generation.frequencyPenalty\n }\n if (ir.generation.seed !== undefined) {\n request.seed = ir.generation.seed\n }\n if (ir.generation.responseFormat) {\n if (ir.generation.responseFormat.type === 'json_object') {\n request.response_format = { type: 'json_object' }\n }\n }\n // Qwen-specific: thinking mode\n if (ir.generation.thinking) {\n request.enable_thinking = ir.generation.thinking.enabled\n }\n // Qwen-specific: web search\n if (ir.generation.enableSearch !== undefined) {\n request.enable_search = ir.generation.enableSearch\n }\n }\n\n // Qwen-specific: fps for video\n const qwenExt = ir.extensions?.qwen as { fps?: number } | undefined\n if (qwenExt?.fps !== undefined) {\n request.fps = qwenExt.fps\n }\n\n // Add stream options for usage in streaming\n if (ir.stream) {\n request.stream_options = { include_usage: true }\n }\n\n return request\n}\n\nfunction buildContent(\n content: string | ContentPart[]\n): string | QwenContentPart[] | null {\n if (typeof content === 'string') {\n return content || null\n }\n\n if (!content || content.length === 0) {\n return null\n }\n\n // Check if all parts are text - if so, concatenate them\n const allText = content.every((part) => part.type === 'text')\n if (allText) {\n return content\n .map((part) => (part.type === 'text' ? part.text : ''))\n .join('')\n }\n\n // Build multimodal content\n return content.map((part): QwenContentPart => {\n if (part.type === 'text') {\n return { type: 'text', text: part.text }\n }\n\n if (part.type === 'image') {\n const imgPart = part as ImageContent\n if (imgPart.source.type === 'url') {\n return {\n type: 'image_url',\n image_url: { url: imgPart.source.url },\n }\n }\n return {\n type: 'image_url',\n image_url: {\n url: `data:${imgPart.source.mediaType};base64,${imgPart.source.data}`,\n },\n }\n }\n\n return { type: 'text', text: JSON.stringify(part) }\n })\n}\n","import type { LLMResponseIR } from '@amux.ai/llm-bridge'\nimport { contentToString } from '@amux.ai/llm-bridge'\n\nimport type { QwenResponse } from '../types'\n\n/**\n * Build Qwen response from IR\n */\nexport function buildResponse(ir: LLMResponseIR): QwenResponse {\n return {\n id: ir.id,\n object: 'chat.completion',\n created: ir.created ?? Math.floor(Date.now() / 1000),\n model: ir.model,\n system_fingerprint: ir.systemFingerprint,\n choices: ir.choices.map((choice) => ({\n index: choice.index,\n message: {\n role: choice.message.role,\n content: contentToString(choice.message.content),\n tool_calls: choice.message.toolCalls,\n // Qwen-specific: reasoning content\n reasoning_content: choice.message.reasoningContent,\n },\n finish_reason: choice.finishReason ?? 'stop',\n })),\n usage: ir.usage\n ? {\n prompt_tokens: ir.usage.promptTokens,\n completion_tokens: ir.usage.completionTokens,\n total_tokens: ir.usage.totalTokens,\n }\n : undefined,\n }\n}\n","import type { LLMStreamEvent, SSEEvent, StreamEventBuilder } from '@amux.ai/llm-bridge'\n\n/**\n * OpenAI stream event builder\n * Converts IR stream events to OpenAI SSE format\n *\n * OpenAI uses a simpler SSE format compared to Anthropic:\n * - All events use \"data:\" prefix (no event type)\n * - Each chunk contains the full delta structure\n * - Stream ends with \"data: [DONE]\"\n */\nexport function createStreamBuilder(): StreamEventBuilder {\n let chunkId = `chatcmpl-${Date.now()}`\n let model = ''\n let created = Math.floor(Date.now() / 1000)\n const toolCallsState: Map<number, { id: string; name: string }> = new Map()\n\n return {\n process(event: LLMStreamEvent): SSEEvent[] {\n const events: SSEEvent[] = []\n\n // Update metadata from event\n if (event.id) chunkId = event.id\n if (event.model) model = event.model\n\n // Handle start event\n if (event.type === 'start') {\n // OpenAI doesn't have a separate start event\n // The first content chunk serves as the start\n events.push({\n event: 'data',\n data: {\n id: chunkId,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{\n index: 0,\n delta: { role: 'assistant', content: '' },\n finish_reason: null,\n }],\n },\n })\n }\n\n // Handle content delta\n if (event.type === 'content' && event.content?.delta) {\n events.push({\n event: 'data',\n data: {\n id: chunkId,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{\n index: 0,\n delta: { content: event.content.delta },\n finish_reason: null,\n }],\n },\n })\n }\n\n // Handle reasoning delta (for Qwen QwQ model)\n if (event.type === 'reasoning' && event.reasoning?.delta) {\n // Qwen uses reasoning_content field for thinking process\n events.push({\n event: 'data',\n data: {\n id: chunkId,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{\n index: 0,\n delta: { reasoning_content: event.reasoning.delta },\n finish_reason: null,\n }],\n },\n })\n }\n\n // Handle tool call\n if (event.type === 'tool_call' && event.toolCall) {\n const toolIndex = event.toolCall.index ?? 0\n const toolCallDelta: {\n index: number\n id?: string\n type?: string\n function?: { name?: string; arguments?: string }\n } = { index: toolIndex }\n\n // If this is a new tool call (has name)\n if (event.toolCall.name) {\n toolCallDelta.id = event.toolCall.id || `call_${Date.now()}_${toolIndex}`\n toolCallDelta.type = 'function'\n toolCallDelta.function = { name: event.toolCall.name }\n toolCallsState.set(toolIndex, {\n id: toolCallDelta.id,\n name: event.toolCall.name,\n })\n }\n\n // If this has arguments\n if (event.toolCall.arguments) {\n toolCallDelta.function = {\n ...toolCallDelta.function,\n arguments: event.toolCall.arguments,\n }\n }\n\n events.push({\n event: 'data',\n data: {\n id: chunkId,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{\n index: 0,\n delta: { tool_calls: [toolCallDelta] },\n finish_reason: null,\n }],\n },\n })\n }\n\n // Handle end event\n if (event.type === 'end') {\n const finishReason = mapFinishReason(event.finishReason)\n\n // Emit final chunk with finish_reason\n const finalChunk: {\n id: string\n object: string\n created: number\n model: string\n choices: Array<{\n index: number\n delta: Record<string, never>\n finish_reason: string\n }>\n usage?: {\n prompt_tokens: number\n completion_tokens: number\n total_tokens: number\n }\n } = {\n id: chunkId,\n object: 'chat.completion.chunk',\n created,\n model,\n choices: [{\n index: 0,\n delta: {},\n finish_reason: finishReason,\n }],\n }\n\n // Include usage if available\n if (event.usage) {\n finalChunk.usage = {\n prompt_tokens: event.usage.promptTokens ?? 0,\n completion_tokens: event.usage.completionTokens ?? 0,\n total_tokens: event.usage.totalTokens ?? 0,\n }\n }\n\n events.push({ event: 'data', data: finalChunk })\n }\n\n // Handle error event\n if (event.type === 'error' && event.error) {\n events.push({\n event: 'data',\n data: {\n error: {\n message: event.error.message,\n type: 'server_error',\n code: event.error.code,\n },\n },\n })\n }\n\n return events\n },\n\n finalize(): SSEEvent[] {\n // OpenAI streams end with [DONE]\n return [{ event: 'data', data: '[DONE]' }]\n },\n }\n}\n\n/**\n * Map IR finish reason to OpenAI finish reason\n */\nfunction mapFinishReason(reason?: string): string {\n if (!reason) return 'stop'\n\n const reasonMap: Record<string, string> = {\n stop: 'stop',\n length: 'length',\n tool_calls: 'tool_calls',\n content_filter: 'content_filter',\n end_turn: 'stop',\n max_tokens: 'length',\n }\n\n return reasonMap[reason] ?? 'stop'\n}\n","import type {\n LLMAdapter,\n LLMRequestIR,\n LLMResponseIR,\n LLMStreamEvent,\n LLMErrorIR,\n AdapterInfo,\n} from '@amux.ai/llm-bridge'\n\nimport { parseRequest } from './inbound/request-parser'\nimport { parseResponse } from './inbound/response-parser'\nimport { parseStream } from './inbound/stream-parser'\nimport { parseError } from './inbound/error-parser'\nimport { buildRequest } from './outbound/request-builder'\nimport { buildResponse } from './outbound/response-builder'\nimport { createStreamBuilder } from './outbound/stream-builder'\n\n/**\n * Qwen (通义千问) adapter implementation\n * Handles Qwen-specific features like enable_thinking, enable_search, and multimodal\n */\nexport const qwenAdapter: LLMAdapter = {\n name: 'qwen',\n version: '1.0.0',\n capabilities: {\n streaming: true,\n tools: true,\n vision: true,\n multimodal: true, // Supports images, audio, video\n systemPrompt: true,\n toolChoice: true,\n reasoning: true, // QwQ model supports reasoning\n webSearch: true, // Qwen supports web search\n jsonMode: true,\n logprobs: false,\n seed: true,\n },\n\n inbound: {\n parseRequest: (request: unknown): LLMRequestIR => {\n return parseRequest(request)\n },\n\n parseResponse: (response: unknown): LLMResponseIR => {\n return parseResponse(response)\n },\n\n parseStream: (chunk: unknown): LLMStreamEvent | LLMStreamEvent[] | null => {\n return parseStream(chunk)\n },\n\n parseError: (error: unknown): LLMErrorIR => {\n return parseError(error)\n },\n },\n\n outbound: {\n buildRequest: (ir: LLMRequestIR): unknown => {\n return buildRequest(ir)\n },\n\n buildResponse: (ir: LLMResponseIR): unknown => {\n return buildResponse(ir)\n },\n\n createStreamBuilder,\n },\n\n getInfo(): AdapterInfo {\n return {\n name: this.name,\n version: this.version,\n capabilities: this.capabilities,\n endpoint: {\n baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode',\n chatPath: '/v1/chat/completions',\n modelsPath: '/v1/models',\n },\n }\n },\n}\n"]}