@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 CHANGED
@@ -5,6 +5,7 @@
5
5
  * Usage:
6
6
  * vo-mcp # MCP stdio server (default)
7
7
  * vo-mcp install # one-command installer
8
+ * vo-mcp update # update MCP + runner package
8
9
  * vo-mcp login # credential login (browser loopback)
9
10
  * vo-mcp pair # device-code pairing (enter a code in the web)
10
11
  * vo-mcp runner # agent runner daemon
@@ -17,6 +18,8 @@ const subcommand = process.argv[3];
17
18
 
18
19
  if (command === 'install') {
19
20
  import('../dist/install-cli.js');
21
+ } else if (command === 'update') {
22
+ import('../dist/update-cli.js');
20
23
  } else if (command === 'login') {
21
24
  import('../dist/login-cli.js');
22
25
  } else if (command === 'pair') {
package/dist/cli.js CHANGED
@@ -1368,6 +1368,31 @@ var init_credential_store = __esm({
1368
1368
  }
1369
1369
  });
1370
1370
 
1371
+ // src/tools/memory/safe-memory-file.ts
1372
+ import { resolve, sep } from "node:path";
1373
+ function isSafeMemoryFileName(fileName) {
1374
+ return fileName.length <= 200 && fileName.trim() === fileName && !fileName.includes("/") && !fileName.includes("\\") && !fileName.includes(":") && SAFE_MEMORY_FILE_RE.test(fileName);
1375
+ }
1376
+ function resolveMemoryFilePath(memoryDir, fileName) {
1377
+ if (!isSafeMemoryFileName(fileName)) {
1378
+ throw new Error(`unsafe memory file_name: ${fileName.slice(0, 80)}`);
1379
+ }
1380
+ const root = resolve(memoryDir);
1381
+ const filePath = resolve(root, fileName);
1382
+ const rootPrefix = root.endsWith(sep) ? root : `${root}${sep}`;
1383
+ if (filePath !== root && !filePath.startsWith(rootPrefix)) {
1384
+ throw new Error(`memory file path escapes memory directory: ${fileName.slice(0, 80)}`);
1385
+ }
1386
+ return filePath;
1387
+ }
1388
+ var SAFE_MEMORY_FILE_RE;
1389
+ var init_safe_memory_file = __esm({
1390
+ "src/tools/memory/safe-memory-file.ts"() {
1391
+ "use strict";
1392
+ SAFE_MEMORY_FILE_RE = /^[A-Za-z0-9][A-Za-z0-9._ -]*\.md$/i;
1393
+ }
1394
+ });
1395
+
1371
1396
  // src/tools/memory/sync-config.ts
1372
1397
  var sync_config_exports = {};
