negotium 0.5.4 → 0.5.6

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/main.js CHANGED
@@ -1874,7 +1874,7 @@ var exports_version = {};
1874
1874
  __export(exports_version, {
1875
1875
  NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
1876
1876
  });
1877
- var NEGOTIUM_VERSION = "0.5.4";
1877
+ var NEGOTIUM_VERSION = "0.5.6";
1878
1878
 
1879
1879
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
1880
1880
  import { spawn } from "child_process";
@@ -16450,6 +16450,21 @@ function deleteTopicVisuals(topicId) {
16450
16450
  return { visuals, views };
16451
16451
  })();
16452
16452
  }
16453
+ function getPortableTopicVisual(topicId, vizId) {
16454
+ const row = db.query("SELECT * FROM api_topic_visuals WHERE id = ? AND topic_id = ?").get(vizId, topicId);
16455
+ if (!row)
16456
+ return null;
16457
+ return {
16458
+ id: row.id,
16459
+ kind: normalizeVisualKind(row.kind),
16460
+ title: row.title,
16461
+ html: row.html,
16462
+ source: row.source,
16463
+ fileId: row.file_id,
16464
+ mimeType: row.mime_type,
16465
+ createdAt: row.created_at
16466
+ };
16467
+ }
16453
16468
  function topicVisualUrl(topicId, vizId) {
16454
16469
  return `/api/v1/topics/${encodeURIComponent(topicId)}/visual/${vizId}/html`;
16455
16470
  }
@@ -16746,6 +16761,41 @@ var init_token_stats = __esm(async () => {
16746
16761
  };
16747
16762
  });
16748
16763
 
16764
+ // ../../packages/core/src/storage/topic-tool-capabilities.ts
16765
+ function getTopicToolCapabilities(topicId) {
16766
+ const row = db.query(`SELECT visual_tools, file_delivery_tools
16767
+ FROM api_topic_tool_capabilities WHERE topic_id = ?`).get(topicId);
16768
+ if (!row)
16769
+ return null;
16770
+ return {
16771
+ visualTools: row.visual_tools === 1,
16772
+ fileDeliveryTools: row.file_delivery_tools === 1
16773
+ };
16774
+ }
16775
+ function recordTopicToolCapabilities(topicId, capabilities) {
16776
+ db.query(`INSERT INTO api_topic_tool_capabilities
16777
+ (topic_id, visual_tools, file_delivery_tools, updated_at)
16778
+ VALUES (?, ?, ?, ?)
16779
+ ON CONFLICT(topic_id) DO UPDATE SET
16780
+ visual_tools = excluded.visual_tools,
16781
+ file_delivery_tools = excluded.file_delivery_tools,
16782
+ updated_at = excluded.updated_at`).run(topicId, capabilities.visualTools ? 1 : 0, capabilities.fileDeliveryTools ? 1 : 0, new Date().toISOString());
16783
+ }
16784
+ function deleteTopicToolCapabilities(topicId) {
16785
+ db.query("DELETE FROM api_topic_tool_capabilities WHERE topic_id = ?").run(topicId);
16786
+ }
16787
+ var init_topic_tool_capabilities = __esm(async () => {
16788
+ await init_forum_db();
16789
+ db.exec(`
16790
+ CREATE TABLE IF NOT EXISTS api_topic_tool_capabilities (
16791
+ topic_id TEXT PRIMARY KEY,
16792
+ visual_tools INTEGER NOT NULL DEFAULT 0,
16793
+ file_delivery_tools INTEGER NOT NULL DEFAULT 0,
16794
+ updated_at TEXT NOT NULL
16795
+ )
16796
+ `);
16797
+ });
16798
+
16749
16799
  // ../../packages/core/src/topics/lifecycle.ts
16750
16800
  var exports_lifecycle = {};
