@gitlab/gitlab-ai-provider 3.1.3 → 3.3.0
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/CHANGELOG.md +8 -0
- package/README.md +117 -29
- package/dist/gitlab-gitlab-ai-provider-3.3.0.tgz +0 -0
- package/dist/index.d.mts +113 -46
- package/dist/index.d.ts +113 -46
- package/dist/index.js +792 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +782 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/dist/gitlab-gitlab-ai-provider-3.1.3.tgz +0 -0
package/dist/index.js
CHANGED
|
@@ -32,22 +32,30 @@ __export(index_exports, {
|
|
|
32
32
|
BUNDLED_CLIENT_ID: () => BUNDLED_CLIENT_ID,
|
|
33
33
|
DEFAULT_AI_GATEWAY_URL: () => DEFAULT_AI_GATEWAY_URL,
|
|
34
34
|
GITLAB_COM_URL: () => GITLAB_COM_URL,
|
|
35
|
-
|
|
35
|
+
GitLabAnthropicLanguageModel: () => GitLabAnthropicLanguageModel,
|
|
36
36
|
GitLabDirectAccessClient: () => GitLabDirectAccessClient,
|
|
37
37
|
GitLabError: () => GitLabError,
|
|
38
38
|
GitLabOAuthManager: () => GitLabOAuthManager,
|
|
39
|
+
GitLabOpenAILanguageModel: () => GitLabOpenAILanguageModel,
|
|
39
40
|
GitLabProjectCache: () => GitLabProjectCache,
|
|
40
41
|
GitLabProjectDetector: () => GitLabProjectDetector,
|
|
41
42
|
MODEL_ID_TO_ANTHROPIC_MODEL: () => MODEL_ID_TO_ANTHROPIC_MODEL,
|
|
43
|
+
MODEL_MAPPINGS: () => MODEL_MAPPINGS,
|
|
42
44
|
OAUTH_SCOPES: () => OAUTH_SCOPES,
|
|
43
45
|
TOKEN_EXPIRY_SKEW_MS: () => TOKEN_EXPIRY_SKEW_MS,
|
|
44
46
|
createGitLab: () => createGitLab,
|
|
45
47
|
getAnthropicModelForModelId: () => getAnthropicModelForModelId,
|
|
46
|
-
|
|
48
|
+
getModelMapping: () => getModelMapping,
|
|
49
|
+
getOpenAIApiType: () => getOpenAIApiType,
|
|
50
|
+
getOpenAIModelForModelId: () => getOpenAIModelForModelId,
|
|
51
|
+
getProviderForModelId: () => getProviderForModelId,
|
|
52
|
+
getValidModelsForProvider: () => getValidModelsForProvider,
|
|
53
|
+
gitlab: () => gitlab,
|
|
54
|
+
isResponsesApiModel: () => isResponsesApiModel
|
|
47
55
|
});
|
|
48
56
|
module.exports = __toCommonJS(index_exports);
|
|
49
57
|
|
|
50
|
-
// src/gitlab-
|
|
58
|
+
// src/gitlab-anthropic-language-model.ts
|
|
51
59
|
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
52
60
|
|
|
53
61
|
// src/gitlab-direct-access.ts
|
|
@@ -182,6 +190,15 @@ var GitLabDirectAccessClient = class {
|
|
|
182
190
|
const baseUrl = this.aiGatewayUrl.replace(/\/$/, "");
|
|
183
191
|
return `${baseUrl}/ai/v1/proxy/anthropic/`;
|
|
184
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* Get the OpenAI proxy base URL
|
|
195
|
+
* Note: The OpenAI SDK expects a base URL like https://api.openai.com/v1
|
|
196
|
+
* and appends paths like /chat/completions. So we need /v1 at the end.
|
|
197
|
+
*/
|
|
198
|
+
getOpenAIProxyUrl() {
|
|
199
|
+
const baseUrl = this.aiGatewayUrl.replace(/\/$/, "");
|
|
200
|
+
return `${baseUrl}/ai/v1/proxy/openai/v1`;
|
|
201
|
+
}
|
|
185
202
|
/**
|
|
186
203
|
* Invalidate the cached token
|
|
187
204
|
*/
|
|
@@ -191,8 +208,8 @@ var GitLabDirectAccessClient = class {
|
|
|
191
208
|
}
|
|
192
209
|
};
|
|
193
210
|
|
|
194
|
-
// src/gitlab-
|
|
195
|
-
var
|
|
211
|
+
// src/gitlab-anthropic-language-model.ts
|
|
212
|
+
var GitLabAnthropicLanguageModel = class {
|
|
196
213
|
specificationVersion = "v2";
|
|
197
214
|
modelId;
|
|
198
215
|
supportedUrls = {};
|
|
@@ -645,6 +662,741 @@ var GitLabAgenticLanguageModel = class {
|
|
|
645
662
|
}
|
|
646
663
|
};
|
|
647
664
|
|
|
665
|
+
// src/gitlab-openai-language-model.ts
|
|
666
|
+
var import_openai = __toESM(require("openai"));
|
|
667
|
+
|
|
668
|
+
// src/model-mappings.ts
|
|
669
|
+
var MODEL_MAPPINGS = {
|
|
670
|
+
// Anthropic models
|
|
671
|
+
"duo-chat-opus-4-5": { provider: "anthropic", model: "claude-opus-4-5-20251101" },
|
|
672
|
+
"duo-chat-sonnet-4-5": { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
|
|
673
|
+
"duo-chat-haiku-4-5": { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
|
|
674
|
+
// OpenAI models - Chat Completions API
|
|
675
|
+
"duo-chat-gpt-5-1": { provider: "openai", model: "gpt-5.1-2025-11-13", openaiApiType: "chat" },
|
|
676
|
+
"duo-chat-gpt-5-2": { provider: "openai", model: "gpt-5.2-2025-12-11", openaiApiType: "chat" },
|
|
677
|
+
"duo-chat-gpt-5-mini": {
|
|
678
|
+
provider: "openai",
|
|
679
|
+
model: "gpt-5-mini-2025-08-07",
|
|
680
|
+
openaiApiType: "chat"
|
|
681
|
+
},
|
|
682
|
+
// OpenAI models - Responses API (Codex models)
|
|
683
|
+
"duo-chat-gpt-5-codex": { provider: "openai", model: "gpt-5-codex", openaiApiType: "responses" },
|
|
684
|
+
"duo-chat-gpt-5-2-codex": {
|
|
685
|
+
provider: "openai",
|
|
686
|
+
model: "gpt-5.2-codex",
|
|
687
|
+
openaiApiType: "responses"
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
function getModelMapping(modelId) {
|
|
691
|
+
return MODEL_MAPPINGS[modelId];
|
|
692
|
+
}
|
|
693
|
+
function getProviderForModelId(modelId) {
|
|
694
|
+
return MODEL_MAPPINGS[modelId]?.provider;
|
|
695
|
+
}
|
|
696
|
+
function getValidModelsForProvider(provider) {
|
|
697
|
+
return Object.values(MODEL_MAPPINGS).filter((m) => m.provider === provider).map((m) => m.model);
|
|
698
|
+
}
|
|
699
|
+
function getAnthropicModelForModelId(modelId) {
|
|
700
|
+
const mapping = MODEL_MAPPINGS[modelId];
|
|
701
|
+
return mapping?.provider === "anthropic" ? mapping.model : void 0;
|
|
702
|
+
}
|
|
703
|
+
function getOpenAIModelForModelId(modelId) {
|
|
704
|
+
const mapping = MODEL_MAPPINGS[modelId];
|
|
705
|
+
return mapping?.provider === "openai" ? mapping.model : void 0;
|
|
706
|
+
}
|
|
707
|
+
function getOpenAIApiType(modelId) {
|
|
708
|
+
const mapping = MODEL_MAPPINGS[modelId];
|
|
709
|
+
return mapping?.openaiApiType ?? "chat";
|
|
710
|
+
}
|
|
711
|
+
function isResponsesApiModel(modelId) {
|
|
712
|
+
return getOpenAIApiType(modelId) === "responses";
|
|
713
|
+
}
|
|
714
|
+
var MODEL_ID_TO_ANTHROPIC_MODEL = Object.fromEntries(
|
|
715
|
+
Object.entries(MODEL_MAPPINGS).filter(([, v]) => v.provider === "anthropic").map(([k, v]) => [k, v.model])
|
|
716
|
+
);
|
|
717
|
+
|
|
718
|
+
// src/gitlab-openai-language-model.ts
|
|
719
|
+
var GitLabOpenAILanguageModel = class {
|
|
720
|
+
specificationVersion = "v2";
|
|
721
|
+
modelId;
|
|
722
|
+
supportedUrls = {};
|
|
723
|
+
config;
|
|
724
|
+
directAccessClient;
|
|
725
|
+
useResponsesApi;
|
|
726
|
+
openaiClient = null;
|
|
727
|
+
constructor(modelId, config) {
|
|
728
|
+
this.modelId = modelId;
|
|
729
|
+
this.config = config;
|
|
730
|
+
this.useResponsesApi = config.useResponsesApi ?? isResponsesApiModel(modelId);
|
|
731
|
+
this.directAccessClient = new GitLabDirectAccessClient({
|
|
732
|
+
instanceUrl: config.instanceUrl,
|
|
733
|
+
getHeaders: config.getHeaders,
|
|
734
|
+
refreshApiKey: config.refreshApiKey,
|
|
735
|
+
fetch: config.fetch,
|
|
736
|
+
featureFlags: config.featureFlags,
|
|
737
|
+
aiGatewayUrl: config.aiGatewayUrl
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
get provider() {
|
|
741
|
+
return this.config.provider;
|
|
742
|
+
}
|
|
743
|
+
async getOpenAIClient(forceRefresh = false) {
|
|
744
|
+
const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);
|
|
745
|
+
const { "x-api-key": _removed, ...filteredHeaders } = tokenData.headers;
|
|
746
|
+
this.openaiClient = new import_openai.default({
|
|
747
|
+
apiKey: tokenData.token,
|
|
748
|
+
baseURL: this.directAccessClient.getOpenAIProxyUrl(),
|
|
749
|
+
defaultHeaders: filteredHeaders
|
|
750
|
+
});
|
|
751
|
+
return this.openaiClient;
|
|
752
|
+
}
|
|
753
|
+
isTokenError(error) {
|
|
754
|
+
if (error instanceof import_openai.default.APIError) {
|
|
755
|
+
if (error.status === 401) {
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
const message = error.message?.toLowerCase() || "";
|
|
759
|
+
if (message.includes("token") && (message.includes("expired") || message.includes("revoked") || message.includes("invalid"))) {
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return false;
|
|
764
|
+
}
|
|
765
|
+
convertTools(tools) {
|
|
766
|
+
if (!tools || tools.length === 0) {
|
|
767
|
+
return void 0;
|
|
768
|
+
}
|
|
769
|
+
return tools.filter((tool) => tool.type === "function").map((tool) => {
|
|
770
|
+
const schema = tool.inputSchema;
|
|
771
|
+
return {
|
|
772
|
+
type: "function",
|
|
773
|
+
function: {
|
|
774
|
+
name: tool.name,
|
|
775
|
+
description: tool.description || "",
|
|
776
|
+
// Ensure the schema has type: 'object' as OpenAI requires it
|
|
777
|
+
parameters: {
|
|
778
|
+
type: "object",
|
|
779
|
+
...schema
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
convertToolChoice(toolChoice) {
|
|
786
|
+
if (!toolChoice) {
|
|
787
|
+
return void 0;
|
|
788
|
+
}
|
|
789
|
+
switch (toolChoice.type) {
|
|
790
|
+
case "auto":
|
|
791
|
+
return "auto";
|
|
792
|
+
case "none":
|
|
793
|
+
return "none";
|
|
794
|
+
case "required":
|
|
795
|
+
return "required";
|
|
796
|
+
case "tool":
|
|
797
|
+
return { type: "function", function: { name: toolChoice.toolName } };
|
|
798
|
+
default:
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
convertPrompt(prompt) {
|
|
803
|
+
const messages = [];
|
|
804
|
+
for (const message of prompt) {
|
|
805
|
+
if (message.role === "system") {
|
|
806
|
+
messages.push({ role: "system", content: message.content });
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
if (message.role === "user") {
|
|
810
|
+
const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text);
|
|
811
|
+
if (textParts.length > 0) {
|
|
812
|
+
messages.push({ role: "user", content: textParts.join("\n") });
|
|
813
|
+
}
|
|
814
|
+
} else if (message.role === "assistant") {
|
|
815
|
+
const textParts = [];
|
|
816
|
+
const toolCalls = [];
|
|
817
|
+
for (const part of message.content) {
|
|
818
|
+
if (part.type === "text") {
|
|
819
|
+
textParts.push(part.text);
|
|
820
|
+
} else if (part.type === "tool-call") {
|
|
821
|
+
toolCalls.push({
|
|
822
|
+
id: part.toolCallId,
|
|
823
|
+
type: "function",
|
|
824
|
+
function: {
|
|
825
|
+
name: part.toolName,
|
|
826
|
+
arguments: typeof part.input === "string" ? part.input : JSON.stringify(part.input)
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const assistantMessage = {
|
|
832
|
+
role: "assistant",
|
|
833
|
+
content: textParts.length > 0 ? textParts.join("\n") : null
|
|
834
|
+
};
|
|
835
|
+
if (toolCalls.length > 0) {
|
|
836
|
+
assistantMessage.tool_calls = toolCalls;
|
|
837
|
+
}
|
|
838
|
+
messages.push(assistantMessage);
|
|
839
|
+
} else if (message.role === "tool") {
|
|
840
|
+
for (const part of message.content) {
|
|
841
|
+
if (part.type === "tool-result") {
|
|
842
|
+
let resultContent;
|
|
843
|
+
if (part.output.type === "text") {
|
|
844
|
+
resultContent = part.output.value;
|
|
845
|
+
} else if (part.output.type === "json") {
|
|
846
|
+
resultContent = JSON.stringify(part.output.value);
|
|
847
|
+
} else if (part.output.type === "error-text") {
|
|
848
|
+
resultContent = part.output.value;
|
|
849
|
+
} else if (part.output.type === "error-json") {
|
|
850
|
+
resultContent = JSON.stringify(part.output.value);
|
|
851
|
+
} else {
|
|
852
|
+
resultContent = JSON.stringify(part.output);
|
|
853
|
+
}
|
|
854
|
+
messages.push({
|
|
855
|
+
role: "tool",
|
|
856
|
+
tool_call_id: part.toolCallId,
|
|
857
|
+
content: resultContent
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return messages;
|
|
864
|
+
}
|
|
865
|
+
convertFinishReason(finishReason) {
|
|
866
|
+
switch (finishReason) {
|
|
867
|
+
case "stop":
|
|
868
|
+
return "stop";
|
|
869
|
+
case "length":
|
|
870
|
+
return "length";
|
|
871
|
+
case "tool_calls":
|
|
872
|
+
return "tool-calls";
|
|
873
|
+
case "content_filter":
|
|
874
|
+
return "content-filter";
|
|
875
|
+
default:
|
|
876
|
+
return "unknown";
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Convert tools to Responses API format
|
|
881
|
+
*/
|
|
882
|
+
convertToolsForResponses(tools) {
|
|
883
|
+
if (!tools || tools.length === 0) {
|
|
884
|
+
return void 0;
|
|
885
|
+
}
|
|
886
|
+
return tools.filter((tool) => tool.type === "function").map((tool) => {
|
|
887
|
+
const schema = { ...tool.inputSchema };
|
|
888
|
+
delete schema["$schema"];
|
|
889
|
+
return {
|
|
890
|
+
type: "function",
|
|
891
|
+
name: tool.name,
|
|
892
|
+
description: tool.description || "",
|
|
893
|
+
parameters: schema,
|
|
894
|
+
strict: false
|
|
895
|
+
};
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Convert prompt to Responses API input format
|
|
900
|
+
*/
|
|
901
|
+
convertPromptForResponses(prompt) {
|
|
902
|
+
const items = [];
|
|
903
|
+
for (const message of prompt) {
|
|
904
|
+
if (message.role === "system") {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
if (message.role === "user") {
|
|
908
|
+
const textParts = message.content.filter((part) => part.type === "text").map((part) => part.text);
|
|
909
|
+
if (textParts.length > 0) {
|
|
910
|
+
items.push({
|
|
911
|
+
type: "message",
|
|
912
|
+
role: "user",
|
|
913
|
+
content: textParts.map((text) => ({ type: "input_text", text }))
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
} else if (message.role === "assistant") {
|
|
917
|
+
const textParts = [];
|
|
918
|
+
for (const part of message.content) {
|
|
919
|
+
if (part.type === "text") {
|
|
920
|
+
textParts.push(part.text);
|
|
921
|
+
} else if (part.type === "tool-call") {
|
|
922
|
+
items.push({
|
|
923
|
+
type: "function_call",
|
|
924
|
+
call_id: part.toolCallId,
|
|
925
|
+
name: part.toolName,
|
|
926
|
+
arguments: typeof part.input === "string" ? part.input : JSON.stringify(part.input)
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
if (textParts.length > 0) {
|
|
931
|
+
items.push({
|
|
932
|
+
type: "message",
|
|
933
|
+
role: "assistant",
|
|
934
|
+
content: [{ type: "output_text", text: textParts.join("\n"), annotations: [] }]
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
} else if (message.role === "tool") {
|
|
938
|
+
for (const part of message.content) {
|
|
939
|
+
if (part.type === "tool-result") {
|
|
940
|
+
let resultContent;
|
|
941
|
+
if (part.output.type === "text") {
|
|
942
|
+
resultContent = part.output.value;
|
|
943
|
+
} else if (part.output.type === "json") {
|
|
944
|
+
resultContent = JSON.stringify(part.output.value);
|
|
945
|
+
} else if (part.output.type === "error-text") {
|
|
946
|
+
resultContent = part.output.value;
|
|
947
|
+
} else if (part.output.type === "error-json") {
|
|
948
|
+
resultContent = JSON.stringify(part.output.value);
|
|
949
|
+
} else {
|
|
950
|
+
resultContent = JSON.stringify(part.output);
|
|
951
|
+
}
|
|
952
|
+
items.push({
|
|
953
|
+
type: "function_call_output",
|
|
954
|
+
call_id: part.toolCallId,
|
|
955
|
+
output: resultContent
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return items;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Extract system instructions from prompt
|
|
965
|
+
*/
|
|
966
|
+
extractSystemInstructions(prompt) {
|
|
967
|
+
const systemMessages = prompt.filter((m) => m.role === "system").map((m) => m.content).join("\n");
|
|
968
|
+
return systemMessages || void 0;
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Convert Responses API status to finish reason
|
|
972
|
+
* Note: Responses API returns 'completed' even when making tool calls,
|
|
973
|
+
* so we need to check the content for tool calls separately.
|
|
974
|
+
*/
|
|
975
|
+
convertResponsesStatus(status, hasToolCalls = false) {
|
|
976
|
+
if (hasToolCalls) {
|
|
977
|
+
return "tool-calls";
|
|
978
|
+
}
|
|
979
|
+
switch (status) {
|
|
980
|
+
case "completed":
|
|
981
|
+
return "stop";
|
|
982
|
+
case "incomplete":
|
|
983
|
+
return "length";
|
|
984
|
+
case "cancelled":
|
|
985
|
+
return "stop";
|
|
986
|
+
case "failed":
|
|
987
|
+
return "error";
|
|
988
|
+
default:
|
|
989
|
+
return "unknown";
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
async doGenerate(options) {
|
|
993
|
+
if (this.useResponsesApi) {
|
|
994
|
+
return this.doGenerateWithResponsesApi(options, false);
|
|
995
|
+
}
|
|
996
|
+
return this.doGenerateWithChatApi(options, false);
|
|
997
|
+
}
|
|
998
|
+
async doGenerateWithChatApi(options, isRetry) {
|
|
999
|
+
const client = await this.getOpenAIClient(isRetry);
|
|
1000
|
+
const messages = this.convertPrompt(options.prompt);
|
|
1001
|
+
const tools = this.convertTools(options.tools);
|
|
1002
|
+
const toolChoice = options.toolChoice?.type !== "none" ? this.convertToolChoice(options.toolChoice) : void 0;
|
|
1003
|
+
const openaiModel = this.config.openaiModel || "gpt-4o";
|
|
1004
|
+
const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;
|
|
1005
|
+
try {
|
|
1006
|
+
const response = await client.chat.completions.create({
|
|
1007
|
+
model: openaiModel,
|
|
1008
|
+
max_completion_tokens: maxTokens,
|
|
1009
|
+
messages,
|
|
1010
|
+
tools,
|
|
1011
|
+
tool_choice: tools ? toolChoice : void 0,
|
|
1012
|
+
temperature: options.temperature,
|
|
1013
|
+
top_p: options.topP,
|
|
1014
|
+
stop: options.stopSequences
|
|
1015
|
+
});
|
|
1016
|
+
const choice = response.choices[0];
|
|
1017
|
+
const content = [];
|
|
1018
|
+
if (choice?.message.content) {
|
|
1019
|
+
content.push({ type: "text", text: choice.message.content });
|
|
1020
|
+
}
|
|
1021
|
+
if (choice?.message.tool_calls) {
|
|
1022
|
+
for (const toolCall of choice.message.tool_calls) {
|
|
1023
|
+
if (toolCall.type === "function") {
|
|
1024
|
+
content.push({
|
|
1025
|
+
type: "tool-call",
|
|
1026
|
+
toolCallId: toolCall.id,
|
|
1027
|
+
toolName: toolCall.function.name,
|
|
1028
|
+
input: toolCall.function.arguments
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
const usage = {
|
|
1034
|
+
inputTokens: response.usage?.prompt_tokens || 0,
|
|
1035
|
+
outputTokens: response.usage?.completion_tokens || 0,
|
|
1036
|
+
totalTokens: response.usage?.total_tokens || 0
|
|
1037
|
+
};
|
|
1038
|
+
return {
|
|
1039
|
+
content,
|
|
1040
|
+
finishReason: this.convertFinishReason(choice?.finish_reason),
|
|
1041
|
+
usage,
|
|
1042
|
+
warnings: []
|
|
1043
|
+
};
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
if (!isRetry && this.isTokenError(error)) {
|
|
1046
|
+
this.directAccessClient.invalidateToken();
|
|
1047
|
+
return this.doGenerateWithChatApi(options, true);
|
|
1048
|
+
}
|
|
1049
|
+
if (error instanceof import_openai.default.APIError) {
|
|
1050
|
+
throw new GitLabError({
|
|
1051
|
+
message: `OpenAI API error: ${error.message}`,
|
|
1052
|
+
cause: error
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
throw error;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
async doGenerateWithResponsesApi(options, isRetry) {
|
|
1059
|
+
const client = await this.getOpenAIClient(isRetry);
|
|
1060
|
+
const input = this.convertPromptForResponses(options.prompt);
|
|
1061
|
+
const tools = this.convertToolsForResponses(options.tools);
|
|
1062
|
+
const instructions = this.extractSystemInstructions(options.prompt);
|
|
1063
|
+
const openaiModel = this.config.openaiModel || "gpt-5-codex";
|
|
1064
|
+
const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;
|
|
1065
|
+
try {
|
|
1066
|
+
const response = await client.responses.create({
|
|
1067
|
+
model: openaiModel,
|
|
1068
|
+
input,
|
|
1069
|
+
instructions,
|
|
1070
|
+
tools,
|
|
1071
|
+
max_output_tokens: maxTokens,
|
|
1072
|
+
temperature: options.temperature,
|
|
1073
|
+
top_p: options.topP,
|
|
1074
|
+
store: false
|
|
1075
|
+
});
|
|
1076
|
+
const content = [];
|
|
1077
|
+
let hasToolCalls = false;
|
|
1078
|
+
for (const item of response.output || []) {
|
|
1079
|
+
if (item.type === "message" && item.role === "assistant") {
|
|
1080
|
+
for (const contentItem of item.content || []) {
|
|
1081
|
+
if (contentItem.type === "output_text") {
|
|
1082
|
+
content.push({ type: "text", text: contentItem.text });
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
} else if (item.type === "function_call") {
|
|
1086
|
+
hasToolCalls = true;
|
|
1087
|
+
content.push({
|
|
1088
|
+
type: "tool-call",
|
|
1089
|
+
toolCallId: item.call_id,
|
|
1090
|
+
toolName: item.name,
|
|
1091
|
+
input: item.arguments
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const usage = {
|
|
1096
|
+
inputTokens: response.usage?.input_tokens || 0,
|
|
1097
|
+
outputTokens: response.usage?.output_tokens || 0,
|
|
1098
|
+
totalTokens: response.usage?.total_tokens || 0
|
|
1099
|
+
};
|
|
1100
|
+
return {
|
|
1101
|
+
content,
|
|
1102
|
+
finishReason: this.convertResponsesStatus(response.status, hasToolCalls),
|
|
1103
|
+
usage,
|
|
1104
|
+
warnings: []
|
|
1105
|
+
};
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
if (!isRetry && this.isTokenError(error)) {
|
|
1108
|
+
this.directAccessClient.invalidateToken();
|
|
1109
|
+
return this.doGenerateWithResponsesApi(options, true);
|
|
1110
|
+
}
|
|
1111
|
+
if (error instanceof import_openai.default.APIError) {
|
|
1112
|
+
throw new GitLabError({
|
|
1113
|
+
message: `OpenAI API error: ${error.message}`,
|
|
1114
|
+
cause: error
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
throw error;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
async doStream(options) {
|
|
1121
|
+
if (this.useResponsesApi) {
|
|
1122
|
+
return this.doStreamWithResponsesApi(options, false);
|
|
1123
|
+
}
|
|
1124
|
+
return this.doStreamWithChatApi(options, false);
|
|
1125
|
+
}
|
|
1126
|
+
async doStreamWithChatApi(options, isRetry) {
|
|
1127
|
+
const client = await this.getOpenAIClient(isRetry);
|
|
1128
|
+
const messages = this.convertPrompt(options.prompt);
|
|
1129
|
+
const tools = this.convertTools(options.tools);
|
|
1130
|
+
const toolChoice = options.toolChoice?.type !== "none" ? this.convertToolChoice(options.toolChoice) : void 0;
|
|
1131
|
+
const openaiModel = this.config.openaiModel || "gpt-4o";
|
|
1132
|
+
const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;
|
|
1133
|
+
const requestBody = {
|
|
1134
|
+
model: openaiModel,
|
|
1135
|
+
max_completion_tokens: maxTokens,
|
|
1136
|
+
messages,
|
|
1137
|
+
tools,
|
|
1138
|
+
tool_choice: tools ? toolChoice : void 0,
|
|
1139
|
+
temperature: options.temperature,
|
|
1140
|
+
top_p: options.topP,
|
|
1141
|
+
stop: options.stopSequences,
|
|
1142
|
+
stream: true,
|
|
1143
|
+
stream_options: { include_usage: true }
|
|
1144
|
+
};
|
|
1145
|
+
const self = this;
|
|
1146
|
+
const stream = new ReadableStream({
|
|
1147
|
+
start: async (controller) => {
|
|
1148
|
+
const toolCalls = {};
|
|
1149
|
+
const usage = {
|
|
1150
|
+
inputTokens: 0,
|
|
1151
|
+
outputTokens: 0,
|
|
1152
|
+
totalTokens: 0
|
|
1153
|
+
};
|
|
1154
|
+
let finishReason = "unknown";
|
|
1155
|
+
let textStarted = false;
|
|
1156
|
+
const textId = "text-0";
|
|
1157
|
+
try {
|
|
1158
|
+
const openaiStream = await client.chat.completions.create({
|
|
1159
|
+
...requestBody,
|
|
1160
|
+
stream: true
|
|
1161
|
+
});
|
|
1162
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
1163
|
+
for await (const chunk of openaiStream) {
|
|
1164
|
+
const choice = chunk.choices?.[0];
|
|
1165
|
+
if (chunk.id && !textStarted) {
|
|
1166
|
+
controller.enqueue({
|
|
1167
|
+
type: "response-metadata",
|
|
1168
|
+
id: chunk.id,
|
|
1169
|
+
modelId: chunk.model
|
|
1170
|
+
});
|
|
1171
|
+
}
|
|
1172
|
+
if (choice?.delta?.content) {
|
|
1173
|
+
if (!textStarted) {
|
|
1174
|
+
controller.enqueue({ type: "text-start", id: textId });
|
|
1175
|
+
textStarted = true;
|
|
1176
|
+
}
|
|
1177
|
+
controller.enqueue({
|
|
1178
|
+
type: "text-delta",
|
|
1179
|
+
id: textId,
|
|
1180
|
+
delta: choice.delta.content
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
if (choice?.delta?.tool_calls) {
|
|
1184
|
+
for (const tc of choice.delta.tool_calls) {
|
|
1185
|
+
const idx = tc.index;
|
|
1186
|
+
if (!toolCalls[idx]) {
|
|
1187
|
+
toolCalls[idx] = {
|
|
1188
|
+
id: tc.id || "",
|
|
1189
|
+
name: tc.function?.name || "",
|
|
1190
|
+
arguments: ""
|
|
1191
|
+
};
|
|
1192
|
+
controller.enqueue({
|
|
1193
|
+
type: "tool-input-start",
|
|
1194
|
+
id: toolCalls[idx].id,
|
|
1195
|
+
toolName: toolCalls[idx].name
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
if (tc.function?.arguments) {
|
|
1199
|
+
toolCalls[idx].arguments += tc.function.arguments;
|
|
1200
|
+
controller.enqueue({
|
|
1201
|
+
type: "tool-input-delta",
|
|
1202
|
+
id: toolCalls[idx].id,
|
|
1203
|
+
delta: tc.function.arguments
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
if (choice?.finish_reason) {
|
|
1209
|
+
finishReason = self.convertFinishReason(choice.finish_reason);
|
|
1210
|
+
}
|
|
1211
|
+
if (chunk.usage) {
|
|
1212
|
+
usage.inputTokens = chunk.usage.prompt_tokens || 0;
|
|
1213
|
+
usage.outputTokens = chunk.usage.completion_tokens || 0;
|
|
1214
|
+
usage.totalTokens = chunk.usage.total_tokens || 0;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
if (textStarted) {
|
|
1218
|
+
controller.enqueue({ type: "text-end", id: textId });
|
|
1219
|
+
}
|
|
1220
|
+
for (const [, tc] of Object.entries(toolCalls)) {
|
|
1221
|
+
controller.enqueue({ type: "tool-input-end", id: tc.id });
|
|
1222
|
+
controller.enqueue({
|
|
1223
|
+
type: "tool-call",
|
|
1224
|
+
toolCallId: tc.id,
|
|
1225
|
+
toolName: tc.name,
|
|
1226
|
+
input: tc.arguments || "{}"
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
controller.enqueue({ type: "finish", finishReason, usage });
|
|
1230
|
+
controller.close();
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
if (!isRetry && self.isTokenError(error)) {
|
|
1233
|
+
self.directAccessClient.invalidateToken();
|
|
1234
|
+
controller.enqueue({
|
|
1235
|
+
type: "error",
|
|
1236
|
+
error: new GitLabError({ message: "TOKEN_REFRESH_NEEDED", cause: error })
|
|
1237
|
+
});
|
|
1238
|
+
controller.close();
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
if (error instanceof import_openai.default.APIError) {
|
|
1242
|
+
controller.enqueue({
|
|
1243
|
+
type: "error",
|
|
1244
|
+
error: new GitLabError({
|
|
1245
|
+
message: `OpenAI API error: ${error.message}`,
|
|
1246
|
+
cause: error
|
|
1247
|
+
})
|
|
1248
|
+
});
|
|
1249
|
+
} else {
|
|
1250
|
+
controller.enqueue({ type: "error", error });
|
|
1251
|
+
}
|
|
1252
|
+
controller.close();
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
return { stream, request: { body: requestBody } };
|
|
1257
|
+
}
|
|
1258
|
+
async doStreamWithResponsesApi(options, isRetry) {
|
|
1259
|
+
const client = await this.getOpenAIClient(isRetry);
|
|
1260
|
+
const input = this.convertPromptForResponses(options.prompt);
|
|
1261
|
+
const tools = this.convertToolsForResponses(options.tools);
|
|
1262
|
+
const instructions = this.extractSystemInstructions(options.prompt);
|
|
1263
|
+
const openaiModel = this.config.openaiModel || "gpt-5-codex";
|
|
1264
|
+
const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;
|
|
1265
|
+
const requestBody = {
|
|
1266
|
+
model: openaiModel,
|
|
1267
|
+
input,
|
|
1268
|
+
instructions,
|
|
1269
|
+
tools,
|
|
1270
|
+
max_output_tokens: maxTokens,
|
|
1271
|
+
temperature: options.temperature,
|
|
1272
|
+
top_p: options.topP,
|
|
1273
|
+
store: false,
|
|
1274
|
+
stream: true
|
|
1275
|
+
};
|
|
1276
|
+
const self = this;
|
|
1277
|
+
const stream = new ReadableStream({
|
|
1278
|
+
start: async (controller) => {
|
|
1279
|
+
const toolCalls = {};
|
|
1280
|
+
const usage = {
|
|
1281
|
+
inputTokens: 0,
|
|
1282
|
+
outputTokens: 0,
|
|
1283
|
+
totalTokens: 0
|
|
1284
|
+
};
|
|
1285
|
+
let finishReason = "unknown";
|
|
1286
|
+
let textStarted = false;
|
|
1287
|
+
const textId = "text-0";
|
|
1288
|
+
try {
|
|
1289
|
+
const openaiStream = await client.responses.create({
|
|
1290
|
+
...requestBody,
|
|
1291
|
+
stream: true
|
|
1292
|
+
});
|
|
1293
|
+
controller.enqueue({ type: "stream-start", warnings: [] });
|
|
1294
|
+
for await (const event of openaiStream) {
|
|
1295
|
+
if (event.type === "response.created") {
|
|
1296
|
+
controller.enqueue({
|
|
1297
|
+
type: "response-metadata",
|
|
1298
|
+
id: event.response.id,
|
|
1299
|
+
modelId: event.response.model
|
|
1300
|
+
});
|
|
1301
|
+
} else if (event.type === "response.output_item.added") {
|
|
1302
|
+
if (event.item.type === "function_call") {
|
|
1303
|
+
const outputIndex = event.output_index;
|
|
1304
|
+
const callId = event.item.call_id;
|
|
1305
|
+
toolCalls[outputIndex] = {
|
|
1306
|
+
callId,
|
|
1307
|
+
name: event.item.name,
|
|
1308
|
+
arguments: ""
|
|
1309
|
+
};
|
|
1310
|
+
controller.enqueue({
|
|
1311
|
+
type: "tool-input-start",
|
|
1312
|
+
id: callId,
|
|
1313
|
+
toolName: event.item.name
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
} else if (event.type === "response.output_text.delta") {
|
|
1317
|
+
if (!textStarted) {
|
|
1318
|
+
controller.enqueue({ type: "text-start", id: textId });
|
|
1319
|
+
textStarted = true;
|
|
1320
|
+
}
|
|
1321
|
+
controller.enqueue({
|
|
1322
|
+
type: "text-delta",
|
|
1323
|
+
id: textId,
|
|
1324
|
+
delta: event.delta
|
|
1325
|
+
});
|
|
1326
|
+
} else if (event.type === "response.function_call_arguments.delta") {
|
|
1327
|
+
const outputIndex = event.output_index;
|
|
1328
|
+
const tc = toolCalls[outputIndex];
|
|
1329
|
+
if (tc) {
|
|
1330
|
+
tc.arguments += event.delta;
|
|
1331
|
+
controller.enqueue({
|
|
1332
|
+
type: "tool-input-delta",
|
|
1333
|
+
id: tc.callId,
|
|
1334
|
+
delta: event.delta
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
} else if (event.type === "response.function_call_arguments.done") {
|
|
1338
|
+
const outputIndex = event.output_index;
|
|
1339
|
+
const tc = toolCalls[outputIndex];
|
|
1340
|
+
if (tc) {
|
|
1341
|
+
tc.arguments = event.arguments;
|
|
1342
|
+
}
|
|
1343
|
+
} else if (event.type === "response.completed") {
|
|
1344
|
+
const hasToolCalls2 = Object.keys(toolCalls).length > 0;
|
|
1345
|
+
finishReason = self.convertResponsesStatus(event.response.status, hasToolCalls2);
|
|
1346
|
+
if (event.response.usage) {
|
|
1347
|
+
usage.inputTokens = event.response.usage.input_tokens || 0;
|
|
1348
|
+
usage.outputTokens = event.response.usage.output_tokens || 0;
|
|
1349
|
+
usage.totalTokens = event.response.usage.total_tokens || 0;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
if (textStarted) {
|
|
1354
|
+
controller.enqueue({ type: "text-end", id: textId });
|
|
1355
|
+
}
|
|
1356
|
+
const hasToolCalls = Object.keys(toolCalls).length > 0;
|
|
1357
|
+
if (hasToolCalls && finishReason === "stop") {
|
|
1358
|
+
finishReason = "tool-calls";
|
|
1359
|
+
}
|
|
1360
|
+
for (const tc of Object.values(toolCalls)) {
|
|
1361
|
+
controller.enqueue({ type: "tool-input-end", id: tc.callId });
|
|
1362
|
+
controller.enqueue({
|
|
1363
|
+
type: "tool-call",
|
|
1364
|
+
toolCallId: tc.callId,
|
|
1365
|
+
toolName: tc.name,
|
|
1366
|
+
input: tc.arguments || "{}"
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
controller.enqueue({ type: "finish", finishReason, usage });
|
|
1370
|
+
controller.close();
|
|
1371
|
+
} catch (error) {
|
|
1372
|
+
if (!isRetry && self.isTokenError(error)) {
|
|
1373
|
+
self.directAccessClient.invalidateToken();
|
|
1374
|
+
controller.enqueue({
|
|
1375
|
+
type: "error",
|
|
1376
|
+
error: new GitLabError({ message: "TOKEN_REFRESH_NEEDED", cause: error })
|
|
1377
|
+
});
|
|
1378
|
+
controller.close();
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
if (error instanceof import_openai.default.APIError) {
|
|
1382
|
+
controller.enqueue({
|
|
1383
|
+
type: "error",
|
|
1384
|
+
error: new GitLabError({
|
|
1385
|
+
message: `OpenAI API error: ${error.message}`,
|
|
1386
|
+
cause: error
|
|
1387
|
+
})
|
|
1388
|
+
});
|
|
1389
|
+
} else {
|
|
1390
|
+
controller.enqueue({ type: "error", error });
|
|
1391
|
+
}
|
|
1392
|
+
controller.close();
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
return { stream, request: { body: requestBody } };
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
|
|
648
1400
|
// src/gitlab-oauth-types.ts
|
|
649
1401
|
var BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
|
|
650
1402
|
var GITLAB_COM_URL = "https://gitlab.com";
|
|
@@ -807,16 +1559,6 @@ var GitLabOAuthManager = class {
|
|
|
807
1559
|
}
|
|
808
1560
|
};
|
|
809
1561
|
|
|
810
|
-
// src/model-mappings.ts
|
|
811
|
-
var MODEL_ID_TO_ANTHROPIC_MODEL = {
|
|
812
|
-
"duo-chat-opus-4-5": "claude-opus-4-5-20251101",
|
|
813
|
-
"duo-chat-sonnet-4-5": "claude-sonnet-4-5-20250929",
|
|
814
|
-
"duo-chat-haiku-4-5": "claude-haiku-4-5-20251001"
|
|
815
|
-
};
|
|
816
|
-
function getAnthropicModelForModelId(modelId) {
|
|
817
|
-
return MODEL_ID_TO_ANTHROPIC_MODEL[modelId];
|
|
818
|
-
}
|
|
819
|
-
|
|
820
1562
|
// src/gitlab-provider.ts
|
|
821
1563
|
var fs = __toESM(require("fs"));
|
|
822
1564
|
var path = __toESM(require("path"));
|
|
@@ -952,21 +1694,44 @@ function createGitLab(options = {}) {
|
|
|
952
1694
|
getApiKey().catch(() => {
|
|
953
1695
|
});
|
|
954
1696
|
const createAgenticChatModel = (modelId, agenticOptions) => {
|
|
1697
|
+
const mapping = getModelMapping(modelId);
|
|
1698
|
+
if (!mapping) {
|
|
1699
|
+
throw new GitLabError({
|
|
1700
|
+
message: `Unknown model ID: ${modelId}. Model must be registered in MODEL_MAPPINGS.`
|
|
1701
|
+
});
|
|
1702
|
+
}
|
|
1703
|
+
if (agenticOptions?.providerModel) {
|
|
1704
|
+
const validModels = getValidModelsForProvider(mapping.provider);
|
|
1705
|
+
if (!validModels.includes(agenticOptions.providerModel)) {
|
|
1706
|
+
throw new GitLabError({
|
|
1707
|
+
message: `Invalid providerModel '${agenticOptions.providerModel}' for provider '${mapping.provider}'. Valid models: ${validModels.join(", ")}`
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
955
1711
|
const featureFlags = {
|
|
956
1712
|
DuoAgentPlatformNext: true,
|
|
957
1713
|
...options.featureFlags,
|
|
958
1714
|
...agenticOptions?.featureFlags
|
|
959
1715
|
};
|
|
960
|
-
|
|
1716
|
+
const baseConfig = {
|
|
961
1717
|
provider: `${providerName}.agentic`,
|
|
962
1718
|
instanceUrl,
|
|
963
1719
|
getHeaders,
|
|
964
1720
|
refreshApiKey,
|
|
965
1721
|
fetch: options.fetch,
|
|
966
|
-
anthropicModel: agenticOptions?.anthropicModel ?? getAnthropicModelForModelId(modelId),
|
|
967
1722
|
maxTokens: agenticOptions?.maxTokens,
|
|
968
1723
|
featureFlags,
|
|
969
1724
|
aiGatewayUrl: options.aiGatewayUrl
|
|
1725
|
+
};
|
|
1726
|
+
if (mapping.provider === "openai") {
|
|
1727
|
+
return new GitLabOpenAILanguageModel(modelId, {
|
|
1728
|
+
...baseConfig,
|
|
1729
|
+
openaiModel: agenticOptions?.providerModel ?? mapping.model
|
|
1730
|
+
});
|
|
1731
|
+
}
|
|
1732
|
+
return new GitLabAnthropicLanguageModel(modelId, {
|
|
1733
|
+
...baseConfig,
|
|
1734
|
+
anthropicModel: agenticOptions?.providerModel ?? mapping.model
|
|
970
1735
|
});
|
|
971
1736
|
};
|
|
972
1737
|
const createDefaultModel = (modelId) => {
|
|
@@ -1266,17 +2031,25 @@ var GitLabProjectDetector = class {
|
|
|
1266
2031
|
BUNDLED_CLIENT_ID,
|
|
1267
2032
|
DEFAULT_AI_GATEWAY_URL,
|
|
1268
2033
|
GITLAB_COM_URL,
|
|
1269
|
-
|
|
2034
|
+
GitLabAnthropicLanguageModel,
|
|
1270
2035
|
GitLabDirectAccessClient,
|
|
1271
2036
|
GitLabError,
|
|
1272
2037
|
GitLabOAuthManager,
|
|
2038
|
+
GitLabOpenAILanguageModel,
|
|
1273
2039
|
GitLabProjectCache,
|
|
1274
2040
|
GitLabProjectDetector,
|
|
1275
2041
|
MODEL_ID_TO_ANTHROPIC_MODEL,
|
|
2042
|
+
MODEL_MAPPINGS,
|
|
1276
2043
|
OAUTH_SCOPES,
|
|
1277
2044
|
TOKEN_EXPIRY_SKEW_MS,
|
|
1278
2045
|
createGitLab,
|
|
1279
2046
|
getAnthropicModelForModelId,
|
|
1280
|
-
|
|
2047
|
+
getModelMapping,
|
|
2048
|
+
getOpenAIApiType,
|
|
2049
|
+
getOpenAIModelForModelId,
|
|
2050
|
+
getProviderForModelId,
|
|
2051
|
+
getValidModelsForProvider,
|
|
2052
|
+
gitlab,
|
|
2053
|
+
isResponsesApiModel
|
|
1281
2054
|
});
|
|
1282
2055
|
//# sourceMappingURL=index.js.map
|