@ainyc/canonry 1.26.2 → 1.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NVCAUQ33.js → chunk-727N35MW.js} +214 -40
- package/dist/cli.js +14 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/package.json +8 -7
|
@@ -88,13 +88,42 @@ Do not write config.yaml by hand; use "canonry init", "canonry settings", or "ca
|
|
|
88
88
|
}
|
|
89
89
|
return parsed;
|
|
90
90
|
}
|
|
91
|
+
function loadConfigRaw() {
|
|
92
|
+
const configPath = getConfigPath();
|
|
93
|
+
if (!fs.existsSync(configPath)) return null;
|
|
94
|
+
try {
|
|
95
|
+
return parse(fs.readFileSync(configPath, "utf-8")) ?? null;
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
91
100
|
function saveConfig(config) {
|
|
92
101
|
const configDir = getConfigDir();
|
|
93
102
|
if (!fs.existsSync(configDir)) {
|
|
94
103
|
fs.mkdirSync(configDir, { recursive: true });
|
|
95
104
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
105
|
+
const configPath = getConfigPath();
|
|
106
|
+
const onDisk = loadConfigRaw();
|
|
107
|
+
const merged = onDisk ? { ...onDisk } : {};
|
|
108
|
+
for (const [key, value] of Object.entries(config)) {
|
|
109
|
+
if (value !== void 0) {
|
|
110
|
+
merged[key] = value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (onDisk) {
|
|
114
|
+
if (process.env.CANONRY_PORT?.trim() || onDisk.basePath) {
|
|
115
|
+
merged.apiUrl = onDisk.apiUrl;
|
|
116
|
+
}
|
|
117
|
+
if ("CANONRY_BASE_PATH" in process.env) {
|
|
118
|
+
if (onDisk.basePath !== void 0) {
|
|
119
|
+
merged.basePath = onDisk.basePath;
|
|
120
|
+
} else {
|
|
121
|
+
delete merged.basePath;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const yaml = stringify(merged);
|
|
126
|
+
fs.writeFileSync(configPath, yaml, { encoding: "utf-8", mode: 384 });
|
|
98
127
|
}
|
|
99
128
|
function configExists() {
|
|
100
129
|
return fs.existsSync(getConfigPath());
|
|
@@ -5051,6 +5080,14 @@ async function settingsRoutes(app, opts) {
|
|
|
5051
5080
|
const err = validationError("baseUrl is required for local provider");
|
|
5052
5081
|
return reply.status(err.statusCode).send(err.toJSON());
|
|
5053
5082
|
}
|
|
5083
|
+
} else if (name === "gemini" && !apiKey) {
|
|
5084
|
+
const geminiSummary = (opts.providerSummary ?? []).find((p) => p.name === "gemini");
|
|
5085
|
+
if (!geminiSummary?.vertexConfigured) {
|
|
5086
|
+
const err = validationError(
|
|
5087
|
+
"apiKey is required for Gemini unless Vertex AI is configured (set GEMINI_VERTEX_PROJECT env var or vertexProject in config file)"
|
|
5088
|
+
);
|
|
5089
|
+
return reply.status(err.statusCode).send(err.toJSON());
|
|
5090
|
+
}
|
|
5054
5091
|
} else {
|
|
5055
5092
|
if (!apiKey || typeof apiKey !== "string") {
|
|
5056
5093
|
const err = validationError("apiKey is required");
|
|
@@ -7631,18 +7668,58 @@ async function apiRoutes(app, opts) {
|
|
|
7631
7668
|
|
|
7632
7669
|
// ../provider-gemini/src/normalize.ts
|
|
7633
7670
|
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
7671
|
+
import { VertexAI } from "@google-cloud/vertexai";
|
|
7634
7672
|
var DEFAULT_MODEL = "gemini-3-flash";
|
|
7635
7673
|
var VALIDATION_PATTERN = /^gemini-/;
|
|
7674
|
+
function isVertexConfig(config) {
|
|
7675
|
+
return !!config.vertexProject;
|
|
7676
|
+
}
|
|
7636
7677
|
function resolveModel(config) {
|
|
7637
7678
|
const m = config.model;
|
|
7638
7679
|
if (!m) return DEFAULT_MODEL;
|
|
7639
7680
|
if (VALIDATION_PATTERN.test(m)) return m;
|
|
7681
|
+
const backend = isVertexConfig(config) ? "Vertex AI" : "AI Studio";
|
|
7640
7682
|
console.warn(
|
|
7641
|
-
`[provider-gemini] Invalid model name "${m}" \u2014 this provider uses the Gemini
|
|
7683
|
+
`[provider-gemini] Invalid model name "${m}" \u2014 this provider uses the Gemini ${backend} API which only accepts "gemini-*" model names. Falling back to ${DEFAULT_MODEL}.`
|
|
7642
7684
|
);
|
|
7643
7685
|
return DEFAULT_MODEL;
|
|
7644
7686
|
}
|
|
7687
|
+
function wrapVertexResponse(response) {
|
|
7688
|
+
return {
|
|
7689
|
+
text: () => {
|
|
7690
|
+
const parts = response.candidates?.[0]?.content?.parts;
|
|
7691
|
+
return parts?.map((p) => p.text ?? "").join("") ?? "";
|
|
7692
|
+
},
|
|
7693
|
+
candidates: response.candidates?.map((c) => ({
|
|
7694
|
+
content: c.content,
|
|
7695
|
+
finishReason: c.finishReason,
|
|
7696
|
+
groundingMetadata: c.groundingMetadata
|
|
7697
|
+
})),
|
|
7698
|
+
usageMetadata: response.usageMetadata
|
|
7699
|
+
};
|
|
7700
|
+
}
|
|
7701
|
+
function createVertexModel(config, model, tools) {
|
|
7702
|
+
const vertexOpts = {
|
|
7703
|
+
project: config.vertexProject,
|
|
7704
|
+
location: config.vertexRegion || "us-central1",
|
|
7705
|
+
googleAuthOptions: config.vertexCredentials ? { keyFilename: config.vertexCredentials } : void 0
|
|
7706
|
+
};
|
|
7707
|
+
const vertexAI = new VertexAI(vertexOpts);
|
|
7708
|
+
return vertexAI.getGenerativeModel({
|
|
7709
|
+
model,
|
|
7710
|
+
...tools ? { tools } : {}
|
|
7711
|
+
});
|
|
7712
|
+
}
|
|
7645
7713
|
function validateConfig(config) {
|
|
7714
|
+
if (isVertexConfig(config)) {
|
|
7715
|
+
const model2 = resolveModel(config);
|
|
7716
|
+
return {
|
|
7717
|
+
ok: true,
|
|
7718
|
+
provider: "gemini",
|
|
7719
|
+
message: "config valid (Vertex AI)",
|
|
7720
|
+
model: model2
|
|
7721
|
+
};
|
|
7722
|
+
}
|
|
7646
7723
|
if (!config.apiKey || config.apiKey.length === 0) {
|
|
7647
7724
|
return { ok: false, provider: "gemini", message: "missing api key" };
|
|
7648
7725
|
}
|
|
@@ -7659,16 +7736,29 @@ async function healthcheck(config) {
|
|
|
7659
7736
|
const validation = validateConfig(config);
|
|
7660
7737
|
if (!validation.ok) return validation;
|
|
7661
7738
|
try {
|
|
7662
|
-
const
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7739
|
+
const model = resolveModel(config);
|
|
7740
|
+
if (isVertexConfig(config)) {
|
|
7741
|
+
const generativeModel = createVertexModel(config, model);
|
|
7742
|
+
const result = await generativeModel.generateContent('Say "ok"');
|
|
7743
|
+
const text2 = result.response.candidates?.[0]?.content?.parts?.map((p) => p.text ?? "").join("") ?? "";
|
|
7744
|
+
return {
|
|
7745
|
+
ok: text2.length > 0,
|
|
7746
|
+
provider: "gemini",
|
|
7747
|
+
message: text2.length > 0 ? "gemini vertex ai verified" : "empty response from gemini vertex ai",
|
|
7748
|
+
model
|
|
7749
|
+
};
|
|
7750
|
+
} else {
|
|
7751
|
+
const genAI = new GoogleGenerativeAI(config.apiKey);
|
|
7752
|
+
const generativeModel = genAI.getGenerativeModel({ model });
|
|
7753
|
+
const result = await generativeModel.generateContent('Say "ok"');
|
|
7754
|
+
const text2 = result.response.text();
|
|
7755
|
+
return {
|
|
7756
|
+
ok: text2.length > 0,
|
|
7757
|
+
provider: "gemini",
|
|
7758
|
+
message: text2.length > 0 ? "gemini api key verified" : "empty response from gemini",
|
|
7759
|
+
model
|
|
7760
|
+
};
|
|
7761
|
+
}
|
|
7672
7762
|
} catch (err) {
|
|
7673
7763
|
return {
|
|
7674
7764
|
ok: false,
|
|
@@ -7680,23 +7770,41 @@ async function healthcheck(config) {
|
|
|
7680
7770
|
}
|
|
7681
7771
|
async function executeTrackedQuery(input) {
|
|
7682
7772
|
const model = resolveModel(input.config);
|
|
7683
|
-
const genAI = new GoogleGenerativeAI(input.config.apiKey);
|
|
7684
|
-
const generativeModel = genAI.getGenerativeModel({
|
|
7685
|
-
model,
|
|
7686
|
-
tools: [{ googleSearch: {} }]
|
|
7687
|
-
});
|
|
7688
7773
|
const prompt = buildPrompt(input.keyword, input.location);
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7774
|
+
if (isVertexConfig(input.config)) {
|
|
7775
|
+
const vertexSearchTool = { googleSearchRetrieval: {} };
|
|
7776
|
+
const generativeModel = createVertexModel(input.config, model, [vertexSearchTool]);
|
|
7777
|
+
const result = await generativeModel.generateContent(prompt);
|
|
7778
|
+
const response = result.response;
|
|
7779
|
+
const unified = wrapVertexResponse(response);
|
|
7780
|
+
const groundingMetadata = extractGroundingMetadataFromUnified(unified);
|
|
7781
|
+
const searchQueries = extractSearchQueriesFromUnified(unified);
|
|
7782
|
+
return {
|
|
7783
|
+
provider: "gemini",
|
|
7784
|
+
rawResponse: unifiedToRecord(unified),
|
|
7785
|
+
model,
|
|
7786
|
+
groundingSources: groundingMetadata,
|
|
7787
|
+
searchQueries
|
|
7788
|
+
};
|
|
7789
|
+
} else {
|
|
7790
|
+
const searchTool = { googleSearch: {} };
|
|
7791
|
+
const genAI = new GoogleGenerativeAI(input.config.apiKey);
|
|
7792
|
+
const generativeModel = genAI.getGenerativeModel({
|
|
7793
|
+
model,
|
|
7794
|
+
tools: [searchTool]
|
|
7795
|
+
});
|
|
7796
|
+
const result = await generativeModel.generateContent(prompt);
|
|
7797
|
+
const response = result.response;
|
|
7798
|
+
const groundingMetadata = extractGroundingMetadata(response);
|
|
7799
|
+
const searchQueries = extractSearchQueries(response);
|
|
7800
|
+
return {
|
|
7801
|
+
provider: "gemini",
|
|
7802
|
+
rawResponse: responseToRecord(response),
|
|
7803
|
+
model,
|
|
7804
|
+
groundingSources: groundingMetadata,
|
|
7805
|
+
searchQueries
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7700
7808
|
}
|
|
7701
7809
|
function normalizeResult(raw) {
|
|
7702
7810
|
const answerText = extractAnswerText(raw.rawResponse);
|
|
@@ -7742,6 +7850,22 @@ function extractGroundingMetadata(response) {
|
|
|
7742
7850
|
return [];
|
|
7743
7851
|
}
|
|
7744
7852
|
}
|
|
7853
|
+
function extractGroundingMetadataFromUnified(response) {
|
|
7854
|
+
try {
|
|
7855
|
+
const candidate = response.candidates?.[0];
|
|
7856
|
+
if (!candidate) return [];
|
|
7857
|
+
const metadata = candidate.groundingMetadata;
|
|
7858
|
+
if (!metadata) return [];
|
|
7859
|
+
const chunks = metadata.groundingChunks;
|
|
7860
|
+
if (!chunks) return [];
|
|
7861
|
+
return chunks.filter((chunk) => chunk.web?.uri).map((chunk) => ({
|
|
7862
|
+
uri: chunk.web.uri,
|
|
7863
|
+
title: chunk.web?.title ?? ""
|
|
7864
|
+
}));
|
|
7865
|
+
} catch {
|
|
7866
|
+
return [];
|
|
7867
|
+
}
|
|
7868
|
+
}
|
|
7745
7869
|
function extractSearchQueries(response) {
|
|
7746
7870
|
try {
|
|
7747
7871
|
const candidate = response.candidates?.[0];
|
|
@@ -7750,6 +7874,14 @@ function extractSearchQueries(response) {
|
|
|
7750
7874
|
return [];
|
|
7751
7875
|
}
|
|
7752
7876
|
}
|
|
7877
|
+
function extractSearchQueriesFromUnified(response) {
|
|
7878
|
+
try {
|
|
7879
|
+
const candidate = response.candidates?.[0];
|
|
7880
|
+
return candidate?.groundingMetadata?.webSearchQueries ?? [];
|
|
7881
|
+
} catch {
|
|
7882
|
+
return [];
|
|
7883
|
+
}
|
|
7884
|
+
}
|
|
7753
7885
|
function extractCitedDomains(raw) {
|
|
7754
7886
|
const domains = /* @__PURE__ */ new Set();
|
|
7755
7887
|
for (const source of raw.groundingSources) {
|
|
@@ -7797,10 +7929,16 @@ function extractDomainFromUri(uri) {
|
|
|
7797
7929
|
}
|
|
7798
7930
|
async function generateText(prompt, config) {
|
|
7799
7931
|
const model = resolveModel(config);
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7932
|
+
if (isVertexConfig(config)) {
|
|
7933
|
+
const generativeModel = createVertexModel(config, model);
|
|
7934
|
+
const result = await generativeModel.generateContent(prompt);
|
|
7935
|
+
return result.response.candidates?.[0]?.content?.parts?.map((p) => p.text ?? "").join("") ?? "";
|
|
7936
|
+
} else {
|
|
7937
|
+
const genAI = new GoogleGenerativeAI(config.apiKey);
|
|
7938
|
+
const generativeModel = genAI.getGenerativeModel({ model });
|
|
7939
|
+
const result = await generativeModel.generateContent(prompt);
|
|
7940
|
+
return result.response.text();
|
|
7941
|
+
}
|
|
7804
7942
|
}
|
|
7805
7943
|
function responseToRecord(response) {
|
|
7806
7944
|
try {
|
|
@@ -7820,13 +7958,34 @@ function responseToRecord(response) {
|
|
|
7820
7958
|
return { error: "failed to serialize response" };
|
|
7821
7959
|
}
|
|
7822
7960
|
}
|
|
7961
|
+
function unifiedToRecord(response) {
|
|
7962
|
+
try {
|
|
7963
|
+
const candidates = response.candidates?.map((c) => ({
|
|
7964
|
+
content: c.content,
|
|
7965
|
+
finishReason: c.finishReason,
|
|
7966
|
+
groundingMetadata: c.groundingMetadata ? {
|
|
7967
|
+
webSearchQueries: c.groundingMetadata.webSearchQueries,
|
|
7968
|
+
groundingChunks: c.groundingMetadata.groundingChunks
|
|
7969
|
+
} : void 0
|
|
7970
|
+
}));
|
|
7971
|
+
return {
|
|
7972
|
+
candidates: candidates ?? [],
|
|
7973
|
+
usageMetadata: response.usageMetadata ?? null
|
|
7974
|
+
};
|
|
7975
|
+
} catch {
|
|
7976
|
+
return { error: "failed to serialize response" };
|
|
7977
|
+
}
|
|
7978
|
+
}
|
|
7823
7979
|
|
|
7824
7980
|
// ../provider-gemini/src/adapter.ts
|
|
7825
7981
|
function toGeminiConfig(config) {
|
|
7826
7982
|
return {
|
|
7827
7983
|
apiKey: config.apiKey ?? "",
|
|
7828
7984
|
model: config.model,
|
|
7829
|
-
quotaPolicy: config.quotaPolicy
|
|
7985
|
+
quotaPolicy: config.quotaPolicy,
|
|
7986
|
+
vertexProject: config.vertexProject,
|
|
7987
|
+
vertexRegion: config.vertexRegion,
|
|
7988
|
+
vertexCredentials: config.vertexCredentials
|
|
7830
7989
|
};
|
|
7831
7990
|
}
|
|
7832
7991
|
var geminiAdapter = {
|
|
@@ -10876,19 +11035,22 @@ async function createServer(opts) {
|
|
|
10876
11035
|
}
|
|
10877
11036
|
log6.info("providers.configured", { providers: Object.keys(providers).filter((k) => {
|
|
10878
11037
|
const p = providers[k];
|
|
10879
|
-
return p?.apiKey || p?.baseUrl;
|
|
11038
|
+
return p?.apiKey || p?.baseUrl || p?.vertexProject;
|
|
10880
11039
|
}) });
|
|
10881
11040
|
for (const adapter of API_ADAPTERS) {
|
|
10882
11041
|
const entry = providers[adapter.name];
|
|
10883
11042
|
if (!entry) continue;
|
|
10884
|
-
const isConfigured = adapter.name === "local" ? !!entry.baseUrl : !!entry.apiKey;
|
|
11043
|
+
const isConfigured = adapter.name === "local" ? !!entry.baseUrl : adapter.name === "gemini" ? !!(entry.apiKey || entry.vertexProject) : !!entry.apiKey;
|
|
10885
11044
|
if (isConfigured) {
|
|
10886
11045
|
registry.register(adapter, {
|
|
10887
11046
|
provider: adapter.name,
|
|
10888
11047
|
apiKey: entry.apiKey,
|
|
10889
11048
|
baseUrl: entry.baseUrl,
|
|
10890
11049
|
model: entry.model,
|
|
10891
|
-
quotaPolicy: entry.quota ?? DEFAULT_QUOTA
|
|
11050
|
+
quotaPolicy: entry.quota ?? DEFAULT_QUOTA,
|
|
11051
|
+
vertexProject: entry.vertexProject,
|
|
11052
|
+
vertexRegion: entry.vertexRegion,
|
|
11053
|
+
vertexCredentials: entry.vertexCredentials
|
|
10892
11054
|
});
|
|
10893
11055
|
}
|
|
10894
11056
|
}
|
|
@@ -10922,7 +11084,8 @@ async function createServer(opts) {
|
|
|
10922
11084
|
modelHint: `e.g. ${adapter.modelRegistry.defaultModel}`,
|
|
10923
11085
|
model: registry.get(adapter.name)?.config.model,
|
|
10924
11086
|
configured: !!registry.get(adapter.name),
|
|
10925
|
-
quota: registry.get(adapter.name)?.config.quotaPolicy
|
|
11087
|
+
quota: registry.get(adapter.name)?.config.quotaPolicy,
|
|
11088
|
+
vertexConfigured: adapter.name === "gemini" ? !!opts.config.providers?.gemini?.vertexProject : void 0
|
|
10926
11089
|
}));
|
|
10927
11090
|
const googleSettingsSummary = {
|
|
10928
11091
|
configured: Boolean(opts.config.google?.clientId && opts.config.google?.clientSecret)
|
|
@@ -11216,7 +11379,12 @@ async function createServer(opts) {
|
|
|
11216
11379
|
apiKey: apiKey || existing?.apiKey,
|
|
11217
11380
|
baseUrl: baseUrl || existing?.baseUrl,
|
|
11218
11381
|
model: model || existing?.model,
|
|
11219
|
-
quota: mergedQuota
|
|
11382
|
+
quota: mergedQuota,
|
|
11383
|
+
// Preserve Vertex AI config (Gemini provider) — these are set via
|
|
11384
|
+
// config file or env vars, not through the dashboard update payload
|
|
11385
|
+
vertexProject: existing?.vertexProject,
|
|
11386
|
+
vertexRegion: existing?.vertexRegion,
|
|
11387
|
+
vertexCredentials: existing?.vertexCredentials
|
|
11220
11388
|
};
|
|
11221
11389
|
try {
|
|
11222
11390
|
saveConfig(opts.config);
|
|
@@ -11230,13 +11398,19 @@ async function createServer(opts) {
|
|
|
11230
11398
|
apiKey: apiKey || existing?.apiKey,
|
|
11231
11399
|
baseUrl: baseUrl || existing?.baseUrl,
|
|
11232
11400
|
model: model || existing?.model,
|
|
11233
|
-
quotaPolicy: quota
|
|
11401
|
+
quotaPolicy: quota,
|
|
11402
|
+
vertexProject: existing?.vertexProject,
|
|
11403
|
+
vertexRegion: existing?.vertexRegion,
|
|
11404
|
+
vertexCredentials: existing?.vertexCredentials
|
|
11234
11405
|
});
|
|
11235
11406
|
const entry = providerSummary.find((p) => p.name === name);
|
|
11236
11407
|
if (entry) {
|
|
11237
11408
|
entry.configured = true;
|
|
11238
11409
|
entry.model = model || registry.get(name)?.config.model;
|
|
11239
11410
|
entry.quota = quota;
|
|
11411
|
+
if (name === "gemini") {
|
|
11412
|
+
entry.vertexConfigured = !!opts.config.providers?.[name]?.vertexProject;
|
|
11413
|
+
}
|
|
11240
11414
|
}
|
|
11241
11415
|
const afterConfig = summarizeProviderConfig(name, opts.config.providers[name]);
|
|
11242
11416
|
if (JSON.stringify(beforeConfig) !== JSON.stringify(afterConfig)) {
|
package/dist/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
setGoogleAuthConfig,
|
|
20
20
|
showFirstRunNotice,
|
|
21
21
|
trackEvent
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-727N35MW.js";
|
|
23
23
|
|
|
24
24
|
// src/cli.ts
|
|
25
25
|
import { pathToFileURL } from "url";
|
|
@@ -4174,6 +4174,10 @@ var envSchema = z.object({
|
|
|
4174
4174
|
GEMINI_MAX_CONCURRENCY: z.coerce.number().int().positive().default(2),
|
|
4175
4175
|
GEMINI_MAX_REQUESTS_PER_MINUTE: z.coerce.number().int().positive().default(10),
|
|
4176
4176
|
GEMINI_MAX_REQUESTS_PER_DAY: z.coerce.number().int().positive().default(1e3),
|
|
4177
|
+
// Gemini Vertex AI (alternative to API key auth)
|
|
4178
|
+
GEMINI_VERTEX_PROJECT: z.string().optional(),
|
|
4179
|
+
GEMINI_VERTEX_REGION: z.string().optional(),
|
|
4180
|
+
GEMINI_VERTEX_CREDENTIALS: z.string().optional(),
|
|
4177
4181
|
// OpenAI
|
|
4178
4182
|
OPENAI_API_KEY: z.string().optional(),
|
|
4179
4183
|
OPENAI_MODEL: z.string().optional(),
|
|
@@ -4199,6 +4203,9 @@ var bootstrapEnvSchema = z.object({
|
|
|
4199
4203
|
CANONRY_DATABASE_PATH: z.string().optional(),
|
|
4200
4204
|
GEMINI_API_KEY: z.string().optional(),
|
|
4201
4205
|
GEMINI_MODEL: z.string().optional(),
|
|
4206
|
+
GEMINI_VERTEX_PROJECT: z.string().optional(),
|
|
4207
|
+
GEMINI_VERTEX_REGION: z.string().optional(),
|
|
4208
|
+
GEMINI_VERTEX_CREDENTIALS: z.string().optional(),
|
|
4202
4209
|
OPENAI_API_KEY: z.string().optional(),
|
|
4203
4210
|
OPENAI_MODEL: z.string().optional(),
|
|
4204
4211
|
ANTHROPIC_API_KEY: z.string().optional(),
|
|
@@ -4215,15 +4222,18 @@ function getBootstrapEnv(source, overrides) {
|
|
|
4215
4222
|
const filtered = overrides ? Object.fromEntries(Object.entries(overrides).filter(([, v]) => v != null)) : {};
|
|
4216
4223
|
const parsed = bootstrapEnvSchema.parse({ ...source, ...filtered });
|
|
4217
4224
|
const providers = {};
|
|
4218
|
-
if (parsed.GEMINI_API_KEY) {
|
|
4225
|
+
if (parsed.GEMINI_API_KEY || parsed.GEMINI_VERTEX_PROJECT) {
|
|
4219
4226
|
providers.gemini = {
|
|
4220
|
-
apiKey: parsed.GEMINI_API_KEY,
|
|
4227
|
+
apiKey: parsed.GEMINI_API_KEY ?? "",
|
|
4221
4228
|
model: parsed.GEMINI_MODEL || "gemini-3-flash",
|
|
4222
4229
|
quota: providerQuotaPolicySchema.parse({
|
|
4223
4230
|
maxConcurrency: 2,
|
|
4224
4231
|
maxRequestsPerMinute: 10,
|
|
4225
4232
|
maxRequestsPerDay: 500
|
|
4226
|
-
})
|
|
4233
|
+
}),
|
|
4234
|
+
vertexProject: parsed.GEMINI_VERTEX_PROJECT,
|
|
4235
|
+
vertexRegion: parsed.GEMINI_VERTEX_REGION,
|
|
4236
|
+
vertexCredentials: parsed.GEMINI_VERTEX_CREDENTIALS
|
|
4227
4237
|
};
|
|
4228
4238
|
}
|
|
4229
4239
|
if (parsed.OPENAI_API_KEY) {
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,12 @@ interface ProviderConfigEntry {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
model?: string;
|
|
10
10
|
quota?: ProviderQuotaPolicy;
|
|
11
|
+
/** Vertex AI GCP project ID (Gemini provider only) */
|
|
12
|
+
vertexProject?: string;
|
|
13
|
+
/** Vertex AI region, e.g. "us-central1" (Gemini provider only) */
|
|
14
|
+
vertexRegion?: string;
|
|
15
|
+
/** Path to service account JSON for Vertex AI auth (falls back to ADC) */
|
|
16
|
+
vertexCredentials?: string;
|
|
11
17
|
}
|
|
12
18
|
interface CdpConfigEntry {
|
|
13
19
|
host?: string;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ainyc/canonry",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.27.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The ultimate open-source AEO monitoring tool - track how answer engines cite your domain",
|
|
6
6
|
"license": "FSL-1.1-ALv2",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
38
38
|
"@fastify/static": "^8.1.0",
|
|
39
|
+
"@google-cloud/vertexai": "^1.10.3",
|
|
39
40
|
"@google/generative-ai": "^0.24.1",
|
|
40
41
|
"better-sqlite3": "^12.6.2",
|
|
41
42
|
"drizzle-orm": "^0.45.1",
|
|
@@ -52,18 +53,18 @@
|
|
|
52
53
|
"@types/node-cron": "^3.0.11",
|
|
53
54
|
"tsup": "^8.5.1",
|
|
54
55
|
"tsx": "^4.19.0",
|
|
55
|
-
"@ainyc/canonry-contracts": "0.0.0",
|
|
56
56
|
"@ainyc/canonry-api-routes": "0.0.0",
|
|
57
|
-
"@ainyc/canonry-db": "0.0.0",
|
|
58
|
-
"@ainyc/canonry-config": "0.0.0",
|
|
59
57
|
"@ainyc/canonry-provider-claude": "0.0.0",
|
|
58
|
+
"@ainyc/canonry-contracts": "0.0.0",
|
|
60
59
|
"@ainyc/canonry-provider-gemini": "0.0.0",
|
|
61
|
-
"@ainyc/canonry-
|
|
60
|
+
"@ainyc/canonry-config": "0.0.0",
|
|
62
61
|
"@ainyc/canonry-provider-local": "0.0.0",
|
|
63
|
-
"@ainyc/canonry-
|
|
62
|
+
"@ainyc/canonry-db": "0.0.0",
|
|
63
|
+
"@ainyc/canonry-provider-cdp": "0.0.0",
|
|
64
64
|
"@ainyc/canonry-integration-google": "0.0.0",
|
|
65
|
+
"@ainyc/canonry-provider-perplexity": "0.0.0",
|
|
65
66
|
"@ainyc/canonry-provider-openai": "0.0.0",
|
|
66
|
-
"@ainyc/canonry-
|
|
67
|
+
"@ainyc/canonry-integration-bing": "0.0.0"
|
|
67
68
|
},
|
|
68
69
|
"scripts": {
|
|
69
70
|
"build": "tsup && tsx build-web.ts",
|