@algosuite/vo-mcp 0.2.0-beta.7 → 0.2.0-beta.9

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/index.js CHANGED
@@ -5249,6 +5249,148 @@ async function handlePrivateKnowledgeContext(_deps, rawInput, _signal, fetchFn =
5249
5249
  return jsonContent({ tool: CONTEXT_TOOL_NAME, schema_version: 1, payload });
5250
5250
  }
5251
5251
 
5252
+ // src/tools/hq/whiteboard.ts
5253
+ init_auth_token_source();
5254
+ init_credential_store();
5255
+ var POST_TOOL_NAME = "hq_whiteboard_post";
5256
+ var READ_TOOL_NAME = "hq_whiteboard_read";
5257
+ var postDescription = "Post an append-only coordination note to the live AlgoHQ whiteboard. Uses the scoped credential from vo-mcp login; operator and tenant ownership are derived by the server.";
5258
+ var readDescription = "Read recent coordination notes from the caller's live AlgoHQ whiteboard. Uses the scoped credential from vo-mcp login and cannot widen tenant scope.";
5259
+ var postInputSchema = {
5260
+ type: "object",
5261
+ properties: {
5262
+ from: { type: "string", minLength: 1, maxLength: 100, description: "Agent/session display name." },
5263
+ type: { type: "string", minLength: 1, maxLength: 64, description: "Message kind, such as intent, worklog, blocker, or completion." },
5264
+ content: { type: "string", minLength: 1, maxLength: 500, description: "Short coordination note." },
5265
+ targetAgent: { type: "string", maxLength: 100 },
5266
+ tester: { type: "string", maxLength: 100 },
5267
+ tier: { type: "string", maxLength: 32 }
5268
+ },
5269
+ required: ["from", "type", "content"],
5270
+ additionalProperties: false
5271
+ };
5272
+ var readInputSchema = {
5273
+ type: "object",
5274
+ properties: {
5275
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
5276
+ since: { type: "string", description: "Optional ISO-8601 lower bound." },
5277
+ type: { type: "string", minLength: 1, maxLength: 64 }
5278
+ },
5279
+ additionalProperties: false
5280
+ };
5281
+ function resolveTimeoutMs() {
5282
+ const parsed = Number(process.env["HQ_WHITEBOARD_TIMEOUT_MS"]);
5283
+ return Number.isFinite(parsed) && parsed >= 10 && parsed <= 12e4 ? parsed : 1e4;
5284
+ }
5285
+ function isRecord(value) {
5286
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5287
+ }
5288
+ function onlyKeys(value, allowed) {
5289
+ return Object.keys(value).every((key) => allowed.includes(key));
5290
+ }
5291
+ function isBoundedString(value, min, max) {
5292
+ return typeof value === "string" && value.trim().length >= min && value.trim().length <= max;
5293
+ }
5294
+ function parsePostInput(value) {
5295
+ if (!isRecord(value) || !onlyKeys(value, ["from", "type", "content", "targetAgent", "tester", "tier"])) return null;
5296
+ if (!isBoundedString(value["from"], 1, 100)) return null;
5297
+ if (!isBoundedString(value["type"], 1, 64) || !/^[a-zA-Z0-9_-]+$/.test(value["type"].trim())) return null;
5298
+ if (!isBoundedString(value["content"], 1, 500)) return null;
5299
+ for (const [key, max] of [["targetAgent", 100], ["tester", 100], ["tier", 32]]) {
5300
+ if (value[key] !== void 0 && !isBoundedString(value[key], 0, max)) return null;
5301
+ }
5302
+ return {
5303
+ from: value["from"].trim(),
5304
+ type: value["type"].trim(),
5305
+ content: value["content"].trim(),
5306
+ ...typeof value["targetAgent"] === "string" ? { targetAgent: value["targetAgent"].trim() } : {},
5307
+ ...typeof value["tester"] === "string" ? { tester: value["tester"].trim() } : {},
5308
+ ...typeof value["tier"] === "string" ? { tier: value["tier"].trim() } : {}
5309
+ };
5310
+ }
5311
+ function parseReadInput(value) {
5312
+ if (!isRecord(value) || !onlyKeys(value, ["limit", "since", "type"])) return null;
5313
+ if (value["limit"] !== void 0 && (!Number.isInteger(value["limit"]) || Number(value["limit"]) < 1 || Number(value["limit"]) > 100)) return null;
5314
+ if (value["since"] !== void 0 && (typeof value["since"] !== "string" || Number.isNaN(Date.parse(value["since"])))) return null;
5315
+ if (value["type"] !== void 0 && !isBoundedString(value["type"], 1, 64)) return null;
5316
+ return {
5317
+ ...typeof value["limit"] === "number" ? { limit: value["limit"] } : {},
5318
+ ...typeof value["since"] === "string" ? { since: value["since"] } : {},
5319
+ ...typeof value["type"] === "string" ? { type: value["type"].trim() } : {}
5320
+ };
5321
+ }
5322
+ async function resolveCloud(fetchFn) {
5323
+ const url = process.env["VO_CONTROL_PLANE_URL"]?.trim().replace(/\/$/, "");
5324
+ if (!url) return null;
5325
+ try {
5326
+ const source = createAuthTokenSourceFromEnv(process.env, fetchFn, () => readStoredCredential(process.env));
5327
+ const token = await source?.getToken();
5328
+ return token ? { url, token } : null;
5329
+ } catch {
5330
+ return null;
5331
+ }
5332
+ }
5333
+ async function callWhiteboard(method, bodyOrQuery, signal, fetchFn = fetch) {
5334
+ const cloud = await resolveCloud(fetchFn);
5335
+ if (!cloud) {
5336
+ return {
5337
+ ok: false,
5338
+ error: "hq_whiteboard_not_configured",
5339
+ message: "Set VO_CONTROL_PLANE_URL and run vo-mcp login to install a scoped HQ credential."
5340
+ };
5341
+ }
5342
+ const timeoutSignal = AbortSignal.timeout(resolveTimeoutMs());
5343
+ const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
5344
+ const query = new URLSearchParams();
5345
+ if (method === "GET") {
5346
+ const input = bodyOrQuery;
5347
+ query.set("limit", String(input.limit ?? 25));
5348
+ if (input.since) query.set("since", input.since);
5349
+ if (input.type) query.set("type", input.type);
5350
+ }
5351
+ try {
5352
+ const response = await fetchFn(
5353
+ `${cloud.url}/api/v1/hq/whiteboard/messages${query.size ? `?${query}` : ""}`,
5354
+ {
5355
+ method,
5356
+ headers: {
5357
+ Authorization: `Bearer ${cloud.token}`,
5358
+ ...method === "POST" ? { "Content-Type": "application/json" } : {}
5359
+ },
5360
+ ...method === "POST" ? { body: JSON.stringify(bodyOrQuery) } : {},
5361
+ signal: requestSignal
5362
+ }
5363
+ );
5364
+ const text = await response.text();
5365
+ let payload;
5366
+ try {
5367
+ payload = JSON.parse(text);
5368
+ } catch {
5369
+ payload = { ok: false, error: "invalid_response", message: text.slice(0, 200) };
5370
+ }
5371
+ if (!response.ok) {
5372
+ return { ok: false, error: "hq_whiteboard_http_error", status: response.status, response: payload };
5373
+ }
5374
+ return payload;
5375
+ } catch (error) {
5376
+ return {
5377
+ ok: false,
5378
+ error: signal?.aborted ? "cancelled" : timeoutSignal.aborted ? "hq_whiteboard_timeout" : "hq_whiteboard_unreachable",
5379
+ message: error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200)
5380
+ };
5381
+ }
5382
+ }
5383
+ async function handleHqWhiteboardPost(_deps, rawInput, signal) {
5384
+ const input = parsePostInput(rawInput);
5385
+ if (!input) throw invalidParams(POST_TOOL_NAME, "requires from, type, and 1-500 character content; unknown fields are rejected");
5386
+ return jsonContent(await callWhiteboard("POST", input, signal));
5387
+ }
5388
+ async function handleHqWhiteboardRead(_deps, rawInput, signal) {
5389
+ const input = parseReadInput(rawInput);
5390
+ if (!input) throw invalidParams(READ_TOOL_NAME, "limit must be 1-100, since must be ISO-8601, and unknown fields are rejected");
5391
+ return jsonContent(await callWhiteboard("GET", input, signal));
5392
+ }
5393
+
5252
5394
  // src/server.ts
