@aliceshimada/mica 1.2.0 → 1.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.1 - 2026-06-17
4
+
5
+ - Add watchdog on agent tick loop: force-reset `$HiddenAgentInProgress` if stuck > 120s.
6
+ - Add periodic backend sweep (every 10s) for liveness and timed-out requests.
7
+ - Fix `markTimedOut` to use `claimedAt` for running requests.
8
+ - Remove `runCell` timeout upper bound; default to no timeout.
9
+
3
10
  ## 1.2.0 - 2026-06-16
4
11
 
5
12
  - Add `mma_create_notebook` tool: create a new blank notebook in the Wolfram FrontEnd.
@@ -81,7 +81,10 @@ export class BackendQueue {
81
81
  for (const request of this.requests.values()) {
82
82
  if (request.status !== "queued" && request.status !== "running")
83
83
  continue;
84
- if (now - request.createdAt < request.timeoutMs)
84
+ const elapsed = request.status === "running" && request.claimedAt
85
+ ? now - request.claimedAt
86
+ : now - request.createdAt;
87
+ if (elapsed < request.timeoutMs)
85
88
  continue;
86
89
  const updated = this.cloneRequest({ ...request, status: "timed_out" });
87
90
  this.requests.set(request.requestId, updated);
@@ -6,7 +6,7 @@ export const DEFAULT_TIMEOUTS_MS = {
6
6
  readCell: 10_000,
7
7
  mutation: 10_000,
8
8
  insertCell: 60_000,
9
- runCell: 120_000,
9
+ runCell: 3_600_000,
10
10
  symbolLookup: 30_000,
11
11
  agentHeartbeatDegradedMs: 10_000,
12
12
  agentHeartbeatOfflineMs: 30_000,
@@ -3,7 +3,7 @@ import http from "node:http";
3
3
  import { executeBackendMcpTool } from "../mcp/backendTools.js";
4
4
  import { renderDashboard } from "./dashboard.js";
5
5
  const JSON_BODY_LIMIT_BYTES = 1024 * 1024;
6
- const DEFAULT_VERSION = "1.2.0";
6
+ const DEFAULT_VERSION = "1.2.1";
7
7
  export async function createBunHttpApp({ state, host = "127.0.0.1", port, authToken, version = DEFAULT_VERSION }) {
8
8
  const runtimeInfo = {
9
9
  host,
@@ -8,7 +8,7 @@ import { loadRuntimeConfig } from "../runtime/config.js";
8
8
  import { writeSessionFile } from "../runtime/session.js";
9
9
  import { createBunHttpApp } from "./httpServer.js";
10
10
  const MCP_SERVER_NAME = "mica-bun";
11
- const MICA_PACKAGE_VERSION = "1.2.0";
11
+ const MICA_PACKAGE_VERSION = "1.2.1";
12
12
  export async function startBunRuntime(deps = {}) {
13
13
  const config = deps.runtimeConfig ?? loadRuntimeConfig();
14
14
  const bridgeOnly = deps.bridgeOnly ?? config.bridgeOnly;
@@ -65,6 +65,11 @@ export async function startBunRuntime(deps = {}) {
65
65
  console.error("Bun MCP mode enabled; connecting stdio transport.");
66
66
  await server.connect(createTransport());
67
67
  }
68
+ const sweepInterval = setInterval(() => {
69
+ state.sweepLiveness();
70
+ state.queue.markTimedOut(Date.now());
71
+ }, 10_000);
72
+ sweepInterval.unref();
68
73
  }
69
74
  catch (error) {
70
75
  await stop();
@@ -128,7 +128,7 @@ const queuedNotebookTools = [
128
128
  schema: runCellSchema.shape,
129
129
  permission: "RunCell",
130
130
  timeoutMs: (args) => {
131
- const timeoutSec = typeof args.timeoutSec === "number" ? args.timeoutSec : 120;
131
+ const timeoutSec = typeof args.timeoutSec === "number" ? args.timeoutSec : 86_400;
132
132
  return timeoutSec * 1000;
133
133
  },
134
134
  requiresExplicitTarget: true,
@@ -37,7 +37,7 @@ export const MICA_AGENT_INSTRUCTIONS = [
37
37
  "Tools:",
38
38
  ...TOOL_GUIDE.map(([name, description]) => `- ${name}: ${description}`),
39
39
  ].join("\n");
40
- export function createMicaMcpServer(name, version = "1.2.0") {
40
+ export function createMicaMcpServer(name, version = "1.2.1") {
41
41
  return new McpServer({ name, version }, { instructions: MICA_AGENT_INSTRUCTIONS });
42
42
  }
43
43
  export function registerMicaPrompts(server) {
@@ -33,7 +33,7 @@ export const deleteCellSchema = z.object({
33
33
  export const runCellSchema = z.object({
34
34
  ...notebookSelectorFields,
35
35
  cellId: z.string().min(1),
36
- timeoutSec: z.number().int().positive().max(3600).default(120)
36
+ timeoutSec: z.number().int().positive().optional()
37
37
  }).strict();
38
38
  export const abortEvaluationSchema = z.object({
39
39
  ...notebookSelectorFields
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliceshimada/mica",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Local MCP bridge for controlling live Wolfram Desktop / Mathematica notebooks.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1376,7 +1376,7 @@ DeleteCellRequest[args_Association] := Module[{notebookId, record, notebook, cel
1376
1376
  <|"status" -> "deleted", "cellId" -> cellId, "deletedArtifactCount" -> Length[artifacts]|>
1377
1377
  ];
1378
1378
 
1379
- RunCellRequest[args_Association] := Module[{notebookId, record, notebook, cellId, cell, timeoutSec = Lookup[args, "timeoutSec", 120], installedEpilog, evaluateResult},
1379
+ RunCellRequest[args_Association] := Module[{notebookId, record, notebook, cellId, cell, timeoutSec = Lookup[args, "timeoutSec", Infinity], installedEpilog, evaluateResult},
1380
1380
  notebookId = TargetNotebookId[args];
1381
1381
  If[Not @ ConfirmAction["RunCell", "AI requests running 1 cell. Allow?", notebookId], Return[$Canceled]];
1382
1382
  If[!StringQ[notebookId] || StringLength[notebookId] == 0, Return[Failure["BAD_REQUEST", <|"message" -> "No notebook is selected."|>]]];
@@ -1402,8 +1402,7 @@ RunCellRequest[args_Association] := Module[{notebookId, record, notebook, cellId
1402
1402
  $RunningNotebookId = notebookId;
1403
1403
  $RunningNotebookObject = notebook;
1404
1404
  $RunningStartedAt = AbsoluteTime[];
1405
- If[!NumericQ[timeoutSec], timeoutSec = 120];
1406
- $RunningTimeoutAt = AbsoluteTime[] + timeoutSec;
1405
+ $RunningTimeoutAt = If[NumericQ[timeoutSec] && timeoutSec < Infinity, AbsoluteTime[] + timeoutSec, Infinity];
1407
1406
  SelectionMove[cell, All, Cell];
1408
1407
  (* RunCell returns immediately; Palette-local cancellation can still abort the running evaluation. *)
1409
1408
  evaluateResult = Quiet @ Check[FrontEndTokenExecute[notebook, "EvaluateCells"], $Failed];
@@ -1700,7 +1699,15 @@ ExecuteAgentRequest[request_Association] := Module[{args = Lookup[request, "argu
1700
1699
  ];
1701
1700
 
1702
1701
  SafeHiddenAgentTick[] := Module[{payload, request},
1703
- If[TrueQ[$HiddenAgentInProgress], Return[$LastResultStatus]];
1702
+ If[TrueQ[$HiddenAgentInProgress],
1703
+ If[NumberQ[$HiddenAgentStartedAt] && AbsoluteTime[] - $HiddenAgentStartedAt > 120,
1704
+ $HiddenAgentInProgress = False;
1705
+ $HiddenAgentStartedAt = None;
1706
+ $HiddenAgentStartedAt = None,
1707
+ Return[$LastResultStatus]
1708
+ ]
1709
+ ];
1710
+ $HiddenAgentStartedAt = AbsoluteTime[];
1704
1711
  Internal`WithLocalSettings[
1705
1712
  $HiddenAgentInProgress = True,
1706
1713
  (
@@ -1725,7 +1732,9 @@ SafeHiddenAgentTick[] := Module[{payload, request},
1725
1732
  ];
1726
1733
  Null
1727
1734
  ),
1728
- $HiddenAgentInProgress = False
1735
+ $HiddenAgentInProgress = False;
1736
+ $HiddenAgentStartedAt = None;
1737
+ $HiddenAgentStartedAt = None
1729
1738
  ]
1730
1739
  ];
1731
1740