@barivia/barmesh-mcp 0.7.1 → 0.8.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.
@@ -16,6 +16,48 @@ export function isKernelTrainingComplete(data, status) {
16
16
  return true;
17
17
  return status === "completed";
18
18
  }
19
+ /**
20
+ * True only for actual FLooP / FLOOP_SIOM jobs.
21
+ * Do NOT infer from "ordering-only" curve shape — mesh_convergence generic/pitz
22
+ * presets use epochs=[N,0] (regular SOM ordering, no convergence phase).
23
+ */
24
+ export function isFloopJob(data) {
25
+ const phase = String(data.training_progress_phase ?? data.progress_phase ?? "").toLowerCase();
26
+ if (phase === "floop")
27
+ return true;
28
+ const jt = String(data.job_type ?? data._job_type ?? "").toLowerCase();
29
+ if (jt.includes("floop"))
30
+ return true;
31
+ const rc = data.run_config;
32
+ if (rc && typeof rc === "object") {
33
+ const model = String(rc.model ?? "").toLowerCase();
34
+ if (model.includes("floop"))
35
+ return true;
36
+ }
37
+ const model = String(data.model ?? "").toLowerCase();
38
+ if (model.includes("floop"))
39
+ return true;
40
+ return false;
41
+ }
42
+ /** Axis / series labels keyed by actual training type (SOM batch steps vs FLooP). */
43
+ export function curveAxisLabel(data) {
44
+ return isFloopJob(data) ? "FLooP step" : "Batch sample";
45
+ }
46
+ export function qeSeriesLabel(data, phase) {
47
+ if (phase === "floop" || isFloopJob(data))
48
+ return "QE (FLooP steps)";
49
+ if (phase === "convergence")
50
+ return "QE convergence";
51
+ return "QE ordering";
52
+ }
53
+ export function teSeriesLabel(data, phase) {
54
+ const base = phase === "floop" || isFloopJob(data)
55
+ ? "TE (FLooP steps)"
56
+ : phase === "convergence"
57
+ ? "TE convergence"
58
+ : "TE ordering";
59
+ return teCurveLabel(base);
60
+ }
19
61
  export function teCurveLabel(base) {
20
62
  return `${base} (panel)`;
21
63
  }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Client-capability adaptation for barmesh MCP App tools.