5253
5395
  function buildToolRegistry() {
5254
5396
  return {
@@ -5443,6 +5585,22 @@ function buildToolRegistry() {
5443
5585
  inputSchema: contextInputSchema
5444
5586
  },
5445
5587
  handler: handlePrivateKnowledgeContext
5588
+ },
5589
+ [POST_TOOL_NAME]: {
5590
+ definition: {
5591
+ name: POST_TOOL_NAME,
5592
+ description: postDescription,
5593
+ inputSchema: postInputSchema
5594
+ },
5595
+ handler: handleHqWhiteboardPost
5596
+ },
5597
+ [READ_TOOL_NAME]: {
5598
+ definition: {
5599
+ name: READ_TOOL_NAME,
5600
+ description: readDescription,
5601
+ inputSchema: readInputSchema
5602
+ },
5603
+ handler: handleHqWhiteboardRead
5446
5604
  }
5447
5605
  };
5448
5606
  }
@@ -5935,6 +6093,9 @@ function createClaimClassifier(model, options = {}) {
5935
6093
  };
5936
6094
  }
5937
6095
 
6096
+ // src/constants/consensus-models.ts
6097
+ var XAI_CONSENSUS_MODEL = "grok-4.5";
6098
+
5938
6099
  // src/consensus/engine-client.ts
