claudish 3.4.1 → 3.5.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/AI_AGENT_GUIDE.md +158 -5
- package/dist/index.js +1165 -190
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -56261,6 +56261,9 @@ function getModelPricing(provider, modelName) {
|
|
|
56261
56261
|
case "google":
|
|
56262
56262
|
pricingTable = GEMINI_PRICING;
|
|
56263
56263
|
break;
|
|
56264
|
+
case "vertex":
|
|
56265
|
+
pricingTable = VERTEX_PRICING;
|
|
56266
|
+
break;
|
|
56264
56267
|
case "openai":
|
|
56265
56268
|
case "oai":
|
|
56266
56269
|
pricingTable = OPENAI_PRICING;
|
|
@@ -56290,7 +56293,7 @@ function getModelPricing(provider, modelName) {
|
|
|
56290
56293
|
}
|
|
56291
56294
|
return pricingTable.default;
|
|
56292
56295
|
}
|
|
56293
|
-
var GEMINI_PRICING, OPENAI_PRICING, MINIMAX_PRICING, KIMI_PRICING, GLM_PRICING;
|
|
56296
|
+
var GEMINI_PRICING, OPENAI_PRICING, MINIMAX_PRICING, KIMI_PRICING, GLM_PRICING, VERTEX_PRICING;
|
|
56294
56297
|
var init_remote_provider_types = __esm(() => {
|
|
56295
56298
|
GEMINI_PRICING = {
|
|
56296
56299
|
"gemini-2.5-flash": { inputCostPer1M: 0.15, outputCostPer1M: 0.6 },
|
|
@@ -56361,6 +56364,17 @@ var init_remote_provider_types = __esm(() => {
|
|
|
56361
56364
|
"glm-4-plus": { inputCostPer1M: 0.5, outputCostPer1M: 2 },
|
|
56362
56365
|
default: { inputCostPer1M: 0.16, outputCostPer1M: 0.8, isEstimate: true }
|
|
56363
56366
|
};
|
|
56367
|
+
VERTEX_PRICING = {
|
|
56368
|
+
"gemini-2.5-flash": { inputCostPer1M: 0.15, outputCostPer1M: 0.6 },
|
|
56369
|
+
"gemini-2.5-flash-preview-05-20": { inputCostPer1M: 0.15, outputCostPer1M: 0.6 },
|
|
56370
|
+
"gemini-2.5-pro": { inputCostPer1M: 1.25, outputCostPer1M: 10 },
|
|
56371
|
+
"gemini-2.5-pro-preview-05-06": { inputCostPer1M: 1.25, outputCostPer1M: 10 },
|
|
56372
|
+
"gemini-3-pro-preview": { inputCostPer1M: 2.5, outputCostPer1M: 10 },
|
|
56373
|
+
"gemini-3.0-flash": { inputCostPer1M: 0.1, outputCostPer1M: 0.4 },
|
|
56374
|
+
"gemini-2.0-flash": { inputCostPer1M: 0.1, outputCostPer1M: 0.4 },
|
|
56375
|
+
"gemini-2.0-flash-thinking": { inputCostPer1M: 0.1, outputCostPer1M: 0.4 },
|
|
56376
|
+
default: { inputCostPer1M: 0.5, outputCostPer1M: 2, isEstimate: true }
|
|
56377
|
+
};
|
|
56364
56378
|
});
|
|
56365
56379
|
|
|
56366
56380
|
// ../core/dist/handlers/gemini-handler.js
|
|
@@ -57712,161 +57726,1070 @@ var init_anthropic_compat_handler = __esm(() => {
|
|
|
57712
57726
|
init_remote_provider_types();
|
|
57713
57727
|
});
|
|
57714
57728
|
|
|
57715
|
-
// ../core/dist/
|
|
57716
|
-
|
|
57717
|
-
|
|
57718
|
-
}
|
|
57719
|
-
|
|
57720
|
-
|
|
57721
|
-
|
|
57722
|
-
|
|
57723
|
-
|
|
57724
|
-
|
|
57725
|
-
|
|
57726
|
-
|
|
57727
|
-
|
|
57728
|
-
|
|
57729
|
+
// ../core/dist/auth/vertex-auth.js
|
|
57730
|
+
import { exec as exec2 } from "node:child_process";
|
|
57731
|
+
import { promisify } from "node:util";
|
|
57732
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
57733
|
+
import { homedir as homedir7 } from "node:os";
|
|
57734
|
+
import { join as join11 } from "node:path";
|
|
57735
|
+
|
|
57736
|
+
class VertexAuthManager {
|
|
57737
|
+
cachedToken = null;
|
|
57738
|
+
refreshPromise = null;
|
|
57739
|
+
tokenRefreshMargin = 5 * 60 * 1000;
|
|
57740
|
+
async getAccessToken() {
|
|
57741
|
+
if (this.refreshPromise) {
|
|
57742
|
+
log("[VertexAuth] Waiting for in-progress refresh");
|
|
57743
|
+
return this.refreshPromise;
|
|
57744
|
+
}
|
|
57745
|
+
if (this.isTokenValid()) {
|
|
57746
|
+
return this.cachedToken.token;
|
|
57747
|
+
}
|
|
57748
|
+
this.refreshPromise = this.doRefresh();
|
|
57749
|
+
try {
|
|
57750
|
+
const token = await this.refreshPromise;
|
|
57751
|
+
return token;
|
|
57752
|
+
} finally {
|
|
57753
|
+
this.refreshPromise = null;
|
|
57729
57754
|
}
|
|
57730
57755
|
}
|
|
57731
|
-
|
|
57732
|
-
|
|
57733
|
-
|
|
57734
|
-
if (resolveProvider(modelId) !== null) {
|
|
57735
|
-
return true;
|
|
57756
|
+
async refreshToken() {
|
|
57757
|
+
this.cachedToken = null;
|
|
57758
|
+
await this.getAccessToken();
|
|
57736
57759
|
}
|
|
57737
|
-
|
|
57738
|
-
|
|
57760
|
+
isTokenValid() {
|
|
57761
|
+
if (!this.cachedToken)
|
|
57762
|
+
return false;
|
|
57763
|
+
return Date.now() < this.cachedToken.expiresAt - this.tokenRefreshMargin;
|
|
57764
|
+
}
|
|
57765
|
+
async doRefresh() {
|
|
57766
|
+
log("[VertexAuth] Refreshing token");
|
|
57767
|
+
const adcToken = await this.tryADC();
|
|
57768
|
+
if (adcToken) {
|
|
57769
|
+
this.cachedToken = adcToken;
|
|
57770
|
+
log(`[VertexAuth] ADC token valid until ${new Date(adcToken.expiresAt).toISOString()}`);
|
|
57771
|
+
return adcToken.token;
|
|
57772
|
+
}
|
|
57773
|
+
const saToken = await this.tryServiceAccount();
|
|
57774
|
+
if (saToken) {
|
|
57775
|
+
this.cachedToken = saToken;
|
|
57776
|
+
log(`[VertexAuth] Service account token valid until ${new Date(saToken.expiresAt).toISOString()}`);
|
|
57777
|
+
return saToken.token;
|
|
57778
|
+
}
|
|
57779
|
+
throw new Error(`Failed to authenticate with Vertex AI.
|
|
57780
|
+
|
|
57781
|
+
` + `Options:
|
|
57782
|
+
` + `1. Run: gcloud auth application-default login
|
|
57783
|
+
` + `2. Set: export GOOGLE_APPLICATION_CREDENTIALS='/path/to/service-account.json'
|
|
57784
|
+
`);
|
|
57739
57785
|
}
|
|
57740
|
-
|
|
57741
|
-
|
|
57742
|
-
|
|
57743
|
-
|
|
57744
|
-
|
|
57786
|
+
async tryADC() {
|
|
57787
|
+
try {
|
|
57788
|
+
const adcPath = join11(homedir7(), ".config/gcloud/application_default_credentials.json");
|
|
57789
|
+
if (!existsSync6(adcPath)) {
|
|
57790
|
+
log("[VertexAuth] ADC credentials file not found");
|
|
57791
|
+
return null;
|
|
57792
|
+
}
|
|
57793
|
+
const { stdout } = await execAsync("gcloud auth application-default print-access-token", {
|
|
57794
|
+
timeout: 1e4
|
|
57795
|
+
});
|
|
57796
|
+
const token = stdout.trim();
|
|
57797
|
+
if (!token) {
|
|
57798
|
+
log("[VertexAuth] ADC returned empty token");
|
|
57799
|
+
return null;
|
|
57800
|
+
}
|
|
57801
|
+
const expiresAt = Date.now() + 55 * 60 * 1000;
|
|
57802
|
+
return { token, expiresAt };
|
|
57803
|
+
} catch (e) {
|
|
57804
|
+
log(`[VertexAuth] ADC failed: ${e.message}`);
|
|
57805
|
+
return null;
|
|
57806
|
+
}
|
|
57745
57807
|
}
|
|
57746
|
-
|
|
57747
|
-
const
|
|
57748
|
-
|
|
57749
|
-
if (pathParts.length === 0) {
|
|
57808
|
+
async tryServiceAccount() {
|
|
57809
|
+
const credPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
57810
|
+
if (!credPath) {
|
|
57750
57811
|
return null;
|
|
57751
57812
|
}
|
|
57752
|
-
|
|
57753
|
-
|
|
57754
|
-
|
|
57755
|
-
|
|
57756
|
-
|
|
57757
|
-
|
|
57813
|
+
if (!existsSync6(credPath)) {
|
|
57814
|
+
throw new Error(`Service account file not found: ${credPath}
|
|
57815
|
+
|
|
57816
|
+
Check GOOGLE_APPLICATION_CREDENTIALS path.`);
|
|
57817
|
+
}
|
|
57818
|
+
try {
|
|
57819
|
+
const { stdout } = await execAsync(`gcloud auth print-access-token --credential-file-override="${credPath}"`, { timeout: 1e4 });
|
|
57820
|
+
const token = stdout.trim();
|
|
57821
|
+
if (!token) {
|
|
57822
|
+
log("[VertexAuth] Service account returned empty token");
|
|
57823
|
+
return null;
|
|
57824
|
+
}
|
|
57825
|
+
const expiresAt = Date.now() + 55 * 60 * 1000;
|
|
57826
|
+
return { token, expiresAt };
|
|
57827
|
+
} catch (e) {
|
|
57828
|
+
log(`[VertexAuth] Service account auth failed: ${e.message}`);
|
|
57829
|
+
return null;
|
|
57758
57830
|
}
|
|
57759
|
-
const baseUrl = `${url2.protocol}//${url2.host}${basePath}`;
|
|
57760
|
-
return {
|
|
57761
|
-
baseUrl,
|
|
57762
|
-
modelName
|
|
57763
|
-
};
|
|
57764
|
-
} catch {
|
|
57765
|
-
return null;
|
|
57766
57831
|
}
|
|
57767
57832
|
}
|
|
57768
|
-
function
|
|
57833
|
+
function getVertexConfig() {
|
|
57834
|
+
const projectId = process.env.VERTEX_PROJECT || process.env.GOOGLE_CLOUD_PROJECT;
|
|
57835
|
+
if (!projectId) {
|
|
57836
|
+
return null;
|
|
57837
|
+
}
|
|
57769
57838
|
return {
|
|
57770
|
-
|
|
57771
|
-
|
|
57772
|
-
apiPath: "/v1/chat/completions",
|
|
57773
|
-
envVar: "",
|
|
57774
|
-
prefixes: [],
|
|
57775
|
-
capabilities: {
|
|
57776
|
-
supportsTools: true,
|
|
57777
|
-
supportsVision: false,
|
|
57778
|
-
supportsStreaming: true,
|
|
57779
|
-
supportsJsonMode: true
|
|
57780
|
-
}
|
|
57839
|
+
projectId,
|
|
57840
|
+
location: process.env.VERTEX_LOCATION || "us-central1"
|
|
57781
57841
|
};
|
|
57782
57842
|
}
|
|
57783
|
-
|
|
57784
|
-
|
|
57785
|
-
|
|
57786
|
-
|
|
57787
|
-
|
|
57788
|
-
|
|
57789
|
-
|
|
57790
|
-
|
|
57791
|
-
|
|
57792
|
-
|
|
57793
|
-
|
|
57794
|
-
|
|
57795
|
-
|
|
57796
|
-
|
|
57797
|
-
|
|
57798
|
-
|
|
57799
|
-
|
|
57800
|
-
|
|
57801
|
-
|
|
57802
|
-
|
|
57803
|
-
|
|
57804
|
-
|
|
57805
|
-
|
|
57806
|
-
|
|
57807
|
-
|
|
57843
|
+
function validateVertexOAuthConfig() {
|
|
57844
|
+
const config3 = getVertexConfig();
|
|
57845
|
+
if (!config3) {
|
|
57846
|
+
return `Missing VERTEX_PROJECT environment variable.
|
|
57847
|
+
|
|
57848
|
+
` + `Set it with:
|
|
57849
|
+
` + ` export VERTEX_PROJECT='your-gcp-project-id'
|
|
57850
|
+
` + " export VERTEX_LOCATION='us-central1' # optional";
|
|
57851
|
+
}
|
|
57852
|
+
const adcPath = join11(homedir7(), ".config/gcloud/application_default_credentials.json");
|
|
57853
|
+
const hasADC = existsSync6(adcPath);
|
|
57854
|
+
const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
57855
|
+
if (!hasADC && !hasServiceAccount) {
|
|
57856
|
+
return `No Vertex AI credentials found.
|
|
57857
|
+
|
|
57858
|
+
` + `Options:
|
|
57859
|
+
` + `1. Run: gcloud auth application-default login
|
|
57860
|
+
` + "2. Set: export GOOGLE_APPLICATION_CREDENTIALS='/path/to/service-account.json'";
|
|
57861
|
+
}
|
|
57862
|
+
return null;
|
|
57863
|
+
}
|
|
57864
|
+
function buildVertexOAuthEndpoint(config3, publisher, model, streaming = true) {
|
|
57865
|
+
const method = streaming ? "streamGenerateContent" : "generateContent";
|
|
57866
|
+
if (publisher === "google") {
|
|
57867
|
+
const sseParam = streaming ? "?alt=sse" : "";
|
|
57868
|
+
return `https://${config3.location}-aiplatform.googleapis.com/v1/` + `projects/${config3.projectId}/locations/${config3.location}/` + `publishers/${publisher}/models/${model}:${method}${sseParam}`;
|
|
57869
|
+
} else if (publisher === "mistralai") {
|
|
57870
|
+
const mistralMethod = streaming ? "streamRawPredict" : "rawPredict";
|
|
57871
|
+
return `https://${config3.location}-aiplatform.googleapis.com/v1/` + `projects/${config3.projectId}/locations/${config3.location}/` + `publishers/mistralai/models/${model}:${mistralMethod}`;
|
|
57872
|
+
} else {
|
|
57873
|
+
return `https://aiplatform.googleapis.com/v1/` + `projects/${config3.projectId}/locations/global/` + `endpoints/openapi/chat/completions`;
|
|
57874
|
+
}
|
|
57875
|
+
}
|
|
57876
|
+
function getVertexAuthManager() {
|
|
57877
|
+
if (!authManagerInstance) {
|
|
57878
|
+
authManagerInstance = new VertexAuthManager;
|
|
57879
|
+
}
|
|
57880
|
+
return authManagerInstance;
|
|
57881
|
+
}
|
|
57882
|
+
var execAsync, authManagerInstance = null;
|
|
57883
|
+
var init_vertex_auth = __esm(() => {
|
|
57884
|
+
init_logger();
|
|
57885
|
+
execAsync = promisify(exec2);
|
|
57886
|
+
});
|
|
57887
|
+
|
|
57888
|
+
// ../core/dist/handlers/vertex-oauth-handler.js
|
|
57889
|
+
import { writeFileSync as writeFileSync10, mkdirSync as mkdirSync8 } from "node:fs";
|
|
57890
|
+
import { homedir as homedir8 } from "node:os";
|
|
57891
|
+
import { join as join12 } from "node:path";
|
|
57892
|
+
function parseVertexModel(modelId) {
|
|
57893
|
+
const parts = modelId.split("/");
|
|
57894
|
+
if (parts.length === 1) {
|
|
57895
|
+
return { publisher: "google", model: parts[0] };
|
|
57896
|
+
}
|
|
57897
|
+
return { publisher: parts[0], model: parts.slice(1).join("/") };
|
|
57898
|
+
}
|
|
57899
|
+
|
|
57900
|
+
class VertexOAuthHandler {
|
|
57901
|
+
modelName;
|
|
57902
|
+
port;
|
|
57903
|
+
config;
|
|
57904
|
+
parsed;
|
|
57905
|
+
adapterManager;
|
|
57906
|
+
middlewareManager;
|
|
57907
|
+
sessionTotalCost = 0;
|
|
57908
|
+
sessionInputTokens = 0;
|
|
57909
|
+
sessionOutputTokens = 0;
|
|
57910
|
+
contextWindow = 1e6;
|
|
57911
|
+
toolCallMap = new Map;
|
|
57912
|
+
constructor(modelName, port) {
|
|
57913
|
+
this.modelName = modelName;
|
|
57914
|
+
this.port = port;
|
|
57915
|
+
this.config = getVertexConfig();
|
|
57916
|
+
this.parsed = parseVertexModel(modelName);
|
|
57917
|
+
this.adapterManager = new AdapterManager(`vertex/${modelName}`);
|
|
57918
|
+
this.middlewareManager = new MiddlewareManager;
|
|
57919
|
+
if (this.parsed.publisher === "google") {
|
|
57920
|
+
this.middlewareManager.register(new GeminiThoughtSignatureMiddleware);
|
|
57808
57921
|
}
|
|
57809
|
-
|
|
57810
|
-
|
|
57811
|
-
|
|
57812
|
-
|
|
57813
|
-
|
|
57814
|
-
|
|
57815
|
-
|
|
57816
|
-
|
|
57817
|
-
|
|
57818
|
-
|
|
57819
|
-
|
|
57820
|
-
|
|
57922
|
+
this.middlewareManager.initialize().catch((err) => log(`[VertexOAuth:${modelName}] Middleware init error: ${err}`));
|
|
57923
|
+
}
|
|
57924
|
+
getPricing() {
|
|
57925
|
+
return getModelPricing("vertex", this.parsed.model);
|
|
57926
|
+
}
|
|
57927
|
+
getApiEndpoint() {
|
|
57928
|
+
return buildVertexOAuthEndpoint(this.config, this.parsed.publisher, this.parsed.model, true);
|
|
57929
|
+
}
|
|
57930
|
+
writeTokenFile(input, output) {
|
|
57931
|
+
try {
|
|
57932
|
+
const total = input + output;
|
|
57933
|
+
const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
|
|
57934
|
+
const data = {
|
|
57935
|
+
input_tokens: input,
|
|
57936
|
+
output_tokens: output,
|
|
57937
|
+
total_tokens: total,
|
|
57938
|
+
total_cost: this.sessionTotalCost,
|
|
57939
|
+
context_window: this.contextWindow,
|
|
57940
|
+
context_left_percent: leftPct,
|
|
57941
|
+
updated_at: Date.now()
|
|
57942
|
+
};
|
|
57943
|
+
const claudishDir = join12(homedir8(), ".claudish");
|
|
57944
|
+
mkdirSync8(claudishDir, { recursive: true });
|
|
57945
|
+
writeFileSync10(join12(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
|
|
57946
|
+
} catch (e) {
|
|
57947
|
+
log(`[VertexOAuth] Error writing token file: ${e}`);
|
|
57821
57948
|
}
|
|
57822
|
-
}
|
|
57823
|
-
{
|
|
57824
|
-
|
|
57825
|
-
|
|
57826
|
-
|
|
57827
|
-
|
|
57828
|
-
|
|
57829
|
-
|
|
57830
|
-
|
|
57831
|
-
|
|
57832
|
-
|
|
57833
|
-
|
|
57949
|
+
}
|
|
57950
|
+
updateTokenTracking(inputTokens, outputTokens) {
|
|
57951
|
+
this.sessionInputTokens = inputTokens;
|
|
57952
|
+
this.sessionOutputTokens += outputTokens;
|
|
57953
|
+
const pricing = this.getPricing();
|
|
57954
|
+
const cost = inputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M;
|
|
57955
|
+
this.sessionTotalCost += cost;
|
|
57956
|
+
this.writeTokenFile(inputTokens, this.sessionOutputTokens);
|
|
57957
|
+
}
|
|
57958
|
+
buildPayload(claudeRequest) {
|
|
57959
|
+
if (this.parsed.publisher === "google") {
|
|
57960
|
+
return this.buildGeminiPayload(claudeRequest);
|
|
57961
|
+
} else if (this.parsed.publisher === "anthropic") {
|
|
57962
|
+
return this.buildAnthropicPayload(claudeRequest);
|
|
57963
|
+
} else if (this.parsed.publisher === "mistralai" || this.parsed.publisher === "meta") {
|
|
57964
|
+
return this.buildOpenAIPayload(claudeRequest);
|
|
57965
|
+
} else {
|
|
57966
|
+
return this.buildOpenAIPayload(claudeRequest);
|
|
57834
57967
|
}
|
|
57835
57968
|
}
|
|
57836
|
-
|
|
57969
|
+
buildGeminiPayload(claudeRequest) {
|
|
57970
|
+
const contents = this.convertToGeminiMessages(claudeRequest);
|
|
57971
|
+
const payload = {
|
|
57972
|
+
contents,
|
|
57973
|
+
generationConfig: {
|
|
57974
|
+
temperature: claudeRequest.temperature ?? 1,
|
|
57975
|
+
maxOutputTokens: claudeRequest.max_tokens
|
|
57976
|
+
}
|
|
57977
|
+
};
|
|
57978
|
+
if (claudeRequest.system) {
|
|
57979
|
+
let systemContent = Array.isArray(claudeRequest.system) ? claudeRequest.system.map((i) => i.text || i).join(`
|
|
57837
57980
|
|
|
57838
|
-
|
|
57839
|
-
|
|
57840
|
-
|
|
57841
|
-
|
|
57842
|
-
|
|
57843
|
-
|
|
57844
|
-
|
|
57845
|
-
|
|
57846
|
-
|
|
57981
|
+
`) : claudeRequest.system;
|
|
57982
|
+
systemContent = filterIdentity(systemContent);
|
|
57983
|
+
payload.systemInstruction = { parts: [{ text: systemContent }] };
|
|
57984
|
+
}
|
|
57985
|
+
const tools = this.convertToGeminiTools(claudeRequest);
|
|
57986
|
+
if (tools) {
|
|
57987
|
+
payload.tools = tools;
|
|
57988
|
+
}
|
|
57989
|
+
if (claudeRequest.thinking) {
|
|
57990
|
+
const { budget_tokens } = claudeRequest.thinking;
|
|
57991
|
+
if (this.parsed.model.includes("gemini-3")) {
|
|
57992
|
+
payload.generationConfig.thinkingConfig = {
|
|
57993
|
+
thinkingLevel: budget_tokens >= 16000 ? "high" : "low"
|
|
57994
|
+
};
|
|
57995
|
+
} else {
|
|
57996
|
+
const MAX_GEMINI_BUDGET = 24576;
|
|
57997
|
+
payload.generationConfig.thinkingConfig = {
|
|
57998
|
+
thinkingBudget: Math.min(budget_tokens, MAX_GEMINI_BUDGET)
|
|
57847
57999
|
};
|
|
57848
58000
|
}
|
|
57849
58001
|
}
|
|
58002
|
+
return payload;
|
|
57850
58003
|
}
|
|
57851
|
-
|
|
57852
|
-
|
|
57853
|
-
|
|
57854
|
-
|
|
57855
|
-
|
|
57856
|
-
|
|
57857
|
-
GEMINI_API_KEY: "export GEMINI_API_KEY='your-key' (get from https://aistudio.google.com/app/apikey)",
|
|
57858
|
-
OPENAI_API_KEY: "export OPENAI_API_KEY='sk-...' (get from https://platform.openai.com/api-keys)",
|
|
57859
|
-
OPENROUTER_API_KEY: "export OPENROUTER_API_KEY='sk-or-...' (get from https://openrouter.ai/keys)",
|
|
57860
|
-
MINIMAX_API_KEY: "export MINIMAX_API_KEY='your-key' (get from https://www.minimaxi.com/)",
|
|
57861
|
-
MOONSHOT_API_KEY: "export MOONSHOT_API_KEY='your-key' (get from https://platform.moonshot.cn/)",
|
|
57862
|
-
ZHIPU_API_KEY: "export ZHIPU_API_KEY='your-key' (get from https://open.bigmodel.cn/)"
|
|
58004
|
+
buildAnthropicPayload(claudeRequest) {
|
|
58005
|
+
const payload = {
|
|
58006
|
+
anthropic_version: "vertex-2023-10-16",
|
|
58007
|
+
messages: claudeRequest.messages,
|
|
58008
|
+
max_tokens: claudeRequest.max_tokens || 4096,
|
|
58009
|
+
stream: true
|
|
57863
58010
|
};
|
|
57864
|
-
|
|
57865
|
-
|
|
58011
|
+
if (claudeRequest.system) {
|
|
58012
|
+
payload.system = Array.isArray(claudeRequest.system) ? claudeRequest.system.map((i) => i.text || i).join(`
|
|
57866
58013
|
|
|
57867
|
-
|
|
57868
|
-
|
|
57869
|
-
|
|
58014
|
+
`) : claudeRequest.system;
|
|
58015
|
+
}
|
|
58016
|
+
if (claudeRequest.temperature !== undefined) {
|
|
58017
|
+
payload.temperature = claudeRequest.temperature;
|
|
58018
|
+
}
|
|
58019
|
+
if (claudeRequest.tools && claudeRequest.tools.length > 0) {
|
|
58020
|
+
payload.tools = claudeRequest.tools;
|
|
58021
|
+
}
|
|
58022
|
+
return payload;
|
|
58023
|
+
}
|
|
58024
|
+
buildOpenAIPayload(claudeRequest) {
|
|
58025
|
+
const messages = [];
|
|
58026
|
+
if (claudeRequest.system) {
|
|
58027
|
+
const systemContent = Array.isArray(claudeRequest.system) ? claudeRequest.system.map((i) => i.text || i).join(`
|
|
58028
|
+
|
|
58029
|
+
`) : claudeRequest.system;
|
|
58030
|
+
messages.push({ role: "system", content: filterIdentity(systemContent) });
|
|
58031
|
+
}
|
|
58032
|
+
if (claudeRequest.messages) {
|
|
58033
|
+
for (const msg of claudeRequest.messages) {
|
|
58034
|
+
if (msg.role === "user") {
|
|
58035
|
+
const content = this.convertClaudeContentToOpenAI(msg.content);
|
|
58036
|
+
messages.push({ role: "user", content });
|
|
58037
|
+
} else if (msg.role === "assistant") {
|
|
58038
|
+
const content = this.convertClaudeContentToOpenAI(msg.content);
|
|
58039
|
+
messages.push({ role: "assistant", content });
|
|
58040
|
+
}
|
|
58041
|
+
}
|
|
58042
|
+
}
|
|
58043
|
+
const modelId = this.parsed.publisher === "mistralai" ? this.parsed.model : `${this.parsed.publisher}/${this.parsed.model}`;
|
|
58044
|
+
const payload = {
|
|
58045
|
+
model: modelId,
|
|
58046
|
+
messages,
|
|
58047
|
+
max_tokens: claudeRequest.max_tokens || 4096,
|
|
58048
|
+
stream: true
|
|
58049
|
+
};
|
|
58050
|
+
if (claudeRequest.temperature !== undefined) {
|
|
58051
|
+
payload.temperature = claudeRequest.temperature;
|
|
58052
|
+
}
|
|
58053
|
+
if (claudeRequest.tools && claudeRequest.tools.length > 0) {
|
|
58054
|
+
payload.tools = claudeRequest.tools.map((tool) => ({
|
|
58055
|
+
type: "function",
|
|
58056
|
+
function: {
|
|
58057
|
+
name: tool.name,
|
|
58058
|
+
description: tool.description,
|
|
58059
|
+
parameters: tool.input_schema
|
|
58060
|
+
}
|
|
58061
|
+
}));
|
|
58062
|
+
}
|
|
58063
|
+
return payload;
|
|
58064
|
+
}
|
|
58065
|
+
convertClaudeContentToOpenAI(content) {
|
|
58066
|
+
if (typeof content === "string") {
|
|
58067
|
+
return content;
|
|
58068
|
+
}
|
|
58069
|
+
if (Array.isArray(content)) {
|
|
58070
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join(`
|
|
58071
|
+
`);
|
|
58072
|
+
}
|
|
58073
|
+
return "";
|
|
58074
|
+
}
|
|
58075
|
+
convertToGeminiMessages(claudeRequest) {
|
|
58076
|
+
const messages = [];
|
|
58077
|
+
if (claudeRequest.messages) {
|
|
58078
|
+
for (const msg of claudeRequest.messages) {
|
|
58079
|
+
if (msg.role === "user") {
|
|
58080
|
+
const parts = this.convertUserMessageParts(msg);
|
|
58081
|
+
if (parts.length > 0) {
|
|
58082
|
+
messages.push({ role: "user", parts });
|
|
58083
|
+
}
|
|
58084
|
+
} else if (msg.role === "assistant") {
|
|
58085
|
+
const parts = this.convertAssistantMessageParts(msg);
|
|
58086
|
+
if (parts.length > 0) {
|
|
58087
|
+
messages.push({ role: "model", parts });
|
|
58088
|
+
}
|
|
58089
|
+
}
|
|
58090
|
+
}
|
|
58091
|
+
}
|
|
58092
|
+
return messages;
|
|
58093
|
+
}
|
|
58094
|
+
convertUserMessageParts(msg) {
|
|
58095
|
+
const parts = [];
|
|
58096
|
+
if (Array.isArray(msg.content)) {
|
|
58097
|
+
for (const block of msg.content) {
|
|
58098
|
+
if (block.type === "text") {
|
|
58099
|
+
parts.push({ text: block.text });
|
|
58100
|
+
} else if (block.type === "image") {
|
|
58101
|
+
parts.push({
|
|
58102
|
+
inlineData: {
|
|
58103
|
+
mimeType: block.source.media_type,
|
|
58104
|
+
data: block.source.data
|
|
58105
|
+
}
|
|
58106
|
+
});
|
|
58107
|
+
} else if (block.type === "tool_result") {
|
|
58108
|
+
const toolInfo = this.toolCallMap.get(block.tool_use_id);
|
|
58109
|
+
if (toolInfo) {
|
|
58110
|
+
parts.push({
|
|
58111
|
+
functionResponse: {
|
|
58112
|
+
name: toolInfo.name,
|
|
58113
|
+
response: {
|
|
58114
|
+
content: typeof block.content === "string" ? block.content : JSON.stringify(block.content)
|
|
58115
|
+
}
|
|
58116
|
+
}
|
|
58117
|
+
});
|
|
58118
|
+
}
|
|
58119
|
+
}
|
|
58120
|
+
}
|
|
58121
|
+
} else if (typeof msg.content === "string") {
|
|
58122
|
+
parts.push({ text: msg.content });
|
|
58123
|
+
}
|
|
58124
|
+
return parts;
|
|
58125
|
+
}
|
|
58126
|
+
convertAssistantMessageParts(msg) {
|
|
58127
|
+
const parts = [];
|
|
58128
|
+
if (Array.isArray(msg.content)) {
|
|
58129
|
+
for (const block of msg.content) {
|
|
58130
|
+
if (block.type === "text") {
|
|
58131
|
+
parts.push({ text: block.text });
|
|
58132
|
+
} else if (block.type === "tool_use") {
|
|
58133
|
+
const toolInfo = this.toolCallMap.get(block.id);
|
|
58134
|
+
let thoughtSignature = toolInfo?.thoughtSignature || "skip_thought_signature_validator";
|
|
58135
|
+
const functionCallPart = {
|
|
58136
|
+
functionCall: {
|
|
58137
|
+
name: block.name,
|
|
58138
|
+
args: block.input
|
|
58139
|
+
}
|
|
58140
|
+
};
|
|
58141
|
+
if (thoughtSignature) {
|
|
58142
|
+
functionCallPart.thoughtSignature = thoughtSignature;
|
|
58143
|
+
}
|
|
58144
|
+
parts.push(functionCallPart);
|
|
58145
|
+
}
|
|
58146
|
+
}
|
|
58147
|
+
} else if (typeof msg.content === "string") {
|
|
58148
|
+
parts.push({ text: msg.content });
|
|
58149
|
+
}
|
|
58150
|
+
return parts;
|
|
58151
|
+
}
|
|
58152
|
+
convertToGeminiTools(claudeRequest) {
|
|
58153
|
+
if (!claudeRequest.tools || claudeRequest.tools.length === 0) {
|
|
58154
|
+
return;
|
|
58155
|
+
}
|
|
58156
|
+
const functionDeclarations = claudeRequest.tools.map((tool) => ({
|
|
58157
|
+
name: tool.name,
|
|
58158
|
+
description: tool.description,
|
|
58159
|
+
parameters: this.sanitizeSchemaForGemini(tool.input_schema)
|
|
58160
|
+
}));
|
|
58161
|
+
return [{ functionDeclarations }];
|
|
58162
|
+
}
|
|
58163
|
+
sanitizeSchemaForGemini(schema) {
|
|
58164
|
+
if (!schema || typeof schema !== "object")
|
|
58165
|
+
return schema;
|
|
58166
|
+
if (Array.isArray(schema))
|
|
58167
|
+
return schema.map((item) => this.sanitizeSchemaForGemini(item));
|
|
58168
|
+
const result = {};
|
|
58169
|
+
const normalizedType = Array.isArray(schema.type) ? schema.type.filter((t) => t !== "null")[0] || "string" : schema.type || "string";
|
|
58170
|
+
result.type = normalizedType;
|
|
58171
|
+
if (schema.description)
|
|
58172
|
+
result.description = schema.description;
|
|
58173
|
+
if (Array.isArray(schema.enum))
|
|
58174
|
+
result.enum = schema.enum;
|
|
58175
|
+
if (Array.isArray(schema.required))
|
|
58176
|
+
result.required = schema.required;
|
|
58177
|
+
if (schema.properties) {
|
|
58178
|
+
result.properties = {};
|
|
58179
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
58180
|
+
if (value && typeof value === "object") {
|
|
58181
|
+
result.properties[key] = this.sanitizeSchemaForGemini(value);
|
|
58182
|
+
}
|
|
58183
|
+
}
|
|
58184
|
+
}
|
|
58185
|
+
if (schema.items) {
|
|
58186
|
+
result.items = this.sanitizeSchemaForGemini(Array.isArray(schema.items) ? schema.items[0] : schema.items);
|
|
58187
|
+
}
|
|
58188
|
+
return result;
|
|
58189
|
+
}
|
|
58190
|
+
handleGeminiStreamingResponse(c, response) {
|
|
58191
|
+
let isClosed = false;
|
|
58192
|
+
let ping2 = null;
|
|
58193
|
+
const encoder = new TextEncoder;
|
|
58194
|
+
const decoder = new TextDecoder;
|
|
58195
|
+
const toolCallMap = this.toolCallMap;
|
|
58196
|
+
const modelName = this.modelName;
|
|
58197
|
+
return c.body(new ReadableStream({
|
|
58198
|
+
start: async (controller) => {
|
|
58199
|
+
const send = (e, d) => {
|
|
58200
|
+
if (!isClosed) {
|
|
58201
|
+
controller.enqueue(encoder.encode(`event: ${e}
|
|
58202
|
+
data: ${JSON.stringify(d)}
|
|
58203
|
+
|
|
58204
|
+
`));
|
|
58205
|
+
}
|
|
58206
|
+
};
|
|
58207
|
+
const msgId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
58208
|
+
let usage = null;
|
|
58209
|
+
let finalized = false;
|
|
58210
|
+
let textStarted = false;
|
|
58211
|
+
let textIdx = -1;
|
|
58212
|
+
let thinkingStarted = false;
|
|
58213
|
+
let thinkingIdx = -1;
|
|
58214
|
+
let curIdx = 0;
|
|
58215
|
+
const tools = new Map;
|
|
58216
|
+
let lastActivity = Date.now();
|
|
58217
|
+
send("message_start", {
|
|
58218
|
+
type: "message_start",
|
|
58219
|
+
message: {
|
|
58220
|
+
id: msgId,
|
|
58221
|
+
type: "message",
|
|
58222
|
+
role: "assistant",
|
|
58223
|
+
content: [],
|
|
58224
|
+
model: `vertex/${this.modelName}`,
|
|
58225
|
+
stop_reason: null,
|
|
58226
|
+
stop_sequence: null,
|
|
58227
|
+
usage: { input_tokens: 100, output_tokens: 1 }
|
|
58228
|
+
}
|
|
58229
|
+
});
|
|
58230
|
+
ping2 = setInterval(() => {
|
|
58231
|
+
if (!isClosed && Date.now() - lastActivity > 1000) {
|
|
58232
|
+
send("ping", { type: "ping" });
|
|
58233
|
+
}
|
|
58234
|
+
}, 1000);
|
|
58235
|
+
const finalize = async (reason, err) => {
|
|
58236
|
+
if (finalized)
|
|
58237
|
+
return;
|
|
58238
|
+
finalized = true;
|
|
58239
|
+
if (thinkingStarted)
|
|
58240
|
+
send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
|
|
58241
|
+
if (textStarted)
|
|
58242
|
+
send("content_block_stop", { type: "content_block_stop", index: textIdx });
|
|
58243
|
+
for (const t of Array.from(tools.values())) {
|
|
58244
|
+
if (t.started && !t.closed) {
|
|
58245
|
+
send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
|
|
58246
|
+
t.closed = true;
|
|
58247
|
+
}
|
|
58248
|
+
}
|
|
58249
|
+
if (usage) {
|
|
58250
|
+
this.updateTokenTracking(usage.promptTokenCount || 0, usage.candidatesTokenCount || 0);
|
|
58251
|
+
}
|
|
58252
|
+
if (reason === "error") {
|
|
58253
|
+
send("error", { type: "error", error: { type: "api_error", message: err } });
|
|
58254
|
+
} else {
|
|
58255
|
+
const hasToolCalls = tools.size > 0;
|
|
58256
|
+
send("message_delta", {
|
|
58257
|
+
type: "message_delta",
|
|
58258
|
+
delta: { stop_reason: hasToolCalls ? "tool_use" : "end_turn", stop_sequence: null },
|
|
58259
|
+
usage: { output_tokens: usage?.candidatesTokenCount || 0 }
|
|
58260
|
+
});
|
|
58261
|
+
send("message_stop", { type: "message_stop" });
|
|
58262
|
+
}
|
|
58263
|
+
if (!isClosed) {
|
|
58264
|
+
try {
|
|
58265
|
+
controller.enqueue(encoder.encode(`data: [DONE]
|
|
58266
|
+
|
|
58267
|
+
|
|
58268
|
+
`));
|
|
58269
|
+
} catch {}
|
|
58270
|
+
controller.close();
|
|
58271
|
+
isClosed = true;
|
|
58272
|
+
if (ping2)
|
|
58273
|
+
clearInterval(ping2);
|
|
58274
|
+
}
|
|
58275
|
+
};
|
|
58276
|
+
try {
|
|
58277
|
+
const reader = response.body.getReader();
|
|
58278
|
+
let buffer = "";
|
|
58279
|
+
while (true) {
|
|
58280
|
+
const { done, value } = await reader.read();
|
|
58281
|
+
if (done)
|
|
58282
|
+
break;
|
|
58283
|
+
buffer += decoder.decode(value, { stream: true });
|
|
58284
|
+
const lines = buffer.split(`
|
|
58285
|
+
`);
|
|
58286
|
+
buffer = lines.pop() || "";
|
|
58287
|
+
for (const line of lines) {
|
|
58288
|
+
if (!line.trim() || !line.startsWith("data: "))
|
|
58289
|
+
continue;
|
|
58290
|
+
const dataStr = line.slice(6);
|
|
58291
|
+
if (dataStr === "[DONE]") {
|
|
58292
|
+
await finalize("done");
|
|
58293
|
+
return;
|
|
58294
|
+
}
|
|
58295
|
+
try {
|
|
58296
|
+
const chunk = JSON.parse(dataStr);
|
|
58297
|
+
if (chunk.usageMetadata)
|
|
58298
|
+
usage = chunk.usageMetadata;
|
|
58299
|
+
const candidate = chunk.candidates?.[0];
|
|
58300
|
+
if (candidate?.content?.parts) {
|
|
58301
|
+
for (const part of candidate.content.parts) {
|
|
58302
|
+
lastActivity = Date.now();
|
|
58303
|
+
if (part.thought || part.thoughtText) {
|
|
58304
|
+
const thinkingContent = part.thought || part.thoughtText;
|
|
58305
|
+
if (!thinkingStarted) {
|
|
58306
|
+
thinkingIdx = curIdx++;
|
|
58307
|
+
send("content_block_start", {
|
|
58308
|
+
type: "content_block_start",
|
|
58309
|
+
index: thinkingIdx,
|
|
58310
|
+
content_block: { type: "thinking", thinking: "" }
|
|
58311
|
+
});
|
|
58312
|
+
thinkingStarted = true;
|
|
58313
|
+
}
|
|
58314
|
+
send("content_block_delta", {
|
|
58315
|
+
type: "content_block_delta",
|
|
58316
|
+
index: thinkingIdx,
|
|
58317
|
+
delta: { type: "thinking_delta", thinking: thinkingContent }
|
|
58318
|
+
});
|
|
58319
|
+
}
|
|
58320
|
+
if (part.text) {
|
|
58321
|
+
if (thinkingStarted) {
|
|
58322
|
+
send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
|
|
58323
|
+
thinkingStarted = false;
|
|
58324
|
+
}
|
|
58325
|
+
if (!textStarted) {
|
|
58326
|
+
textIdx = curIdx++;
|
|
58327
|
+
send("content_block_start", {
|
|
58328
|
+
type: "content_block_start",
|
|
58329
|
+
index: textIdx,
|
|
58330
|
+
content_block: { type: "text", text: "" }
|
|
58331
|
+
});
|
|
58332
|
+
textStarted = true;
|
|
58333
|
+
}
|
|
58334
|
+
send("content_block_delta", {
|
|
58335
|
+
type: "content_block_delta",
|
|
58336
|
+
index: textIdx,
|
|
58337
|
+
delta: { type: "text_delta", text: part.text }
|
|
58338
|
+
});
|
|
58339
|
+
}
|
|
58340
|
+
if (part.functionCall) {
|
|
58341
|
+
if (thinkingStarted) {
|
|
58342
|
+
send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
|
|
58343
|
+
thinkingStarted = false;
|
|
58344
|
+
}
|
|
58345
|
+
if (textStarted) {
|
|
58346
|
+
send("content_block_stop", { type: "content_block_stop", index: textIdx });
|
|
58347
|
+
textStarted = false;
|
|
58348
|
+
}
|
|
58349
|
+
const toolIdx = tools.size;
|
|
58350
|
+
const toolId = `tool_${Date.now()}_${toolIdx}`;
|
|
58351
|
+
const t = {
|
|
58352
|
+
id: toolId,
|
|
58353
|
+
name: part.functionCall.name,
|
|
58354
|
+
blockIndex: curIdx++,
|
|
58355
|
+
started: true,
|
|
58356
|
+
closed: false,
|
|
58357
|
+
arguments: JSON.stringify(part.functionCall.args || {})
|
|
58358
|
+
};
|
|
58359
|
+
tools.set(toolIdx, t);
|
|
58360
|
+
const thoughtSignature = part.thoughtSignature;
|
|
58361
|
+
toolCallMap.set(t.id, { name: t.name, thoughtSignature });
|
|
58362
|
+
send("content_block_start", {
|
|
58363
|
+
type: "content_block_start",
|
|
58364
|
+
index: t.blockIndex,
|
|
58365
|
+
content_block: { type: "tool_use", id: t.id, name: t.name }
|
|
58366
|
+
});
|
|
58367
|
+
send("content_block_delta", {
|
|
58368
|
+
type: "content_block_delta",
|
|
58369
|
+
index: t.blockIndex,
|
|
58370
|
+
delta: { type: "input_json_delta", partial_json: t.arguments }
|
|
58371
|
+
});
|
|
58372
|
+
send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
|
|
58373
|
+
t.closed = true;
|
|
58374
|
+
}
|
|
58375
|
+
}
|
|
58376
|
+
}
|
|
58377
|
+
if (candidate?.finishReason === "STOP" || candidate?.finishReason === "MAX_TOKENS") {
|
|
58378
|
+
await finalize("done");
|
|
58379
|
+
return;
|
|
58380
|
+
}
|
|
58381
|
+
} catch {}
|
|
58382
|
+
}
|
|
58383
|
+
}
|
|
58384
|
+
await finalize("unexpected");
|
|
58385
|
+
} catch (e) {
|
|
58386
|
+
await finalize("error", String(e));
|
|
58387
|
+
}
|
|
58388
|
+
},
|
|
58389
|
+
cancel() {
|
|
58390
|
+
isClosed = true;
|
|
58391
|
+
if (ping2)
|
|
58392
|
+
clearInterval(ping2);
|
|
58393
|
+
}
|
|
58394
|
+
}), {
|
|
58395
|
+
headers: {
|
|
58396
|
+
"Content-Type": "text/event-stream",
|
|
58397
|
+
"Cache-Control": "no-cache",
|
|
58398
|
+
Connection: "keep-alive"
|
|
58399
|
+
}
|
|
58400
|
+
});
|
|
58401
|
+
}
|
|
58402
|
+
handleAnthropicStreamingResponse(_c, response) {
|
|
58403
|
+
return new Response(response.body, {
|
|
58404
|
+
headers: {
|
|
58405
|
+
"Content-Type": "text/event-stream",
|
|
58406
|
+
"Cache-Control": "no-cache",
|
|
58407
|
+
Connection: "keep-alive"
|
|
58408
|
+
}
|
|
58409
|
+
});
|
|
58410
|
+
}
|
|
58411
|
+
handleOpenAIStreamingResponse(c, response) {
|
|
58412
|
+
let isClosed = false;
|
|
58413
|
+
let ping2 = null;
|
|
58414
|
+
const encoder = new TextEncoder;
|
|
58415
|
+
const decoder = new TextDecoder;
|
|
58416
|
+
return c.body(new ReadableStream({
|
|
58417
|
+
start: async (controller) => {
|
|
58418
|
+
const send = (e, d) => {
|
|
58419
|
+
if (!isClosed) {
|
|
58420
|
+
controller.enqueue(encoder.encode(`event: ${e}
|
|
58421
|
+
data: ${JSON.stringify(d)}
|
|
58422
|
+
|
|
58423
|
+
`));
|
|
58424
|
+
}
|
|
58425
|
+
};
|
|
58426
|
+
const msgId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
58427
|
+
let finalized = false;
|
|
58428
|
+
let textStarted = false;
|
|
58429
|
+
let textIdx = 0;
|
|
58430
|
+
let lastActivity = Date.now();
|
|
58431
|
+
send("message_start", {
|
|
58432
|
+
type: "message_start",
|
|
58433
|
+
message: {
|
|
58434
|
+
id: msgId,
|
|
58435
|
+
type: "message",
|
|
58436
|
+
role: "assistant",
|
|
58437
|
+
content: [],
|
|
58438
|
+
model: `vertex/${this.modelName}`,
|
|
58439
|
+
stop_reason: null,
|
|
58440
|
+
stop_sequence: null,
|
|
58441
|
+
usage: { input_tokens: 100, output_tokens: 1 }
|
|
58442
|
+
}
|
|
58443
|
+
});
|
|
58444
|
+
ping2 = setInterval(() => {
|
|
58445
|
+
if (!isClosed && Date.now() - lastActivity > 1000) {
|
|
58446
|
+
send("ping", { type: "ping" });
|
|
58447
|
+
}
|
|
58448
|
+
}, 1000);
|
|
58449
|
+
const finalize = async (reason, err) => {
|
|
58450
|
+
if (finalized)
|
|
58451
|
+
return;
|
|
58452
|
+
finalized = true;
|
|
58453
|
+
if (textStarted) {
|
|
58454
|
+
send("content_block_stop", { type: "content_block_stop", index: textIdx });
|
|
58455
|
+
}
|
|
58456
|
+
if (reason === "error") {
|
|
58457
|
+
send("error", { type: "error", error: { type: "api_error", message: err } });
|
|
58458
|
+
} else {
|
|
58459
|
+
send("message_delta", {
|
|
58460
|
+
type: "message_delta",
|
|
58461
|
+
delta: { stop_reason: "end_turn", stop_sequence: null },
|
|
58462
|
+
usage: { output_tokens: 100 }
|
|
58463
|
+
});
|
|
58464
|
+
send("message_stop", { type: "message_stop" });
|
|
58465
|
+
}
|
|
58466
|
+
if (!isClosed) {
|
|
58467
|
+
try {
|
|
58468
|
+
controller.enqueue(encoder.encode(`data: [DONE]
|
|
58469
|
+
|
|
58470
|
+
|
|
58471
|
+
`));
|
|
58472
|
+
} catch {}
|
|
58473
|
+
controller.close();
|
|
58474
|
+
isClosed = true;
|
|
58475
|
+
if (ping2)
|
|
58476
|
+
clearInterval(ping2);
|
|
58477
|
+
}
|
|
58478
|
+
};
|
|
58479
|
+
try {
|
|
58480
|
+
const reader = response.body.getReader();
|
|
58481
|
+
let buffer = "";
|
|
58482
|
+
while (true) {
|
|
58483
|
+
const { done, value } = await reader.read();
|
|
58484
|
+
if (done)
|
|
58485
|
+
break;
|
|
58486
|
+
buffer += decoder.decode(value, { stream: true });
|
|
58487
|
+
const lines = buffer.split(`
|
|
58488
|
+
`);
|
|
58489
|
+
buffer = lines.pop() || "";
|
|
58490
|
+
for (const line of lines) {
|
|
58491
|
+
if (!line.trim() || !line.startsWith("data: "))
|
|
58492
|
+
continue;
|
|
58493
|
+
const dataStr = line.slice(6);
|
|
58494
|
+
if (dataStr === "[DONE]") {
|
|
58495
|
+
await finalize("done");
|
|
58496
|
+
return;
|
|
58497
|
+
}
|
|
58498
|
+
try {
|
|
58499
|
+
const chunk = JSON.parse(dataStr);
|
|
58500
|
+
const choice = chunk.choices?.[0];
|
|
58501
|
+
if (choice?.delta?.content) {
|
|
58502
|
+
lastActivity = Date.now();
|
|
58503
|
+
if (!textStarted) {
|
|
58504
|
+
send("content_block_start", {
|
|
58505
|
+
type: "content_block_start",
|
|
58506
|
+
index: textIdx,
|
|
58507
|
+
content_block: { type: "text", text: "" }
|
|
58508
|
+
});
|
|
58509
|
+
textStarted = true;
|
|
58510
|
+
}
|
|
58511
|
+
send("content_block_delta", {
|
|
58512
|
+
type: "content_block_delta",
|
|
58513
|
+
index: textIdx,
|
|
58514
|
+
delta: { type: "text_delta", text: choice.delta.content }
|
|
58515
|
+
});
|
|
58516
|
+
}
|
|
58517
|
+
if (choice?.finish_reason) {
|
|
58518
|
+
await finalize("done");
|
|
58519
|
+
return;
|
|
58520
|
+
}
|
|
58521
|
+
} catch {}
|
|
58522
|
+
}
|
|
58523
|
+
}
|
|
58524
|
+
await finalize("done");
|
|
58525
|
+
} catch (e) {
|
|
58526
|
+
await finalize("error", String(e));
|
|
58527
|
+
}
|
|
58528
|
+
},
|
|
58529
|
+
cancel() {
|
|
58530
|
+
isClosed = true;
|
|
58531
|
+
if (ping2)
|
|
58532
|
+
clearInterval(ping2);
|
|
58533
|
+
}
|
|
58534
|
+
}), {
|
|
58535
|
+
headers: {
|
|
58536
|
+
"Content-Type": "text/event-stream",
|
|
58537
|
+
"Cache-Control": "no-cache",
|
|
58538
|
+
Connection: "keep-alive"
|
|
58539
|
+
}
|
|
58540
|
+
});
|
|
58541
|
+
}
|
|
58542
|
+
async handle(c, payload) {
|
|
58543
|
+
const { claudeRequest, droppedParams } = transformOpenAIToClaude(payload);
|
|
58544
|
+
logStructured("Vertex OAuth Request", {
|
|
58545
|
+
targetModel: `vertex/${this.modelName}`,
|
|
58546
|
+
publisher: this.parsed.publisher,
|
|
58547
|
+
model: this.parsed.model,
|
|
58548
|
+
project: this.config.projectId,
|
|
58549
|
+
location: this.config.location,
|
|
58550
|
+
messageCount: claudeRequest.messages?.length || 0,
|
|
58551
|
+
toolCount: claudeRequest.tools?.length || 0
|
|
58552
|
+
});
|
|
58553
|
+
const authManager = getVertexAuthManager();
|
|
58554
|
+
let accessToken;
|
|
58555
|
+
try {
|
|
58556
|
+
accessToken = await authManager.getAccessToken();
|
|
58557
|
+
} catch (e) {
|
|
58558
|
+
log(`[VertexOAuth] Auth failed: ${e.message}`);
|
|
58559
|
+
return c.json({
|
|
58560
|
+
error: {
|
|
58561
|
+
type: "authentication_error",
|
|
58562
|
+
message: e.message
|
|
58563
|
+
}
|
|
58564
|
+
}, 401);
|
|
58565
|
+
}
|
|
58566
|
+
const requestPayload = this.buildPayload(claudeRequest);
|
|
58567
|
+
const endpoint = this.getApiEndpoint();
|
|
58568
|
+
log(`[VertexOAuth] Calling API: ${endpoint}`);
|
|
58569
|
+
const controller = new AbortController;
|
|
58570
|
+
const timeoutId = setTimeout(() => controller.abort(), 30000);
|
|
58571
|
+
let response;
|
|
58572
|
+
try {
|
|
58573
|
+
response = await fetch(endpoint, {
|
|
58574
|
+
method: "POST",
|
|
58575
|
+
headers: {
|
|
58576
|
+
"Content-Type": "application/json",
|
|
58577
|
+
Authorization: `Bearer ${accessToken}`
|
|
58578
|
+
},
|
|
58579
|
+
body: JSON.stringify(requestPayload),
|
|
58580
|
+
signal: controller.signal
|
|
58581
|
+
});
|
|
58582
|
+
} catch (fetchError) {
|
|
58583
|
+
clearTimeout(timeoutId);
|
|
58584
|
+
if (fetchError.name === "AbortError") {
|
|
58585
|
+
return c.json({ error: { type: "timeout_error", message: "Request timed out" } }, 504);
|
|
58586
|
+
}
|
|
58587
|
+
return c.json({ error: { type: "network_error", message: fetchError.message } }, 503);
|
|
58588
|
+
} finally {
|
|
58589
|
+
clearTimeout(timeoutId);
|
|
58590
|
+
}
|
|
58591
|
+
log(`[VertexOAuth] Response status: ${response.status}`);
|
|
58592
|
+
if (response.status === 401) {
|
|
58593
|
+
log("[VertexOAuth] Got 401, refreshing token and retrying");
|
|
58594
|
+
await authManager.refreshToken();
|
|
58595
|
+
const newToken = await authManager.getAccessToken();
|
|
58596
|
+
response = await fetch(endpoint, {
|
|
58597
|
+
method: "POST",
|
|
58598
|
+
headers: {
|
|
58599
|
+
"Content-Type": "application/json",
|
|
58600
|
+
Authorization: `Bearer ${newToken}`
|
|
58601
|
+
},
|
|
58602
|
+
body: JSON.stringify(requestPayload)
|
|
58603
|
+
});
|
|
58604
|
+
if (!response.ok) {
|
|
58605
|
+
const errorText = await response.text();
|
|
58606
|
+
return c.json({ error: errorText }, response.status);
|
|
58607
|
+
}
|
|
58608
|
+
}
|
|
58609
|
+
if (!response.ok) {
|
|
58610
|
+
const errorText = await response.text();
|
|
58611
|
+
log(`[VertexOAuth] Error: ${errorText}`);
|
|
58612
|
+
return c.json({ error: errorText }, response.status);
|
|
58613
|
+
}
|
|
58614
|
+
if (droppedParams.length > 0) {
|
|
58615
|
+
c.header("X-Dropped-Params", droppedParams.join(", "));
|
|
58616
|
+
}
|
|
58617
|
+
if (this.parsed.publisher === "google") {
|
|
58618
|
+
return this.handleGeminiStreamingResponse(c, response);
|
|
58619
|
+
} else if (this.parsed.publisher === "anthropic") {
|
|
58620
|
+
return this.handleAnthropicStreamingResponse(c, response);
|
|
58621
|
+
} else {
|
|
58622
|
+
return this.handleOpenAIStreamingResponse(c, response);
|
|
58623
|
+
}
|
|
58624
|
+
}
|
|
58625
|
+
async shutdown() {}
|
|
58626
|
+
}
|
|
58627
|
+
var init_vertex_oauth_handler = __esm(() => {
|
|
58628
|
+
init_adapter_manager();
|
|
58629
|
+
init_middleware();
|
|
58630
|
+
init_transform();
|
|
58631
|
+
init_logger();
|
|
58632
|
+
init_openai_compat();
|
|
58633
|
+
init_remote_provider_types();
|
|
58634
|
+
init_vertex_auth();
|
|
58635
|
+
});
|
|
58636
|
+
|
|
58637
|
+
// ../core/dist/providers/provider-registry.js
|
|
58638
|
+
function getRegisteredProviders() {
|
|
58639
|
+
return getProviders();
|
|
58640
|
+
}
|
|
58641
|
+
function resolveProvider(modelId) {
|
|
58642
|
+
const providers = getProviders();
|
|
58643
|
+
for (const provider of providers) {
|
|
58644
|
+
for (const prefix of provider.prefixes) {
|
|
58645
|
+
if (modelId.startsWith(prefix)) {
|
|
58646
|
+
return {
|
|
58647
|
+
provider,
|
|
58648
|
+
modelName: modelId.slice(prefix.length)
|
|
58649
|
+
};
|
|
58650
|
+
}
|
|
58651
|
+
}
|
|
58652
|
+
}
|
|
58653
|
+
return null;
|
|
58654
|
+
}
|
|
58655
|
+
function isLocalProvider(modelId) {
|
|
58656
|
+
if (resolveProvider(modelId) !== null) {
|
|
58657
|
+
return true;
|
|
58658
|
+
}
|
|
58659
|
+
if (parseUrlModel(modelId) !== null) {
|
|
58660
|
+
return true;
|
|
58661
|
+
}
|
|
58662
|
+
return false;
|
|
58663
|
+
}
|
|
58664
|
+
function parseUrlModel(modelId) {
|
|
58665
|
+
if (!modelId.startsWith("http://") && !modelId.startsWith("https://")) {
|
|
58666
|
+
return null;
|
|
58667
|
+
}
|
|
58668
|
+
try {
|
|
58669
|
+
const url2 = new URL(modelId);
|
|
58670
|
+
const pathParts = url2.pathname.split("/").filter(Boolean);
|
|
58671
|
+
if (pathParts.length === 0) {
|
|
58672
|
+
return null;
|
|
58673
|
+
}
|
|
58674
|
+
const modelName = pathParts[pathParts.length - 1];
|
|
58675
|
+
let basePath = "";
|
|
58676
|
+
if (pathParts.length > 1) {
|
|
58677
|
+
const prefix = pathParts.slice(0, -1).join("/");
|
|
58678
|
+
if (prefix)
|
|
58679
|
+
basePath = "/" + prefix;
|
|
58680
|
+
}
|
|
58681
|
+
const baseUrl = `${url2.protocol}//${url2.host}${basePath}`;
|
|
58682
|
+
return {
|
|
58683
|
+
baseUrl,
|
|
58684
|
+
modelName
|
|
58685
|
+
};
|
|
58686
|
+
} catch {
|
|
58687
|
+
return null;
|
|
58688
|
+
}
|
|
58689
|
+
}
|
|
58690
|
+
function createUrlProvider(parsed) {
|
|
58691
|
+
return {
|
|
58692
|
+
name: "custom-url",
|
|
58693
|
+
baseUrl: parsed.baseUrl,
|
|
58694
|
+
apiPath: "/v1/chat/completions",
|
|
58695
|
+
envVar: "",
|
|
58696
|
+
prefixes: [],
|
|
58697
|
+
capabilities: {
|
|
58698
|
+
supportsTools: true,
|
|
58699
|
+
supportsVision: false,
|
|
58700
|
+
supportsStreaming: true,
|
|
58701
|
+
supportsJsonMode: true
|
|
58702
|
+
}
|
|
58703
|
+
};
|
|
58704
|
+
}
|
|
58705
|
+
var getProviders = () => [
|
|
58706
|
+
{
|
|
58707
|
+
name: "ollama",
|
|
58708
|
+
baseUrl: process.env.OLLAMA_HOST || process.env.OLLAMA_BASE_URL || "http://localhost:11434",
|
|
58709
|
+
apiPath: "/v1/chat/completions",
|
|
58710
|
+
envVar: "OLLAMA_BASE_URL",
|
|
58711
|
+
prefixes: ["ollama/", "ollama:"],
|
|
58712
|
+
capabilities: {
|
|
58713
|
+
supportsTools: true,
|
|
58714
|
+
supportsVision: false,
|
|
58715
|
+
supportsStreaming: true,
|
|
58716
|
+
supportsJsonMode: true
|
|
58717
|
+
}
|
|
58718
|
+
},
|
|
58719
|
+
{
|
|
58720
|
+
name: "lmstudio",
|
|
58721
|
+
baseUrl: process.env.LMSTUDIO_BASE_URL || "http://localhost:1234",
|
|
58722
|
+
apiPath: "/v1/chat/completions",
|
|
58723
|
+
envVar: "LMSTUDIO_BASE_URL",
|
|
58724
|
+
prefixes: ["lmstudio/", "lmstudio:", "mlstudio/", "mlstudio:"],
|
|
58725
|
+
capabilities: {
|
|
58726
|
+
supportsTools: true,
|
|
58727
|
+
supportsVision: false,
|
|
58728
|
+
supportsStreaming: true,
|
|
58729
|
+
supportsJsonMode: true
|
|
58730
|
+
}
|
|
58731
|
+
},
|
|
58732
|
+
{
|
|
58733
|
+
name: "vllm",
|
|
58734
|
+
baseUrl: process.env.VLLM_BASE_URL || "http://localhost:8000",
|
|
58735
|
+
apiPath: "/v1/chat/completions",
|
|
58736
|
+
envVar: "VLLM_BASE_URL",
|
|
58737
|
+
prefixes: ["vllm/", "vllm:"],
|
|
58738
|
+
capabilities: {
|
|
58739
|
+
supportsTools: true,
|
|
58740
|
+
supportsVision: false,
|
|
58741
|
+
supportsStreaming: true,
|
|
58742
|
+
supportsJsonMode: true
|
|
58743
|
+
}
|
|
58744
|
+
},
|
|
58745
|
+
{
|
|
58746
|
+
name: "mlx",
|
|
58747
|
+
baseUrl: process.env.MLX_BASE_URL || "http://127.0.0.1:8080",
|
|
58748
|
+
apiPath: "/v1/chat/completions",
|
|
58749
|
+
envVar: "MLX_BASE_URL",
|
|
58750
|
+
prefixes: ["mlx/", "mlx:"],
|
|
58751
|
+
capabilities: {
|
|
58752
|
+
supportsTools: true,
|
|
58753
|
+
supportsVision: false,
|
|
58754
|
+
supportsStreaming: true,
|
|
58755
|
+
supportsJsonMode: true
|
|
58756
|
+
}
|
|
58757
|
+
}
|
|
58758
|
+
];
|
|
58759
|
+
|
|
58760
|
+
// ../core/dist/providers/remote-provider-registry.js
|
|
58761
|
+
function resolveRemoteProvider(modelId) {
|
|
58762
|
+
const providers = getRemoteProviders();
|
|
58763
|
+
for (const provider of providers) {
|
|
58764
|
+
for (const prefix of provider.prefixes) {
|
|
58765
|
+
if (modelId.startsWith(prefix)) {
|
|
58766
|
+
return {
|
|
58767
|
+
provider,
|
|
58768
|
+
modelName: modelId.slice(prefix.length)
|
|
58769
|
+
};
|
|
58770
|
+
}
|
|
58771
|
+
}
|
|
58772
|
+
}
|
|
58773
|
+
return null;
|
|
58774
|
+
}
|
|
58775
|
+
function validateRemoteProviderApiKey(provider) {
|
|
58776
|
+
const apiKey = process.env[provider.apiKeyEnvVar];
|
|
58777
|
+
if (!apiKey) {
|
|
58778
|
+
const examples = {
|
|
58779
|
+
GEMINI_API_KEY: "export GEMINI_API_KEY='your-key' (get from https://aistudio.google.com/app/apikey)",
|
|
58780
|
+
VERTEX_API_KEY: "export VERTEX_API_KEY='your-key' (get from Google Cloud Console)",
|
|
58781
|
+
OPENAI_API_KEY: "export OPENAI_API_KEY='sk-...' (get from https://platform.openai.com/api-keys)",
|
|
58782
|
+
OPENROUTER_API_KEY: "export OPENROUTER_API_KEY='sk-or-...' (get from https://openrouter.ai/keys)",
|
|
58783
|
+
MINIMAX_API_KEY: "export MINIMAX_API_KEY='your-key' (get from https://www.minimaxi.com/)",
|
|
58784
|
+
MOONSHOT_API_KEY: "export MOONSHOT_API_KEY='your-key' (get from https://platform.moonshot.cn/)",
|
|
58785
|
+
ZHIPU_API_KEY: "export ZHIPU_API_KEY='your-key' (get from https://open.bigmodel.cn/)"
|
|
58786
|
+
};
|
|
58787
|
+
const example = examples[provider.apiKeyEnvVar] || `export ${provider.apiKeyEnvVar}='your-key'`;
|
|
58788
|
+
return `Missing ${provider.apiKeyEnvVar} environment variable.
|
|
58789
|
+
|
|
58790
|
+
Set it with:
|
|
58791
|
+
${example}`;
|
|
58792
|
+
}
|
|
57870
58793
|
return null;
|
|
57871
58794
|
}
|
|
57872
58795
|
function getRegisteredRemoteProviders() {
|
|
@@ -57887,6 +58810,20 @@ var getRemoteProviders = () => [
|
|
|
57887
58810
|
supportsReasoning: true
|
|
57888
58811
|
}
|
|
57889
58812
|
},
|
|
58813
|
+
{
|
|
58814
|
+
name: "vertex",
|
|
58815
|
+
baseUrl: process.env.VERTEX_BASE_URL || "https://aiplatform.googleapis.com",
|
|
58816
|
+
apiPath: "/v1/publishers/google/models/{model}:streamGenerateContent?alt=sse",
|
|
58817
|
+
apiKeyEnvVar: "VERTEX_API_KEY",
|
|
58818
|
+
prefixes: ["vertex/", "v/"],
|
|
58819
|
+
capabilities: {
|
|
58820
|
+
supportsTools: true,
|
|
58821
|
+
supportsVision: true,
|
|
58822
|
+
supportsStreaming: true,
|
|
58823
|
+
supportsJsonMode: false,
|
|
58824
|
+
supportsReasoning: true
|
|
58825
|
+
}
|
|
58826
|
+
},
|
|
57890
58827
|
{
|
|
57891
58828
|
name: "openai",
|
|
57892
58829
|
baseUrl: process.env.OPENAI_BASE_URL || "https://api.openai.com",
|
|
@@ -58010,6 +58947,29 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
|
|
|
58010
58947
|
if (resolved.provider.name === "openrouter") {
|
|
58011
58948
|
return null;
|
|
58012
58949
|
}
|
|
58950
|
+
if (resolved.provider.name === "vertex") {
|
|
58951
|
+
const hasApiKey = !!process.env.VERTEX_API_KEY;
|
|
58952
|
+
const vertexConfig = getVertexConfig();
|
|
58953
|
+
let handler2;
|
|
58954
|
+
if (hasApiKey) {
|
|
58955
|
+
const apiKey2 = process.env.VERTEX_API_KEY;
|
|
58956
|
+
handler2 = new GeminiHandler(resolved.provider, resolved.modelName, apiKey2, port);
|
|
58957
|
+
log(`[Proxy] Created Vertex AI Express handler: ${resolved.modelName}`);
|
|
58958
|
+
} else if (vertexConfig) {
|
|
58959
|
+
const oauthError = validateVertexOAuthConfig();
|
|
58960
|
+
if (oauthError) {
|
|
58961
|
+
log(`[Proxy] Vertex OAuth config error: ${oauthError}`);
|
|
58962
|
+
return null;
|
|
58963
|
+
}
|
|
58964
|
+
handler2 = new VertexOAuthHandler(resolved.modelName, port);
|
|
58965
|
+
log(`[Proxy] Created Vertex AI OAuth handler: ${resolved.modelName} (project: ${vertexConfig.projectId})`);
|
|
58966
|
+
} else {
|
|
58967
|
+
log(`[Proxy] Vertex AI requires either VERTEX_API_KEY or VERTEX_PROJECT`);
|
|
58968
|
+
return null;
|
|
58969
|
+
}
|
|
58970
|
+
remoteProviderHandlers.set(targetModel, handler2);
|
|
58971
|
+
return handler2;
|
|
58972
|
+
}
|
|
58013
58973
|
const apiKeyError = validateRemoteProviderApiKey(resolved.provider);
|
|
58014
58974
|
if (apiKeyError) {
|
|
58015
58975
|
throw new Error(apiKeyError);
|
|
@@ -58125,6 +59085,8 @@ var init_proxy_server = __esm(() => {
|
|
|
58125
59085
|
init_gemini_handler();
|
|
58126
59086
|
init_openai_handler();
|
|
58127
59087
|
init_anthropic_compat_handler();
|
|
59088
|
+
init_vertex_oauth_handler();
|
|
59089
|
+
init_vertex_auth();
|
|
58128
59090
|
});
|
|
58129
59091
|
|
|
58130
59092
|
// ../core/dist/index.js
|
|
@@ -58177,15 +59139,15 @@ var init_dist11 = __esm(() => {
|
|
|
58177
59139
|
});
|
|
58178
59140
|
|
|
58179
59141
|
// src/model-loader.ts
|
|
58180
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
58181
|
-
import { join as
|
|
59142
|
+
import { readFileSync as readFileSync5, existsSync as existsSync7 } from "node:fs";
|
|
59143
|
+
import { join as join13, dirname as dirname4 } from "node:path";
|
|
58182
59144
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
58183
59145
|
function loadModelInfo2() {
|
|
58184
59146
|
if (_cachedModelInfo2) {
|
|
58185
59147
|
return _cachedModelInfo2;
|
|
58186
59148
|
}
|
|
58187
|
-
const jsonPath =
|
|
58188
|
-
if (
|
|
59149
|
+
const jsonPath = join13(__dirname5, "../recommended-models.json");
|
|
59150
|
+
if (existsSync7(jsonPath)) {
|
|
58189
59151
|
try {
|
|
58190
59152
|
const jsonContent = readFileSync5(jsonPath, "utf-8");
|
|
58191
59153
|
const data = JSON.parse(jsonContent);
|
|
@@ -58217,8 +59179,8 @@ function getAvailableModels() {
|
|
|
58217
59179
|
if (_cachedModelIds) {
|
|
58218
59180
|
return _cachedModelIds;
|
|
58219
59181
|
}
|
|
58220
|
-
const jsonPath =
|
|
58221
|
-
if (
|
|
59182
|
+
const jsonPath = join13(__dirname5, "../recommended-models.json");
|
|
59183
|
+
if (existsSync7(jsonPath)) {
|
|
58222
59184
|
try {
|
|
58223
59185
|
const jsonContent = readFileSync5(jsonPath, "utf-8");
|
|
58224
59186
|
const data = JSON.parse(jsonContent);
|
|
@@ -58280,9 +59242,9 @@ __export(exports_cli, {
|
|
|
58280
59242
|
parseArgs: () => parseArgs,
|
|
58281
59243
|
getVersion: () => getVersion
|
|
58282
59244
|
});
|
|
58283
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
59245
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync11, existsSync as existsSync8, mkdirSync as mkdirSync9, copyFileSync } from "node:fs";
|
|
58284
59246
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
58285
|
-
import { dirname as dirname5, join as
|
|
59247
|
+
import { dirname as dirname5, join as join14 } from "node:path";
|
|
58286
59248
|
function getVersion() {
|
|
58287
59249
|
return VERSION;
|
|
58288
59250
|
}
|
|
@@ -58555,7 +59517,7 @@ async function fetchOllamaModels() {
|
|
|
58555
59517
|
}
|
|
58556
59518
|
async function searchAndPrintModels(query, forceUpdate) {
|
|
58557
59519
|
let models = [];
|
|
58558
|
-
if (!forceUpdate &&
|
|
59520
|
+
if (!forceUpdate && existsSync8(ALL_MODELS_JSON_PATH2)) {
|
|
58559
59521
|
try {
|
|
58560
59522
|
const cacheData = JSON.parse(readFileSync6(ALL_MODELS_JSON_PATH2, "utf-8"));
|
|
58561
59523
|
const lastUpdated = new Date(cacheData.lastUpdated);
|
|
@@ -58574,7 +59536,7 @@ async function searchAndPrintModels(query, forceUpdate) {
|
|
|
58574
59536
|
throw new Error(`API returned ${response.status}`);
|
|
58575
59537
|
const data = await response.json();
|
|
58576
59538
|
models = data.data;
|
|
58577
|
-
|
|
59539
|
+
writeFileSync11(ALL_MODELS_JSON_PATH2, JSON.stringify({
|
|
58578
59540
|
lastUpdated: new Date().toISOString(),
|
|
58579
59541
|
models
|
|
58580
59542
|
}), "utf-8");
|
|
@@ -58653,7 +59615,7 @@ Found ${results.length} matching models:
|
|
|
58653
59615
|
async function printAllModels(jsonOutput, forceUpdate) {
|
|
58654
59616
|
let models = [];
|
|
58655
59617
|
const ollamaModels = await fetchOllamaModels();
|
|
58656
|
-
if (!forceUpdate &&
|
|
59618
|
+
if (!forceUpdate && existsSync8(ALL_MODELS_JSON_PATH2)) {
|
|
58657
59619
|
try {
|
|
58658
59620
|
const cacheData = JSON.parse(readFileSync6(ALL_MODELS_JSON_PATH2, "utf-8"));
|
|
58659
59621
|
const lastUpdated = new Date(cacheData.lastUpdated);
|
|
@@ -58675,7 +59637,7 @@ async function printAllModels(jsonOutput, forceUpdate) {
|
|
|
58675
59637
|
throw new Error(`API returned ${response.status}`);
|
|
58676
59638
|
const data = await response.json();
|
|
58677
59639
|
models = data.data;
|
|
58678
|
-
|
|
59640
|
+
writeFileSync11(ALL_MODELS_JSON_PATH2, JSON.stringify({
|
|
58679
59641
|
lastUpdated: new Date().toISOString(),
|
|
58680
59642
|
models
|
|
58681
59643
|
}), "utf-8");
|
|
@@ -58785,7 +59747,7 @@ async function printAllModels(jsonOutput, forceUpdate) {
|
|
|
58785
59747
|
console.log("Top models: claudish --top-models");
|
|
58786
59748
|
}
|
|
58787
59749
|
function isCacheStale() {
|
|
58788
|
-
if (!
|
|
59750
|
+
if (!existsSync8(MODELS_JSON_PATH)) {
|
|
58789
59751
|
return true;
|
|
58790
59752
|
}
|
|
58791
59753
|
try {
|
|
@@ -58884,7 +59846,7 @@ async function updateModelsFromOpenRouter() {
|
|
|
58884
59846
|
providers.add(provider);
|
|
58885
59847
|
}
|
|
58886
59848
|
let version2 = "1.1.5";
|
|
58887
|
-
if (
|
|
59849
|
+
if (existsSync8(MODELS_JSON_PATH)) {
|
|
58888
59850
|
try {
|
|
58889
59851
|
const existing = JSON.parse(readFileSync6(MODELS_JSON_PATH, "utf-8"));
|
|
58890
59852
|
version2 = existing.version || version2;
|
|
@@ -58896,7 +59858,7 @@ async function updateModelsFromOpenRouter() {
|
|
|
58896
59858
|
source: "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
|
|
58897
59859
|
models: recommendations
|
|
58898
59860
|
};
|
|
58899
|
-
|
|
59861
|
+
writeFileSync11(MODELS_JSON_PATH, JSON.stringify(updatedData, null, 2), "utf-8");
|
|
58900
59862
|
console.error(`✅ Updated ${recommendations.length} models (last updated: ${updatedData.lastUpdated})`);
|
|
58901
59863
|
} catch (error46) {
|
|
58902
59864
|
console.error(`❌ Failed to update models: ${error46 instanceof Error ? error46.message : String(error46)}`);
|
|
@@ -58933,6 +59895,7 @@ USAGE:
|
|
|
58933
59895
|
MODEL ROUTING (prefix-based):
|
|
58934
59896
|
(no prefix) OpenRouter (default) claudish --model openai/gpt-5.2 "task"
|
|
58935
59897
|
g/, gemini/ Google Gemini API claudish --model g/gemini-2.0-flash "task"
|
|
59898
|
+
v/, vertex/ Vertex AI (OAuth) claudish --model v/gemini-2.5-flash "task"
|
|
58936
59899
|
oai/ OpenAI Direct API claudish --model oai/gpt-4o "task"
|
|
58937
59900
|
mmax/, mm/ MiniMax Direct API claudish --model mmax/MiniMax-M2.1 "task"
|
|
58938
59901
|
kimi/, moonshot/ Kimi Direct API claudish --model kimi/kimi-k2-thinking-turbo "task"
|
|
@@ -59009,6 +59972,9 @@ ENVIRONMENT VARIABLES:
|
|
|
59009
59972
|
API Keys (at least one required for cloud models):
|
|
59010
59973
|
OPENROUTER_API_KEY OpenRouter API key (default backend)
|
|
59011
59974
|
GEMINI_API_KEY Google Gemini API key (for g/ prefix)
|
|
59975
|
+
VERTEX_API_KEY Vertex AI Express API key (for v/ prefix)
|
|
59976
|
+
VERTEX_PROJECT Vertex AI project ID (OAuth mode, for v/ prefix)
|
|
59977
|
+
VERTEX_LOCATION Vertex AI region (default: us-central1)
|
|
59012
59978
|
OPENAI_API_KEY OpenAI API key (for oai/ prefix)
|
|
59013
59979
|
MINIMAX_API_KEY MiniMax API key (for mmax/, mm/ prefix)
|
|
59014
59980
|
MOONSHOT_API_KEY Kimi/Moonshot API key (for kimi/, moonshot/ prefix)
|
|
@@ -59060,6 +60026,15 @@ EXAMPLES:
|
|
|
59060
60026
|
claudish --model g/gemini-2.0-flash "quick fix"
|
|
59061
60027
|
claudish --model gemini/gemini-2.5-pro "complex analysis"
|
|
59062
60028
|
|
|
60029
|
+
# Vertex AI (Google Cloud - supports Google + partner models)
|
|
60030
|
+
# Express mode (API key):
|
|
60031
|
+
VERTEX_API_KEY=... claudish --model v/gemini-2.5-flash "task"
|
|
60032
|
+
# OAuth mode (gcloud auth):
|
|
60033
|
+
VERTEX_PROJECT=my-project claudish --model v/gemini-2.5-flash "task"
|
|
60034
|
+
# Partner models (MiniMax, Mistral on Vertex):
|
|
60035
|
+
claudish --model vertex/minimaxai/minimax-m2-maas "task"
|
|
60036
|
+
claudish --model vertex/mistralai/codestral-2 "write code"
|
|
60037
|
+
|
|
59063
60038
|
# Direct OpenAI API
|
|
59064
60039
|
claudish --model oai/gpt-4o "implement feature"
|
|
59065
60040
|
claudish --model oai/o1 "complex reasoning"
|
|
@@ -59142,7 +60117,7 @@ MORE INFO:
|
|
|
59142
60117
|
}
|
|
59143
60118
|
function printAIAgentGuide() {
|
|
59144
60119
|
try {
|
|
59145
|
-
const guidePath =
|
|
60120
|
+
const guidePath = join14(__dirname6, "../AI_AGENT_GUIDE.md");
|
|
59146
60121
|
const guideContent = readFileSync6(guidePath, "utf-8");
|
|
59147
60122
|
console.log(guideContent);
|
|
59148
60123
|
} catch (error46) {
|
|
@@ -59159,19 +60134,19 @@ async function initializeClaudishSkill() {
|
|
|
59159
60134
|
console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
|
|
59160
60135
|
`);
|
|
59161
60136
|
const cwd = process.cwd();
|
|
59162
|
-
const claudeDir =
|
|
59163
|
-
const skillsDir =
|
|
59164
|
-
const claudishSkillDir =
|
|
59165
|
-
const skillFile =
|
|
59166
|
-
if (
|
|
60137
|
+
const claudeDir = join14(cwd, ".claude");
|
|
60138
|
+
const skillsDir = join14(claudeDir, "skills");
|
|
60139
|
+
const claudishSkillDir = join14(skillsDir, "claudish-usage");
|
|
60140
|
+
const skillFile = join14(claudishSkillDir, "SKILL.md");
|
|
60141
|
+
if (existsSync8(skillFile)) {
|
|
59167
60142
|
console.log("✅ Claudish skill already installed at:");
|
|
59168
60143
|
console.log(` ${skillFile}
|
|
59169
60144
|
`);
|
|
59170
60145
|
console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
|
|
59171
60146
|
return;
|
|
59172
60147
|
}
|
|
59173
|
-
const sourceSkillPath =
|
|
59174
|
-
if (!
|
|
60148
|
+
const sourceSkillPath = join14(__dirname6, "../skills/claudish-usage/SKILL.md");
|
|
60149
|
+
if (!existsSync8(sourceSkillPath)) {
|
|
59175
60150
|
console.error("❌ Error: Claudish skill file not found in installation.");
|
|
59176
60151
|
console.error(` Expected at: ${sourceSkillPath}`);
|
|
59177
60152
|
console.error(`
|
|
@@ -59180,16 +60155,16 @@ async function initializeClaudishSkill() {
|
|
|
59180
60155
|
process.exit(1);
|
|
59181
60156
|
}
|
|
59182
60157
|
try {
|
|
59183
|
-
if (!
|
|
59184
|
-
|
|
60158
|
+
if (!existsSync8(claudeDir)) {
|
|
60159
|
+
mkdirSync9(claudeDir, { recursive: true });
|
|
59185
60160
|
console.log("\uD83D\uDCC1 Created .claude/ directory");
|
|
59186
60161
|
}
|
|
59187
|
-
if (!
|
|
59188
|
-
|
|
60162
|
+
if (!existsSync8(skillsDir)) {
|
|
60163
|
+
mkdirSync9(skillsDir, { recursive: true });
|
|
59189
60164
|
console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
|
|
59190
60165
|
}
|
|
59191
|
-
if (!
|
|
59192
|
-
|
|
60166
|
+
if (!existsSync8(claudishSkillDir)) {
|
|
60167
|
+
mkdirSync9(claudishSkillDir, { recursive: true });
|
|
59193
60168
|
console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
|
|
59194
60169
|
}
|
|
59195
60170
|
copyFileSync(sourceSkillPath, skillFile);
|
|
@@ -59231,7 +60206,7 @@ function printAvailableModels() {
|
|
|
59231
60206
|
let lastUpdated = "unknown";
|
|
59232
60207
|
let models = [];
|
|
59233
60208
|
try {
|
|
59234
|
-
if (
|
|
60209
|
+
if (existsSync8(MODELS_JSON_PATH)) {
|
|
59235
60210
|
const data = JSON.parse(readFileSync6(MODELS_JSON_PATH, "utf-8"));
|
|
59236
60211
|
lastUpdated = data.lastUpdated || "unknown";
|
|
59237
60212
|
models = data.models || [];
|
|
@@ -59283,7 +60258,7 @@ Force update: claudish --list-models --force-update
|
|
|
59283
60258
|
`);
|
|
59284
60259
|
}
|
|
59285
60260
|
function printAvailableModelsJSON() {
|
|
59286
|
-
const jsonPath =
|
|
60261
|
+
const jsonPath = join14(__dirname6, "../recommended-models.json");
|
|
59287
60262
|
try {
|
|
59288
60263
|
const jsonContent = readFileSync6(jsonPath, "utf-8");
|
|
59289
60264
|
const data = JSON.parse(jsonContent);
|
|
@@ -59309,7 +60284,7 @@ function printAvailableModelsJSON() {
|
|
|
59309
60284
|
console.log(JSON.stringify(output, null, 2));
|
|
59310
60285
|
}
|
|
59311
60286
|
}
|
|
59312
|
-
var __filename6, __dirname6, VERSION = "3.
|
|
60287
|
+
var __filename6, __dirname6, VERSION = "3.5.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, ALL_MODELS_JSON_PATH2;
|
|
59313
60288
|
var init_cli = __esm(() => {
|
|
59314
60289
|
init_dist11();
|
|
59315
60290
|
init_model_loader2();
|
|
@@ -59317,11 +60292,11 @@ var init_cli = __esm(() => {
|
|
|
59317
60292
|
__filename6 = fileURLToPath5(import.meta.url);
|
|
59318
60293
|
__dirname6 = dirname5(__filename6);
|
|
59319
60294
|
try {
|
|
59320
|
-
const packageJson = JSON.parse(readFileSync6(
|
|
60295
|
+
const packageJson = JSON.parse(readFileSync6(join14(__dirname6, "../package.json"), "utf-8"));
|
|
59321
60296
|
VERSION = packageJson.version;
|
|
59322
60297
|
} catch {}
|
|
59323
|
-
MODELS_JSON_PATH =
|
|
59324
|
-
ALL_MODELS_JSON_PATH2 =
|
|
60298
|
+
MODELS_JSON_PATH = join14(__dirname6, "../recommended-models.json");
|
|
60299
|
+
ALL_MODELS_JSON_PATH2 = join14(__dirname6, "../all-models.json");
|
|
59325
60300
|
});
|
|
59326
60301
|
|
|
59327
60302
|
// src/update-checker.ts
|
|
@@ -59333,31 +60308,31 @@ __export(exports_update_checker, {
|
|
|
59333
60308
|
checkForUpdates: () => checkForUpdates
|
|
59334
60309
|
});
|
|
59335
60310
|
import { execSync } from "node:child_process";
|
|
59336
|
-
import { existsSync as
|
|
59337
|
-
import { homedir as
|
|
59338
|
-
import { join as
|
|
60311
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync10, readFileSync as readFileSync7, unlinkSync, writeFileSync as writeFileSync12 } from "node:fs";
|
|
60312
|
+
import { homedir as homedir9, platform, tmpdir } from "node:os";
|
|
60313
|
+
import { join as join15 } from "node:path";
|
|
59339
60314
|
import { createInterface as createInterface2 } from "node:readline";
|
|
59340
60315
|
function getCacheFilePath() {
|
|
59341
60316
|
let cacheDir;
|
|
59342
60317
|
if (isWindows) {
|
|
59343
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
59344
|
-
cacheDir =
|
|
60318
|
+
const localAppData = process.env.LOCALAPPDATA || join15(homedir9(), "AppData", "Local");
|
|
60319
|
+
cacheDir = join15(localAppData, "claudish");
|
|
59345
60320
|
} else {
|
|
59346
|
-
cacheDir =
|
|
60321
|
+
cacheDir = join15(homedir9(), ".cache", "claudish");
|
|
59347
60322
|
}
|
|
59348
60323
|
try {
|
|
59349
|
-
if (!
|
|
59350
|
-
|
|
60324
|
+
if (!existsSync9(cacheDir)) {
|
|
60325
|
+
mkdirSync10(cacheDir, { recursive: true });
|
|
59351
60326
|
}
|
|
59352
|
-
return
|
|
60327
|
+
return join15(cacheDir, "update-check.json");
|
|
59353
60328
|
} catch {
|
|
59354
|
-
return
|
|
60329
|
+
return join15(tmpdir(), "claudish-update-check.json");
|
|
59355
60330
|
}
|
|
59356
60331
|
}
|
|
59357
60332
|
function readCache() {
|
|
59358
60333
|
try {
|
|
59359
60334
|
const cachePath = getCacheFilePath();
|
|
59360
|
-
if (!
|
|
60335
|
+
if (!existsSync9(cachePath)) {
|
|
59361
60336
|
return null;
|
|
59362
60337
|
}
|
|
59363
60338
|
const data = JSON.parse(readFileSync7(cachePath, "utf-8"));
|
|
@@ -59373,7 +60348,7 @@ function writeCache(latestVersion) {
|
|
|
59373
60348
|
lastCheck: Date.now(),
|
|
59374
60349
|
latestVersion
|
|
59375
60350
|
};
|
|
59376
|
-
|
|
60351
|
+
writeFileSync12(cachePath, JSON.stringify(data), "utf-8");
|
|
59377
60352
|
} catch {}
|
|
59378
60353
|
}
|
|
59379
60354
|
function isCacheValid(cache) {
|
|
@@ -59383,7 +60358,7 @@ function isCacheValid(cache) {
|
|
|
59383
60358
|
function clearCache() {
|
|
59384
60359
|
try {
|
|
59385
60360
|
const cachePath = getCacheFilePath();
|
|
59386
|
-
if (
|
|
60361
|
+
if (existsSync9(cachePath)) {
|
|
59387
60362
|
unlinkSync(cachePath);
|
|
59388
60363
|
}
|
|
59389
60364
|
} catch {}
|
|
@@ -59649,17 +60624,17 @@ __export(exports_claude_runner, {
|
|
|
59649
60624
|
checkClaudeInstalled: () => checkClaudeInstalled
|
|
59650
60625
|
});
|
|
59651
60626
|
import { spawn } from "node:child_process";
|
|
59652
|
-
import { writeFileSync as
|
|
60627
|
+
import { writeFileSync as writeFileSync13, unlinkSync as unlinkSync2, mkdirSync as mkdirSync11 } from "node:fs";
|
|
59653
60628
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
59654
|
-
import { join as
|
|
60629
|
+
import { join as join16 } from "node:path";
|
|
59655
60630
|
function isWindows2() {
|
|
59656
60631
|
return process.platform === "win32";
|
|
59657
60632
|
}
|
|
59658
60633
|
function createStatusLineScript(tokenFilePath) {
|
|
59659
60634
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
59660
|
-
const claudishDir =
|
|
60635
|
+
const claudishDir = join16(homeDir, ".claudish");
|
|
59661
60636
|
const timestamp = Date.now();
|
|
59662
|
-
const scriptPath =
|
|
60637
|
+
const scriptPath = join16(claudishDir, `status-${timestamp}.js`);
|
|
59663
60638
|
const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
|
|
59664
60639
|
const script = `
|
|
59665
60640
|
const fs = require('fs');
|
|
@@ -59703,18 +60678,18 @@ process.stdin.on('end', () => {
|
|
|
59703
60678
|
}
|
|
59704
60679
|
});
|
|
59705
60680
|
`;
|
|
59706
|
-
|
|
60681
|
+
writeFileSync13(scriptPath, script, "utf-8");
|
|
59707
60682
|
return scriptPath;
|
|
59708
60683
|
}
|
|
59709
60684
|
function createTempSettingsFile(modelDisplay, port) {
|
|
59710
60685
|
const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
|
|
59711
|
-
const claudishDir =
|
|
60686
|
+
const claudishDir = join16(homeDir, ".claudish");
|
|
59712
60687
|
try {
|
|
59713
|
-
|
|
60688
|
+
mkdirSync11(claudishDir, { recursive: true });
|
|
59714
60689
|
} catch {}
|
|
59715
60690
|
const timestamp = Date.now();
|
|
59716
|
-
const tempPath =
|
|
59717
|
-
const tokenFilePath =
|
|
60691
|
+
const tempPath = join16(claudishDir, `settings-${timestamp}.json`);
|
|
60692
|
+
const tokenFilePath = join16(claudishDir, `tokens-${port}.json`);
|
|
59718
60693
|
let statusCommand;
|
|
59719
60694
|
if (isWindows2()) {
|
|
59720
60695
|
const scriptPath = createStatusLineScript(tokenFilePath);
|
|
@@ -59736,7 +60711,7 @@ function createTempSettingsFile(modelDisplay, port) {
|
|
|
59736
60711
|
padding: 0
|
|
59737
60712
|
}
|
|
59738
60713
|
};
|
|
59739
|
-
|
|
60714
|
+
writeFileSync13(tempPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
59740
60715
|
return tempPath;
|
|
59741
60716
|
}
|
|
59742
60717
|
async function runClaudeWithProxy(config3, proxyUrl) {
|