@barivia/barsom-mcp 0.15.3 → 0.15.4
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.
|
@@ -23,10 +23,27 @@ export function formatJobStatusText(job_id, data) {
|
|
|
23
23
|
const startedAt = data.started_at != null ? String(data.started_at) : null;
|
|
24
24
|
if (startedAt) {
|
|
25
25
|
parts.push(`started_at: ${startedAt}`);
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const trainingElapsed = data.training_elapsed_sec != null ? Number(data.training_elapsed_sec) : null;
|
|
27
|
+
if (trainingElapsed != null && trainingElapsed >= 0) {
|
|
28
|
+
parts.push(`elapsed: ${Math.round(trainingElapsed)}s`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
const startedMs = Date.parse(startedAt);
|
|
32
|
+
if (!Number.isNaN(startedMs)) {
|
|
33
|
+
const elapsedSec = Math.max(0, Math.round((Date.now() - startedMs) / 1000));
|
|
34
|
+
parts.push(`elapsed: ${elapsedSec}s`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (status === "running") {
|
|
39
|
+
const etaSec = data.training_eta_sec != null ? Number(data.training_eta_sec) : null;
|
|
40
|
+
if (etaSec != null && etaSec > 0) {
|
|
41
|
+
parts.push(`ETA ~${Math.round(etaSec)}s`);
|
|
42
|
+
}
|
|
43
|
+
const epoch = data.epoch != null ? Number(data.epoch) : null;
|
|
44
|
+
const totalEpochs = data.total_epochs != null ? Number(data.total_epochs) : null;
|
|
45
|
+
if (epoch != null && totalEpochs != null && totalEpochs > 0) {
|
|
46
|
+
parts.push(`epoch ${epoch}/${totalEpochs}`);
|
|
30
47
|
}
|
|
31
48
|
}
|
|
32
49
|
const datasetRows = data.dataset_rows != null ? Number(data.dataset_rows) : null;
|
package/dist/shared.js
CHANGED
|
@@ -26,7 +26,7 @@ export const RETRYABLE_STATUS = new Set([502, 503, 504]);
|
|
|
26
26
|
* X-Barsom-Client-Version so the server can annotate tool guidance with the
|
|
27
27
|
* wrapper version each action requires. Keep in sync with package.json on bump.
|
|
28
28
|
*/
|
|
29
|
-
export const CLIENT_VERSION = "0.15.
|
|
29
|
+
export const CLIENT_VERSION = "0.15.4";
|
|
30
30
|
/** User-facing links; keep aligned with barivia.se / api.barivia.se. */
|
|
31
31
|
export const PUBLIC_SITE_ORIGIN = "https://barivia.se";
|
|
32
32
|
/** Self-serve account dashboard (manage plan, billing, and API keys). */
|
|
@@ -3,6 +3,7 @@ import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
|
|
|
3
3
|
import { runMcpToolAudit } from "../audit.js";
|
|
4
4
|
import { apiCall, getClientSupportsMcpApps, getVizPort, structuredTextResult, } from "../shared.js";
|
|
5
5
|
export const TRAINING_MONITOR_URI = "ui://barsom/training-monitor";
|
|
6
|
+
export const TRAINING_MONITOR_REFRESH_MS = 5000;
|
|
6
7
|
function buildStructuredContent(job_id, data) {
|
|
7
8
|
const id = String(data.id ?? job_id);
|
|
8
9
|
return {
|
|
@@ -11,12 +12,13 @@ function buildStructuredContent(job_id, data) {
|
|
|
11
12
|
jobId: id,
|
|
12
13
|
id,
|
|
13
14
|
job_id: id,
|
|
15
|
+
refresh_interval_ms: TRAINING_MONITOR_REFRESH_MS,
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
18
|
export function registerTrainingMonitorTool(server) {
|
|
17
19
|
registerAppTool(server, "training_monitor", {
|
|
18
20
|
title: "Training Monitor",
|
|
19
|
-
description: "Optional embedded or standalone view of training progress for a job_id.
|
|
21
|
+
description: "Optional embedded or standalone view of training progress for a job_id. When embedded in a client that supports MCP Apps, the panel auto-refreshes every 5s until the job completes. A standalone browser URL is also available. Same fields are available via jobs(action=status)—not required to complete training or read results.",
|
|
20
22
|
inputSchema: {
|
|
21
23
|
job_id: z.string().describe("Training job ID to monitor"),
|
|
22
24
|
},
|
|
@@ -27,8 +29,20 @@ export function registerTrainingMonitorTool(server) {
|
|
|
27
29
|
const structuredContent = buildStructuredContent(job_id, data);
|
|
28
30
|
const status = String(data.status ?? "unknown");
|
|
29
31
|
const progress = (data.progress ?? 0) * 100;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
+
const etaSec = data.training_eta_sec != null ? Number(data.training_eta_sec) : null;
|
|
33
|
+
const elapsedSec = data.training_elapsed_sec != null ? Number(data.training_elapsed_sec) : null;
|
|
34
|
+
const epoch = data.epoch != null ? Number(data.epoch) : null;
|
|
35
|
+
const totalEpochs = data.total_epochs != null ? Number(data.total_epochs) : null;
|
|
36
|
+
const timingParts = [];
|
|
37
|
+
if (elapsedSec != null && elapsedSec >= 0)
|
|
38
|
+
timingParts.push(`elapsed ${Math.round(elapsedSec)}s`);
|
|
39
|
+
if (etaSec != null && etaSec > 0)
|
|
40
|
+
timingParts.push(`ETA ~${Math.round(etaSec)}s`);
|
|
41
|
+
if (epoch != null && totalEpochs != null)
|
|
42
|
+
timingParts.push(`epoch ${epoch}/${totalEpochs}`);
|
|
43
|
+
const timingNote = timingParts.length > 0 ? ` ${timingParts.join(", ")}.` : "";
|
|
44
|
+
const text = `Training monitor (live when embedded, refreshes every ${TRAINING_MONITOR_REFRESH_MS / 1000}s): job ${job_id} — ${status} (${progress.toFixed(1)}%).${timingNote} ` +
|
|
45
|
+
`Optional UI; jobs(action=status) is enough to finish the workflow.`;
|
|
32
46
|
const content = [{ type: "text", text }];
|
|
33
47
|
const port = getVizPort();
|
|
34
48
|
const standaloneUrl = port
|