5939
6100
  function raceAbort(signal) {
5940
6101
  return new Promise((_, reject) => {
@@ -6085,6 +6246,7 @@ var DEFAULT_MODELS = {
6085
6246
  // Flash is also ~10x cheaper. 2026-06-02.
6086
6247
  google: "gemini-2.5-flash",
6087
6248
  deepseek: "deepseek-chat",
6249
+ xai: XAI_CONSENSUS_MODEL,
6088
6250
  meta: META_CONSENSUS_MODEL
6089
6251
  };
6090
6252
  function probeProviders(env = process.env) {
@@ -6093,6 +6255,7 @@ function probeProviders(env = process.env) {
6093
6255
  if ((env["OPENAI_API_KEY"] ?? "").trim().length > 0) out.push("openai");
6094
6256
  if ((env["GOOGLE_API_KEY"] ?? "").trim().length > 0) out.push("google");
6095
6257
  if ((env["DEEPSEEK_API_KEY"] ?? "").trim().length > 0) out.push("deepseek");
6258
+ if ((env["XAI_API_KEY"] ?? "").trim().length > 0) out.push("xai");
6096
6259
  if ((env[META_MODEL_API_KEY_ENV] ?? "").trim().length > 0 || (env[META_MODEL_API_KEY_ALIAS] ?? "").trim().length > 0) out.push("meta");
6097
6260
  return out;
6098
6261
  }
@@ -6116,7 +6279,7 @@ async function loadFactoryAndCallers(injectedEngine, injectedShared) {
6116
6279
  return { ok: false, reason: ENGINE_UNAVAILABLE_REASONS.FUNCTIONS_SHARED_NOT_INSTALLED };
6117
6280
  }
6118
6281
  }
6119
- if (sharedMod === null || typeof sharedMod !== "object" || typeof sharedMod.callAnthropicWithMetrics !== "function" || typeof sharedMod.callOpenAIWithMetrics !== "function" || typeof sharedMod.callGeminiWithMetrics !== "function") {
6282
+ if (sharedMod === null || typeof sharedMod !== "object" || typeof sharedMod.callAnthropicWithMetrics !== "function" || typeof sharedMod.callOpenAIWithMetrics !== "function" || typeof sharedMod.callGeminiWithMetrics !== "function" || typeof sharedMod.callXAIWithMetrics !== "function") {
6120
6283
  return { ok: false, reason: ENGINE_UNAVAILABLE_REASONS.FUNCTIONS_SHARED_NOT_INSTALLED };
6121
6284
  }
6122
6285
  return {
@@ -6140,6 +6303,7 @@ async function tryCreateEngineConsensusClientFromEnvAsync(options = {}) {
6140
6303
  openai: loaded.shared.callOpenAIWithMetrics,
6141
6304
  google: loaded.shared.callGeminiWithMetrics,
6142
6305
  deepseek: loaded.shared.callDeepSeekWithMetrics,
6306
+ xai: loaded.shared.callXAIWithMetrics,
6143
6307
  meta: options.metaCaller ?? callMetaWithMetrics
6144
6308
  };
6145
6309
  const modelByProvider = {
@@ -6147,6 +6311,7 @@ async function tryCreateEngineConsensusClientFromEnvAsync(options = {}) {
6147
6311
  openai: options.models?.openai ?? DEFAULT_MODELS.openai,
6148
6312
  google: options.models?.google ?? DEFAULT_MODELS.google,
6149
6313
  deepseek: options.models?.deepseek ?? DEFAULT_MODELS.deepseek,
6314
+ xai: options.models?.xai ?? DEFAULT_MODELS.xai,
6150
6315
  meta: options.models?.meta ?? DEFAULT_MODELS.meta
6151
6316
  };
6152
6317
  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;