@absolutejs/absolute 0.19.0-beta.248 → 0.19.0-beta.249
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/.absolutejs/eslint-cache +1 -1
- package/.absolutejs/prettier.cache.json +17 -13
- package/.absolutejs/vue-tsc.tsbuildinfo +1 -1
- package/.claude/settings.local.json +2 -1
- package/dist/ai/index.js +636 -1
- package/dist/ai/index.js.map +10 -8
- package/dist/ai/providers/anthropic.js.map +2 -2
- package/dist/ai/providers/gemini.js +331 -0
- package/dist/ai/providers/gemini.js.map +10 -0
- package/dist/ai/providers/ollama.js.map +2 -2
- package/dist/ai/providers/openai.js.map +2 -2
- package/dist/ai/providers/openaiCompatible.js.map +3 -3
- package/dist/ai/providers/openaiResponses.js +432 -0
- package/dist/ai/providers/openaiResponses.js.map +10 -0
- package/dist/ai-client/angular/ai/index.js +61 -1
- package/dist/ai-client/react/ai/index.js +61 -1
- package/dist/ai-client/vue/ai/index.js +61 -1
- package/dist/angular/ai/index.js +62 -2
- package/dist/angular/ai/index.js.map +5 -5
- package/dist/build.js +3 -1
- package/dist/build.js.map +3 -3
- package/dist/index.js +3 -1
- package/dist/index.js.map +3 -3
- package/dist/react/ai/index.js +62 -2
- package/dist/react/ai/index.js.map +6 -6
- package/dist/src/ai/client/actions.d.ts +43 -0
- package/dist/src/ai/index.d.ts +2 -0
- package/dist/src/ai/providers/gemini.d.ts +7 -0
- package/dist/src/ai/providers/openaiResponses.d.ts +10 -0
- package/dist/svelte/ai/index.js +62 -2
- package/dist/svelte/ai/index.js.map +5 -5
- package/dist/types/ai.d.ts +38 -2
- package/dist/vue/ai/index.js +62 -2
- package/dist/vue/ai/index.js.map +5 -5
- package/package.json +9 -1
- package/scripts/build.ts +2 -0
- package/types/ai.ts +73 -6
- package/types/typeGuards.ts +11 -0
|
@@ -263,7 +263,8 @@
|
|
|
263
263
|
"WebFetch(domain:platform.openai.com)",
|
|
264
264
|
"Bash(bunx absolute:*)",
|
|
265
265
|
"mcp__playwright__browser_file_upload",
|
|
266
|
-
"WebFetch(domain:docs.anthropic.com)"
|
|
266
|
+
"WebFetch(domain:docs.anthropic.com)",
|
|
267
|
+
"WebFetch(domain:ai.google.dev)"
|
|
267
268
|
]
|
|
268
269
|
}
|
|
269
270
|
}
|
package/dist/ai/index.js
CHANGED
|
@@ -106,6 +106,8 @@ var isValidAIClientMessage = (data) => {
|
|
|
106
106
|
return "content" in data && typeof data.content === "string" && "messageId" in data && "conversationId" in data;
|
|
107
107
|
case "tool_status":
|
|
108
108
|
return "name" in data && "status" in data && "messageId" in data && "conversationId" in data;
|
|
109
|
+
case "image":
|
|
110
|
+
return "data" in data && typeof data.data === "string" && "format" in data && typeof data.format === "string" && "isPartial" in data && typeof data.isPartial === "boolean" && "messageId" in data && "conversationId" in data;
|
|
109
111
|
case "complete":
|
|
110
112
|
return "messageId" in data && "conversationId" in data;
|
|
111
113
|
case "error":
|
|
@@ -481,6 +483,607 @@ var moonshot = (config) => openaiCompatible({
|
|
|
481
483
|
baseUrl: "https://api.moonshot.ai"
|
|
482
484
|
});
|
|
483
485
|
|
|
486
|
+
// src/ai/providers/openaiResponses.ts
|
|
487
|
+
var DEFAULT_BASE_URL2 = "https://api.openai.com";
|
|
488
|
+
var EVENT_PREFIX_LENGTH = 7;
|
|
489
|
+
var DATA_PREFIX_LENGTH = 6;
|
|
490
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
491
|
+
var isRecordArray2 = (value) => Array.isArray(value) && value.length > 0 && isRecord2(value[0]);
|
|
492
|
+
var mapContentToResponsesFormat = (content) => {
|
|
493
|
+
if (typeof content === "string") {
|
|
494
|
+
return content;
|
|
495
|
+
}
|
|
496
|
+
const parts = [];
|
|
497
|
+
for (const block of content) {
|
|
498
|
+
if (block.type === "text") {
|
|
499
|
+
parts.push({ text: block.content, type: "input_text" });
|
|
500
|
+
} else if (block.type === "image") {
|
|
501
|
+
parts.push({
|
|
502
|
+
image_url: {
|
|
503
|
+
url: `data:${block.source.media_type};base64,${block.source.data}`
|
|
504
|
+
},
|
|
505
|
+
type: "input_image"
|
|
506
|
+
});
|
|
507
|
+
} else if (block.type === "document") {
|
|
508
|
+
parts.push({
|
|
509
|
+
file: {
|
|
510
|
+
file_data: `data:${block.source.media_type};base64,${block.source.data}`,
|
|
511
|
+
filename: block.name ?? "document.pdf"
|
|
512
|
+
},
|
|
513
|
+
type: "input_file"
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return parts.length > 0 ? parts : "";
|
|
518
|
+
};
|
|
519
|
+
var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
|
|
520
|
+
var convertToolBlocks = (content) => {
|
|
521
|
+
const items = [];
|
|
522
|
+
for (const block of content) {
|
|
523
|
+
if (block.type === "tool_use") {
|
|
524
|
+
items.push({
|
|
525
|
+
arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
|
|
526
|
+
call_id: block.id,
|
|
527
|
+
name: block.name,
|
|
528
|
+
type: "function_call"
|
|
529
|
+
});
|
|
530
|
+
} else if (block.type === "tool_result") {
|
|
531
|
+
items.push({
|
|
532
|
+
call_id: block.tool_use_id,
|
|
533
|
+
output: typeof block.content === "string" ? block.content : "",
|
|
534
|
+
type: "function_call_output"
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return items;
|
|
539
|
+
};
|
|
540
|
+
var convertMessage = (msg) => {
|
|
541
|
+
if (typeof msg.content !== "string" && Array.isArray(msg.content)) {
|
|
542
|
+
if (hasToolBlocks(msg.content)) {
|
|
543
|
+
return convertToolBlocks(msg.content);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
const content = mapContentToResponsesFormat(msg.content);
|
|
547
|
+
return [
|
|
548
|
+
{
|
|
549
|
+
content,
|
|
550
|
+
role: msg.role === "system" ? "developer" : msg.role,
|
|
551
|
+
type: "message"
|
|
552
|
+
}
|
|
553
|
+
];
|
|
554
|
+
};
|
|
555
|
+
var buildInput = (messages) => {
|
|
556
|
+
const input = [];
|
|
557
|
+
for (const msg of messages) {
|
|
558
|
+
input.push(...convertMessage(msg));
|
|
559
|
+
}
|
|
560
|
+
return input;
|
|
561
|
+
};
|
|
562
|
+
var mapToolDefinition = (tool) => ({
|
|
563
|
+
description: tool.description,
|
|
564
|
+
name: tool.name,
|
|
565
|
+
parameters: tool.input_schema,
|
|
566
|
+
type: "function"
|
|
567
|
+
});
|
|
568
|
+
var buildTools = (tools, imageGeneration) => {
|
|
569
|
+
const result = [];
|
|
570
|
+
if (tools) {
|
|
571
|
+
for (const tool of tools) {
|
|
572
|
+
result.push(mapToolDefinition(tool));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (imageGeneration) {
|
|
576
|
+
const imageGenTool = {
|
|
577
|
+
type: "image_generation"
|
|
578
|
+
};
|
|
579
|
+
if (imageGeneration.partialImages !== undefined) {
|
|
580
|
+
imageGenTool.partial_images = imageGeneration.partialImages;
|
|
581
|
+
}
|
|
582
|
+
result.push(imageGenTool);
|
|
583
|
+
}
|
|
584
|
+
return result.length > 0 ? result : undefined;
|
|
585
|
+
};
|
|
586
|
+
var buildRequestBody2 = (params, imageGeneration) => {
|
|
587
|
+
const body = {
|
|
588
|
+
input: buildInput(params.messages),
|
|
589
|
+
model: params.model,
|
|
590
|
+
stream: true
|
|
591
|
+
};
|
|
592
|
+
if (params.systemPrompt) {
|
|
593
|
+
body.instructions = params.systemPrompt;
|
|
594
|
+
}
|
|
595
|
+
const tools = buildTools(params.tools, imageGeneration);
|
|
596
|
+
if (tools) {
|
|
597
|
+
body.tools = tools;
|
|
598
|
+
}
|
|
599
|
+
return body;
|
|
600
|
+
};
|
|
601
|
+
var parseJSON = (data) => {
|
|
602
|
+
try {
|
|
603
|
+
return JSON.parse(data);
|
|
604
|
+
} catch {
|
|
605
|
+
return null;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
var parseToolInput2 = (rawArguments) => {
|
|
609
|
+
try {
|
|
610
|
+
return JSON.parse(rawArguments);
|
|
611
|
+
} catch {
|
|
612
|
+
return rawArguments;
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
var extractUsage2 = (response) => {
|
|
616
|
+
if (!isRecord2(response.usage)) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const { usage } = response;
|
|
620
|
+
return {
|
|
621
|
+
inputTokens: typeof usage.input_tokens === "number" ? usage.input_tokens : 0,
|
|
622
|
+
outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0
|
|
623
|
+
};
|
|
624
|
+
};
|
|
625
|
+
var extractMimeFormat = (mimeType) => {
|
|
626
|
+
if (typeof mimeType !== "string") {
|
|
627
|
+
return "png";
|
|
628
|
+
}
|
|
629
|
+
if (mimeType.includes("jpeg"))
|
|
630
|
+
return "jpeg";
|
|
631
|
+
if (mimeType.includes("webp"))
|
|
632
|
+
return "webp";
|
|
633
|
+
return "png";
|
|
634
|
+
};
|
|
635
|
+
var processTextDelta = function* (parsed) {
|
|
636
|
+
if (typeof parsed.delta === "string") {
|
|
637
|
+
yield { content: parsed.delta, type: "text" };
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
var processPartialImage = function* (parsed) {
|
|
641
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : undefined;
|
|
642
|
+
const b64 = typeof parsed.partial_image_b64 === "string" ? parsed.partial_image_b64 : undefined;
|
|
643
|
+
if (b64) {
|
|
644
|
+
yield {
|
|
645
|
+
data: b64,
|
|
646
|
+
format: "png",
|
|
647
|
+
imageId: itemId,
|
|
648
|
+
isPartial: true,
|
|
649
|
+
type: "image"
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
var processFunctionCallArgumentsDelta = (parsed, pendingCalls) => {
|
|
654
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
|
|
655
|
+
const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
|
|
656
|
+
const delta = typeof parsed.arguments_delta === "string" ? parsed.arguments_delta : "";
|
|
657
|
+
const existing = pendingCalls.get(itemId);
|
|
658
|
+
if (existing) {
|
|
659
|
+
existing.arguments += delta;
|
|
660
|
+
} else {
|
|
661
|
+
pendingCalls.set(itemId, {
|
|
662
|
+
arguments: delta,
|
|
663
|
+
callId,
|
|
664
|
+
name: ""
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
var processFunctionCallArgumentsDone = function* (parsed, pendingCalls) {
|
|
669
|
+
const itemId = typeof parsed.item_id === "string" ? parsed.item_id : "";
|
|
670
|
+
const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
|
|
671
|
+
const fullArgs = typeof parsed.arguments === "string" ? parsed.arguments : "";
|
|
672
|
+
const pending = pendingCalls.get(itemId);
|
|
673
|
+
const name = pending?.name ?? "";
|
|
674
|
+
const args = fullArgs || pending?.arguments || "";
|
|
675
|
+
pendingCalls.delete(itemId);
|
|
676
|
+
yield {
|
|
677
|
+
id: callId,
|
|
678
|
+
input: parseToolInput2(args),
|
|
679
|
+
name,
|
|
680
|
+
type: "tool_use"
|
|
681
|
+
};
|
|
682
|
+
};
|
|
683
|
+
var processOutputItemAdded = (parsed, pendingCalls) => {
|
|
684
|
+
if (!isRecord2(parsed.item)) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const { item } = parsed;
|
|
688
|
+
const itemId = typeof item.id === "string" ? item.id : "";
|
|
689
|
+
const itemType = typeof item.type === "string" ? item.type : "";
|
|
690
|
+
if (itemType === "function_call") {
|
|
691
|
+
const callId = typeof item.call_id === "string" ? item.call_id : "";
|
|
692
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
693
|
+
pendingCalls.set(itemId, {
|
|
694
|
+
arguments: "",
|
|
695
|
+
callId,
|
|
696
|
+
name
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
var extractImageFromOutput = function* (output) {
|
|
701
|
+
for (const item of output) {
|
|
702
|
+
if (item.type !== "image_generation_call") {
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
if (item.status !== "completed") {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
const data = typeof item.result === "string" ? item.result : "";
|
|
709
|
+
if (!data) {
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
const format = extractMimeFormat(item.output_format);
|
|
713
|
+
const revisedPrompt = typeof item.revised_prompt === "string" ? item.revised_prompt : undefined;
|
|
714
|
+
const imageId = typeof item.id === "string" ? item.id : undefined;
|
|
715
|
+
yield {
|
|
716
|
+
data,
|
|
717
|
+
format,
|
|
718
|
+
imageId,
|
|
719
|
+
isPartial: false,
|
|
720
|
+
revisedPrompt,
|
|
721
|
+
type: "image"
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
var processCompleted = function* (parsed) {
|
|
726
|
+
if (!isRecord2(parsed.response)) {
|
|
727
|
+
yield { type: "done", usage: undefined };
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
const { response } = parsed;
|
|
731
|
+
const usage = extractUsage2(response);
|
|
732
|
+
if (isRecordArray2(response.output)) {
|
|
733
|
+
yield* extractImageFromOutput(response.output);
|
|
734
|
+
}
|
|
735
|
+
yield { type: "done", usage };
|
|
736
|
+
};
|
|
737
|
+
var processSSEEvent = function* (eventType, parsed, pendingCalls) {
|
|
738
|
+
switch (eventType) {
|
|
739
|
+
case "response.output_text.delta":
|
|
740
|
+
yield* processTextDelta(parsed);
|
|
741
|
+
break;
|
|
742
|
+
case "response.image_generation_call.partial_image":
|
|
743
|
+
yield* processPartialImage(parsed);
|
|
744
|
+
break;
|
|
745
|
+
case "response.output_item.added":
|
|
746
|
+
processOutputItemAdded(parsed, pendingCalls);
|
|
747
|
+
break;
|
|
748
|
+
case "response.function_call_arguments.delta":
|
|
749
|
+
processFunctionCallArgumentsDelta(parsed, pendingCalls);
|
|
750
|
+
break;
|
|
751
|
+
case "response.function_call_arguments.done":
|
|
752
|
+
yield* processFunctionCallArgumentsDone(parsed, pendingCalls);
|
|
753
|
+
break;
|
|
754
|
+
case "response.completed":
|
|
755
|
+
yield* processCompleted(parsed);
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
var processSSELines2 = function* (lines, state) {
|
|
760
|
+
for (const line of lines) {
|
|
761
|
+
const trimmed = line.trim();
|
|
762
|
+
if (!trimmed) {
|
|
763
|
+
if (state.currentEvent && state.buffer) {
|
|
764
|
+
const parsed = parseJSON(state.buffer);
|
|
765
|
+
if (parsed) {
|
|
766
|
+
yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls);
|
|
767
|
+
}
|
|
768
|
+
state.currentEvent = "";
|
|
769
|
+
state.buffer = "";
|
|
770
|
+
}
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
if (trimmed.startsWith("event: ")) {
|
|
774
|
+
state.currentEvent = trimmed.slice(EVENT_PREFIX_LENGTH);
|
|
775
|
+
} else if (trimmed.startsWith("data: ")) {
|
|
776
|
+
state.buffer = trimmed.slice(DATA_PREFIX_LENGTH);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
var drainReader2 = async function* (reader, decoder, state, signal) {
|
|
781
|
+
let textBuffer = "";
|
|
782
|
+
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
783
|
+
textBuffer += decoder.decode(result.value, { stream: true });
|
|
784
|
+
const lines = textBuffer.split(`
|
|
785
|
+
`);
|
|
786
|
+
textBuffer = lines.pop() ?? "";
|
|
787
|
+
yield* processSSELines2(lines, state);
|
|
788
|
+
}
|
|
789
|
+
if (textBuffer.trim()) {
|
|
790
|
+
yield* processSSELines2([textBuffer, ""], state);
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
var parseSSEStream2 = async function* (body, signal) {
|
|
794
|
+
const reader = body.getReader();
|
|
795
|
+
const decoder = new TextDecoder;
|
|
796
|
+
const state = {
|
|
797
|
+
buffer: "",
|
|
798
|
+
currentEvent: "",
|
|
799
|
+
pendingCalls: new Map,
|
|
800
|
+
usage: undefined
|
|
801
|
+
};
|
|
802
|
+
try {
|
|
803
|
+
yield* drainReader2(reader, decoder, state, signal);
|
|
804
|
+
} finally {
|
|
805
|
+
reader.releaseLock();
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
var fetchResponsesStream = async function* (baseUrl, apiKey, body, signal) {
|
|
809
|
+
const response = await fetch(`${baseUrl}/v1/responses`, {
|
|
810
|
+
body: JSON.stringify(body),
|
|
811
|
+
headers: {
|
|
812
|
+
Authorization: `Bearer ${apiKey}`,
|
|
813
|
+
"Content-Type": "application/json"
|
|
814
|
+
},
|
|
815
|
+
method: "POST",
|
|
816
|
+
signal
|
|
817
|
+
});
|
|
818
|
+
if (!response.ok) {
|
|
819
|
+
const errorText = await response.text();
|
|
820
|
+
throw new Error(`OpenAI Responses API error ${response.status}: ${errorText}`);
|
|
821
|
+
}
|
|
822
|
+
if (!response.body) {
|
|
823
|
+
throw new Error("OpenAI Responses API returned no response body");
|
|
824
|
+
}
|
|
825
|
+
yield* parseSSEStream2(response.body, signal);
|
|
826
|
+
};
|
|
827
|
+
var openaiResponses = (config) => {
|
|
828
|
+
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL2;
|
|
829
|
+
return {
|
|
830
|
+
stream: (params) => {
|
|
831
|
+
const body = buildRequestBody2(params, config.imageGeneration);
|
|
832
|
+
return fetchResponsesStream(baseUrl, config.apiKey, body, params.signal);
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/ai/providers/gemini.ts
|
|
838
|
+
var DEFAULT_BASE_URL3 = "https://generativelanguage.googleapis.com";
|
|
839
|
+
var SSE_DATA_PREFIX_LENGTH2 = 6;
|
|
840
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null;
|
|
841
|
+
var isRecordArray3 = (value) => Array.isArray(value) && value.length > 0 && isRecord3(value[0]);
|
|
842
|
+
var mapRole = (role) => {
|
|
843
|
+
if (role === "assistant" || role === "system")
|
|
844
|
+
return "model";
|
|
845
|
+
return "user";
|
|
846
|
+
};
|
|
847
|
+
var mapContentBlock = (block) => {
|
|
848
|
+
switch (block.type) {
|
|
849
|
+
case "text":
|
|
850
|
+
return { text: block.content };
|
|
851
|
+
case "image":
|
|
852
|
+
return {
|
|
853
|
+
inlineData: {
|
|
854
|
+
data: block.source.data,
|
|
855
|
+
mimeType: block.source.media_type
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
case "document":
|
|
859
|
+
return {
|
|
860
|
+
inlineData: {
|
|
861
|
+
data: block.source.data,
|
|
862
|
+
mimeType: block.source.media_type
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
case "tool_use":
|
|
866
|
+
return {
|
|
867
|
+
functionCall: {
|
|
868
|
+
args: typeof block.input === "string" ? JSON.parse(block.input) : block.input,
|
|
869
|
+
name: block.name
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
case "tool_result":
|
|
873
|
+
return {
|
|
874
|
+
functionResponse: {
|
|
875
|
+
name: block.tool_use_id,
|
|
876
|
+
response: { result: block.content }
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
default:
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
var convertMessageContent = (content) => {
|
|
884
|
+
if (typeof content === "string") {
|
|
885
|
+
return [{ text: content }];
|
|
886
|
+
}
|
|
887
|
+
const parts = [];
|
|
888
|
+
for (const block of content) {
|
|
889
|
+
const mapped = mapContentBlock(block);
|
|
890
|
+
if (mapped) {
|
|
891
|
+
parts.push(mapped);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return parts;
|
|
895
|
+
};
|
|
896
|
+
var hasFunctionResponse = (content) => content.some((block) => block.type === "tool_result");
|
|
897
|
+
var convertMessages = (messages) => {
|
|
898
|
+
const contents = [];
|
|
899
|
+
for (const msg of messages) {
|
|
900
|
+
if (typeof msg.content !== "string" && hasFunctionResponse(msg.content)) {
|
|
901
|
+
const parts = convertMessageContent(msg.content);
|
|
902
|
+
contents.push({ parts, role: "user" });
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
contents.push({
|
|
906
|
+
parts: convertMessageContent(msg.content),
|
|
907
|
+
role: mapRole(msg.role)
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
return contents;
|
|
911
|
+
};
|
|
912
|
+
var mapToolDefinitions2 = (tools) => tools.map((tool) => ({
|
|
913
|
+
description: tool.description,
|
|
914
|
+
name: tool.name,
|
|
915
|
+
parameters: tool.input_schema
|
|
916
|
+
}));
|
|
917
|
+
var buildRequestBody3 = (params) => {
|
|
918
|
+
const body = {
|
|
919
|
+
contents: convertMessages(params.messages),
|
|
920
|
+
generationConfig: {
|
|
921
|
+
responseModalities: ["TEXT", "IMAGE"]
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
if (params.systemPrompt) {
|
|
925
|
+
body.systemInstruction = {
|
|
926
|
+
parts: [{ text: params.systemPrompt }]
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
if (params.tools && params.tools.length > 0) {
|
|
930
|
+
body.tools = [
|
|
931
|
+
{ functionDeclarations: mapToolDefinitions2(params.tools) }
|
|
932
|
+
];
|
|
933
|
+
}
|
|
934
|
+
return body;
|
|
935
|
+
};
|
|
936
|
+
var extractMimeFormat2 = (mimeType) => {
|
|
937
|
+
if (typeof mimeType !== "string") {
|
|
938
|
+
return "png";
|
|
939
|
+
}
|
|
940
|
+
if (mimeType.includes("jpeg") || mimeType.includes("jpg"))
|
|
941
|
+
return "jpeg";
|
|
942
|
+
if (mimeType.includes("webp"))
|
|
943
|
+
return "webp";
|
|
944
|
+
return "png";
|
|
945
|
+
};
|
|
946
|
+
var processTextPart = function* (part) {
|
|
947
|
+
if (typeof part.text === "string" && part.text) {
|
|
948
|
+
yield { content: part.text, type: "text" };
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
var processInlineDataPart = function* (inlineData) {
|
|
952
|
+
const data = typeof inlineData.data === "string" ? inlineData.data : "";
|
|
953
|
+
const mimeType = inlineData.mimeType;
|
|
954
|
+
if (!data) {
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
yield {
|
|
958
|
+
data,
|
|
959
|
+
format: extractMimeFormat2(mimeType),
|
|
960
|
+
isPartial: false,
|
|
961
|
+
type: "image"
|
|
962
|
+
};
|
|
963
|
+
};
|
|
964
|
+
var processFunctionCallPart = function* (functionCall) {
|
|
965
|
+
const name = typeof functionCall.name === "string" ? functionCall.name : "";
|
|
966
|
+
const args = functionCall.args ?? {};
|
|
967
|
+
yield {
|
|
968
|
+
id: `gemini-${name}-${Date.now()}`,
|
|
969
|
+
input: args,
|
|
970
|
+
name,
|
|
971
|
+
type: "tool_use"
|
|
972
|
+
};
|
|
973
|
+
};
|
|
974
|
+
var processPart = function* (part) {
|
|
975
|
+
if ("text" in part) {
|
|
976
|
+
yield* processTextPart(part);
|
|
977
|
+
}
|
|
978
|
+
if (isRecord3(part.inlineData)) {
|
|
979
|
+
yield* processInlineDataPart(part.inlineData);
|
|
980
|
+
}
|
|
981
|
+
if (isRecord3(part.functionCall)) {
|
|
982
|
+
yield* processFunctionCallPart(part.functionCall);
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
var extractUsage3 = (parsed) => {
|
|
986
|
+
if (!isRecord3(parsed.usageMetadata)) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const { usageMetadata } = parsed;
|
|
990
|
+
return {
|
|
991
|
+
inputTokens: typeof usageMetadata.promptTokenCount === "number" ? usageMetadata.promptTokenCount : 0,
|
|
992
|
+
outputTokens: typeof usageMetadata.candidatesTokenCount === "number" ? usageMetadata.candidatesTokenCount : 0
|
|
993
|
+
};
|
|
994
|
+
};
|
|
995
|
+
var processChunk = function* (parsed, state) {
|
|
996
|
+
const usage = extractUsage3(parsed);
|
|
997
|
+
if (usage) {
|
|
998
|
+
state.usage = usage;
|
|
999
|
+
}
|
|
1000
|
+
if (!isRecordArray3(parsed.candidates)) {
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
const candidate = parsed.candidates[0];
|
|
1004
|
+
if (!candidate || !isRecord3(candidate.content)) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
const { content } = candidate;
|
|
1008
|
+
if (!isRecordArray3(content.parts)) {
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
for (const part of content.parts) {
|
|
1012
|
+
yield* processPart(part);
|
|
1013
|
+
}
|
|
1014
|
+
};
|
|
1015
|
+
var processSSELine2 = function* (line, state) {
|
|
1016
|
+
const trimmed = line.trim();
|
|
1017
|
+
if (!trimmed || !trimmed.startsWith("data: ")) {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const data = trimmed.slice(SSE_DATA_PREFIX_LENGTH2);
|
|
1021
|
+
let parsed;
|
|
1022
|
+
try {
|
|
1023
|
+
parsed = JSON.parse(data);
|
|
1024
|
+
} catch {
|
|
1025
|
+
return;
|
|
1026
|
+
}
|
|
1027
|
+
yield* processChunk(parsed, state);
|
|
1028
|
+
};
|
|
1029
|
+
var drainReader3 = async function* (reader, decoder, state, signal) {
|
|
1030
|
+
let textBuffer = "";
|
|
1031
|
+
for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
|
|
1032
|
+
textBuffer += decoder.decode(result.value, { stream: true });
|
|
1033
|
+
const lines = textBuffer.split(`
|
|
1034
|
+
`);
|
|
1035
|
+
textBuffer = lines.pop() ?? "";
|
|
1036
|
+
for (const line of lines) {
|
|
1037
|
+
yield* processSSELine2(line, state);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (textBuffer.trim()) {
|
|
1041
|
+
yield* processSSELine2(textBuffer, state);
|
|
1042
|
+
}
|
|
1043
|
+
yield { type: "done", usage: state.usage };
|
|
1044
|
+
};
|
|
1045
|
+
var parseSSEStream3 = async function* (body, signal) {
|
|
1046
|
+
const reader = body.getReader();
|
|
1047
|
+
const decoder = new TextDecoder;
|
|
1048
|
+
const state = {
|
|
1049
|
+
buffer: "",
|
|
1050
|
+
usage: undefined
|
|
1051
|
+
};
|
|
1052
|
+
try {
|
|
1053
|
+
yield* drainReader3(reader, decoder, state, signal);
|
|
1054
|
+
} finally {
|
|
1055
|
+
reader.releaseLock();
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
var fetchGeminiStream = async function* (baseUrl, apiKey, model, body, signal) {
|
|
1059
|
+
const url = `${baseUrl}/v1beta/models/${model}:streamGenerateContent?alt=sse&key=${apiKey}`;
|
|
1060
|
+
const response = await fetch(url, {
|
|
1061
|
+
body: JSON.stringify(body),
|
|
1062
|
+
headers: {
|
|
1063
|
+
"Content-Type": "application/json"
|
|
1064
|
+
},
|
|
1065
|
+
method: "POST",
|
|
1066
|
+
signal
|
|
1067
|
+
});
|
|
1068
|
+
if (!response.ok) {
|
|
1069
|
+
const errorText = await response.text();
|
|
1070
|
+
throw new Error(`Gemini API error ${response.status}: ${errorText}`);
|
|
1071
|
+
}
|
|
1072
|
+
if (!response.body) {
|
|
1073
|
+
throw new Error("Gemini API returned no response body");
|
|
1074
|
+
}
|
|
1075
|
+
yield* parseSSEStream3(response.body, signal);
|
|
1076
|
+
};
|
|
1077
|
+
var gemini = (config) => {
|
|
1078
|
+
const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL3;
|
|
1079
|
+
return {
|
|
1080
|
+
stream: (params) => {
|
|
1081
|
+
const body = buildRequestBody3(params);
|
|
1082
|
+
return fetchGeminiStream(baseUrl, config.apiKey, params.model, body, params.signal);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
};
|
|
1086
|
+
|
|
484
1087
|
// src/plugins/aiChat.ts
|
|
485
1088
|
import { Elysia } from "elysia";
|
|
486
1089
|
|
|
@@ -651,6 +1254,16 @@ var extractTextContent = (chunk, onChunk) => {
|
|
|
651
1254
|
}
|
|
652
1255
|
return chunk.content;
|
|
653
1256
|
};
|
|
1257
|
+
var sendImageMessage = async (socket, chunk, messageId, conversationId) => sendMessage(socket, {
|
|
1258
|
+
conversationId,
|
|
1259
|
+
data: chunk.data,
|
|
1260
|
+
format: chunk.format,
|
|
1261
|
+
imageId: chunk.imageId,
|
|
1262
|
+
isPartial: chunk.isPartial,
|
|
1263
|
+
messageId,
|
|
1264
|
+
revisedPrompt: chunk.revisedPrompt,
|
|
1265
|
+
type: "image"
|
|
1266
|
+
});
|
|
654
1267
|
var sendToolRunning = async (socket, toolName, toolInput, messageId, conversationId) => sendMessage(socket, {
|
|
655
1268
|
conversationId,
|
|
656
1269
|
input: toolInput,
|
|
@@ -715,6 +1328,16 @@ var processToolChunk = (chunk, state, options, socket, messageId, conversationId
|
|
|
715
1328
|
case "text":
|
|
716
1329
|
handleToolChunkText(chunk, state, options, socket, messageId, conversationId);
|
|
717
1330
|
break;
|
|
1331
|
+
case "image":
|
|
1332
|
+
sendImageMessage(socket, chunk, messageId, conversationId);
|
|
1333
|
+
options.onImage?.({
|
|
1334
|
+
data: chunk.data,
|
|
1335
|
+
format: chunk.format,
|
|
1336
|
+
imageId: chunk.imageId,
|
|
1337
|
+
isPartial: chunk.isPartial,
|
|
1338
|
+
revisedPrompt: chunk.revisedPrompt
|
|
1339
|
+
});
|
|
1340
|
+
break;
|
|
718
1341
|
case "tool_use":
|
|
719
1342
|
handleToolChunkToolUse(chunk, state);
|
|
720
1343
|
hitAnotherTool = true;
|
|
@@ -865,6 +1488,16 @@ var consumeStreamChunk = async (chunk, options, socket, messages, messageId, con
|
|
|
865
1488
|
return "";
|
|
866
1489
|
case "text":
|
|
867
1490
|
return processStreamTextChunk(chunk, options, socket, messageId, conversationId);
|
|
1491
|
+
case "image":
|
|
1492
|
+
await sendImageMessage(socket, chunk, messageId, conversationId);
|
|
1493
|
+
options.onImage?.({
|
|
1494
|
+
data: chunk.data,
|
|
1495
|
+
format: chunk.format,
|
|
1496
|
+
imageId: chunk.imageId,
|
|
1497
|
+
isPartial: chunk.isPartial,
|
|
1498
|
+
revisedPrompt: chunk.revisedPrompt
|
|
1499
|
+
});
|
|
1500
|
+
return "";
|
|
868
1501
|
case "tool_use":
|
|
869
1502
|
await processStreamToolUseChunk(chunk, socket, options, messages, messageId, conversationId, signal, fullResponse, startTime);
|
|
870
1503
|
return { earlyReturn: true, fullResponse, usage: undefined };
|
|
@@ -1059,17 +1692,19 @@ export {
|
|
|
1059
1692
|
streamAI,
|
|
1060
1693
|
serializeAIMessage,
|
|
1061
1694
|
parseAIMessage,
|
|
1695
|
+
openaiResponses,
|
|
1062
1696
|
openaiCompatible,
|
|
1063
1697
|
moonshot,
|
|
1064
1698
|
mistralai,
|
|
1065
1699
|
meta,
|
|
1066
1700
|
google,
|
|
1067
1701
|
generateId,
|
|
1702
|
+
gemini,
|
|
1068
1703
|
deepseek,
|
|
1069
1704
|
createConversationManager,
|
|
1070
1705
|
alibaba,
|
|
1071
1706
|
aiChat
|
|
1072
1707
|
};
|
|
1073
1708
|
|
|
1074
|
-
//# debugId=
|
|
1709
|
+
//# debugId=214AE01443FBB99E64756E2164756E21
|
|
1075
1710
|
//# sourceMappingURL=index.js.map
|