@amux.ai/adapter-anthropic 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,722 @@
1
+ // src/inbound/request-parser.ts
2
+ function parseRequest(request) {
3
+ const req = request;
4
+ const messages = [];
5
+ for (const msg of req.messages) {
6
+ const parsed = parseMessage(msg);
7
+ messages.push(...parsed);
8
+ }
9
+ return {
10
+ messages,
11
+ model: req.model,
12
+ // Set system directly in IR instead of adding to messages
13
+ system: req.system,
14
+ tools: req.tools?.map((tool) => ({
15
+ type: "function",
16
+ function: {
17
+ name: tool.name,
18
+ description: tool.description,
19
+ parameters: tool.input_schema
20
+ }
21
+ })),
22
+ toolChoice: req.tool_choice ? req.tool_choice.type === "any" ? "required" : req.tool_choice.type === "auto" ? "auto" : req.tool_choice.name ? { type: "function", function: { name: req.tool_choice.name } } : void 0 : void 0,
23
+ stream: req.stream,
24
+ generation: {
25
+ maxTokens: req.max_tokens,
26
+ temperature: req.temperature,
27
+ topP: req.top_p,
28
+ topK: req.top_k,
29
+ stopSequences: req.stop_sequences
30
+ },
31
+ metadata: {
32
+ userId: req.metadata?.user_id
33
+ },
34
+ raw: request
35
+ };
36
+ }
37
+ function parseMessage(msg) {
38
+ if (typeof msg.content === "string") {
39
+ return [{
40
+ role: msg.role,
41
+ content: msg.content
42
+ }];
43
+ }
44
+ const contentParts = [];
45
+ const toolCalls = [];
46
+ const toolResults = [];
47
+ for (const part of msg.content) {
48
+ if (part.type === "tool_use") {
49
+ toolCalls.push({
50
+ id: part.id,
51
+ type: "function",
52
+ function: {
53
+ name: part.name,
54
+ arguments: JSON.stringify(part.input)
55
+ }
56
+ });
57
+ } else if (part.type === "tool_result") {
58
+ toolResults.push({
59
+ role: "tool",
60
+ content: typeof part.content === "string" ? part.content : JSON.stringify(part.content),
61
+ toolCallId: part.tool_use_id
62
+ });
63
+ } else {
64
+ contentParts.push(parseContentPart(part));
65
+ }
66
+ }
67
+ const messages = [];
68
+ if (contentParts.length > 0 || toolCalls.length > 0) {
69
+ const message = {
70
+ role: msg.role,
71
+ content: contentParts.length === 1 && contentParts[0]?.type === "text" ? contentParts[0].text : contentParts.length > 0 ? contentParts : ""
72
+ };
73
+ if (toolCalls.length > 0) {
74
+ message.toolCalls = toolCalls;
75
+ }
76
+ messages.push(message);
77
+ }
78
+ messages.push(...toolResults);
79
+ return messages;
80
+ }
81
+ function parseContentPart(part) {
82
+ switch (part.type) {
83
+ case "text":
84
+ return {
85
+ type: "text",
86
+ text: part.text
87
+ };
88
+ case "image":
89
+ return {
90
+ type: "image",
91
+ source: part.source.data ? {
92
+ type: "base64",
93
+ mediaType: part.source.media_type ?? "image/jpeg",
94
+ data: part.source.data
95
+ } : {
96
+ type: "url",
97
+ url: part.source.url ?? ""
98
+ }
99
+ };
100
+ default:
101
+ return {
102
+ type: "text",
103
+ text: JSON.stringify(part)
104
+ };
105
+ }
106
+ }
107
+
108
+ // src/inbound/response-parser.ts
109
+ function parseResponse(response) {
110
+ const res = response;
111
+ const contentParts = [];
112
+ const toolCalls = [];
113
+ for (const part of res.content) {
114
+ if (part.type === "tool_use") {
115
+ toolCalls.push({
116
+ id: part.id,
117
+ type: "function",
118
+ function: {
119
+ name: part.name,
120
+ arguments: JSON.stringify(part.input)
121
+ }
122
+ });
123
+ } else {
124
+ contentParts.push(parseContentPart2(part));
125
+ }
126
+ }
127
+ const message = {
128
+ role: "assistant",
129
+ content: contentParts.length === 1 && contentParts[0]?.type === "text" ? contentParts[0].text : contentParts.length > 0 ? contentParts : ""
130
+ };
131
+ if (toolCalls.length > 0) {
132
+ message.toolCalls = toolCalls;
133
+ }
134
+ const choice = {
135
+ index: 0,
136
+ message,
137
+ finishReason: mapStopReason(res.stop_reason)
138
+ };
139
+ return {
140
+ id: res.id,
141
+ model: res.model,
142
+ choices: [choice],
143
+ usage: {
144
+ promptTokens: res.usage.input_tokens,
145
+ completionTokens: res.usage.output_tokens,
146
+ totalTokens: res.usage.input_tokens + res.usage.output_tokens
147
+ },
148
+ raw: response
149
+ };
150
+ }
151
+ function parseContentPart2(part) {
152
+ switch (part.type) {
153
+ case "text":
154
+ return {
155
+ type: "text",
156
+ text: part.text
157
+ };
158
+ default:
159
+ return {
160
+ type: "text",
161
+ text: JSON.stringify(part)
162
+ };
163
+ }
164
+ }
165
+ function mapStopReason(reason) {
166
+ if (!reason) return "stop";
167
+ const reasonMap = {
168
+ "end_turn": "stop",
169
+ "max_tokens": "length",
170
+ "stop_sequence": "stop",
171
+ "tool_use": "tool_calls"
172
+ };
173
+ return reasonMap[reason] ?? "stop";
174
+ }
175
+
176
+ // src/inbound/stream-parser.ts
177
+ function parseStream(chunk) {
178
+ const event = chunk;
179
+ switch (event.type) {
180
+ case "message_start":
181
+ return {
182
+ type: "start",
183
+ id: event.message?.id,
184
+ model: event.message?.model,
185
+ raw: chunk
186
+ };
187
+ case "content_block_start":
188
+ if (event.content_block?.type === "text") {
189
+ return {
190
+ type: "content",
191
+ content: {
192
+ type: "content",
193
+ delta: "",
194
+ index: event.index
195
+ },
196
+ raw: chunk
197
+ };
198
+ }
199
+ if (event.content_block?.type === "tool_use") {
200
+ return {
201
+ type: "tool_call",
202
+ toolCall: {
203
+ type: "tool_call",
204
+ id: event.content_block.id,
205
+ name: event.content_block.name,
206
+ index: event.index
207
+ },
208
+ raw: chunk
209
+ };
210
+ }
211
+ return null;
212
+ case "content_block_delta":
213
+ if (event.delta?.type === "text_delta" && event.delta.text !== void 0) {
214
+ return {
215
+ type: "content",
216
+ content: {
217
+ type: "content",
218
+ delta: event.delta.text,
219
+ index: event.index
220
+ },
221
+ raw: chunk
222
+ };
223
+ }
224
+ if (event.delta?.type === "input_json_delta" && event.delta.partial_json !== void 0) {
225
+ return {
226
+ type: "tool_call",
227
+ toolCall: {
228
+ type: "tool_call",
229
+ arguments: event.delta.partial_json,
230
+ index: event.index
231
+ },
232
+ raw: chunk
233
+ };
234
+ }
235
+ return null;
236
+ case "content_block_stop":
237
+ return null;
238
+ case "message_delta":
239
+ if (event.delta?.stop_reason) {
240
+ return {
241
+ type: "end",
242
+ finishReason: mapStopReason2(event.delta.stop_reason),
243
+ raw: chunk
244
+ };
245
+ }
246
+ return null;
247
+ case "message_stop":
248
+ return {
249
+ type: "end",
250
+ raw: chunk
251
+ };
252
+ default:
253
+ return null;
254
+ }
255
+ }
256
+ function mapStopReason2(reason) {
257
+ const reasonMap = {
258
+ "end_turn": "stop",
259
+ "max_tokens": "length",
260
+ "stop_sequence": "stop",
261
+ "tool_use": "tool_calls"
262
+ };
263
+ return reasonMap[reason] ?? "stop";
264
+ }
265
+
266
+ // src/inbound/error-parser.ts
267
+ function parseError(error) {
268
+ if (error && typeof error === "object") {
269
+ if ("type" in error && error.type === "error" && "error" in error) {
270
+ const err = error.error;
271
+ return {
272
+ type: mapErrorType(err.type),
273
+ message: err.message,
274
+ code: err.type,
275
+ raw: error
276
+ };
277
+ }
278
+ if ("error" in error) {
279
+ const err = error.error;
280
+ return {
281
+ type: mapErrorType(err.type),
282
+ message: err.message,
283
+ code: err.type,
284
+ raw: error
285
+ };
286
+ }
287
+ }
288
+ return {
289
+ type: "unknown",
290
+ message: String(error),
291
+ raw: error
292
+ };
293
+ }
294
+ function mapErrorType(type) {
295
+ if (!type) return "unknown";
296
+ const typeMap = {
297
+ invalid_request_error: "validation",
298
+ authentication_error: "authentication",
299
+ permission_error: "permission",
300
+ not_found_error: "not_found",
301
+ rate_limit_error: "rate_limit",
302
+ api_error: "api",
303
+ overloaded_error: "server"
304
+ };
305
+ return typeMap[type] ?? "unknown";
306
+ }
307
+
308
+ // src/outbound/request-builder.ts
309
+ function buildRequest(ir) {
310
+ let system = ir.system;
311
+ const messages = [];
312
+ for (const msg of ir.messages) {
313
+ if (msg.role === "system") {
314
+ if (!system) {
315
+ system = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
316
+ }
317
+ } else {
318
+ messages.push(msg);
319
+ }
320
+ }
321
+ return {
322
+ model: ir.model ?? "claude-3-5-sonnet-20241022",
323
+ messages: messages.map((msg) => buildMessage(msg)),
324
+ system,
325
+ tools: ir.tools?.map((tool) => ({
326
+ name: tool.function.name,
327
+ description: tool.function.description,
328
+ input_schema: tool.function.parameters ?? { type: "object", properties: {} }
329
+ })),
330
+ tool_choice: ir.toolChoice ? typeof ir.toolChoice === "string" ? ir.toolChoice === "required" ? { type: "any" } : { type: ir.toolChoice } : { type: "tool", name: ir.toolChoice.function.name } : void 0,
331
+ max_tokens: ir.generation?.maxTokens ?? 4096,
332
+ temperature: ir.generation?.temperature,
333
+ top_p: ir.generation?.topP,
334
+ top_k: ir.generation?.topK,
335
+ stop_sequences: ir.generation?.stopSequences,
336
+ stream: ir.stream,
337
+ metadata: ir.metadata?.userId ? {
338
+ user_id: ir.metadata.userId
339
+ } : void 0
340
+ };
341
+ }
342
+ function buildMessage(msg) {
343
+ const content = [];
344
+ if (typeof msg.content === "string") {
345
+ if (msg.content) {
346
+ content.push({ type: "text", text: msg.content });
347
+ }
348
+ } else if (Array.isArray(msg.content)) {
349
+ for (const part of msg.content) {
350
+ content.push(buildContentPart(part));
351
+ }
352
+ }
353
+ if (msg.role === "tool" && msg.toolCallId) {
354
+ const resultContent = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
355
+ return {
356
+ role: "user",
357
+ content: [{
358
+ type: "tool_result",
359
+ tool_use_id: msg.toolCallId,
360
+ content: resultContent
361
+ }]
362
+ };
363
+ }
364
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
365
+ for (const toolCall of msg.toolCalls) {
366
+ content.push({
367
+ type: "tool_use",
368
+ id: toolCall.id,
369
+ name: toolCall.function.name,
370
+ input: JSON.parse(toolCall.function.arguments)
371
+ });
372
+ }
373
+ }
374
+ if (content.length === 0) {
375
+ content.push({ type: "text", text: "" });
376
+ }
377
+ const firstContent = content[0];
378
+ const simplifiedContent = content.length === 1 && firstContent?.type === "text" ? firstContent.text : content;
379
+ return {
380
+ role: msg.role === "user" ? "user" : "assistant",
381
+ content: simplifiedContent
382
+ };
383
+ }
384
+ function buildContentPart(part) {
385
+ switch (part.type) {
386
+ case "text":
387
+ return {
388
+ type: "text",
389
+ text: part.text
390
+ };
391
+ case "image":
392
+ return {
393
+ type: "image",
394
+ source: part.source.type === "base64" ? {
395
+ type: "base64",
396
+ media_type: part.source.mediaType,
397
+ data: part.source.data
398
+ } : {
399
+ type: "url",
400
+ url: part.source.url
401
+ }
402
+ };
403
+ default:
404
+ return {
405
+ type: "text",
406
+ text: JSON.stringify(part)
407
+ };
408
+ }
409
+ }
410
+
411
+ // src/outbound/response-builder.ts
412
+ function buildResponse(ir) {
413
+ const choice = ir.choices[0];
414
+ if (!choice) {
415
+ throw new Error("No choices in response");
416
+ }
417
+ const content = buildContent(choice.message);
418
+ return {
419
+ id: ir.id,
420
+ type: "message",
421
+ role: "assistant",
422
+ content,
423
+ model: ir.model,
424
+ stop_reason: mapFinishReason(choice.finishReason),
425
+ stop_sequence: null,
426
+ usage: {
427
+ input_tokens: ir.usage?.promptTokens ?? 0,
428
+ output_tokens: ir.usage?.completionTokens ?? 0
429
+ }
430
+ };
431
+ }
432
+ function buildContent(message) {
433
+ const content = [];
434
+ if (typeof message.content === "string") {
435
+ if (message.content) {
436
+ content.push({ type: "text", text: message.content });
437
+ }
438
+ } else if (Array.isArray(message.content)) {
439
+ for (const part of message.content) {
440
+ content.push(buildContentPart2(part));
441
+ }
442
+ }
443
+ if (message.toolCalls && message.toolCalls.length > 0) {
444
+ for (const toolCall of message.toolCalls) {
445
+ content.push({
446
+ type: "tool_use",
447
+ id: toolCall.id,
448
+ name: toolCall.function.name,
449
+ input: JSON.parse(toolCall.function.arguments)
450
+ });
451
+ }
452
+ }
453
+ if (content.length === 0) {
454
+ content.push({ type: "text", text: "" });
455
+ }
456
+ return content;
457
+ }
458
+ function buildContentPart2(part) {
459
+ switch (part.type) {
460
+ case "text":
461
+ return {
462
+ type: "text",
463
+ text: part.text
464
+ };
465
+ default:
466
+ return {
467
+ type: "text",
468
+ text: JSON.stringify(part)
469
+ };
470
+ }
471
+ }
472
+ function mapFinishReason(reason) {
473
+ if (!reason) return "end_turn";
474
+ const reasonMap = {
475
+ "stop": "end_turn",
476
+ "length": "max_tokens",
477
+ "tool_calls": "tool_use"
478
+ };
479
+ return reasonMap[reason] ?? "end_turn";
480
+ }
481
+
482
+ // src/outbound/stream-builder.ts
483
+ function createStreamBuilder() {
484
+ let hasStarted = false;
485
+ let messageId = `msg_${Date.now()}`;
486
+ let model = "";
487
+ let contentIndex = 0;
488
+ let currentBlockType = null;
489
+ let outputTokens = 0;
490
+ return {
491
+ process(event) {
492
+ const events = [];
493
+ const ensureStarted = () => {
494
+ if (!hasStarted) {
495
+ hasStarted = true;
496
+ if (event.id) messageId = event.id;
497
+ if (event.model) model = event.model;
498
+ events.push({
499
+ event: "message_start",
500
+ data: {
501
+ type: "message_start",
502
+ message: {
503
+ id: messageId,
504
+ type: "message",
505
+ role: "assistant",
506
+ content: [],
507
+ model,
508
+ stop_reason: null,
509
+ stop_sequence: null,
510
+ usage: { input_tokens: 0, output_tokens: 0 }
511
+ }
512
+ }
513
+ });
514
+ }
515
+ };
516
+ if (event.type === "start") {
517
+ ensureStarted();
518
+ }
519
+ if (event.type === "reasoning" && event.reasoning?.delta) {
520
+ ensureStarted();
521
+ if (currentBlockType !== "thinking") {
522
+ if (currentBlockType !== null) {
523
+ events.push({
524
+ event: "content_block_stop",
525
+ data: { type: "content_block_stop", index: contentIndex }
526
+ });
527
+ contentIndex++;
528
+ }
529
+ events.push({
530
+ event: "content_block_start",
531
+ data: {
532
+ type: "content_block_start",
533
+ index: contentIndex,
534
+ content_block: { type: "thinking", thinking: "" }
535
+ }
536
+ });
537
+ currentBlockType = "thinking";
538
+ }
539
+ events.push({
540
+ event: "content_block_delta",
541
+ data: {
542
+ type: "content_block_delta",
543
+ index: contentIndex,
544
+ delta: { type: "thinking_delta", thinking: event.reasoning.delta }
545
+ }
546
+ });
547
+ }
548
+ if (event.type === "content" && event.content?.delta) {
549
+ ensureStarted();
550
+ if (currentBlockType !== "text") {
551
+ if (currentBlockType !== null) {
552
+ events.push({
553
+ event: "content_block_stop",
554
+ data: { type: "content_block_stop", index: contentIndex }
555
+ });
556
+ contentIndex++;
557
+ }
558
+ events.push({
559
+ event: "content_block_start",
560
+ data: {
561
+ type: "content_block_start",
562
+ index: contentIndex,
563
+ content_block: { type: "text", text: "" }
564
+ }
565
+ });
566
+ currentBlockType = "text";
567
+ }
568
+ events.push({
569
+ event: "content_block_delta",
570
+ data: {
571
+ type: "content_block_delta",
572
+ index: contentIndex,
573
+ delta: { type: "text_delta", text: event.content.delta }
574
+ }
575
+ });
576
+ }
577
+ if (event.type === "tool_call" && event.toolCall) {
578
+ ensureStarted();
579
+ if (event.toolCall.name) {
580
+ if (currentBlockType !== null) {
581
+ events.push({
582
+ event: "content_block_stop",
583
+ data: { type: "content_block_stop", index: contentIndex }
584
+ });
585
+ contentIndex++;
586
+ }
587
+ events.push({
588
+ event: "content_block_start",
589
+ data: {
590
+ type: "content_block_start",
591
+ index: contentIndex,
592
+ content_block: {
593
+ type: "tool_use",
594
+ id: event.toolCall.id || `toolu_${Date.now()}`,
595
+ name: event.toolCall.name,
596
+ input: {}
597
+ }
598
+ }
599
+ });
600
+ currentBlockType = "tool_use";
601
+ }
602
+ if (event.toolCall.arguments) {
603
+ events.push({
604
+ event: "content_block_delta",
605
+ data: {
606
+ type: "content_block_delta",
607
+ index: contentIndex,
608
+ delta: { type: "input_json_delta", partial_json: event.toolCall.arguments }
609
+ }
610
+ });
611
+ }
612
+ }
613
+ if (event.type === "end") {
614
+ if (event.usage) {
615
+ if (event.usage.completionTokens) outputTokens = event.usage.completionTokens;
616
+ }
617
+ if (currentBlockType !== null) {
618
+ events.push({
619
+ event: "content_block_stop",
620
+ data: { type: "content_block_stop", index: contentIndex }
621
+ });
622
+ }
623
+ const stopReason = mapFinishReason2(event.finishReason);
624
+ events.push({
625
+ event: "message_delta",
626
+ data: {
627
+ type: "message_delta",
628
+ delta: { stop_reason: stopReason, stop_sequence: null },
629
+ usage: { output_tokens: outputTokens }
630
+ }
631
+ });
632
+ events.push({
633
+ event: "message_stop",
634
+ data: { type: "message_stop" }
635
+ });
636
+ }
637
+ if (event.type === "error" && event.error) {
638
+ events.push({
639
+ event: "error",
640
+ data: {
641
+ type: "error",
642
+ error: {
643
+ type: "api_error",
644
+ message: event.error.message
645
+ }
646
+ }
647
+ });
648
+ }
649
+ return events;
650
+ }
651
+ };
652
+ }
653
+ function mapFinishReason2(reason) {
654
+ if (!reason) return "end_turn";
655
+ const reasonMap = {
656
+ stop: "end_turn",
657
+ length: "max_tokens",
658
+ tool_calls: "tool_use",
659
+ content_filter: "end_turn"
660
+ };
661
+ return reasonMap[reason] ?? "end_turn";
662
+ }
663
+
664
+ // src/adapter.ts
665
+ var anthropicAdapter = {
666
+ name: "anthropic",
667
+ version: "1.0.0",
668
+ capabilities: {
669
+ streaming: true,
670
+ tools: true,
671
+ vision: true,
672
+ multimodal: true,
673
+ systemPrompt: true,
674
+ toolChoice: true,
675
+ reasoning: true,
676
+ // Extended thinking
677
+ webSearch: false,
678
+ jsonMode: false,
679
+ // Anthropic doesn't have native JSON mode
680
+ logprobs: false,
681
+ seed: false
682
+ },
683
+ inbound: {
684
+ parseRequest: (request) => {
685
+ return parseRequest(request);
686
+ },
687
+ parseResponse: (response) => {
688
+ return parseResponse(response);
689
+ },
690
+ parseStream: (chunk) => {
691
+ return parseStream(chunk);
692
+ },
693
+ parseError: (error) => {
694
+ return parseError(error);
695
+ }
696
+ },
697
+ outbound: {
698
+ buildRequest: (ir) => {
699
+ return buildRequest(ir);
700
+ },
701
+ buildResponse: (ir) => {
702
+ return buildResponse(ir);
703
+ },
704
+ createStreamBuilder
705
+ },
706
+ getInfo() {
707
+ return {
708
+ name: this.name,
709
+ version: this.version,
710
+ capabilities: this.capabilities,
711
+ endpoint: {
712
+ baseUrl: "https://api.anthropic.com",
713
+ chatPath: "/v1/messages",
714
+ modelsPath: "/v1/models"
715
+ }
716
+ };
717
+ }
718
+ };
719
+
720
+ export { anthropicAdapter };
721
+ //# sourceMappingURL=index.js.map
722
+ //# sourceMappingURL=index.js.map