@algosuite/vo-mcp 0.2.0-beta.4 → 0.2.0-beta.7
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/bin/vo-mcp +3 -0
- package/dist/cli.js +261 -22
- package/dist/cli.js.map +4 -4
- package/dist/index.js +251 -20
- package/dist/index.js.map +4 -4
- package/dist/install-cli.js +88 -263
- package/dist/install-cli.js.map +4 -4
- package/dist/runner-cli.js +5417 -1017
- package/dist/runner-cli.js.map +4 -4
- package/dist/set-key-cli.js +13 -3
- package/dist/set-key-cli.js.map +2 -2
- package/dist/update-cli.js +62 -0
- package/dist/update-cli.js.map +7 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4496,6 +4496,8 @@ function suggestedHandoffPath(session_id, isoTimestamp) {
|
|
|
4496
4496
|
}
|
|
4497
4497
|
|
|
4498
4498
|
// src/tools/session/report-session-state.ts
|
|
4499
|
+
init_auth_token_source();
|
|
4500
|
+
init_credential_store();
|
|
4499
4501
|
var TOOL_NAME19 = "vo_report_session_state";
|
|
4500
4502
|
var VALID_AGENT_TYPES = ["claude-code", "codex", "cursor", "continue"];
|
|
4501
4503
|
var MAX_GOAL_CHARS = 500;
|
|
@@ -4546,7 +4548,7 @@ var inputSchema19 = {
|
|
|
4546
4548
|
required: ["operator_id", "session_id", "agent_type", "context_used_pct"],
|
|
4547
4549
|
additionalProperties: false
|
|
4548
4550
|
};
|
|
4549
|
-
var description19 = "Reports per-session context-window utilization to VO and returns a directive: 'continue' (under 70%), 'prepare_handoff' (70-84%), or 'execute_handoff_now' (\u226585%). Implements V1 launch gate #9 (fleet context lifecycle management) per the official VO roadmap. Cloud-control-plane mode when VO_CONTROL_PLANE_URL
|
|
4551
|
+
var description19 = "Reports per-session context-window utilization to VO and returns a directive: 'continue' (under 70%), 'prepare_handoff' (70-84%), or 'execute_handoff_now' (\u226585%). Implements V1 launch gate #9 (fleet context lifecycle management) per the official VO roadmap. Cloud-control-plane mode when VO_CONTROL_PLANE_URL plus a user/scoped VO credential (or legacy admin token) is available; auto-allocates the session on first report so interactive agents (Claude Code, Cursor, Codex, Continue) appear on the live fleet whiteboard. Stub-local fallback when cloud config is absent or fails. The response shape stays stable across modes (`backend_mode` field in the payload tells the caller which mode produced the verdict).";
|
|
4550
4552
|
function isStringArray2(v, maxItems) {
|
|
4551
4553
|
if (!Array.isArray(v)) return false;
|
|
4552
4554
|
if (v.length > maxItems) return false;
|
|
@@ -4571,14 +4573,39 @@ function isToolInput19(v) {
|
|
|
4571
4573
|
}
|
|
4572
4574
|
return true;
|
|
4573
4575
|
}
|
|
4574
|
-
function
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4576
|
+
async function fetchCloudIdentity(url, token, fetchFn) {
|
|
4577
|
+
try {
|
|
4578
|
+
const response = await fetchFn(`${url}/api/v1/auth/me`, {
|
|
4579
|
+
method: "GET",
|
|
4580
|
+
headers: {
|
|
4581
|
+
"Authorization": `Bearer ${token}`
|
|
4582
|
+
}
|
|
4583
|
+
});
|
|
4584
|
+
if (!response.ok) return null;
|
|
4585
|
+
const data = await response.json();
|
|
4586
|
+
if (!data.ok || !data.provisioned || !data.operator_id || !data.tenant_id) return null;
|
|
4587
|
+
return { operator_id: data.operator_id, tenant_id: data.tenant_id };
|
|
4588
|
+
} catch {
|
|
4589
|
+
return null;
|
|
4590
|
+
}
|
|
4580
4591
|
}
|
|
4581
|
-
async function
|
|
4592
|
+
async function getCloudConfig(fetchFn = fetch) {
|
|
4593
|
+
const url = process.env["VO_CONTROL_PLANE_URL"]?.trim();
|
|
4594
|
+
if (!url) return null;
|
|
4595
|
+
const tokenSource = createAuthTokenSourceFromEnv(
|
|
4596
|
+
process.env,
|
|
4597
|
+
fetchFn,
|
|
4598
|
+
() => readStoredCredential(process.env)
|
|
4599
|
+
);
|
|
4600
|
+
const token = await tokenSource?.getToken();
|
|
4601
|
+
if (!token) return null;
|
|
4602
|
+
const tenant_id = process.env["VO_TENANT_ID"]?.trim();
|
|
4603
|
+
if (tenant_id) return { url, token, tenant_id };
|
|
4604
|
+
const identity = await fetchCloudIdentity(url, token, fetchFn);
|
|
4605
|
+
if (!identity) return null;
|
|
4606
|
+
return { url, token, tenant_id: identity.tenant_id, operator_id: identity.operator_id };
|
|
4607
|
+
}
|
|
4608
|
+
async function tryCloudReportState(cloud, input, fetchFn = fetch) {
|
|
4582
4609
|
try {
|
|
4583
4610
|
const reportBody = {
|
|
4584
4611
|
context_used_pct: input.context_used_pct
|
|
@@ -4591,7 +4618,7 @@ async function tryCloudReportState(cloud, input) {
|
|
|
4591
4618
|
reportBody["recent_tool_uses"] = input.recent_tool_uses;
|
|
4592
4619
|
}
|
|
4593
4620
|
const reportUrl = `${cloud.url}/api/v1/session/${input.session_id}/report-state`;
|
|
4594
|
-
let response = await
|
|
4621
|
+
let response = await fetchFn(reportUrl, {
|
|
4595
4622
|
method: "POST",
|
|
4596
4623
|
headers: {
|
|
4597
4624
|
"Content-Type": "application/json",
|
|
@@ -4601,7 +4628,7 @@ async function tryCloudReportState(cloud, input) {
|
|
|
4601
4628
|
});
|
|
4602
4629
|
if (response.status === 404) {
|
|
4603
4630
|
const allocateBody = {
|
|
4604
|
-
operator_id: input.operator_id,
|
|
4631
|
+
operator_id: cloud.operator_id ?? input.operator_id,
|
|
4605
4632
|
tenant_id: cloud.tenant_id,
|
|
4606
4633
|
agent_type: input.agent_type,
|
|
4607
4634
|
current_goal: input.current_goal ?? "Interactive session"
|
|
@@ -4610,7 +4637,7 @@ async function tryCloudReportState(cloud, input) {
|
|
|
4610
4637
|
allocateBody["initial_context_used_pct"] = input.context_used_pct;
|
|
4611
4638
|
}
|
|
4612
4639
|
const allocateUrl = `${cloud.url}/api/v1/session`;
|
|
4613
|
-
const allocateResponse = await
|
|
4640
|
+
const allocateResponse = await fetchFn(allocateUrl, {
|
|
4614
4641
|
method: "POST",
|
|
4615
4642
|
headers: {
|
|
4616
4643
|
"Content-Type": "application/json",
|
|
@@ -4621,7 +4648,10 @@ async function tryCloudReportState(cloud, input) {
|
|
|
4621
4648
|
if (!allocateResponse.ok) {
|
|
4622
4649
|
return null;
|
|
4623
4650
|
}
|
|
4624
|
-
|
|
4651
|
+
const allocateData = await allocateResponse.json();
|
|
4652
|
+
const retrySessionId = typeof allocateData.session?.session_id === "string" && allocateData.session.session_id.length > 0 ? allocateData.session.session_id : input.session_id;
|
|
4653
|
+
const retryReportUrl = `${cloud.url}/api/v1/session/${retrySessionId}/report-state`;
|
|
4654
|
+
response = await fetchFn(retryReportUrl, {
|
|
4625
4655
|
method: "POST",
|
|
4626
4656
|
headers: {
|
|
4627
4657
|
"Content-Type": "application/json",
|
|
@@ -4660,7 +4690,7 @@ async function handleReportSessionState(deps, rawInput, _signal) {
|
|
|
4660
4690
|
`invalid input. Required fields: operator_id (non-empty string), session_id (non-empty string), agent_type (one of: ${VALID_AGENT_TYPES.join(" | ")}), context_used_pct (number 0-100). Optional: current_goal (string \u2264${MAX_GOAL_CHARS} chars), recent_files_touched (string[] \u2264${MAX_RECENT_FILES}), recent_tool_uses (string[] \u2264${MAX_RECENT_TOOLS}).`
|
|
4661
4691
|
);
|
|
4662
4692
|
}
|
|
4663
|
-
const cloud = getCloudConfig();
|
|
4693
|
+
const cloud = await getCloudConfig();
|
|
4664
4694
|
if (cloud !== null) {
|
|
4665
4695
|
const cloudPayload = await tryCloudReportState(cloud, rawInput);
|
|
4666
4696
|
if (cloudPayload !== null) {
|
|
@@ -4904,6 +4934,27 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
|
|
|
4904
4934
|
import { homedir as homedir5 } from "node:os";
|
|
4905
4935
|
import { join as join7 } from "node:path";
|
|
4906
4936
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync4 } from "node:fs";
|
|
4937
|
+
|
|
4938
|
+
// src/tools/memory/safe-memory-file.ts
|
|
4939
|
+
import { resolve, sep } from "node:path";
|
|
4940
|
+
var SAFE_MEMORY_FILE_RE = /^[A-Za-z0-9][A-Za-z0-9._ -]*\.md$/i;
|
|
4941
|
+
function isSafeMemoryFileName(fileName) {
|
|
4942
|
+
return fileName.length <= 200 && fileName.trim() === fileName && !fileName.includes("/") && !fileName.includes("\\") && !fileName.includes(":") && SAFE_MEMORY_FILE_RE.test(fileName);
|
|
4943
|
+
}
|
|
4944
|
+
function resolveMemoryFilePath(memoryDir, fileName) {
|
|
4945
|
+
if (!isSafeMemoryFileName(fileName)) {
|
|
4946
|
+
throw new Error(`unsafe memory file_name: ${fileName.slice(0, 80)}`);
|
|
4947
|
+
}
|
|
4948
|
+
const root = resolve(memoryDir);
|
|
4949
|
+
const filePath = resolve(root, fileName);
|
|
4950
|
+
const rootPrefix = root.endsWith(sep) ? root : `${root}${sep}`;
|
|
4951
|
+
if (filePath !== root && !filePath.startsWith(rootPrefix)) {
|
|
4952
|
+
throw new Error(`memory file path escapes memory directory: ${fileName.slice(0, 80)}`);
|
|
4953
|
+
}
|
|
4954
|
+
return filePath;
|
|
4955
|
+
}
|
|
4956
|
+
|
|
4957
|
+
// src/tools/memory/sync-config.ts
|
|
4907
4958
|
var TOOL_NAME22 = "vo_sync_config";
|
|
4908
4959
|
var inputSchema22 = {
|
|
4909
4960
|
type: "object",
|
|
@@ -4952,10 +5003,13 @@ async function pullMemory(controlPlaneUrl, token, memoryDir, fetchFn) {
|
|
|
4952
5003
|
if (!data.ok || !Array.isArray(data.entries)) {
|
|
4953
5004
|
throw new Error("GET /api/v1/agent-config/memory/me response missing ok=true or entries array");
|
|
4954
5005
|
}
|
|
5006
|
+
const writes = data.entries.map((entry) => ({
|
|
5007
|
+
entry,
|
|
5008
|
+
filePath: resolveMemoryFilePath(memoryDir, entry.file_name)
|
|
5009
|
+
}));
|
|
4955
5010
|
mkdirSync4(memoryDir, { recursive: true });
|
|
4956
5011
|
const files = [];
|
|
4957
|
-
for (const entry of
|
|
4958
|
-
const filePath = join7(memoryDir, entry.file_name);
|
|
5012
|
+
for (const { entry, filePath } of writes) {
|
|
4959
5013
|
writeFileSync3(filePath, entry.content, "utf8");
|
|
4960
5014
|
files.push(entry.file_name);
|
|
4961
5015
|
}
|
|
@@ -4967,7 +5021,7 @@ async function pushMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn)
|
|
|
4967
5021
|
}
|
|
4968
5022
|
const localFiles = readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).map((f) => ({
|
|
4969
5023
|
file_name: f,
|
|
4970
|
-
content: readFileSync7(
|
|
5024
|
+
content: readFileSync7(resolveMemoryFilePath(memoryDir, f), "utf8"),
|
|
4971
5025
|
entry_type: f === "MEMORY.md" ? "index" : "topic"
|
|
4972
5026
|
}));
|
|
4973
5027
|
if (localFiles.length === 0) {
|
|
@@ -5097,6 +5151,104 @@ async function handleSyncConfig(deps, rawInput, _signal, fetchFn = globalThis.fe
|
|
|
5097
5151
|
return jsonContent({ tool: TOOL_NAME22, schema_version: 1, payload: result });
|
|
5098
5152
|
}
|
|
5099
5153
|
|
|
5154
|
+
// src/tools/memory/private-knowledge.ts
|
|
5155
|
+
var UPSERT_TOOL_NAME = "vo_private_knowledge_upsert";
|
|
5156
|
+
var CONTEXT_TOOL_NAME = "vo_private_knowledge_context";
|
|
5157
|
+
var KNOWLEDGE_CLASSES = ["memory", "skill", "doctrine", "hook", "command"];
|
|
5158
|
+
var PRECISION_CHAR_BUDGET = 12e3;
|
|
5159
|
+
var upsertInputSchema = {
|
|
5160
|
+
type: "object",
|
|
5161
|
+
properties: {
|
|
5162
|
+
knowledge_class: { type: "string", enum: KNOWLEDGE_CLASSES },
|
|
5163
|
+
source_path: { type: "string", description: "Stable private source identifier; not exposed to other users." },
|
|
5164
|
+
title: { type: "string", description: 'Descriptive, retrieval-friendly title (e.g. "AlgoTax OCR redaction architecture", not "notes") \u2014 retrieval matches on it.' },
|
|
5165
|
+
content: { type: "string", description: "Private knowledge text to store server-side. Keep each entry tight and focused (~1-3 pages, under ~12k chars); split larger corpora into separate entries." }
|
|
5166
|
+
},
|
|
5167
|
+
required: ["knowledge_class", "source_path", "title", "content"],
|
|
5168
|
+
additionalProperties: false
|
|
5169
|
+
};
|
|
5170
|
+
var contextInputSchema = {
|
|
5171
|
+
type: "object",
|
|
5172
|
+
properties: {
|
|
5173
|
+
query: { type: "string" },
|
|
5174
|
+
limit: { type: "number", minimum: 1, maximum: 50 },
|
|
5175
|
+
knowledge_class: { type: "string", enum: KNOWLEDGE_CLASSES }
|
|
5176
|
+
},
|
|
5177
|
+
required: ["query"],
|
|
5178
|
+
additionalProperties: false
|
|
5179
|
+
};
|
|
5180
|
+
var upsertDescription = "Uploads or refreshes the authenticated operator\u2019s private cloud knowledge. Works for Claude, Codex, Cursor, and cowork clients via the same vo-mcp login credential. Returns metadata only, not raw stored content. PRECISION DISCIPLINE: keep each entry tight and focused (~1-3 pages) with a descriptive retrieval-friendly title \u2014 retrieval surfaces whole entries, so small dense entries beat bulk dumps. Split large corpora into focused entries, then run a retrieval self-test via vo_private_knowledge_context before relying on the knowledge.";
|
|
5181
|
+
var contextDescription = "Retrieves prompt-ready private knowledge context for the authenticated operator. Returns snippets/context only; no raw corpus download. Also the retrieval self-test surface: after upserting critical knowledge, query for it here and confirm the entry surfaces before trusting it in downstream work.";
|
|
5182
|
+
function isKnowledgeClass(value) {
|
|
5183
|
+
return typeof value === "string" && KNOWLEDGE_CLASSES.includes(value);
|
|
5184
|
+
}
|
|
5185
|
+
function isUpsertInput(value) {
|
|
5186
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5187
|
+
const input = value;
|
|
5188
|
+
return isKnowledgeClass(input["knowledge_class"]) && typeof input["source_path"] === "string" && typeof input["title"] === "string" && typeof input["content"] === "string";
|
|
5189
|
+
}
|
|
5190
|
+
function isContextInput(value) {
|
|
5191
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5192
|
+
const input = value;
|
|
5193
|
+
if (typeof input["query"] !== "string") return false;
|
|
5194
|
+
if (input["limit"] !== void 0 && typeof input["limit"] !== "number") return false;
|
|
5195
|
+
if (input["knowledge_class"] !== void 0 && !isKnowledgeClass(input["knowledge_class"])) return false;
|
|
5196
|
+
return true;
|
|
5197
|
+
}
|
|
5198
|
+
async function getCloudAuth(fetchFn) {
|
|
5199
|
+
const controlPlaneUrl = process.env["VO_CONTROL_PLANE_URL"]?.replace(/\/+$/, "");
|
|
5200
|
+
if (!controlPlaneUrl) {
|
|
5201
|
+
return { ok: false, reason: "VO_CONTROL_PLANE_URL not set \u2014 cloud mode disabled" };
|
|
5202
|
+
}
|
|
5203
|
+
const { createAuthTokenSourceFromEnv: createAuthTokenSourceFromEnv2 } = await Promise.resolve().then(() => (init_auth_token_source(), auth_token_source_exports));
|
|
5204
|
+
const { readStoredCredential: readStoredCredential2 } = await Promise.resolve().then(() => (init_credential_store(), credential_store_exports));
|
|
5205
|
+
const tokenSource = createAuthTokenSourceFromEnv2(process.env, fetchFn, () => readStoredCredential2(process.env));
|
|
5206
|
+
if (!tokenSource) return { ok: false, reason: "No auth configured. Run `vo-mcp login`." };
|
|
5207
|
+
const token = await tokenSource.getToken();
|
|
5208
|
+
if (!token) return { ok: false, reason: "Failed to obtain auth token. Run `vo-mcp login` again." };
|
|
5209
|
+
return { ok: true, controlPlaneUrl, token };
|
|
5210
|
+
}
|
|
5211
|
+
async function callPrivateKnowledge(path3, body, fetchFn) {
|
|
5212
|
+
const auth = await getCloudAuth(fetchFn);
|
|
5213
|
+
if (!auth.ok) return { ok: false, reason: auth.reason };
|
|
5214
|
+
const response = await fetchFn(`${auth.controlPlaneUrl}${path3}`, {
|
|
5215
|
+
method: "POST",
|
|
5216
|
+
headers: {
|
|
5217
|
+
authorization: `Bearer ${auth.token}`,
|
|
5218
|
+
"content-type": "application/json"
|
|
5219
|
+
},
|
|
5220
|
+
body: JSON.stringify(body)
|
|
5221
|
+
});
|
|
5222
|
+
const text = await response.text();
|
|
5223
|
+
const parsed = text ? JSON.parse(text) : null;
|
|
5224
|
+
if (response.status < 200 || response.status >= 300) {
|
|
5225
|
+
return { ok: false, status: response.status, response: parsed ?? text };
|
|
5226
|
+
}
|
|
5227
|
+
return parsed;
|
|
5228
|
+
}
|
|
5229
|
+
async function handlePrivateKnowledgeUpsert(_deps, rawInput, _signal, fetchFn = globalThis.fetch) {
|
|
5230
|
+
if (!isUpsertInput(rawInput)) {
|
|
5231
|
+
throw invalidParams(UPSERT_TOOL_NAME, "expected { knowledge_class, source_path, title, content }.");
|
|
5232
|
+
}
|
|
5233
|
+
const payload = await callPrivateKnowledge("/api/v1/knowledge/private", rawInput, fetchFn);
|
|
5234
|
+
const envelope = {
|
|
5235
|
+
tool: UPSERT_TOOL_NAME,
|
|
5236
|
+
schema_version: 1,
|
|
5237
|
+
payload
|
|
5238
|
+
};
|
|
5239
|
+
if (rawInput.content.length > PRECISION_CHAR_BUDGET) {
|
|
5240
|
+
envelope.precision_note = `content is ${rawInput.content.length} chars (> ${PRECISION_CHAR_BUDGET}). Tight 1-3 page entries retrieve better \u2014 consider splitting into focused entries, then re-test retrieval via ${CONTEXT_TOOL_NAME}.`;
|
|
5241
|
+
}
|
|
5242
|
+
return jsonContent(envelope);
|
|
5243
|
+
}
|
|
5244
|
+
async function handlePrivateKnowledgeContext(_deps, rawInput, _signal, fetchFn = globalThis.fetch) {
|
|
5245
|
+
if (!isContextInput(rawInput)) {
|
|
5246
|
+
throw invalidParams(CONTEXT_TOOL_NAME, "expected { query, optional limit, optional knowledge_class }.");
|
|
5247
|
+
}
|
|
5248
|
+
const payload = await callPrivateKnowledge("/api/v1/knowledge/private/context", rawInput, fetchFn);
|
|
5249
|
+
return jsonContent({ tool: CONTEXT_TOOL_NAME, schema_version: 1, payload });
|
|
5250
|
+
}
|
|
5251
|
+
|
|
5100
5252
|
// src/server.ts
|
|
5101
5253
|
function buildToolRegistry() {
|
|
5102
5254
|
return {
|
|
@@ -5275,6 +5427,22 @@ function buildToolRegistry() {
|
|
|
5275
5427
|
inputSchema: inputSchema22
|
|
5276
5428
|
},
|
|
5277
5429
|
handler: handleSyncConfig
|
|
5430
|
+
},
|
|
5431
|
+
[UPSERT_TOOL_NAME]: {
|
|
5432
|
+
definition: {
|
|
5433
|
+
name: UPSERT_TOOL_NAME,
|
|
5434
|
+
description: upsertDescription,
|
|
5435
|
+
inputSchema: upsertInputSchema
|
|
5436
|
+
},
|
|
5437
|
+
handler: handlePrivateKnowledgeUpsert
|
|
5438
|
+
},
|
|
5439
|
+
[CONTEXT_TOOL_NAME]: {
|
|
5440
|
+
definition: {
|
|
5441
|
+
name: CONTEXT_TOOL_NAME,
|
|
5442
|
+
description: contextDescription,
|
|
5443
|
+
inputSchema: contextInputSchema
|
|
5444
|
+
},
|
|
5445
|
+
handler: handlePrivateKnowledgeContext
|
|
5278
5446
|
}
|
|
5279
5447
|
};
|
|
5280
5448
|
}
|
|
@@ -5564,6 +5732,64 @@ function createNullConsensusEngineClient(reason = NULL_CLIENT_DEFAULT_REASON) {
|
|
|
5564
5732
|
// src/consensus/engine-client.ts
|
|
5565
5733
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
5566
5734
|
|
|
5735
|
+
// src/consensus/meta-model-caller.ts
|
|
5736
|
+
var META_MODEL_API_BASE_URL = "https://api.meta.ai/v1";
|
|
5737
|
+
var META_CONSENSUS_MODEL = "muse-spark-1.1";
|
|
5738
|
+
var META_MODEL_API_KEY_ENV = "MODEL_API_KEY";
|
|
5739
|
+
var META_MODEL_API_KEY_ALIAS = "META_API";
|
|
5740
|
+
function resolveMetaKey(env) {
|
|
5741
|
+
return String(env[META_MODEL_API_KEY_ENV] || env[META_MODEL_API_KEY_ALIAS] || "").trim();
|
|
5742
|
+
}
|
|
5743
|
+
function positiveMaxTokens(value) {
|
|
5744
|
+
const parsed = Math.floor(Number(value));
|
|
5745
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 2048;
|
|
5746
|
+
}
|
|
5747
|
+
function createMetaModelCaller(options = {}) {
|
|
5748
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5749
|
+
const envSource = options.envSource ?? process.env;
|
|
5750
|
+
const reasoningEffort = options.reasoningEffort ?? "high";
|
|
5751
|
+
return async function callMetaWithMetrics2(prompt, systemPrompt, model, maxTokens, _privacyOptions, signal) {
|
|
5752
|
+
const key = resolveMetaKey(envSource);
|
|
5753
|
+
if (!key) throw new Error(`Missing ${META_MODEL_API_KEY_ENV} for Meta Model API`);
|
|
5754
|
+
const messages = [
|
|
5755
|
+
...systemPrompt ? [{ role: "system", content: systemPrompt }] : [],
|
|
5756
|
+
{ role: "user", content: prompt }
|
|
5757
|
+
];
|
|
5758
|
+
const response = await fetchImpl(`${META_MODEL_API_BASE_URL}/chat/completions`, {
|
|
5759
|
+
method: "POST",
|
|
5760
|
+
headers: {
|
|
5761
|
+
Authorization: `Bearer ${key}`,
|
|
5762
|
+
"Content-Type": "application/json"
|
|
5763
|
+
},
|
|
5764
|
+
body: JSON.stringify({
|
|
5765
|
+
model: model || META_CONSENSUS_MODEL,
|
|
5766
|
+
messages,
|
|
5767
|
+
max_tokens: positiveMaxTokens(maxTokens),
|
|
5768
|
+
reasoning_effort: reasoningEffort
|
|
5769
|
+
}),
|
|
5770
|
+
signal
|
|
5771
|
+
});
|
|
5772
|
+
const payload = await response.json();
|
|
5773
|
+
if (!response.ok) {
|
|
5774
|
+
const message = String(payload.error?.message || response.statusText || "request failed").slice(0, 500);
|
|
5775
|
+
throw Object.assign(new Error(`Meta Model API ${response.status}: ${message}`), { status: response.status });
|
|
5776
|
+
}
|
|
5777
|
+
const content = payload.choices?.[0]?.message?.content;
|
|
5778
|
+
if (typeof content !== "string" || !content.trim()) {
|
|
5779
|
+
throw new Error(`Meta Model API returned no text (finish=${payload.choices?.[0]?.finish_reason || "unknown"})`);
|
|
5780
|
+
}
|
|
5781
|
+
const inputTokens = Number(payload.usage?.prompt_tokens || 0);
|
|
5782
|
+
const outputTokens = Number(payload.usage?.completion_tokens || 0);
|
|
5783
|
+
return {
|
|
5784
|
+
content,
|
|
5785
|
+
inputTokens,
|
|
5786
|
+
outputTokens,
|
|
5787
|
+
totalTokens: Number(payload.usage?.total_tokens || inputTokens + outputTokens)
|
|
5788
|
+
};
|
|
5789
|
+
};
|
|
5790
|
+
}
|
|
5791
|
+
var callMetaWithMetrics = createMetaModelCaller();
|
|
5792
|
+
|
|
5567
5793
|
// src/consensus/engine-options.ts
|
|
5568
5794
|
var AGREEMENT_GATE_ENV_VAR = "VO_CONSENSUS_AGREEMENT_GATE";
|
|
5569
5795
|
function isTruthyFlag(raw) {
|
|
@@ -5858,7 +6084,8 @@ var DEFAULT_MODELS = {
|
|
|
5858
6084
|
// callGeminiWithMetrics; 2.5-pro REJECTS budget 0 ("only works in thinking mode").
|
|
5859
6085
|
// Flash is also ~10x cheaper. 2026-06-02.
|
|
5860
6086
|
google: "gemini-2.5-flash",
|
|
5861
|
-
deepseek: "deepseek-chat"
|
|
6087
|
+
deepseek: "deepseek-chat",
|
|
6088
|
+
meta: META_CONSENSUS_MODEL
|
|
5862
6089
|
};
|
|
5863
6090
|
function probeProviders(env = process.env) {
|
|
5864
6091
|
const out = [];
|
|
@@ -5866,6 +6093,7 @@ function probeProviders(env = process.env) {
|
|
|
5866
6093
|
if ((env["OPENAI_API_KEY"] ?? "").trim().length > 0) out.push("openai");
|
|
5867
6094
|
if ((env["GOOGLE_API_KEY"] ?? "").trim().length > 0) out.push("google");
|
|
5868
6095
|
if ((env["DEEPSEEK_API_KEY"] ?? "").trim().length > 0) out.push("deepseek");
|
|
6096
|
+
if ((env[META_MODEL_API_KEY_ENV] ?? "").trim().length > 0 || (env[META_MODEL_API_KEY_ALIAS] ?? "").trim().length > 0) out.push("meta");
|
|
5869
6097
|
return out;
|
|
5870
6098
|
}
|
|
5871
6099
|
async function loadFactoryAndCallers(injectedEngine, injectedShared) {
|
|
@@ -5911,21 +6139,24 @@ async function tryCreateEngineConsensusClientFromEnvAsync(options = {}) {
|
|
|
5911
6139
|
anthropic: loaded.shared.callAnthropicWithMetrics,
|
|
5912
6140
|
openai: loaded.shared.callOpenAIWithMetrics,
|
|
5913
6141
|
google: loaded.shared.callGeminiWithMetrics,
|
|
5914
|
-
deepseek: loaded.shared.callDeepSeekWithMetrics
|
|
6142
|
+
deepseek: loaded.shared.callDeepSeekWithMetrics,
|
|
6143
|
+
meta: options.metaCaller ?? callMetaWithMetrics
|
|
5915
6144
|
};
|
|
5916
6145
|
const modelByProvider = {
|
|
5917
6146
|
anthropic: options.models?.anthropic ?? DEFAULT_MODELS.anthropic,
|
|
5918
6147
|
openai: options.models?.openai ?? DEFAULT_MODELS.openai,
|
|
5919
6148
|
google: options.models?.google ?? DEFAULT_MODELS.google,
|
|
5920
|
-
deepseek: options.models?.deepseek ?? DEFAULT_MODELS.deepseek
|
|
6149
|
+
deepseek: options.models?.deepseek ?? DEFAULT_MODELS.deepseek,
|
|
6150
|
+
meta: options.models?.meta ?? DEFAULT_MODELS.meta
|
|
5921
6151
|
};
|
|
6152
|
+
const adapterEnv = !(env[META_MODEL_API_KEY_ENV] ?? "").trim() && (env[META_MODEL_API_KEY_ALIAS] ?? "").trim() ? { ...env, [META_MODEL_API_KEY_ENV]: env[META_MODEL_API_KEY_ALIAS] } : env;
|
|
5922
6153
|
const panel = [];
|
|
5923
6154
|
for (const p of providers) {
|
|
5924
6155
|
try {
|
|
5925
6156
|
const adapter = loaded.engine.createAdapter(p, {
|
|
5926
6157
|
model: modelByProvider[p],
|
|
5927
6158
|
caller: callerByProvider[p],
|
|
5928
|
-
envSource:
|
|
6159
|
+
envSource: adapterEnv
|
|
5929
6160
|
});
|
|
5930
6161
|
panel.push(adapter);
|
|
5931
6162
|
} catch {
|