3
+ * Mirrors barsom ui-delivery; uses barmesh viz paths via viz_links.
4
+ */
5
+ import { getClientSupportsMcpApps, getVizPort, } from "./shared.js";
6
+ import { buildBarmeshVizStandaloneUrl } from "./viz_links.js";
7
+ export function parseUiDeliveryOverride() {
8
+ const raw = (process.env.BARIVIA_UI_DELIVERY ?? "auto").trim().toLowerCase();
9
+ if (raw === "apps" || raw === "localhost" || raw === "inline" || raw === "auto") {
10
+ return raw;
11
+ }
12
+ return "auto";
13
+ }
14
+ function vizPortPinned() {
15
+ return Boolean(process.env.BARIVIA_VIZ_PORT?.trim());
16
+ }
17
+ function viewForTool(tool) {
18
+ return tool === "training_monitor" ? "barmesh-training-monitor" : "barmesh-results-explorer";
19
+ }
20
+ export function buildStandaloneVizUrl(view, jobId) {
21
+ return buildBarmeshVizStandaloneUrl(viewForTool(view), jobId);
22
+ }
23
+ export function buildHealthUrl(jobId) {
24
+ const port = getVizPort();
25
+ if (!port)
26
+ return undefined;
27
+ const base = `http://localhost:${port}/api/health`;
28
+ return jobId ? `${base}?job_id=${encodeURIComponent(jobId)}` : base;
29
+ }
30
+ function hintForTier(tier, tool, opts) {
31
+ const label = tool === "training_monitor" ? "training monitor" : "results explorer";
32
+ switch (tier) {
33
+ case "embedded":
34
+ return `The ${label} MCP App panel may embed. Always mention the standalone URL — some hosts list ui:// but never mount widgets.`;
35
+ case "localhost":
36
+ return opts.standaloneUrl
37
+ ? `AGENT: Post a clickable markdown link (e.g. "[Open ${label}](${opts.standaloneUrl})") — do not bury it after metrics.`
38
+ : `AGENT: Viz server unavailable — use barmesh_jobs(status) and barmesh_results(get).`;
39
+ case "inline_image":
40
+ return `AGENT: Inline raster figure(s) are attached. Summarize metrics; offer barmesh_results_explorer for more figures.`;
41
+ case "text_only":
42
+ return `AGENT: No embedded panel or localhost viz — use barmesh_jobs(status) and barmesh_results(get).`;
43
+ }
44
+ }
45
+ export function resolveUiDelivery(options) {
46
+ const override = parseUiDeliveryOverride();
47
+ const mcpApps = getClientSupportsMcpApps();
48
+ const port = getVizPort() || null;
49
+ const standaloneUrl = buildStandaloneVizUrl(options.tool, options.jobId);
50
+ let delivery;
51
+ if (override === "apps") {
52
+ delivery = mcpApps ? "embedded" : port ? "localhost" : "text_only";
53
+ }
54
+ else if (override === "localhost") {
55
+ delivery = port ? "localhost" : options.inlineImageAttached ? "inline_image" : "text_only";
56
+ }
57
+ else if (override === "inline") {
58
+ delivery = options.inlineImageAttached ? "inline_image" : "text_only";
59
+ }
60
+ else if (mcpApps) {
61
+ delivery = "embedded";
62
+ }
63
+ else if (port) {
64
+ delivery = "localhost";
65
+ }
66
+ else if (options.inlineImageAttached) {
67
+ delivery = "inline_image";
68
+ }
69
+ else {
70
+ delivery = "text_only";
71
+ }
72
+ const urls = [];
73
+ if (standaloneUrl && (delivery === "embedded" || delivery === "localhost")) {
74
+ urls.push(standaloneUrl);
75
+ }
76
+ const healthUrl = buildHealthUrl(options.jobId);
77
+ if (healthUrl && delivery === "localhost") {
78
+ urls.push(healthUrl);
79
+ }
80
+ const crossLink = options.tool === "training_monitor" && options.jobStatus === "completed"
81
+ ? buildStandaloneVizUrl("results_explorer", options.jobId)
82
+ : options.tool === "results_explorer"
83
+ ? buildStandaloneVizUrl("training_monitor", options.jobId)
84
+ : undefined;
85
+ if (crossLink && !urls.includes(crossLink)) {
86
+ urls.push(crossLink);
87
+ }
88
+ return {
89
+ delivery,
90
+ urls: urls.length > 0 ? urls : undefined,
91
+ hint_for_agent: hintForTier(delivery, options.tool, { standaloneUrl }),
92
+ mcp_apps_supported: mcpApps,
93
+ viz_port: port,
94
+ port_pinned: vizPortPinned(),
95
+ override,
96
+ };
97
+ }
98
+ /** Prepend prominent standalone URL + structured ui_delivery (Apps handshake may lie). */
99
+ export function appendUiDeliveryContent(content, block, options) {
100
+ const primary = options?.primaryUrl ?? block.urls?.[0];
101
+ const label = options?.linkLabel ?? "Open interactive view";
102
+ const prefix = [];
103
+ if (primary) {
104
+ const embedNote = block.delivery === "embedded"
105
+ ? "Embedded panel if your host supports MCP Apps — otherwise open the standalone URL below (expected on some Cursor builds)."
106
+ : "Open the standalone URL below when no inline panel appears.";
107
+ prefix.push({
108
+ type: "text",
109
+ text: `${embedNote}\n` +
110
+ `Standalone URL (copy if Open is blocked):\n${primary}\n` +
111
+ `[${label}](${primary})\n` +
112
+ `${block.hint_for_agent}`,
113
+ });
114
+ }
115
+ prefix.push({
116
+ type: "text",
117
+ text: "```json\n" + JSON.stringify({ ui_delivery: block }, null, 2) + "\n```",
118
+ });
119
+ if (primary && !block.port_pinned && block.delivery !== "text_only") {
120
+ prefix.push({
121
+ type: "text",
122
+ text: "Tip: set BARIVIA_VIZ_PORT in MCP env for a session-stable localhost port; re-run this tool if the page stops updating.",
123
+ });
124
+ }
125
+ content.unshift(...prefix);
126
+ }
127
+ export function getMcpClientDiagnostics() {
128
+ const override = parseUiDeliveryOverride();
129
+ const mcpApps = getClientSupportsMcpApps();
130
+ const port = getVizPort() || null;
131
+ let activeTier = "text_only";
132
+ if (override === "apps") {
133
+ activeTier = mcpApps ? "embedded" : port ? "localhost" : "text_only";
134
+ }
135
+ else if (override === "localhost") {
136
+ activeTier = port ? "localhost" : "text_only";
137
+ }
138
+ else if (override === "inline") {
139
+ activeTier = "inline_image";
140
+ }
141
+ else if (mcpApps) {
142
+ activeTier = "embedded";
143
+ }
144
+ else if (port) {
145
+ activeTier = "localhost";
146
+ }
147
+ return {
148
+ mcp_apps_supported: mcpApps,
149
+ viz_port: port,
150
+ viz_port_pinned: vizPortPinned(),
151
+ ui_delivery_override: override,
152
+ active_delivery_tier: activeTier,
153
+ health_url: buildHealthUrl(),
154
+ };
155
+ }