1373
1398
  __export(sync_config_exports, {
@@ -1413,10 +1438,13 @@ async function pullMemory(controlPlaneUrl, token, memoryDir, fetchFn) {
1413
1438
  if (!data.ok || !Array.isArray(data.entries)) {
1414
1439
  throw new Error("GET /api/v1/agent-config/memory/me response missing ok=true or entries array");
1415
1440
  }
1441
+ const writes = data.entries.map((entry) => ({
1442
+ entry,
1443
+ filePath: resolveMemoryFilePath(memoryDir, entry.file_name)
1444
+ }));
1416
1445
  mkdirSync4(memoryDir, { recursive: true });
1417
1446
  const files = [];
1418
- for (const entry of data.entries) {
1419
- const filePath = join7(memoryDir, entry.file_name);
1447
+ for (const { entry, filePath } of writes) {
1420
1448
  writeFileSync3(filePath, entry.content, "utf8");
1421
1449
  files.push(entry.file_name);
1422
1450
  }
@@ -1428,7 +1456,7 @@ async function pushMemory(controlPlaneUrl, token, memoryDir, sessionId, fetchFn)
1428
1456
  }
1429
1457
  const localFiles = readdirSync4(memoryDir).filter((f) => f.endsWith(".md")).map((f) => ({
1430
1458
  file_name: f,
1431
- content: readFileSync7(join7(memoryDir, f), "utf8"),
1459
+ content: readFileSync7(resolveMemoryFilePath(memoryDir, f), "utf8"),
1432
1460
  entry_type: f === "MEMORY.md" ? "index" : "topic"
1433
1461
  }));
1434
1462
  if (localFiles.length === 0) {
@@ -1566,6 +1594,7 @@ var init_sync_config = __esm({
1566
1594
  "src/tools/memory/sync-config.ts"() {
1567
1595
  "use strict";
1568
1596
  init_common();
1597
+ init_safe_memory_file();
1569
1598
  TOOL_NAME22 = "vo_sync_config";
1570
1599
  inputSchema22 = {
1571
1600
  type: "object",
@@ -5023,6 +5052,8 @@ function suggestedHandoffPath(session_id, isoTimestamp) {
5023
5052
  }
5024
5053
 
5025
5054
  // src/tools/session/report-session-state.ts
5055
+ init_auth_token_source();
5056
+ init_credential_store();
5026
5057
  var TOOL_NAME19 = "vo_report_session_state";
5027
5058
  var VALID_AGENT_TYPES = ["claude-code", "codex", "cursor", "continue"];
5028
5059
  var MAX_GOAL_CHARS = 500;
@@ -5073,7 +5104,7 @@ var inputSchema19 = {
5073
5104
  required: ["operator_id", "session_id", "agent_type", "context_used_pct"],
5074
5105
  additionalProperties: false
5075
5106
  };
5076
- 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 + VO_CONTROL_PLANE_ADMIN_TOKEN + VO_TENANT_ID are set; 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).";
5107
+ 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).";
5077
5108
  function isStringArray2(v, maxItems) {
5078
5109
  if (!Array.isArray(v)) return false;
5079
5110
  if (v.length > maxItems) return false;
@@ -5098,14 +5129,39 @@ function isToolInput19(v) {
5098
5129
  }
5099
5130
  return true;
5100
5131
  }
5101
- function getCloudConfig() {
5102
- const url = process.env["VO_CONTROL_PLANE_URL"];
5103
- const token = process.env["VO_CONTROL_PLANE_ADMIN_TOKEN"];
5104
- const tenant_id = process.env["VO_TENANT_ID"];
5105
- if (!url || !token || !tenant_id) return null;
5106
- return { url, token, tenant_id };
5132
+ async function fetchCloudIdentity(url, token, fetchFn) {
5133
+ try {
5134
+ const response = await fetchFn(`${url}/api/v1/auth/me`, {
5135
+ method: "GET",
5136
+ headers: {
5137
+ "Authorization": `Bearer ${token}`
5138
+ }
5139
+ });
5140
+ if (!response.ok) return null;
5141
+ const data = await response.json();
5142
+ if (!data.ok || !data.provisioned || !data.operator_id || !data.tenant_id) return null;
5143
+ return { operator_id: data.operator_id, tenant_id: data.tenant_id };
5144
+ } catch {
5145
+ return null;
5146
+ }
5107
5147
  }
5108
- async function tryCloudReportState(cloud, input) {
5148
+ async function getCloudConfig(fetchFn = fetch) {
5149
+ const url = process.env["VO_CONTROL_PLANE_URL"]?.trim();
5150
+ if (!url) return null;
5151
+ const tokenSource = createAuthTokenSourceFromEnv(
5152
+ process.env,
5153
+ fetchFn,
5154
+ () => readStoredCredential(process.env)
5155
+ );
5156
+ const token = await tokenSource?.getToken();
5157
+ if (!token) return null;
5158
+ const tenant_id = process.env["VO_TENANT_ID"]?.trim();
5159
+ if (tenant_id) return { url, token, tenant_id };
5160
+ const identity = await fetchCloudIdentity(url, token, fetchFn);
5161
+ if (!identity) return null;
5162
+ return { url, token, tenant_id: identity.tenant_id, operator_id: identity.operator_id };
5163
+ }
5164
+ async function tryCloudReportState(cloud, input, fetchFn = fetch) {
5109
5165
  try {
5110
5166
  const reportBody = {
5111
5167
  context_used_pct: input.context_used_pct
@@ -5118,7 +5174,7 @@ async function tryCloudReportState(cloud, input) {
5118
5174
  reportBody["recent_tool_uses"] = input.recent_tool_uses;
5119
5175
  }
5120
5176
  const reportUrl = `${cloud.url}/api/v1/session/${input.session_id}/report-state`;
5121
- let response = await fetch(reportUrl, {
5177
+ let response = await fetchFn(reportUrl, {
5122
5178
  method: "POST",
5123
5179
  headers: {
5124
5180
  "Content-Type": "application/json",
@@ -5128,7 +5184,7 @@ async function tryCloudReportState(cloud, input) {
5128
5184
  });
5129
5185
  if (response.status === 404) {
5130
5186
  const allocateBody = {
5131
- operator_id: input.operator_id,
5187
+ operator_id: cloud.operator_id ?? input.operator_id,
5132
5188
  tenant_id: cloud.tenant_id,
5133
5189
  agent_type: input.agent_type,
5134
5190
  current_goal: input.current_goal ?? "Interactive session"
@@ -5137,7 +5193,7 @@ async function tryCloudReportState(cloud, input) {
5137
5193
  allocateBody["initial_context_used_pct"] = input.context_used_pct;
5138
5194
  }
5139
5195
  const allocateUrl = `${cloud.url}/api/v1/session`;
5140
- const allocateResponse = await fetch(allocateUrl, {
5196
+ const allocateResponse = await fetchFn(allocateUrl, {
5141
5197
  method: "POST",
5142
5198
  headers: {
5143
5199
  "Content-Type": "application/json",
@@ -5148,7 +5204,10 @@ async function tryCloudReportState(cloud, input) {
5148
5204
  if (!allocateResponse.ok) {
5149
5205
  return null;
5150
5206
  }
5151
- response = await fetch(reportUrl, {
5207
+ const allocateData = await allocateResponse.json();
5208
+ const retrySessionId = typeof allocateData.session?.session_id === "string" && allocateData.session.session_id.length > 0 ? allocateData.session.session_id : input.session_id;
5209
+ const retryReportUrl = `${cloud.url}/api/v1/session/${retrySessionId}/report-state`;
5210
+ response = await fetchFn(retryReportUrl, {
5152
5211
  method: "POST",
5153
5212
  headers: {
5154
5213
  "Content-Type": "application/json",
@@ -5187,7 +5246,7 @@ async function handleReportSessionState(deps, rawInput, _signal) {
5187
5246
  `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}).`
5188
5247
  );
5189
5248
  }
5190
- const cloud = getCloudConfig();
5249
+ const cloud = await getCloudConfig();
5191
5250
  if (cloud !== null) {
5192
5251
  const cloudPayload = await tryCloudReportState(cloud, rawInput);
5193
5252
  if (cloudPayload !== null) {
@@ -5433,6 +5492,107 @@ async function handleConciergeDispatch(deps, rawInput, _signal) {
5433
5492
 
5434
5493
  // src/server.ts
5435
5494
  init_sync_config();
5495
+
5496
+ // src/tools/memory/private-knowledge.ts
5497
+ init_common();
5498
+ var UPSERT_TOOL_NAME = "vo_private_knowledge_upsert";
5499
+ var CONTEXT_TOOL_NAME = "vo_private_knowledge_context";
5500
+ var KNOWLEDGE_CLASSES = ["memory", "skill", "doctrine", "hook", "command"];
5501
+ var PRECISION_CHAR_BUDGET = 12e3;
5502
+ var upsertInputSchema = {
5503
+ type: "object",
5504
+ properties: {
5505
+ knowledge_class: { type: "string", enum: KNOWLEDGE_CLASSES },
5506
+ source_path: { type: "string", description: "Stable private source identifier; not exposed to other users." },
5507
+ title: { type: "string", description: 'Descriptive, retrieval-friendly title (e.g. "AlgoTax OCR redaction architecture", not "notes") \u2014 retrieval matches on it.' },
5508
+ 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." }
5509
+ },
5510
+ required: ["knowledge_class", "source_path", "title", "content"],
5511
+ additionalProperties: false
5512
+ };
5513
+ var contextInputSchema = {
5514
+ type: "object",
5515
+ properties: {
5516
+ query: { type: "string" },
5517
+ limit: { type: "number", minimum: 1, maximum: 50 },
5518
+ knowledge_class: { type: "string", enum: KNOWLEDGE_CLASSES }
5519
+ },
5520
+ required: ["query"],
5521
+ additionalProperties: false
5522
+ };
5523
+ 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.";
5524
+ 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.";
5525
+ function isKnowledgeClass(value) {
5526
+ return typeof value === "string" && KNOWLEDGE_CLASSES.includes(value);
5527
+ }
5528
+ function isUpsertInput(value) {
5529
+ if (typeof value !== "object" || value === null) return false;
5530
+ const input = value;
5531
+ return isKnowledgeClass(input["knowledge_class"]) && typeof input["source_path"] === "string" && typeof input["title"] === "string" && typeof input["content"] === "string";
5532
+ }
5533
+ function isContextInput(value) {
5534
+ if (typeof value !== "object" || value === null) return false;
5535
+ const input = value;
5536
+ if (typeof input["query"] !== "string") return false;
5537
+ if (input["limit"] !== void 0 && typeof input["limit"] !== "number") return false;
5538
+ if (input["knowledge_class"] !== void 0 && !isKnowledgeClass(input["knowledge_class"])) return false;
5539
+ return true;
5540
+ }
5541
+ async function getCloudAuth(fetchFn) {
5542
+ const controlPlaneUrl = process.env["VO_CONTROL_PLANE_URL"]?.replace(/\/+$/, "");
5543
+ if (!controlPlaneUrl) {
5544
+ return { ok: false, reason: "VO_CONTROL_PLANE_URL not set \u2014 cloud mode disabled" };
5545
+ }
5546
+ const { createAuthTokenSourceFromEnv: createAuthTokenSourceFromEnv2 } = await Promise.resolve().then(() => (init_auth_token_source(), auth_token_source_exports));
5547
+ const { readStoredCredential: readStoredCredential2 } = await Promise.resolve().then(() => (init_credential_store(), credential_store_exports));
5548
+ const tokenSource = createAuthTokenSourceFromEnv2(process.env, fetchFn, () => readStoredCredential2(process.env));
5549
+ if (!tokenSource) return { ok: false, reason: "No auth configured. Run `vo-mcp login`." };
5550
+ const token = await tokenSource.getToken();
5551
+ if (!token) return { ok: false, reason: "Failed to obtain auth token. Run `vo-mcp login` again." };
5552
+ return { ok: true, controlPlaneUrl, token };
5553
+ }
5554
+ async function callPrivateKnowledge(path3, body, fetchFn) {
5555
+ const auth = await getCloudAuth(fetchFn);
5556
+ if (!auth.ok) return { ok: false, reason: auth.reason };
5557
+ const response = await fetchFn(`${auth.controlPlaneUrl}${path3}`, {
5558
+ method: "POST",
5559
+ headers: {
5560
+ authorization: `Bearer ${auth.token}`,
5561
+ "content-type": "application/json"
5562
+ },
5563
+ body: JSON.stringify(body)
5564
+ });
5565
+ const text = await response.text();
5566
+ const parsed = text ? JSON.parse(text) : null;
5567
+ if (response.status < 200 || response.status >= 300) {
5568
+ return { ok: false, status: response.status, response: parsed ?? text };
5569
+ }
5570
+ return parsed;
5571
+ }
5572
+ async function handlePrivateKnowledgeUpsert(_deps, rawInput, _signal, fetchFn = globalThis.fetch) {
5573
+ if (!isUpsertInput(rawInput)) {
5574
+ throw invalidParams(UPSERT_TOOL_NAME, "expected { knowledge_class, source_path, title, content }.");
5575
+ }
5576
+ const payload = await callPrivateKnowledge("/api/v1/knowledge/private", rawInput, fetchFn);
5577
+ const envelope = {
5578
+ tool: UPSERT_TOOL_NAME,
5579
+ schema_version: 1,
5580
+ payload
5581
+ };
5582
+ if (rawInput.content.length > PRECISION_CHAR_BUDGET) {
5583
+ 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}.`;
5584
+ }
5585
+ return jsonContent(envelope);
5586
+ }
5587
+ async function handlePrivateKnowledgeContext(_deps, rawInput, _signal, fetchFn = globalThis.fetch) {
5588
+ if (!isContextInput(rawInput)) {
5589
+ throw invalidParams(CONTEXT_TOOL_NAME, "expected { query, optional limit, optional knowledge_class }.");
5590
+ }
5591
+ const payload = await callPrivateKnowledge("/api/v1/knowledge/private/context", rawInput, fetchFn);
5592
+ return jsonContent({ tool: CONTEXT_TOOL_NAME, schema_version: 1, payload });
5593
+ }
5594
+
5595
+ // src/server.ts
5436
5596
  function buildToolRegistry() {
5437
5597
  return {
5438
5598
  [TOOL_NAME]: {
@@ -5610,6 +5770,22 @@ function buildToolRegistry() {
5610
5770
  inputSchema: inputSchema22
5611
5771
  },
5612
5772
  handler: handleSyncConfig
5773
+ },
5774
+ [UPSERT_TOOL_NAME]: {
5775
+ definition: {
5776
+ name: UPSERT_TOOL_NAME,
5777
+ description: upsertDescription,
5778
+ inputSchema: upsertInputSchema
5779
+ },
5780
+ handler: handlePrivateKnowledgeUpsert
5781
+ },
5782
+ [CONTEXT_TOOL_NAME]: {
5783
+ definition: {
5784
+ name: CONTEXT_TOOL_NAME,
5785
+ description: contextDescription,
5786
+ inputSchema: contextInputSchema
5787
+ },
5788
+ handler: handlePrivateKnowledgeContext
5613
5789
  }
5614
5790
  };
5615
5791
  }
@@ -5901,6 +6077,64 @@ function createNullConsensusEngineClient(reason = NULL_CLIENT_DEFAULT_REASON) {
5901
6077
  };
5902
6078
  }
5903
6079
 
6080
+ // src/consensus/meta-model-caller.ts
6081
+ var META_MODEL_API_BASE_URL = "https://api.meta.ai/v1";
6082
+ var META_CONSENSUS_MODEL = "muse-spark-1.1";
6083
+ var META_MODEL_API_KEY_ENV = "MODEL_API_KEY";
6084
+ var META_MODEL_API_KEY_ALIAS = "META_API";
6085
+ function resolveMetaKey(env) {
6086
+ return String(env[META_MODEL_API_KEY_ENV] || env[META_MODEL_API_KEY_ALIAS] || "").trim();
6087
+ }
6088
+ function positiveMaxTokens(value) {
6089
+ const parsed = Math.floor(Number(value));
6090
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 2048;
6091
+ }
6092
+ function createMetaModelCaller(options = {}) {
6093
+ const fetchImpl = options.fetchImpl ?? fetch;
6094
+ const envSource = options.envSource ?? process.env;
6095
+ const reasoningEffort = options.reasoningEffort ?? "high";
6096
+ return async function callMetaWithMetrics2(prompt, systemPrompt, model, maxTokens, _privacyOptions, signal) {
6097
+ const key = resolveMetaKey(envSource);
6098
+ if (!key) throw new Error(`Missing ${META_MODEL_API_KEY_ENV} for Meta Model API`);
6099
+ const messages = [
6100
+ ...systemPrompt ? [{ role: "system", content: systemPrompt }] : [],
6101
+ { role: "user", content: prompt }
6102
+ ];
6103
+ const response = await fetchImpl(`${META_MODEL_API_BASE_URL}/chat/completions`, {
6104
+ method: "POST",
6105
+ headers: {
6106
+ Authorization: `Bearer ${key}`,
6107
+ "Content-Type": "application/json"
6108
+ },
6109
+ body: JSON.stringify({
6110
+ model: model || META_CONSENSUS_MODEL,
6111
+ messages,
6112
+ max_tokens: positiveMaxTokens(maxTokens),
6113
+ reasoning_effort: reasoningEffort
6114
+ }),
6115
+ signal
6116
+ });
6117
+ const payload = await response.json();
6118
+ if (!response.ok) {
6119
+ const message = String(payload.error?.message || response.statusText || "request failed").slice(0, 500);
6120
+ throw Object.assign(new Error(`Meta Model API ${response.status}: ${message}`), { status: response.status });
6121
+ }
6122
+ const content = payload.choices?.[0]?.message?.content;
6123
+ if (typeof content !== "string" || !content.trim()) {
6124
+ throw new Error(`Meta Model API returned no text (finish=${payload.choices?.[0]?.finish_reason || "unknown"})`);
6125
+ }
6126
+ const inputTokens = Number(payload.usage?.prompt_tokens || 0);
6127
+ const outputTokens = Number(payload.usage?.completion_tokens || 0);
6128
+ return {
6129
+ content,
6130
+ inputTokens,
6131
+ outputTokens,
6132
+ totalTokens: Number(payload.usage?.total_tokens || inputTokens + outputTokens)
6133
+ };
6134
+ };
6135
+ }
6136
+ var callMetaWithMetrics = createMetaModelCaller();
6137
+
5904
6138
  // src/consensus/engine-options.ts
5905
6139
  var AGREEMENT_GATE_ENV_VAR = "VO_CONSENSUS_AGREEMENT_GATE";
5906
6140
  function isTruthyFlag(raw) {
@@ -6195,7 +6429,8 @@ var DEFAULT_MODELS = {
6195
6429
  // callGeminiWithMetrics; 2.5-pro REJECTS budget 0 ("only works in thinking mode").
6196
6430
  // Flash is also ~10x cheaper. 2026-06-02.
6197
6431
  google: "gemini-2.5-flash",
6198
- deepseek: "deepseek-chat"
6432
+ deepseek: "deepseek-chat",
6433
+ meta: META_CONSENSUS_MODEL
6199
6434
  };
6200
6435
  function probeProviders(env = process.env) {
6201
6436
  const out = [];
@@ -6203,6 +6438,7 @@ function probeProviders(env = process.env) {
6203
6438
  if ((env["OPENAI_API_KEY"] ?? "").trim().length > 0) out.push("openai");
6204
6439
  if ((env["GOOGLE_API_KEY"] ?? "").trim().length > 0) out.push("google");
6205
6440
  if ((env["DEEPSEEK_API_KEY"] ?? "").trim().length > 0) out.push("deepseek");
6441
+ if ((env[META_MODEL_API_KEY_ENV] ?? "").trim().length > 0 || (env[META_MODEL_API_KEY_ALIAS] ?? "").trim().length > 0) out.push("meta");
6206
6442
  return out;
6207
6443
  }
6208
6444
  async function loadFactoryAndCallers(injectedEngine, injectedShared) {
@@ -6248,21 +6484,24 @@ async function tryCreateEngineConsensusClientFromEnvAsync(options = {}) {
6248
6484
  anthropic: loaded.shared.callAnthropicWithMetrics,
6249
6485
  openai: loaded.shared.callOpenAIWithMetrics,
6250
6486
  google: loaded.shared.callGeminiWithMetrics,
6251
- deepseek: loaded.shared.callDeepSeekWithMetrics
6487
+ deepseek: loaded.shared.callDeepSeekWithMetrics,
6488
+ meta: options.metaCaller ?? callMetaWithMetrics
6252
6489
  };
6253
6490
  const modelByProvider = {
6254
6491
  anthropic: options.models?.anthropic ?? DEFAULT_MODELS.anthropic,
6255
6492
  openai: options.models?.openai ?? DEFAULT_MODELS.openai,
6256
6493
  google: options.models?.google ?? DEFAULT_MODELS.google,
6257
- deepseek: options.models?.deepseek ?? DEFAULT_MODELS.deepseek
6494
+ deepseek: options.models?.deepseek ?? DEFAULT_MODELS.deepseek,
6495
+ meta: options.models?.meta ?? DEFAULT_MODELS.meta
6258
6496
  };
6497
+ 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;
6259
6498
  const panel = [];
6260
6499
  for (const p of providers) {
6261
6500
  try {
6262
6501
  const adapter = loaded.engine.createAdapter(p, {
6263
6502
  model: modelByProvider[p],
6264
6503
  caller: callerByProvider[p],
6265
- envSource: env
6504
+ envSource: adapterEnv
6266
6505
  });
6267
6506
  panel.push(adapter);
6268
6507
  } catch {
@@ -6484,7 +6723,7 @@ async function runLogin(opts = {}) {
6484
6723
  const nowIso = opts.nowIso ?? (() => (/* @__PURE__ */ new Date()).toISOString());
6485
6724
  const openBrowser = opts.openBrowser ?? defaultOpenBrowser;
6486
6725
  const state = randomBytes(32).toString("base64url");
6487
- return new Promise((resolve, reject) => {
6726
+ return new Promise((resolve2, reject) => {
6488
6727
  let settled = false;
6489
6728
  const finish = (err, result) => {
6490
6729
  if (settled) return;
@@ -6492,7 +6731,7 @@ async function runLogin(opts = {}) {
6492
6731
  clearTimeout(timer);
6493
6732
  server.close();
6494
6733
  if (err) reject(err);
6495
- else resolve(result);
6734
+ else resolve2(result);
6496
6735
  };
6497
6736
  const server = createServer2((req, res) => {
6498
6737
  const url = new URL(req.url ?? "/", "http://127.0.0.1");