16751
16801
  __export(exports_lifecycle, {
@@ -16896,6 +16946,7 @@ async function deleteTopicCascadeImpl(topic, userId, options, deletingAncestorId
16896
16946
  logger.warn({ err: err2, topicId, cwd }, "deleteTopicCascade: workspace cleanup failed");
16897
16947
  }
16898
16948
  deleteTopicVisuals(topicId);
16949
+ deleteTopicToolCapabilities(topicId);
16899
16950
  deleteTopicArchiveState(topicId);
16900
16951
  deleteMessagesForTopic(topicId);
16901
16952
  deleteApiTopicConfig(topicId);
@@ -16953,6 +17004,7 @@ var init_lifecycle = __esm(async () => {
16953
17004
  await init_token_stats();
16954
17005
  await init_topic_archive();
16955
17006
  await init_topic_archive_state();
17007
+ await init_topic_tool_capabilities();
16956
17008
  TopicArchiveRequiredError = class TopicArchiveRequiredError extends Error {
16957
17009
  code = "TOPIC_ARCHIVE_FAILED";
16958
17010
  topicId;
@@ -17594,7 +17646,7 @@ function isVisualsShowMermaidTool(name) {
17594
17646
  return isRuntimeTool(name, "show_mermaid");
17595
17647
  }
17596
17648
  function isVisualsShowImageTool(name) {
17597
- return isRuntimeTool(name, "show_image");
17649
+ return isRuntimeTool(name, "show_image") || isRuntimeTool(name, "show_png");
17598
17650
  }
17599
17651
  function isVisualsShowVideoTool(name) {
17600
17652
  return isRuntimeTool(name, "show_video");
@@ -18966,8 +19018,9 @@ function startAiTurn(params) {
18966
19018
  const cwd = params.cwd;
18967
19019
  const sessionName = params.sessionName ?? topic.title;
18968
19020
  const sessionType = params.sessionType;
18969
- const visualTools = params.visualTools === true;
18970
- const fileDeliveryTools = params.fileDeliveryTools === true;
19021
+ const grantedForTopic = params.visualTools === undefined || params.fileDeliveryTools === undefined ? getTopicToolCapabilities(topicId) : null;
19022
+ const visualTools = params.visualTools ?? grantedForTopic?.visualTools ?? false;
19023
+ const fileDeliveryTools = params.fileDeliveryTools ?? grantedForTopic?.fileDeliveryTools ?? false;
18971
19024
  const onSessionId = params.onSessionId;
18972
19025
  const onSessionReset = params.onSessionReset;
18973
19026
  const bridgeSessionFromHistory = params.bridgeSessionFromHistory === true;
@@ -19717,6 +19770,7 @@ var init_turn_runner = __esm(async () => {
19717
19770
  await init_runtime_leases();
19718
19771
  await init_runtime_topic_state();
19719
19772
  await init_runtime_turn_requests();
19773
+ await init_topic_tool_capabilities();
19720
19774
  await init_wiki();
19721
19775
  init_wiki_summary_names();
19722
19776
  await init_derive();
@@ -20754,6 +20808,10 @@ function submitRuntimeGatewayTurn(params) {
20754
20808
  if (existing) {
20755
20809
  return duplicateResult(existing, params, requestId, actorUserId, payloadHash);
20756
20810
  }
20811
+ recordTopicToolCapabilities(params.topic.id, {
20812
+ visualTools: params.visualTools === true,
20813
+ fileDeliveryTools: params.fileDeliveryTools === true
20814
+ });
20757
20815
  const createdAt = new Date().toISOString();
20758
20816
  const attachments2 = params.attachments?.map(resolveAttachmentByFileId);
20759
20817
  if (attachments2?.some((attachment) => !attachment)) {
@@ -20806,6 +20864,8 @@ function submitRuntimeGatewayTurn(params) {
20806
20864
  conversationPrompts: [params.text],
20807
20865
  loggedUserMessageCount: 0,
20808
20866
  vaultUserId: params.vaultUserId,
20867
+ visualTools: params.visualTools,
20868
+ fileDeliveryTools: params.fileDeliveryTools,
20809
20869
  ...params.threadRootId ? { threadRootId: params.threadRootId } : {}
20810
20870
  }
20811
20871
  });
@@ -20850,6 +20910,7 @@ var init_submit_runtime_gateway_turn = __esm(async () => {
20850
20910
  await init_runtime_leases();
20851
20911
  await init_runtime_topic_state();
20852
20912
  await init_runtime_turn_requests();
20913
+ await init_topic_tool_capabilities();
20853
20914
  RuntimeGatewayIdempotencyConflictError = class RuntimeGatewayIdempotencyConflictError extends Error {
20854
20915
  constructor(message = "clientMessageId or requestId is already bound to another turn") {
20855
20916
  super(message);
@@ -20861,6 +20922,10 @@ var init_submit_runtime_gateway_turn = __esm(async () => {
20861
20922
  // ../../packages/core/src/application/submit-user-message.ts
20862
20923
  import { randomUUID as randomUUID18 } from "crypto";
20863
20924
  function submitUserMessage(params) {
20925
+ recordTopicToolCapabilities(params.topic.id, {
20926
+ visualTools: params.visualTools === true,
20927
+ fileDeliveryTools: params.fileDeliveryTools === true
20928
+ });
20864
20929
  const message = {
20865
20930
  id: randomUUID18(),
20866
20931
  topicId: params.topic.id,
@@ -20886,6 +20951,7 @@ var init_submit_user_message = __esm(async () => {
20886
20951
  await init_bus();
20887
20952
  await init_turn_runner();
20888
20953
  await init_api_messages();
20954
+ await init_topic_tool_capabilities();
20889
20955
  });
20890
20956
 
20891
20957
  // ../../packages/core/src/application/switch-topic-effort.ts
@@ -23662,6 +23728,7 @@ __export(exports_node_host, {
23662
23728
  getVisibleTopics: () => getVisibleTopics,
23663
23729
  getTopicStats: () => getTopicStats,
23664
23730
  getTopic: () => getTopic,
23731
+ getPortableTopicVisual: () => getPortableTopicVisual,
23665
23732
  getLastMessagePreviews: () => getLastMessagePreviews,
23666
23733
  getGlobalAiName: () => getGlobalAiName,
23667
23734
  getApiMessage: () => getApiMessage,
@@ -23717,6 +23784,7 @@ var init_node_host = __esm(async () => {
23717
23784
  init_file_hooks();
23718
23785
  await init_inbox();
23719
23786
  await init_turn_runner();
23787
+ await init_visual_store();
23720
23788
  await init_api_messages();
23721
23789
  await init_api_topics();
23722
23790
  await init_app_settings();
@@ -23978,12 +24046,25 @@ var init_publish_html = __esm(() => {
23978
24046
  MAX_PUBLISHED_ASSET_BYTES = 5 * 1024 * 1024;
23979
24047
  });
23980
24048
 
24049
+ // ../../packages/core/src/agents/mcp-tools/visual-compat.ts
24050
+ var showPngTool;
24051
+ var init_visual_compat = __esm(() => {
24052
+ init_visuals2();
24053
+ showPngTool = {
24054
+ name: "show_png",
24055
+ description: "Backward-compatible alias for show_image. Display a PNG or other image from this topic's workspace or an uploaded file in the visual side panel.",
24056
+ schema: showImageTool.schema,
24057
+ handler: showImageTool.handler
24058
+ };
24059
+ });
24060
+
23981
24061
  // ../../packages/core/src/mcp-runtime-host.ts
23982
24062
  var exports_mcp_runtime_host = {};
23983
24063
  __export(exports_mcp_runtime_host, {
23984
24064
  visualToolDefinitions: () => visualToolDefinitions,
23985
24065
  textResult: () => textResult,
23986
24066
  storeLocalFileAsUpload: () => storeLocalFileAsUpload,
24067
+ showPngTool: () => showPngTool,
23987
24068
  sessionInboxPath: () => sessionInboxPath,
23988
24069
  restartTopicSession: () => restartTopicSession,
23989
24070
  resolveRuntimeMcpToken: () => resolveRuntimeMcpToken,
@@ -24038,6 +24119,7 @@ var init_mcp_runtime_host = __esm(async () => {
24038
24119
  init_publish_html();
24039
24120
  await init_self_config();
24040
24121
  await init_spawn_subagent();
24122
+ init_visual_compat();
24041
24123
  init_visuals2();
24042
24124
  await init_bus();
24043
24125
  init_runtime_spec();
@@ -28709,7 +28791,7 @@ function appendAutoContinue(ctx, field) {
28709
28791
  function buildNegotiumMcpServer(ctx) {
28710
28792
  const server = new McpServer8({ name: RUNTIME_MCP_KEY, version: "1.0.0" });
28711
28793
  if (ctx.visualTools === true) {
28712
- for (const def of visualToolDefinitions) {
28794
+ for (const def of [...visualToolDefinitions, showPngTool]) {
28713
28795
  const handler = ctx.peerBridge && (def.name === "show_html" || def.name === "show_mermaid") ? async () => textResult("Visual queued for ordered display on the canonical hub.") : def.handler;
28714
28796
  server.tool(def.name, def.description, def.schema, handler);
28715
28797
  }
@@ -30217,7 +30299,8 @@ function createNodeControlHandler(options) {
30217
30299
  "canonical-topic-abort",
30218
30300
  "canonical-session-reset",
30219
30301
  "canonical-session-compact",
30220
- "canonical-input-files"
30302
+ "canonical-input-files",
30303
+ "canonical-ask-answer"
30221
30304
  ],
30222
30305
  cursor: latestRuntimeEventSeq()
30223
30306
  });
@@ -30295,6 +30378,8 @@ function createNodeControlHandler(options) {
30295
30378
  requestId,
30296
30379
  allowAutoContinue: body.allowAutoContinue !== false,
30297
30380
  respond: body.respond !== false,
30381
+ visualTools: body.visualTools === true,
30382
+ fileDeliveryTools: body.fileDeliveryTools === true,
30298
30383
  ...attachments2.length ? { attachments: attachments2 } : {},
30299
30384
  ...threadRootId ? { threadRootId } : {}
30300
30385
  });
@@ -30477,6 +30562,52 @@ function createNodeControlHandler(options) {
30477
30562
  result: result.text
30478
30563
  });
30479
30564
  }
30565
+ const runtimeAskAnswerMatch = runtimePath.match(/^\/topics\/([^/]+)\/messages\/([^/]+)\/ask-answer$/);
30566
+ if (runtimeAskAnswerMatch && req.method === "POST") {
30567
+ const body = await bodyRecord(req);
30568
+ if (body.v !== NODE_RUNTIME_CONTRACT_VERSION)
30569
+ return jsonError(400, "Unsupported v");
30570
+ const topicId = decodeURIComponent(runtimeAskAnswerMatch[1]);
30571
+ const messageId = decodeURIComponent(runtimeAskAnswerMatch[2]);
30572
+ const topic = getTopic(topicId);
30573
+ if (!topic || !topicInRequestScope(req, topic))
30574
+ return jsonError(404, "Topic not found");
30575
+ const userId = requiredText(body.userId, "userId");
30576
+ const label = requiredText(body.label, "label");
30577
+ const answered = topicService.answerQuestion(topicId, messageId, label, userId);
30578
+ if (!answered.ok)
30579
+ return jsonError(409, answered.error);
30580
+ return Response.json({
30581
+ ok: true,
30582
+ v: NODE_RUNTIME_CONTRACT_VERSION,
30583
+ queryId: answered.queryId,
30584
+ answerMessage: answered.answerMessage
30585
+ });
30586
+ }
30587
+ const runtimeVisualMatch = runtimePath.match(/^\/topics\/([^/]+)\/visuals\/(\d+)$/);
30588
+ if (runtimeVisualMatch && req.method === "GET") {
30589
+ const topicId = decodeURIComponent(runtimeVisualMatch[1]);
30590
+ const topic = getTopic(topicId);
30591
+ if (!topic || !topicInRequestScope(req, topic))
30592
+ return jsonError(404, "Topic not found");
30593
+ const visual = getPortableTopicVisual(topicId, Number(runtimeVisualMatch[2]));
30594
+ if (!visual)
30595
+ return jsonError(404, "Visual not found");
30596
+ return Response.json({ ok: true, v: NODE_RUNTIME_CONTRACT_VERSION, visual });
30597
+ }
30598
+ const runtimeFileMatch = runtimePath.match(/^\/topics\/([^/]+)\/files\/([0-9a-f-]+)$/i);
30599
+ if (runtimeFileMatch && req.method === "GET") {
30600
+ const topicId = decodeURIComponent(runtimeFileMatch[1]);
30601
+ const fileId = runtimeFileMatch[2];
30602
+ const topic = getTopic(topicId);
30603
+ if (!topic || !topicInRequestScope(req, topic))
30604
+ return jsonError(404, "Topic not found");
30605
+ const userId = requiredText(url.searchParams.get("user"), "user");
30606
+ if (!nodeFileStore.allows(fileId, { topicId, ownerUserId: userId })) {
30607
+ return jsonError(404, "File not found");
30608
+ }
30609
+ return nodeFileStore.response(fileId, userId) ?? jsonError(404, "File not found");
30610
+ }
30480
30611
  const runtimeTopicMatch = runtimePath.match(/^\/topics\/([^/]+)$/);
30481
30612
  if (runtimeTopicMatch && req.method === "GET") {
30482
30613
  const topic = getTopic(decodeURIComponent(runtimeTopicMatch[1]));
@@ -45622,6 +45753,8 @@ function allowedRuntimePath(path, method) {
45622
45753
  return true;
45623
45754
  if (path === "/topics")
45624
45755
  return true;
45756
+ if (/^\/topics\/[^/]+\/messages\/[^/]+\/ask-answer$/.test(path))
45757
+ return true;
45625
45758
  return /^\/topics\/[^/]+\/(abort|session\/(reset|compact))$/.test(path);
45626
45759
  }
45627
45760
  if (method === "DELETE" || method === "PATCH")
@@ -47673,4 +47806,4 @@ switch (command) {
47673
47806
  }
47674
47807
  }
47675
47808
 
47676
- //# debugId=5BB48E6D3A61C9D764756E2164756E21
47809
+ //# debugId=C3629018DFB7C36C64756E2164756E21