copilot-api-plus 1.0.11 → 1.0.12
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/auth-Cm_0h9bp.js.map +1 -1
- package/dist/get-models-Bbb8B5jI.js.map +1 -1
- package/dist/main.js +705 -437
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -681,6 +681,165 @@ const apiKeyAuthMiddleware = async (c, next) => {
|
|
|
681
681
|
await next();
|
|
682
682
|
};
|
|
683
683
|
|
|
684
|
+
//#endregion
|
|
685
|
+
//#region src/services/antigravity/stream-parser.ts
|
|
686
|
+
/**
|
|
687
|
+
* Create initial stream state
|
|
688
|
+
*/
|
|
689
|
+
function createStreamState() {
|
|
690
|
+
return {
|
|
691
|
+
buffer: "",
|
|
692
|
+
inputTokens: 0,
|
|
693
|
+
outputTokens: 0,
|
|
694
|
+
contentBlockIndex: 0,
|
|
695
|
+
thinkingBlockStarted: false,
|
|
696
|
+
textBlockStarted: false
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Parse a single SSE line and return the JSON data if valid
|
|
701
|
+
*/
|
|
702
|
+
function parseSSELine(line) {
|
|
703
|
+
if (!line.startsWith("data: ")) return null;
|
|
704
|
+
const data = line.slice(6).trim();
|
|
705
|
+
if (data === "[DONE]" || data === "") return null;
|
|
706
|
+
try {
|
|
707
|
+
return JSON.parse(data);
|
|
708
|
+
} catch {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Extract candidates and usage from parsed data
|
|
714
|
+
*/
|
|
715
|
+
function extractFromData(data) {
|
|
716
|
+
const candidates = data.response?.candidates || data.candidates || [];
|
|
717
|
+
const usage = data.response?.usageMetadata || data.usageMetadata;
|
|
718
|
+
return {
|
|
719
|
+
candidates,
|
|
720
|
+
usage
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Process a single part and emit events
|
|
725
|
+
*/
|
|
726
|
+
function processPart(part, state$1, emit) {
|
|
727
|
+
if (part.thought && part.text) {
|
|
728
|
+
processThinkingPart(part.text, state$1, emit);
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (part.text && !part.thought) {
|
|
732
|
+
processTextPart(part.text, state$1, emit);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
if (part.functionCall) processToolPart(part.functionCall, state$1, emit);
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Process thinking content
|
|
739
|
+
*/
|
|
740
|
+
function processThinkingPart(text, state$1, emit) {
|
|
741
|
+
if (!state$1.thinkingBlockStarted) {
|
|
742
|
+
emit({
|
|
743
|
+
type: "thinking_start",
|
|
744
|
+
index: state$1.contentBlockIndex
|
|
745
|
+
});
|
|
746
|
+
state$1.thinkingBlockStarted = true;
|
|
747
|
+
}
|
|
748
|
+
emit({
|
|
749
|
+
type: "thinking_delta",
|
|
750
|
+
index: state$1.contentBlockIndex,
|
|
751
|
+
text
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Process text content
|
|
756
|
+
*/
|
|
757
|
+
function processTextPart(text, state$1, emit) {
|
|
758
|
+
if (state$1.thinkingBlockStarted && !state$1.textBlockStarted) {
|
|
759
|
+
emit({
|
|
760
|
+
type: "thinking_stop",
|
|
761
|
+
index: state$1.contentBlockIndex
|
|
762
|
+
});
|
|
763
|
+
state$1.contentBlockIndex++;
|
|
764
|
+
state$1.thinkingBlockStarted = false;
|
|
765
|
+
}
|
|
766
|
+
if (!state$1.textBlockStarted) {
|
|
767
|
+
emit({
|
|
768
|
+
type: "text_start",
|
|
769
|
+
index: state$1.contentBlockIndex
|
|
770
|
+
});
|
|
771
|
+
state$1.textBlockStarted = true;
|
|
772
|
+
}
|
|
773
|
+
emit({
|
|
774
|
+
type: "text_delta",
|
|
775
|
+
index: state$1.contentBlockIndex,
|
|
776
|
+
text
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Process tool/function call
|
|
781
|
+
*/
|
|
782
|
+
function processToolPart(functionCall, state$1, emit) {
|
|
783
|
+
if (state$1.textBlockStarted) {
|
|
784
|
+
emit({
|
|
785
|
+
type: "text_stop",
|
|
786
|
+
index: state$1.contentBlockIndex
|
|
787
|
+
});
|
|
788
|
+
state$1.contentBlockIndex++;
|
|
789
|
+
state$1.textBlockStarted = false;
|
|
790
|
+
} else if (state$1.thinkingBlockStarted) {
|
|
791
|
+
emit({
|
|
792
|
+
type: "thinking_stop",
|
|
793
|
+
index: state$1.contentBlockIndex
|
|
794
|
+
});
|
|
795
|
+
state$1.contentBlockIndex++;
|
|
796
|
+
state$1.thinkingBlockStarted = false;
|
|
797
|
+
}
|
|
798
|
+
emit({
|
|
799
|
+
type: "tool_use",
|
|
800
|
+
index: state$1.contentBlockIndex,
|
|
801
|
+
name: functionCall.name,
|
|
802
|
+
args: functionCall.args
|
|
803
|
+
});
|
|
804
|
+
state$1.contentBlockIndex++;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Handle finish reason and close open blocks
|
|
808
|
+
*/
|
|
809
|
+
function handleFinish(state$1, emit) {
|
|
810
|
+
if (state$1.textBlockStarted) {
|
|
811
|
+
emit({
|
|
812
|
+
type: "text_stop",
|
|
813
|
+
index: state$1.contentBlockIndex
|
|
814
|
+
});
|
|
815
|
+
state$1.textBlockStarted = false;
|
|
816
|
+
} else if (state$1.thinkingBlockStarted) {
|
|
817
|
+
emit({
|
|
818
|
+
type: "thinking_stop",
|
|
819
|
+
index: state$1.contentBlockIndex
|
|
820
|
+
});
|
|
821
|
+
state$1.thinkingBlockStarted = false;
|
|
822
|
+
}
|
|
823
|
+
emit({
|
|
824
|
+
type: "usage",
|
|
825
|
+
inputTokens: state$1.inputTokens,
|
|
826
|
+
outputTokens: state$1.outputTokens
|
|
827
|
+
});
|
|
828
|
+
emit({
|
|
829
|
+
type: "finish",
|
|
830
|
+
stopReason: "end_turn"
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Process chunk and update buffer, returning complete lines
|
|
835
|
+
*/
|
|
836
|
+
function processChunk(chunk, state$1) {
|
|
837
|
+
state$1.buffer += chunk;
|
|
838
|
+
const lines = state$1.buffer.split("\n");
|
|
839
|
+
state$1.buffer = lines.pop() || "";
|
|
840
|
+
return lines;
|
|
841
|
+
}
|
|
842
|
+
|
|
684
843
|
//#endregion
|
|
685
844
|
//#region src/services/antigravity/create-chat-completions.ts
|
|
686
845
|
const ANTIGRAVITY_API_HOST$1 = "daily-cloudcode-pa.sandbox.googleapis.com";
|
|
@@ -692,38 +851,18 @@ const ANTIGRAVITY_USER_AGENT$1 = "antigravity/1.11.3 windows/amd64";
|
|
|
692
851
|
*/
|
|
693
852
|
function convertMessages$1(messages) {
|
|
694
853
|
const contents = [];
|
|
695
|
-
let systemInstruction
|
|
854
|
+
let systemInstruction;
|
|
696
855
|
for (const message of messages) {
|
|
697
856
|
if (message.role === "system") {
|
|
698
|
-
systemInstruction =
|
|
699
|
-
role: "user",
|
|
700
|
-
parts: [{ text: typeof message.content === "string" ? message.content : message.content.map((c) => c.text || "").join("") }]
|
|
701
|
-
};
|
|
857
|
+
systemInstruction = buildSystemInstruction(message.content);
|
|
702
858
|
continue;
|
|
703
859
|
}
|
|
704
860
|
const role = message.role === "assistant" ? "model" : "user";
|
|
705
|
-
|
|
861
|
+
const parts = buildMessageParts(message.content);
|
|
862
|
+
contents.push({
|
|
706
863
|
role,
|
|
707
|
-
parts
|
|
864
|
+
parts
|
|
708
865
|
});
|
|
709
|
-
else {
|
|
710
|
-
const parts = [];
|
|
711
|
-
for (const part of message.content) if (part.type === "text") parts.push({ text: part.text });
|
|
712
|
-
else if (part.type === "image_url" && part.image_url?.url) {
|
|
713
|
-
const url = part.image_url.url;
|
|
714
|
-
if (url.startsWith("data:")) {
|
|
715
|
-
const match = url.match(/^data:([^;]+);base64,(.+)$/);
|
|
716
|
-
if (match) parts.push({ inlineData: {
|
|
717
|
-
mimeType: match[1],
|
|
718
|
-
data: match[2]
|
|
719
|
-
} });
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
contents.push({
|
|
723
|
-
role,
|
|
724
|
-
parts
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
866
|
}
|
|
728
867
|
return {
|
|
729
868
|
contents,
|
|
@@ -731,10 +870,44 @@ function convertMessages$1(messages) {
|
|
|
731
870
|
};
|
|
732
871
|
}
|
|
733
872
|
/**
|
|
873
|
+
* Build system instruction from content
|
|
874
|
+
*/
|
|
875
|
+
function buildSystemInstruction(content) {
|
|
876
|
+
return {
|
|
877
|
+
role: "user",
|
|
878
|
+
parts: [{ text: typeof content === "string" ? content : content.map((c) => c.text || "").join("") }]
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Build message parts from content
|
|
883
|
+
*/
|
|
884
|
+
function buildMessageParts(content) {
|
|
885
|
+
if (typeof content === "string") return [{ text: content }];
|
|
886
|
+
const parts = [];
|
|
887
|
+
for (const part of content) if (part.type === "text") parts.push({ text: part.text });
|
|
888
|
+
else if (part.type === "image_url" && part.image_url?.url) {
|
|
889
|
+
const imageData = parseBase64Image(part.image_url.url);
|
|
890
|
+
if (imageData) parts.push({ inlineData: imageData });
|
|
891
|
+
}
|
|
892
|
+
return parts;
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* Parse base64 image URL
|
|
896
|
+
*/
|
|
897
|
+
function parseBase64Image(url) {
|
|
898
|
+
if (!url.startsWith("data:")) return null;
|
|
899
|
+
const match = url.match(/^data:([^;]+);base64,(.+)$/);
|
|
900
|
+
if (!match) return null;
|
|
901
|
+
return {
|
|
902
|
+
mimeType: match[1],
|
|
903
|
+
data: match[2]
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
734
907
|
* Convert tools to Antigravity format
|
|
735
908
|
*/
|
|
736
909
|
function convertTools$1(tools) {
|
|
737
|
-
if (!tools || tools.length === 0) return;
|
|
910
|
+
if (!tools || tools.length === 0) return void 0;
|
|
738
911
|
return tools.map((tool) => {
|
|
739
912
|
const t = tool;
|
|
740
913
|
if (t.type === "function" && t.function) return { functionDeclarations: [{
|
|
@@ -746,20 +919,12 @@ function convertTools$1(tools) {
|
|
|
746
919
|
});
|
|
747
920
|
}
|
|
748
921
|
/**
|
|
749
|
-
*
|
|
922
|
+
* Build Antigravity request body
|
|
750
923
|
*/
|
|
751
|
-
|
|
752
|
-
const accessToken = await getValidAccessToken();
|
|
753
|
-
if (!accessToken) return new Response(JSON.stringify({ error: {
|
|
754
|
-
message: "No valid Antigravity access token available. Please run login first.",
|
|
755
|
-
type: "auth_error"
|
|
756
|
-
} }), {
|
|
757
|
-
status: 401,
|
|
758
|
-
headers: { "Content-Type": "application/json" }
|
|
759
|
-
});
|
|
924
|
+
function buildRequestBody(request) {
|
|
760
925
|
const { contents, systemInstruction } = convertMessages$1(request.messages);
|
|
761
926
|
const tools = convertTools$1(request.tools);
|
|
762
|
-
const
|
|
927
|
+
const body = {
|
|
763
928
|
model: request.model,
|
|
764
929
|
contents,
|
|
765
930
|
generationConfig: {
|
|
@@ -769,13 +934,36 @@ async function createAntigravityChatCompletion(request) {
|
|
|
769
934
|
maxOutputTokens: request.max_tokens ?? 8096
|
|
770
935
|
}
|
|
771
936
|
};
|
|
772
|
-
if (systemInstruction)
|
|
773
|
-
if (tools)
|
|
774
|
-
if (isThinkingModel(request.model))
|
|
775
|
-
...
|
|
937
|
+
if (systemInstruction) body.systemInstruction = systemInstruction;
|
|
938
|
+
if (tools) body.tools = tools;
|
|
939
|
+
if (isThinkingModel(request.model)) body.generationConfig = {
|
|
940
|
+
...body.generationConfig,
|
|
776
941
|
thinkingConfig: { includeThoughts: true }
|
|
777
942
|
};
|
|
943
|
+
return body;
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Create error response
|
|
947
|
+
*/
|
|
948
|
+
function createErrorResponse$1(message, type, status, details) {
|
|
949
|
+
const error = {
|
|
950
|
+
message,
|
|
951
|
+
type
|
|
952
|
+
};
|
|
953
|
+
if (details) error.details = details;
|
|
954
|
+
return new Response(JSON.stringify({ error }), {
|
|
955
|
+
status,
|
|
956
|
+
headers: { "Content-Type": "application/json" }
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Create chat completion with Antigravity
|
|
961
|
+
*/
|
|
962
|
+
async function createAntigravityChatCompletion(request) {
|
|
963
|
+
const accessToken = await getValidAccessToken();
|
|
964
|
+
if (!accessToken) return createErrorResponse$1("No valid Antigravity access token available. Please run login first.", "auth_error", 401);
|
|
778
965
|
const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL$1 : ANTIGRAVITY_NO_STREAM_URL$1;
|
|
966
|
+
const body = buildRequestBody(request);
|
|
779
967
|
consola.debug(`Antigravity request to ${endpoint} with model ${request.model}`);
|
|
780
968
|
try {
|
|
781
969
|
const response = await fetch(endpoint, {
|
|
@@ -787,120 +975,46 @@ async function createAntigravityChatCompletion(request) {
|
|
|
787
975
|
"Content-Type": "application/json",
|
|
788
976
|
"Accept-Encoding": "gzip"
|
|
789
977
|
},
|
|
790
|
-
body: JSON.stringify(
|
|
978
|
+
body: JSON.stringify(body)
|
|
791
979
|
});
|
|
792
|
-
if (!response.ok)
|
|
793
|
-
|
|
794
|
-
consola.error(`Antigravity error: ${response.status} ${errorText}`);
|
|
795
|
-
if (response.status === 403) await disableCurrentAccount();
|
|
796
|
-
if (response.status === 429 || response.status === 503) await rotateAccount();
|
|
797
|
-
return new Response(JSON.stringify({ error: {
|
|
798
|
-
message: `Antigravity API error: ${response.status}`,
|
|
799
|
-
type: "api_error",
|
|
800
|
-
details: errorText
|
|
801
|
-
} }), {
|
|
802
|
-
status: response.status,
|
|
803
|
-
headers: { "Content-Type": "application/json" }
|
|
804
|
-
});
|
|
805
|
-
}
|
|
806
|
-
if (request.stream) return transformStreamResponse(response, request.model);
|
|
807
|
-
else return transformNonStreamResponse(response, request.model);
|
|
980
|
+
if (!response.ok) return await handleApiError$1(response);
|
|
981
|
+
return request.stream ? transformStreamResponse$1(response, request.model) : await transformNonStreamResponse$1(response, request.model);
|
|
808
982
|
} catch (error) {
|
|
809
983
|
consola.error("Antigravity request error:", error);
|
|
810
|
-
return
|
|
811
|
-
message: `Request failed: ${error}`,
|
|
812
|
-
type: "request_error"
|
|
813
|
-
} }), {
|
|
814
|
-
status: 500,
|
|
815
|
-
headers: { "Content-Type": "application/json" }
|
|
816
|
-
});
|
|
984
|
+
return createErrorResponse$1(`Request failed: ${String(error)}`, "request_error", 500);
|
|
817
985
|
}
|
|
818
986
|
}
|
|
819
987
|
/**
|
|
988
|
+
* Handle API error response
|
|
989
|
+
*/
|
|
990
|
+
async function handleApiError$1(response) {
|
|
991
|
+
const errorText = await response.text();
|
|
992
|
+
consola.error(`Antigravity error: ${response.status} ${errorText}`);
|
|
993
|
+
if (response.status === 403) await disableCurrentAccount();
|
|
994
|
+
if (response.status === 429 || response.status === 503) await rotateAccount();
|
|
995
|
+
return createErrorResponse$1(`Antigravity API error: ${response.status}`, "api_error", response.status, errorText);
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Generate request ID
|
|
999
|
+
*/
|
|
1000
|
+
function generateRequestId() {
|
|
1001
|
+
return `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
820
1004
|
* Transform Antigravity stream response to OpenAI format
|
|
821
1005
|
*/
|
|
822
|
-
function transformStreamResponse(response, model) {
|
|
1006
|
+
function transformStreamResponse$1(response, model) {
|
|
823
1007
|
const reader = response.body?.getReader();
|
|
824
1008
|
if (!reader) return new Response("No response body", { status: 500 });
|
|
825
|
-
const encoder = new TextEncoder();
|
|
1009
|
+
const encoder$1 = new TextEncoder();
|
|
826
1010
|
const decoder = new TextDecoder();
|
|
1011
|
+
const requestId = generateRequestId();
|
|
827
1012
|
const stream = new ReadableStream({ async start(controller) {
|
|
828
|
-
|
|
829
|
-
const requestId = `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
1013
|
+
const state$1 = createStreamState();
|
|
830
1014
|
try {
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
controller.enqueue(encoder.encode("data: [DONE]\n\n"));
|
|
835
|
-
controller.close();
|
|
836
|
-
break;
|
|
837
|
-
}
|
|
838
|
-
buffer += decoder.decode(value, { stream: true });
|
|
839
|
-
const lines = buffer.split("\n");
|
|
840
|
-
buffer = lines.pop() || "";
|
|
841
|
-
for (const line of lines) if (line.startsWith("data: ")) {
|
|
842
|
-
const data = line.slice(6).trim();
|
|
843
|
-
if (data === "[DONE]" || data === "") continue;
|
|
844
|
-
try {
|
|
845
|
-
const parsed = JSON.parse(data);
|
|
846
|
-
const candidate = (parsed.response?.candidates || parsed.candidates)?.[0];
|
|
847
|
-
const parts = candidate?.content?.parts || [];
|
|
848
|
-
for (const part of parts) {
|
|
849
|
-
if (part.thought && part.text) {
|
|
850
|
-
const chunk = {
|
|
851
|
-
id: requestId,
|
|
852
|
-
object: "chat.completion.chunk",
|
|
853
|
-
created: Math.floor(Date.now() / 1e3),
|
|
854
|
-
model,
|
|
855
|
-
choices: [{
|
|
856
|
-
index: 0,
|
|
857
|
-
delta: { reasoning_content: part.text },
|
|
858
|
-
finish_reason: null
|
|
859
|
-
}]
|
|
860
|
-
};
|
|
861
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
|
|
862
|
-
continue;
|
|
863
|
-
}
|
|
864
|
-
if (part.text) {
|
|
865
|
-
const chunk = {
|
|
866
|
-
id: requestId,
|
|
867
|
-
object: "chat.completion.chunk",
|
|
868
|
-
created: Math.floor(Date.now() / 1e3),
|
|
869
|
-
model,
|
|
870
|
-
choices: [{
|
|
871
|
-
index: 0,
|
|
872
|
-
delta: { content: part.text },
|
|
873
|
-
finish_reason: candidate?.finishReason === "STOP" ? "stop" : null
|
|
874
|
-
}]
|
|
875
|
-
};
|
|
876
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
|
|
877
|
-
}
|
|
878
|
-
if (part.functionCall) {
|
|
879
|
-
const chunk = {
|
|
880
|
-
id: requestId,
|
|
881
|
-
object: "chat.completion.chunk",
|
|
882
|
-
created: Math.floor(Date.now() / 1e3),
|
|
883
|
-
model,
|
|
884
|
-
choices: [{
|
|
885
|
-
index: 0,
|
|
886
|
-
delta: { tool_calls: [{
|
|
887
|
-
index: 0,
|
|
888
|
-
id: `call_${Date.now()}`,
|
|
889
|
-
type: "function",
|
|
890
|
-
function: {
|
|
891
|
-
name: part.functionCall.name,
|
|
892
|
-
arguments: JSON.stringify(part.functionCall.args)
|
|
893
|
-
}
|
|
894
|
-
}] },
|
|
895
|
-
finish_reason: null
|
|
896
|
-
}]
|
|
897
|
-
};
|
|
898
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
} catch {}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
1015
|
+
await processOpenAIStream(reader, decoder, state$1, controller, encoder$1, requestId, model);
|
|
1016
|
+
controller.enqueue(encoder$1.encode("data: [DONE]\n\n"));
|
|
1017
|
+
controller.close();
|
|
904
1018
|
} catch (error) {
|
|
905
1019
|
consola.error("Stream transform error:", error);
|
|
906
1020
|
controller.error(error);
|
|
@@ -913,27 +1027,78 @@ function transformStreamResponse(response, model) {
|
|
|
913
1027
|
} });
|
|
914
1028
|
}
|
|
915
1029
|
/**
|
|
916
|
-
*
|
|
1030
|
+
* Process stream and emit OpenAI format chunks
|
|
917
1031
|
*/
|
|
918
|
-
async function
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
arguments: JSON.stringify(part.functionCall.args)
|
|
1032
|
+
async function processOpenAIStream(reader, decoder, state$1, controller, encoder$1, requestId, model) {
|
|
1033
|
+
while (true) {
|
|
1034
|
+
const { done, value } = await reader.read();
|
|
1035
|
+
if (done) break;
|
|
1036
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
1037
|
+
const lines = processChunk(chunk, state$1);
|
|
1038
|
+
for (const line of lines) {
|
|
1039
|
+
const data = parseSSELine(line);
|
|
1040
|
+
if (!data) continue;
|
|
1041
|
+
const { candidates } = extractFromData(data);
|
|
1042
|
+
const candidate = candidates[0];
|
|
1043
|
+
const parts = candidate?.content?.parts ?? [];
|
|
1044
|
+
for (const part of parts) {
|
|
1045
|
+
const chunkData = buildOpenAIChunk(part, requestId, model, candidate?.finishReason);
|
|
1046
|
+
if (chunkData) controller.enqueue(encoder$1.encode(`data: ${JSON.stringify(chunkData)}\n\n`));
|
|
934
1047
|
}
|
|
935
|
-
}
|
|
1048
|
+
}
|
|
936
1049
|
}
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Build OpenAI format chunk from part
|
|
1053
|
+
*/
|
|
1054
|
+
function buildOpenAIChunk(part, requestId, model, finishReason) {
|
|
1055
|
+
const baseChunk = {
|
|
1056
|
+
id: requestId,
|
|
1057
|
+
object: "chat.completion.chunk",
|
|
1058
|
+
created: Math.floor(Date.now() / 1e3),
|
|
1059
|
+
model
|
|
1060
|
+
};
|
|
1061
|
+
if (part.thought && part.text) return {
|
|
1062
|
+
...baseChunk,
|
|
1063
|
+
choices: [{
|
|
1064
|
+
index: 0,
|
|
1065
|
+
delta: { reasoning_content: part.text },
|
|
1066
|
+
finish_reason: null
|
|
1067
|
+
}]
|
|
1068
|
+
};
|
|
1069
|
+
if (part.text && !part.thought) return {
|
|
1070
|
+
...baseChunk,
|
|
1071
|
+
choices: [{
|
|
1072
|
+
index: 0,
|
|
1073
|
+
delta: { content: part.text },
|
|
1074
|
+
finish_reason: finishReason === "STOP" ? "stop" : null
|
|
1075
|
+
}]
|
|
1076
|
+
};
|
|
1077
|
+
if (part.functionCall) return {
|
|
1078
|
+
...baseChunk,
|
|
1079
|
+
choices: [{
|
|
1080
|
+
index: 0,
|
|
1081
|
+
delta: { tool_calls: [{
|
|
1082
|
+
index: 0,
|
|
1083
|
+
id: `call_${Date.now()}`,
|
|
1084
|
+
type: "function",
|
|
1085
|
+
function: {
|
|
1086
|
+
name: part.functionCall.name,
|
|
1087
|
+
arguments: JSON.stringify(part.functionCall.args)
|
|
1088
|
+
}
|
|
1089
|
+
}] },
|
|
1090
|
+
finish_reason: null
|
|
1091
|
+
}]
|
|
1092
|
+
};
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Transform Antigravity non-stream response to OpenAI format
|
|
1097
|
+
*/
|
|
1098
|
+
async function transformNonStreamResponse$1(response, model) {
|
|
1099
|
+
const data = await response.json();
|
|
1100
|
+
const parts = (data.candidates?.[0])?.content?.parts ?? [];
|
|
1101
|
+
const { content, reasoningContent, toolCalls } = extractNonStreamContent(parts);
|
|
937
1102
|
const message = {
|
|
938
1103
|
role: "assistant",
|
|
939
1104
|
content: content || null
|
|
@@ -941,23 +1106,48 @@ async function transformNonStreamResponse(response, model) {
|
|
|
941
1106
|
if (reasoningContent) message.reasoning_content = reasoningContent;
|
|
942
1107
|
if (toolCalls.length > 0) message.tool_calls = toolCalls;
|
|
943
1108
|
const openaiResponse = {
|
|
944
|
-
id:
|
|
1109
|
+
id: generateRequestId(),
|
|
945
1110
|
object: "chat.completion",
|
|
946
1111
|
created: Math.floor(Date.now() / 1e3),
|
|
947
1112
|
model,
|
|
948
1113
|
choices: [{
|
|
949
1114
|
index: 0,
|
|
950
1115
|
message,
|
|
951
|
-
finish_reason:
|
|
1116
|
+
finish_reason: "stop"
|
|
952
1117
|
}],
|
|
953
1118
|
usage: {
|
|
954
|
-
prompt_tokens: data.usageMetadata?.promptTokenCount
|
|
955
|
-
completion_tokens: data.usageMetadata?.candidatesTokenCount
|
|
956
|
-
total_tokens: data.usageMetadata?.totalTokenCount
|
|
1119
|
+
prompt_tokens: data.usageMetadata?.promptTokenCount ?? 0,
|
|
1120
|
+
completion_tokens: data.usageMetadata?.candidatesTokenCount ?? 0,
|
|
1121
|
+
total_tokens: data.usageMetadata?.totalTokenCount ?? 0
|
|
957
1122
|
}
|
|
958
1123
|
};
|
|
959
1124
|
return new Response(JSON.stringify(openaiResponse), { headers: { "Content-Type": "application/json" } });
|
|
960
1125
|
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Extract content from non-stream response parts
|
|
1128
|
+
*/
|
|
1129
|
+
function extractNonStreamContent(parts) {
|
|
1130
|
+
let content = "";
|
|
1131
|
+
let reasoningContent = "";
|
|
1132
|
+
const toolCalls = [];
|
|
1133
|
+
for (const part of parts) {
|
|
1134
|
+
if (part.thought && part.text) reasoningContent += part.text;
|
|
1135
|
+
else if (part.text) content += part.text;
|
|
1136
|
+
if (part.functionCall) toolCalls.push({
|
|
1137
|
+
id: `call_${Date.now()}`,
|
|
1138
|
+
type: "function",
|
|
1139
|
+
function: {
|
|
1140
|
+
name: part.functionCall.name,
|
|
1141
|
+
arguments: JSON.stringify(part.functionCall.args)
|
|
1142
|
+
}
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
return {
|
|
1146
|
+
content,
|
|
1147
|
+
reasoningContent,
|
|
1148
|
+
toolCalls
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
961
1151
|
|
|
962
1152
|
//#endregion
|
|
963
1153
|
//#region src/routes/antigravity/chat-completions/route.ts
|
|
@@ -977,6 +1167,166 @@ app$1.post("/", async (c) => {
|
|
|
977
1167
|
});
|
|
978
1168
|
const antigravityChatCompletionsRoute = app$1;
|
|
979
1169
|
|
|
1170
|
+
//#endregion
|
|
1171
|
+
//#region src/services/antigravity/anthropic-events.ts
|
|
1172
|
+
/**
|
|
1173
|
+
* Anthropic SSE Event Builder
|
|
1174
|
+
*
|
|
1175
|
+
* Builds Anthropic-compatible SSE events for streaming responses.
|
|
1176
|
+
* Extracted for better code organization and reusability.
|
|
1177
|
+
*/
|
|
1178
|
+
const encoder = new TextEncoder();
|
|
1179
|
+
/**
|
|
1180
|
+
* Create message_start event
|
|
1181
|
+
*/
|
|
1182
|
+
function createMessageStart(messageId, model) {
|
|
1183
|
+
const event = {
|
|
1184
|
+
type: "message_start",
|
|
1185
|
+
message: {
|
|
1186
|
+
id: messageId,
|
|
1187
|
+
type: "message",
|
|
1188
|
+
role: "assistant",
|
|
1189
|
+
content: [],
|
|
1190
|
+
model,
|
|
1191
|
+
stop_reason: null,
|
|
1192
|
+
stop_sequence: null,
|
|
1193
|
+
usage: {
|
|
1194
|
+
input_tokens: 0,
|
|
1195
|
+
output_tokens: 0
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
};
|
|
1199
|
+
return encoder.encode(`event: message_start\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Create message_stop event
|
|
1203
|
+
*/
|
|
1204
|
+
function createMessageStop() {
|
|
1205
|
+
return encoder.encode(`event: message_stop\ndata: ${JSON.stringify({ type: "message_stop" })}\n\n`);
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Create content_block_start event for thinking
|
|
1209
|
+
*/
|
|
1210
|
+
function createThinkingBlockStart(index) {
|
|
1211
|
+
const event = {
|
|
1212
|
+
type: "content_block_start",
|
|
1213
|
+
index,
|
|
1214
|
+
content_block: {
|
|
1215
|
+
type: "thinking",
|
|
1216
|
+
thinking: ""
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Create content_block_delta event for thinking
|
|
1223
|
+
*/
|
|
1224
|
+
function createThinkingDelta(index, text) {
|
|
1225
|
+
const event = {
|
|
1226
|
+
type: "content_block_delta",
|
|
1227
|
+
index,
|
|
1228
|
+
delta: {
|
|
1229
|
+
type: "thinking_delta",
|
|
1230
|
+
thinking: text
|
|
1231
|
+
}
|
|
1232
|
+
};
|
|
1233
|
+
return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Create content_block_start event for text
|
|
1237
|
+
*/
|
|
1238
|
+
function createTextBlockStart(index) {
|
|
1239
|
+
const event = {
|
|
1240
|
+
type: "content_block_start",
|
|
1241
|
+
index,
|
|
1242
|
+
content_block: {
|
|
1243
|
+
type: "text",
|
|
1244
|
+
text: ""
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Create content_block_delta event for text
|
|
1251
|
+
*/
|
|
1252
|
+
function createTextDelta(index, text) {
|
|
1253
|
+
const event = {
|
|
1254
|
+
type: "content_block_delta",
|
|
1255
|
+
index,
|
|
1256
|
+
delta: {
|
|
1257
|
+
type: "text_delta",
|
|
1258
|
+
text
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Create content_block_stop event
|
|
1265
|
+
*/
|
|
1266
|
+
function createBlockStop(index) {
|
|
1267
|
+
const event = {
|
|
1268
|
+
type: "content_block_stop",
|
|
1269
|
+
index
|
|
1270
|
+
};
|
|
1271
|
+
return encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Create content_block_start event for tool_use
|
|
1275
|
+
*/
|
|
1276
|
+
function createToolBlockStart(index, toolId, name) {
|
|
1277
|
+
const event = {
|
|
1278
|
+
type: "content_block_start",
|
|
1279
|
+
index,
|
|
1280
|
+
content_block: {
|
|
1281
|
+
type: "tool_use",
|
|
1282
|
+
id: toolId,
|
|
1283
|
+
name,
|
|
1284
|
+
input: {}
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
return encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Create content_block_delta event for tool input
|
|
1291
|
+
*/
|
|
1292
|
+
function createToolDelta(index, args) {
|
|
1293
|
+
const event = {
|
|
1294
|
+
type: "content_block_delta",
|
|
1295
|
+
index,
|
|
1296
|
+
delta: {
|
|
1297
|
+
type: "input_json_delta",
|
|
1298
|
+
partial_json: JSON.stringify(args)
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
return encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Create message_delta event with stop reason and usage
|
|
1305
|
+
*/
|
|
1306
|
+
function createMessageDelta(stopReason, outputTokens) {
|
|
1307
|
+
const event = {
|
|
1308
|
+
type: "message_delta",
|
|
1309
|
+
delta: {
|
|
1310
|
+
stop_reason: stopReason,
|
|
1311
|
+
stop_sequence: null
|
|
1312
|
+
},
|
|
1313
|
+
usage: { output_tokens: outputTokens }
|
|
1314
|
+
};
|
|
1315
|
+
return encoder.encode(`event: message_delta\ndata: ${JSON.stringify(event)}\n\n`);
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Generate a unique message ID
|
|
1319
|
+
*/
|
|
1320
|
+
function generateMessageId() {
|
|
1321
|
+
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Generate a unique tool ID
|
|
1325
|
+
*/
|
|
1326
|
+
function generateToolId() {
|
|
1327
|
+
return `toolu_${Date.now()}`;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
980
1330
|
//#endregion
|
|
981
1331
|
//#region src/services/antigravity/create-messages.ts
|
|
982
1332
|
const ANTIGRAVITY_API_HOST = "daily-cloudcode-pa.sandbox.googleapis.com";
|
|
@@ -988,29 +1338,18 @@ const ANTIGRAVITY_USER_AGENT = "antigravity/1.11.3 windows/amd64";
|
|
|
988
1338
|
*/
|
|
989
1339
|
function convertMessages(messages, system) {
|
|
990
1340
|
const contents = [];
|
|
991
|
-
let systemInstruction
|
|
1341
|
+
let systemInstruction;
|
|
992
1342
|
if (system) systemInstruction = {
|
|
993
1343
|
role: "user",
|
|
994
1344
|
parts: [{ text: system }]
|
|
995
1345
|
};
|
|
996
1346
|
for (const message of messages) {
|
|
997
1347
|
const role = message.role === "assistant" ? "model" : "user";
|
|
998
|
-
|
|
1348
|
+
const parts = buildParts(message.content);
|
|
1349
|
+
if (parts.length > 0) contents.push({
|
|
999
1350
|
role,
|
|
1000
|
-
parts
|
|
1351
|
+
parts
|
|
1001
1352
|
});
|
|
1002
|
-
else {
|
|
1003
|
-
const parts = [];
|
|
1004
|
-
for (const block of message.content) if (block.type === "text" && block.text) parts.push({ text: block.text });
|
|
1005
|
-
else if (block.type === "image" && block.source) parts.push({ inlineData: {
|
|
1006
|
-
mimeType: block.source.media_type,
|
|
1007
|
-
data: block.source.data
|
|
1008
|
-
} });
|
|
1009
|
-
if (parts.length > 0) contents.push({
|
|
1010
|
-
role,
|
|
1011
|
-
parts
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
1353
|
}
|
|
1015
1354
|
return {
|
|
1016
1355
|
contents,
|
|
@@ -1018,10 +1357,23 @@ function convertMessages(messages, system) {
|
|
|
1018
1357
|
};
|
|
1019
1358
|
}
|
|
1020
1359
|
/**
|
|
1360
|
+
* Build parts array from message content
|
|
1361
|
+
*/
|
|
1362
|
+
function buildParts(content) {
|
|
1363
|
+
if (typeof content === "string") return [{ text: content }];
|
|
1364
|
+
const parts = [];
|
|
1365
|
+
for (const block of content) if (block.type === "text" && block.text) parts.push({ text: block.text });
|
|
1366
|
+
else if (block.type === "image" && block.source) parts.push({ inlineData: {
|
|
1367
|
+
mimeType: block.source.media_type,
|
|
1368
|
+
data: block.source.data
|
|
1369
|
+
} });
|
|
1370
|
+
return parts;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1021
1373
|
* Convert tools to Antigravity format
|
|
1022
1374
|
*/
|
|
1023
1375
|
function convertTools(tools) {
|
|
1024
|
-
if (!tools || tools.length === 0) return;
|
|
1376
|
+
if (!tools || tools.length === 0) return void 0;
|
|
1025
1377
|
return tools.map((tool) => {
|
|
1026
1378
|
const t = tool;
|
|
1027
1379
|
return { functionDeclarations: [{
|
|
@@ -1032,23 +1384,12 @@ function convertTools(tools) {
|
|
|
1032
1384
|
});
|
|
1033
1385
|
}
|
|
1034
1386
|
/**
|
|
1035
|
-
*
|
|
1387
|
+
* Build Antigravity request body
|
|
1036
1388
|
*/
|
|
1037
|
-
|
|
1038
|
-
const accessToken = await getValidAccessToken();
|
|
1039
|
-
if (!accessToken) return new Response(JSON.stringify({
|
|
1040
|
-
type: "error",
|
|
1041
|
-
error: {
|
|
1042
|
-
type: "authentication_error",
|
|
1043
|
-
message: "No valid Antigravity access token available. Please run login first."
|
|
1044
|
-
}
|
|
1045
|
-
}), {
|
|
1046
|
-
status: 401,
|
|
1047
|
-
headers: { "Content-Type": "application/json" }
|
|
1048
|
-
});
|
|
1389
|
+
function buildAntigravityRequest(request) {
|
|
1049
1390
|
const { contents, systemInstruction } = convertMessages(request.messages, request.system);
|
|
1050
1391
|
const tools = convertTools(request.tools);
|
|
1051
|
-
const
|
|
1392
|
+
const body = {
|
|
1052
1393
|
model: request.model,
|
|
1053
1394
|
contents,
|
|
1054
1395
|
generationConfig: {
|
|
@@ -1058,13 +1399,37 @@ async function createAntigravityMessages(request) {
|
|
|
1058
1399
|
maxOutputTokens: request.max_tokens ?? 8096
|
|
1059
1400
|
}
|
|
1060
1401
|
};
|
|
1061
|
-
if (systemInstruction)
|
|
1062
|
-
if (tools)
|
|
1063
|
-
if (isThinkingModel(request.model))
|
|
1064
|
-
...
|
|
1402
|
+
if (systemInstruction) body.systemInstruction = systemInstruction;
|
|
1403
|
+
if (tools) body.tools = tools;
|
|
1404
|
+
if (isThinkingModel(request.model)) body.generationConfig = {
|
|
1405
|
+
...body.generationConfig,
|
|
1065
1406
|
thinkingConfig: { includeThoughts: true }
|
|
1066
1407
|
};
|
|
1408
|
+
return body;
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Create error response
|
|
1412
|
+
*/
|
|
1413
|
+
function createErrorResponse(type, message, status) {
|
|
1414
|
+
return new Response(JSON.stringify({
|
|
1415
|
+
type: "error",
|
|
1416
|
+
error: {
|
|
1417
|
+
type,
|
|
1418
|
+
message
|
|
1419
|
+
}
|
|
1420
|
+
}), {
|
|
1421
|
+
status,
|
|
1422
|
+
headers: { "Content-Type": "application/json" }
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Create Anthropic-compatible message response using Antigravity
|
|
1427
|
+
*/
|
|
1428
|
+
async function createAntigravityMessages(request) {
|
|
1429
|
+
const accessToken = await getValidAccessToken();
|
|
1430
|
+
if (!accessToken) return createErrorResponse("authentication_error", "No valid Antigravity access token available. Please run login first.", 401);
|
|
1067
1431
|
const endpoint = request.stream ? ANTIGRAVITY_STREAM_URL : ANTIGRAVITY_NO_STREAM_URL;
|
|
1432
|
+
const body = buildAntigravityRequest(request);
|
|
1068
1433
|
consola.debug(`Antigravity messages request to ${endpoint} with model ${request.model}`);
|
|
1069
1434
|
try {
|
|
1070
1435
|
const response = await fetch(endpoint, {
|
|
@@ -1076,212 +1441,84 @@ async function createAntigravityMessages(request) {
|
|
|
1076
1441
|
"Content-Type": "application/json",
|
|
1077
1442
|
"Accept-Encoding": "gzip"
|
|
1078
1443
|
},
|
|
1079
|
-
body: JSON.stringify(
|
|
1444
|
+
body: JSON.stringify(body)
|
|
1080
1445
|
});
|
|
1081
|
-
if (!response.ok)
|
|
1082
|
-
|
|
1083
|
-
consola.error(`Antigravity error: ${response.status} ${errorText}`);
|
|
1084
|
-
if (response.status === 403) await disableCurrentAccount();
|
|
1085
|
-
if (response.status === 429 || response.status === 503) await rotateAccount();
|
|
1086
|
-
return new Response(JSON.stringify({
|
|
1087
|
-
type: "error",
|
|
1088
|
-
error: {
|
|
1089
|
-
type: "api_error",
|
|
1090
|
-
message: `Antigravity API error: ${response.status}`
|
|
1091
|
-
}
|
|
1092
|
-
}), {
|
|
1093
|
-
status: response.status,
|
|
1094
|
-
headers: { "Content-Type": "application/json" }
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
if (request.stream) return transformStreamToAnthropic(response, request.model);
|
|
1098
|
-
else return transformNonStreamToAnthropic(response, request.model);
|
|
1446
|
+
if (!response.ok) return await handleApiError(response);
|
|
1447
|
+
return request.stream ? transformStreamResponse(response, request.model) : await transformNonStreamResponse(response, request.model);
|
|
1099
1448
|
} catch (error) {
|
|
1100
1449
|
consola.error("Antigravity messages request error:", error);
|
|
1101
|
-
return
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1450
|
+
return createErrorResponse("api_error", `Request failed: ${String(error)}`, 500);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
/**
|
|
1454
|
+
* Handle API error response
|
|
1455
|
+
*/
|
|
1456
|
+
async function handleApiError(response) {
|
|
1457
|
+
const errorText = await response.text();
|
|
1458
|
+
consola.error(`Antigravity error: ${response.status} ${errorText}`);
|
|
1459
|
+
if (response.status === 403) await disableCurrentAccount();
|
|
1460
|
+
if (response.status === 429 || response.status === 503) await rotateAccount();
|
|
1461
|
+
return createErrorResponse("api_error", `Antigravity API error: ${response.status}`, response.status);
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Emit SSE event to controller based on stream event type
|
|
1465
|
+
*/
|
|
1466
|
+
function emitSSEEvent(event, controller, state$1) {
|
|
1467
|
+
switch (event.type) {
|
|
1468
|
+
case "thinking_start":
|
|
1469
|
+
controller.enqueue(createThinkingBlockStart(event.index));
|
|
1470
|
+
break;
|
|
1471
|
+
case "thinking_delta":
|
|
1472
|
+
controller.enqueue(createThinkingDelta(event.index, event.text));
|
|
1473
|
+
break;
|
|
1474
|
+
case "thinking_stop":
|
|
1475
|
+
controller.enqueue(createBlockStop(event.index));
|
|
1476
|
+
break;
|
|
1477
|
+
case "text_start":
|
|
1478
|
+
controller.enqueue(createTextBlockStart(event.index));
|
|
1479
|
+
break;
|
|
1480
|
+
case "text_delta":
|
|
1481
|
+
controller.enqueue(createTextDelta(event.index, event.text));
|
|
1482
|
+
break;
|
|
1483
|
+
case "text_stop":
|
|
1484
|
+
controller.enqueue(createBlockStop(event.index));
|
|
1485
|
+
break;
|
|
1486
|
+
case "tool_use":
|
|
1487
|
+
emitToolUseEvents(event, controller);
|
|
1488
|
+
break;
|
|
1489
|
+
case "usage":
|
|
1490
|
+
state$1.inputTokens = event.inputTokens;
|
|
1491
|
+
state$1.outputTokens = event.outputTokens;
|
|
1492
|
+
break;
|
|
1493
|
+
case "finish":
|
|
1494
|
+
controller.enqueue(createMessageDelta(event.stopReason, state$1.outputTokens));
|
|
1495
|
+
break;
|
|
1111
1496
|
}
|
|
1112
1497
|
}
|
|
1113
1498
|
/**
|
|
1499
|
+
* Emit tool use events
|
|
1500
|
+
*/
|
|
1501
|
+
function emitToolUseEvents(event, controller) {
|
|
1502
|
+
const toolId = generateToolId();
|
|
1503
|
+
controller.enqueue(createToolBlockStart(event.index, toolId, event.name));
|
|
1504
|
+
controller.enqueue(createToolDelta(event.index, event.args));
|
|
1505
|
+
controller.enqueue(createBlockStop(event.index));
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1114
1508
|
* Transform Antigravity stream response to Anthropic format
|
|
1115
1509
|
*/
|
|
1116
|
-
function
|
|
1510
|
+
function transformStreamResponse(response, model) {
|
|
1117
1511
|
const reader = response.body?.getReader();
|
|
1118
1512
|
if (!reader) return new Response("No response body", { status: 500 });
|
|
1119
|
-
const encoder = new TextEncoder();
|
|
1120
1513
|
const decoder = new TextDecoder();
|
|
1514
|
+
const messageId = generateMessageId();
|
|
1121
1515
|
const stream = new ReadableStream({ async start(controller) {
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
let inputTokens = 0;
|
|
1125
|
-
let outputTokens = 0;
|
|
1126
|
-
let contentBlockIndex = 0;
|
|
1127
|
-
let thinkingBlockStarted = false;
|
|
1128
|
-
let textBlockStarted = false;
|
|
1129
|
-
const messageStart = {
|
|
1130
|
-
type: "message_start",
|
|
1131
|
-
message: {
|
|
1132
|
-
id: messageId,
|
|
1133
|
-
type: "message",
|
|
1134
|
-
role: "assistant",
|
|
1135
|
-
content: [],
|
|
1136
|
-
model,
|
|
1137
|
-
stop_reason: null,
|
|
1138
|
-
stop_sequence: null,
|
|
1139
|
-
usage: {
|
|
1140
|
-
input_tokens: 0,
|
|
1141
|
-
output_tokens: 0
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
};
|
|
1145
|
-
controller.enqueue(encoder.encode(`event: message_start\ndata: ${JSON.stringify(messageStart)}\n\n`));
|
|
1516
|
+
const state$1 = createStreamState();
|
|
1517
|
+
controller.enqueue(createMessageStart(messageId, model));
|
|
1146
1518
|
try {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
controller.enqueue(encoder.encode(`event: message_stop\ndata: ${JSON.stringify({ type: "message_stop" })}\n\n`));
|
|
1151
|
-
controller.close();
|
|
1152
|
-
break;
|
|
1153
|
-
}
|
|
1154
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1155
|
-
const lines = buffer.split("\n");
|
|
1156
|
-
buffer = lines.pop() || "";
|
|
1157
|
-
for (const line of lines) if (line.startsWith("data: ")) {
|
|
1158
|
-
const data = line.slice(6).trim();
|
|
1159
|
-
if (data === "[DONE]" || data === "") continue;
|
|
1160
|
-
try {
|
|
1161
|
-
const parsed = JSON.parse(data);
|
|
1162
|
-
const candidate = (parsed.response?.candidates || parsed.candidates)?.[0];
|
|
1163
|
-
const parts = candidate?.content?.parts || [];
|
|
1164
|
-
const usage = parsed.response?.usageMetadata || parsed.usageMetadata;
|
|
1165
|
-
if (usage) {
|
|
1166
|
-
inputTokens = usage.promptTokenCount || inputTokens;
|
|
1167
|
-
outputTokens = usage.candidatesTokenCount || outputTokens;
|
|
1168
|
-
}
|
|
1169
|
-
for (const part of parts) {
|
|
1170
|
-
if (part.thought && part.text) {
|
|
1171
|
-
if (!thinkingBlockStarted) {
|
|
1172
|
-
const blockStart = {
|
|
1173
|
-
type: "content_block_start",
|
|
1174
|
-
index: contentBlockIndex,
|
|
1175
|
-
content_block: {
|
|
1176
|
-
type: "thinking",
|
|
1177
|
-
thinking: ""
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(blockStart)}\n\n`));
|
|
1181
|
-
thinkingBlockStarted = true;
|
|
1182
|
-
}
|
|
1183
|
-
const thinkingDelta = {
|
|
1184
|
-
type: "content_block_delta",
|
|
1185
|
-
index: contentBlockIndex,
|
|
1186
|
-
delta: {
|
|
1187
|
-
type: "thinking_delta",
|
|
1188
|
-
thinking: part.text
|
|
1189
|
-
}
|
|
1190
|
-
};
|
|
1191
|
-
controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(thinkingDelta)}\n\n`));
|
|
1192
|
-
continue;
|
|
1193
|
-
}
|
|
1194
|
-
if (part.text && !part.thought) {
|
|
1195
|
-
if (thinkingBlockStarted && !textBlockStarted) {
|
|
1196
|
-
const blockStop = {
|
|
1197
|
-
type: "content_block_stop",
|
|
1198
|
-
index: contentBlockIndex
|
|
1199
|
-
};
|
|
1200
|
-
controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
|
|
1201
|
-
contentBlockIndex++;
|
|
1202
|
-
}
|
|
1203
|
-
if (!textBlockStarted) {
|
|
1204
|
-
const blockStart = {
|
|
1205
|
-
type: "content_block_start",
|
|
1206
|
-
index: contentBlockIndex,
|
|
1207
|
-
content_block: {
|
|
1208
|
-
type: "text",
|
|
1209
|
-
text: ""
|
|
1210
|
-
}
|
|
1211
|
-
};
|
|
1212
|
-
controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(blockStart)}\n\n`));
|
|
1213
|
-
textBlockStarted = true;
|
|
1214
|
-
}
|
|
1215
|
-
const textDelta = {
|
|
1216
|
-
type: "content_block_delta",
|
|
1217
|
-
index: contentBlockIndex,
|
|
1218
|
-
delta: {
|
|
1219
|
-
type: "text_delta",
|
|
1220
|
-
text: part.text
|
|
1221
|
-
}
|
|
1222
|
-
};
|
|
1223
|
-
controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(textDelta)}\n\n`));
|
|
1224
|
-
}
|
|
1225
|
-
if (part.functionCall) {
|
|
1226
|
-
if (textBlockStarted || thinkingBlockStarted) {
|
|
1227
|
-
const blockStop = {
|
|
1228
|
-
type: "content_block_stop",
|
|
1229
|
-
index: contentBlockIndex
|
|
1230
|
-
};
|
|
1231
|
-
controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
|
|
1232
|
-
contentBlockIndex++;
|
|
1233
|
-
textBlockStarted = false;
|
|
1234
|
-
thinkingBlockStarted = false;
|
|
1235
|
-
}
|
|
1236
|
-
const toolBlockStart = {
|
|
1237
|
-
type: "content_block_start",
|
|
1238
|
-
index: contentBlockIndex,
|
|
1239
|
-
content_block: {
|
|
1240
|
-
type: "tool_use",
|
|
1241
|
-
id: `toolu_${Date.now()}`,
|
|
1242
|
-
name: part.functionCall.name,
|
|
1243
|
-
input: {}
|
|
1244
|
-
}
|
|
1245
|
-
};
|
|
1246
|
-
controller.enqueue(encoder.encode(`event: content_block_start\ndata: ${JSON.stringify(toolBlockStart)}\n\n`));
|
|
1247
|
-
const toolDelta = {
|
|
1248
|
-
type: "content_block_delta",
|
|
1249
|
-
index: contentBlockIndex,
|
|
1250
|
-
delta: {
|
|
1251
|
-
type: "input_json_delta",
|
|
1252
|
-
partial_json: JSON.stringify(part.functionCall.args)
|
|
1253
|
-
}
|
|
1254
|
-
};
|
|
1255
|
-
controller.enqueue(encoder.encode(`event: content_block_delta\ndata: ${JSON.stringify(toolDelta)}\n\n`));
|
|
1256
|
-
const toolBlockStop = {
|
|
1257
|
-
type: "content_block_stop",
|
|
1258
|
-
index: contentBlockIndex
|
|
1259
|
-
};
|
|
1260
|
-
controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(toolBlockStop)}\n\n`));
|
|
1261
|
-
contentBlockIndex++;
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
if (candidate?.finishReason === "STOP") {
|
|
1265
|
-
if (textBlockStarted || thinkingBlockStarted) {
|
|
1266
|
-
const blockStop = {
|
|
1267
|
-
type: "content_block_stop",
|
|
1268
|
-
index: contentBlockIndex
|
|
1269
|
-
};
|
|
1270
|
-
controller.enqueue(encoder.encode(`event: content_block_stop\ndata: ${JSON.stringify(blockStop)}\n\n`));
|
|
1271
|
-
}
|
|
1272
|
-
const messageDelta = {
|
|
1273
|
-
type: "message_delta",
|
|
1274
|
-
delta: {
|
|
1275
|
-
stop_reason: "end_turn",
|
|
1276
|
-
stop_sequence: null
|
|
1277
|
-
},
|
|
1278
|
-
usage: { output_tokens: outputTokens }
|
|
1279
|
-
};
|
|
1280
|
-
controller.enqueue(encoder.encode(`event: message_delta\ndata: ${JSON.stringify(messageDelta)}\n\n`));
|
|
1281
|
-
}
|
|
1282
|
-
} catch {}
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1519
|
+
await processStream(reader, decoder, state$1, controller);
|
|
1520
|
+
controller.enqueue(createMessageStop());
|
|
1521
|
+
controller.close();
|
|
1285
1522
|
} catch (error) {
|
|
1286
1523
|
consola.error("Stream transform error:", error);
|
|
1287
1524
|
controller.error(error);
|
|
@@ -1294,12 +1531,56 @@ function transformStreamToAnthropic(response, model) {
|
|
|
1294
1531
|
} });
|
|
1295
1532
|
}
|
|
1296
1533
|
/**
|
|
1534
|
+
* Process the stream and emit events
|
|
1535
|
+
*/
|
|
1536
|
+
async function processStream(reader, decoder, state$1, controller) {
|
|
1537
|
+
const emit = (event) => emitSSEEvent(event, controller, state$1);
|
|
1538
|
+
while (true) {
|
|
1539
|
+
const { done, value } = await reader.read();
|
|
1540
|
+
if (done) break;
|
|
1541
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
1542
|
+
const lines = processChunk(chunk, state$1);
|
|
1543
|
+
for (const line of lines) {
|
|
1544
|
+
const data = parseSSELine(line);
|
|
1545
|
+
if (!data) continue;
|
|
1546
|
+
const { candidates, usage } = extractFromData(data);
|
|
1547
|
+
if (usage) {
|
|
1548
|
+
state$1.inputTokens = usage.promptTokenCount ?? state$1.inputTokens;
|
|
1549
|
+
state$1.outputTokens = usage.candidatesTokenCount ?? state$1.outputTokens;
|
|
1550
|
+
}
|
|
1551
|
+
const candidate = candidates[0];
|
|
1552
|
+
const parts = candidate?.content?.parts ?? [];
|
|
1553
|
+
for (const part of parts) processPart(part, state$1, emit);
|
|
1554
|
+
if (candidate?.finishReason === "STOP") handleFinish(state$1, emit);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1297
1559
|
* Transform Antigravity non-stream response to Anthropic format
|
|
1298
1560
|
*/
|
|
1299
|
-
async function
|
|
1561
|
+
async function transformNonStreamResponse(response, model) {
|
|
1300
1562
|
const data = await response.json();
|
|
1301
|
-
const
|
|
1302
|
-
const
|
|
1563
|
+
const parts = (data.candidates?.[0])?.content?.parts ?? [];
|
|
1564
|
+
const content = buildNonStreamContent(parts);
|
|
1565
|
+
const anthropicResponse = {
|
|
1566
|
+
id: generateMessageId(),
|
|
1567
|
+
type: "message",
|
|
1568
|
+
role: "assistant",
|
|
1569
|
+
content,
|
|
1570
|
+
model,
|
|
1571
|
+
stop_reason: "end_turn",
|
|
1572
|
+
stop_sequence: null,
|
|
1573
|
+
usage: {
|
|
1574
|
+
input_tokens: data.usageMetadata?.promptTokenCount ?? 0,
|
|
1575
|
+
output_tokens: data.usageMetadata?.candidatesTokenCount ?? 0
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
return new Response(JSON.stringify(anthropicResponse), { headers: { "Content-Type": "application/json" } });
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Build content array for non-stream response
|
|
1582
|
+
*/
|
|
1583
|
+
function buildNonStreamContent(parts) {
|
|
1303
1584
|
const content = [];
|
|
1304
1585
|
for (const part of parts) {
|
|
1305
1586
|
if (part.thought && part.text) content.push({
|
|
@@ -1312,25 +1593,12 @@ async function transformNonStreamToAnthropic(response, model) {
|
|
|
1312
1593
|
});
|
|
1313
1594
|
if (part.functionCall) content.push({
|
|
1314
1595
|
type: "tool_use",
|
|
1315
|
-
id:
|
|
1596
|
+
id: generateToolId(),
|
|
1316
1597
|
name: part.functionCall.name,
|
|
1317
1598
|
input: part.functionCall.args
|
|
1318
1599
|
});
|
|
1319
1600
|
}
|
|
1320
|
-
|
|
1321
|
-
id: `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
|
|
1322
|
-
type: "message",
|
|
1323
|
-
role: "assistant",
|
|
1324
|
-
content,
|
|
1325
|
-
model,
|
|
1326
|
-
stop_reason: candidate?.finishReason === "STOP" ? "end_turn" : "end_turn",
|
|
1327
|
-
stop_sequence: null,
|
|
1328
|
-
usage: {
|
|
1329
|
-
input_tokens: data.usageMetadata?.promptTokenCount || 0,
|
|
1330
|
-
output_tokens: data.usageMetadata?.candidatesTokenCount || 0
|
|
1331
|
-
}
|
|
1332
|
-
};
|
|
1333
|
-
return new Response(JSON.stringify(anthropicResponse), { headers: { "Content-Type": "application/json" } });
|
|
1601
|
+
return content;
|
|
1334
1602
|
}
|
|
1335
1603
|
|
|
1336
1604
|
//#endregion
|
|
@@ -1420,11 +1688,11 @@ const encodingCache = /* @__PURE__ */ new Map();
|
|
|
1420
1688
|
/**
|
|
1421
1689
|
* Calculate tokens for tool calls
|
|
1422
1690
|
*/
|
|
1423
|
-
const calculateToolCallsTokens = (toolCalls, encoder, constants) => {
|
|
1691
|
+
const calculateToolCallsTokens = (toolCalls, encoder$1, constants) => {
|
|
1424
1692
|
let tokens = 0;
|
|
1425
1693
|
for (const toolCall of toolCalls) {
|
|
1426
1694
|
tokens += constants.funcInit;
|
|
1427
|
-
tokens += encoder.encode(JSON.stringify(toolCall)).length;
|
|
1695
|
+
tokens += encoder$1.encode(JSON.stringify(toolCall)).length;
|
|
1428
1696
|
}
|
|
1429
1697
|
tokens += constants.funcEnd;
|
|
1430
1698
|
return tokens;
|
|
@@ -1432,34 +1700,34 @@ const calculateToolCallsTokens = (toolCalls, encoder, constants) => {
|
|
|
1432
1700
|
/**
|
|
1433
1701
|
* Calculate tokens for content parts
|
|
1434
1702
|
*/
|
|
1435
|
-
const calculateContentPartsTokens = (contentParts, encoder) => {
|
|
1703
|
+
const calculateContentPartsTokens = (contentParts, encoder$1) => {
|
|
1436
1704
|
let tokens = 0;
|
|
1437
|
-
for (const part of contentParts) if (part.type === "image_url") tokens += encoder.encode(part.image_url.url).length + 85;
|
|
1438
|
-
else if (part.text) tokens += encoder.encode(part.text).length;
|
|
1705
|
+
for (const part of contentParts) if (part.type === "image_url") tokens += encoder$1.encode(part.image_url.url).length + 85;
|
|
1706
|
+
else if (part.text) tokens += encoder$1.encode(part.text).length;
|
|
1439
1707
|
return tokens;
|
|
1440
1708
|
};
|
|
1441
1709
|
/**
|
|
1442
1710
|
* Calculate tokens for a single message
|
|
1443
1711
|
*/
|
|
1444
|
-
const calculateMessageTokens = (message, encoder, constants) => {
|
|
1712
|
+
const calculateMessageTokens = (message, encoder$1, constants) => {
|
|
1445
1713
|
const tokensPerMessage = 3;
|
|
1446
1714
|
const tokensPerName = 1;
|
|
1447
1715
|
let tokens = tokensPerMessage;
|
|
1448
1716
|
for (const [key, value] of Object.entries(message)) {
|
|
1449
|
-
if (typeof value === "string") tokens += encoder.encode(value).length;
|
|
1717
|
+
if (typeof value === "string") tokens += encoder$1.encode(value).length;
|
|
1450
1718
|
if (key === "name") tokens += tokensPerName;
|
|
1451
|
-
if (key === "tool_calls") tokens += calculateToolCallsTokens(value, encoder, constants);
|
|
1452
|
-
if (key === "content" && Array.isArray(value)) tokens += calculateContentPartsTokens(value, encoder);
|
|
1719
|
+
if (key === "tool_calls") tokens += calculateToolCallsTokens(value, encoder$1, constants);
|
|
1720
|
+
if (key === "content" && Array.isArray(value)) tokens += calculateContentPartsTokens(value, encoder$1);
|
|
1453
1721
|
}
|
|
1454
1722
|
return tokens;
|
|
1455
1723
|
};
|
|
1456
1724
|
/**
|
|
1457
1725
|
* Calculate tokens using custom algorithm
|
|
1458
1726
|
*/
|
|
1459
|
-
const calculateTokens = (messages, encoder, constants) => {
|
|
1727
|
+
const calculateTokens = (messages, encoder$1, constants) => {
|
|
1460
1728
|
if (messages.length === 0) return 0;
|
|
1461
1729
|
let numTokens = 0;
|
|
1462
|
-
for (const message of messages) numTokens += calculateMessageTokens(message, encoder, constants);
|
|
1730
|
+
for (const message of messages) numTokens += calculateMessageTokens(message, encoder$1, constants);
|
|
1463
1731
|
numTokens += 3;
|
|
1464
1732
|
return numTokens;
|
|
1465
1733
|
};
|
|
@@ -1511,7 +1779,7 @@ const getModelConstants = (model) => {
|
|
|
1511
1779
|
* Calculate tokens for a single parameter
|
|
1512
1780
|
*/
|
|
1513
1781
|
const calculateParameterTokens = (key, prop, context) => {
|
|
1514
|
-
const { encoder, constants } = context;
|
|
1782
|
+
const { encoder: encoder$1, constants } = context;
|
|
1515
1783
|
let tokens = constants.propKey;
|
|
1516
1784
|
if (typeof prop !== "object" || prop === null) return tokens;
|
|
1517
1785
|
const param = prop;
|
|
@@ -1522,12 +1790,12 @@ const calculateParameterTokens = (key, prop, context) => {
|
|
|
1522
1790
|
tokens += constants.enumInit;
|
|
1523
1791
|
for (const item of param.enum) {
|
|
1524
1792
|
tokens += constants.enumItem;
|
|
1525
|
-
tokens += encoder.encode(String(item)).length;
|
|
1793
|
+
tokens += encoder$1.encode(String(item)).length;
|
|
1526
1794
|
}
|
|
1527
1795
|
}
|
|
1528
1796
|
if (paramDesc.endsWith(".")) paramDesc = paramDesc.slice(0, -1);
|
|
1529
1797
|
const line = `${paramName}:${paramType}:${paramDesc}`;
|
|
1530
|
-
tokens += encoder.encode(line).length;
|
|
1798
|
+
tokens += encoder$1.encode(line).length;
|
|
1531
1799
|
const excludedKeys = new Set([
|
|
1532
1800
|
"type",
|
|
1533
1801
|
"description",
|
|
@@ -1536,14 +1804,14 @@ const calculateParameterTokens = (key, prop, context) => {
|
|
|
1536
1804
|
for (const propertyName of Object.keys(param)) if (!excludedKeys.has(propertyName)) {
|
|
1537
1805
|
const propertyValue = param[propertyName];
|
|
1538
1806
|
const propertyText = typeof propertyValue === "string" ? propertyValue : JSON.stringify(propertyValue);
|
|
1539
|
-
tokens += encoder.encode(`${propertyName}:${propertyText}`).length;
|
|
1807
|
+
tokens += encoder$1.encode(`${propertyName}:${propertyText}`).length;
|
|
1540
1808
|
}
|
|
1541
1809
|
return tokens;
|
|
1542
1810
|
};
|
|
1543
1811
|
/**
|
|
1544
1812
|
* Calculate tokens for function parameters
|
|
1545
1813
|
*/
|
|
1546
|
-
const calculateParametersTokens = (parameters, encoder, constants) => {
|
|
1814
|
+
const calculateParametersTokens = (parameters, encoder$1, constants) => {
|
|
1547
1815
|
if (!parameters || typeof parameters !== "object") return 0;
|
|
1548
1816
|
const params = parameters;
|
|
1549
1817
|
let tokens = 0;
|
|
@@ -1552,36 +1820,36 @@ const calculateParametersTokens = (parameters, encoder, constants) => {
|
|
|
1552
1820
|
if (Object.keys(properties).length > 0) {
|
|
1553
1821
|
tokens += constants.propInit;
|
|
1554
1822
|
for (const propKey of Object.keys(properties)) tokens += calculateParameterTokens(propKey, properties[propKey], {
|
|
1555
|
-
encoder,
|
|
1823
|
+
encoder: encoder$1,
|
|
1556
1824
|
constants
|
|
1557
1825
|
});
|
|
1558
1826
|
}
|
|
1559
1827
|
} else {
|
|
1560
1828
|
const paramText = typeof value === "string" ? value : JSON.stringify(value);
|
|
1561
|
-
tokens += encoder.encode(`${key}:${paramText}`).length;
|
|
1829
|
+
tokens += encoder$1.encode(`${key}:${paramText}`).length;
|
|
1562
1830
|
}
|
|
1563
1831
|
return tokens;
|
|
1564
1832
|
};
|
|
1565
1833
|
/**
|
|
1566
1834
|
* Calculate tokens for a single tool
|
|
1567
1835
|
*/
|
|
1568
|
-
const calculateToolTokens = (tool, encoder, constants) => {
|
|
1836
|
+
const calculateToolTokens = (tool, encoder$1, constants) => {
|
|
1569
1837
|
let tokens = constants.funcInit;
|
|
1570
1838
|
const func = tool.function;
|
|
1571
1839
|
const fName = func.name;
|
|
1572
1840
|
let fDesc = func.description || "";
|
|
1573
1841
|
if (fDesc.endsWith(".")) fDesc = fDesc.slice(0, -1);
|
|
1574
1842
|
const line = fName + ":" + fDesc;
|
|
1575
|
-
tokens += encoder.encode(line).length;
|
|
1576
|
-
if (typeof func.parameters === "object" && func.parameters !== null) tokens += calculateParametersTokens(func.parameters, encoder, constants);
|
|
1843
|
+
tokens += encoder$1.encode(line).length;
|
|
1844
|
+
if (typeof func.parameters === "object" && func.parameters !== null) tokens += calculateParametersTokens(func.parameters, encoder$1, constants);
|
|
1577
1845
|
return tokens;
|
|
1578
1846
|
};
|
|
1579
1847
|
/**
|
|
1580
1848
|
* Calculate token count for tools based on model
|
|
1581
1849
|
*/
|
|
1582
|
-
const numTokensForTools = (tools, encoder, constants) => {
|
|
1850
|
+
const numTokensForTools = (tools, encoder$1, constants) => {
|
|
1583
1851
|
let funcTokenCount = 0;
|
|
1584
|
-
for (const tool of tools) funcTokenCount += calculateToolTokens(tool, encoder, constants);
|
|
1852
|
+
for (const tool of tools) funcTokenCount += calculateToolTokens(tool, encoder$1, constants);
|
|
1585
1853
|
funcTokenCount += constants.funcEnd;
|
|
1586
1854
|
return funcTokenCount;
|
|
1587
1855
|
};
|
|
@@ -1590,14 +1858,14 @@ const numTokensForTools = (tools, encoder, constants) => {
|
|
|
1590
1858
|
*/
|
|
1591
1859
|
const getTokenCount = async (payload, model) => {
|
|
1592
1860
|
const tokenizer = getTokenizerFromModel(model);
|
|
1593
|
-
const encoder = await getEncodeChatFunction(tokenizer);
|
|
1861
|
+
const encoder$1 = await getEncodeChatFunction(tokenizer);
|
|
1594
1862
|
const simplifiedMessages = payload.messages;
|
|
1595
1863
|
const inputMessages = simplifiedMessages.filter((msg) => msg.role !== "assistant");
|
|
1596
1864
|
const outputMessages = simplifiedMessages.filter((msg) => msg.role === "assistant");
|
|
1597
1865
|
const constants = getModelConstants(model);
|
|
1598
|
-
let inputTokens = calculateTokens(inputMessages, encoder, constants);
|
|
1599
|
-
if (payload.tools && payload.tools.length > 0) inputTokens += numTokensForTools(payload.tools, encoder, constants);
|
|
1600
|
-
const outputTokens = calculateTokens(outputMessages, encoder, constants);
|
|
1866
|
+
let inputTokens = calculateTokens(inputMessages, encoder$1, constants);
|
|
1867
|
+
if (payload.tools && payload.tools.length > 0) inputTokens += numTokensForTools(payload.tools, encoder$1, constants);
|
|
1868
|
+
const outputTokens = calculateTokens(outputMessages, encoder$1, constants);
|
|
1601
1869
|
return {
|
|
1602
1870
|
input: inputTokens,
|
|
1603
1871
|
output: outputTokens
|