@uptimizr/agent-core 1.0.1 → 1.1.0

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/AGENTS.md CHANGED
@@ -9,7 +9,9 @@ The **framework-agnostic, browser-safe core** shared by every Uptimizr analytics
9
9
  the agent tool surface **once** (ADR 0050 §1) so `@uptimizr/mcp`, the dashboard assistant, and the
10
10
  demo assistant never drift apart. It owns:
11
11
 
12
- - the **read-only tool catalog** (`readTools`) — one entry per documented collector query endpoint;
12
+ - the **read-only tool catalog** (`readTools`) — one entry per documented collector query endpoint,
13
+ **generated** from the `@uptimizr/metrics` semantic metric registry (ADR 0051 §1), so coverage of the
14
+ collector's read surface cannot drift;
13
15
  - a headless **LLM provider-adapter interface** (`LlmProvider`) — messages + tool schemas in, tool
14
16
  calls or final text out;
15
17
  - the headless **tool-calling loop** (`runAgent`) — LLM ↔ tools ↔ collector.
@@ -17,22 +19,60 @@ demo assistant never drift apart. It owns:
17
19
  The core ships **no model and no key**. It only ever reads a consumer's **own** collector via the
18
20
  `CollectorClient` (`GET`-only, `x-api-key`).
19
21
 
22
+ ## Tool catalog (read-only)
23
+
24
+ <!-- generated:registry-tool-names:start — generated by `pnpm gen:docs`; edit the metric registry, not this list -->
25
+
26
+ `list_sessions`, `session_meta`, `scene_representation`, `list_scenes`, `timeseries`,
27
+ `event_counts`, `pointer_heatmap`, `mesh_uv_heatmap`, `world_heatmap`, `world_heatmap_stats`,
28
+ `gaze_heatmap`, `gaze_heatmap_stats`, `camera_heatmap`, `view_coverage_histogram`,
29
+ `position_heatmap`, `session_trajectory`, `aggregate_paths`, `scene_coverage`, `camera_distance`,
30
+ `click_rays`, `flow_links`, `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_dwell`,
31
+ `mesh_blind_spots`, `mesh_interaction_kinds`, `mesh_reachability`, `dead_clicks`, `rage_clicks`,
32
+ `hover_dwell`, `interaction_sources`, `top_input_actions`, `camera_gestures`, `navigation_stats`,
33
+ `backtrack_ratio`, `perf_summary`, `render_scale_truth`, `perf_distribution`, `fps_histogram`,
34
+ `frame_time_percentiles`, `jank_rate`, `perf_churn`, `perf_by_device`, `perf_by_scene`,
35
+ `perf_heatmap`, `compile_stalls`, `resource_summary`, `resource_percentiles`, `stability_counts`,
36
+ `graphics_diagnostics`, `error_heatmap`, `rendering_technology`, `capability_changes`,
37
+ `xr_rotation`, `xr_sources`, `xr_abandonment`, `xr_locomotion`, `xr_tracking_quality`,
38
+ `boundary_heatmap`, `boundary_heatmap_stats`, `xr_boundary_contacts`,
39
+ `ar_placement_time_to_place`, `ar_placement_attempts`, `ar_placement_surfaces`, `funnel`,
40
+ `scene_retention`, `load_bounce_funnel`, `variant_leaderboard`
41
+
42
+ <!-- generated:registry-tool-names:end -->
43
+
44
+ Each name is a metric in the collector's semantic metric registry (ADR 0051) and maps one-to-one to
45
+ a documented query endpoint. Most accept `since`/`until` (epoch ms) plus endpoint-specific filters.
46
+
20
47
  ## Rules for agents
21
48
 
22
49
  - **Read-only and privacy-preserving.** Never add ingestion, mutation, or raw per-session event
23
50
  tools. The surface is aggregate-only; no data leaves the consumer's infrastructure (ADR 0003 /
24
- ADR 0017). A new tool = a new entry in `readTools` mapping to a documented query endpoint — no
25
- aggregation/business logic (that lives in the collector, ADR 0005).
26
- - **Browser-safe.** No Node dependencies, no `types: ["node"]`; only `zod` at runtime. Anything that
27
- needs `process.env`, stdio, or the filesystem belongs in a consumer package (e.g. `@uptimizr/mcp`),
28
- not here.
51
+ ADR 0017). A new tool = a new **metric registry entry** in `@uptimizr/metrics` for a documented query
52
+ endpoint — never a hand-written catalog entry here — and no aggregation/business logic (that lives
53
+ in the collector, ADR 0005).
54
+ - **Browser-safe.** No Node dependencies, no `types: ["node"]`. At runtime this package uses `zod`
55
+ plus the pure, data-only `@uptimizr/metrics` package — **never** `@uptimizr/db`, which owns the
56
+ DuckDB store and its ~37 MB native binding. `src/__tests__/browserSafety.test.ts` bundles the
57
+ package for the browser and fails if that changes, and `src/__tests__/dependencies.test.ts` fails
58
+ if `@uptimizr/db` (or anything else with a native/optional binary dependency) reappears in the
59
+ manifest. Anything that needs `process.env`, stdio, or the filesystem belongs in a consumer
60
+ package (e.g. `@uptimizr/mcp`), not here.
29
61
  - Tool definitions are pure (`buildRequest`) and must stay unit-testable without a live collector.
62
+ - The 20 tool names (and argument schemas) that shipped before the registry are a public contract:
63
+ `src/__tests__/shippedToolCompat.test.ts` pins them against a frozen fixture. Widening a tool with
64
+ a new **optional** argument is fine; renaming one or making an argument required is not.
30
65
  - Keep provider adapters thin and out of this package: implement `LlmProvider` in the consumer.
31
66
 
32
67
  ## Programmatic API
33
68
 
34
- `readTools`, `createCollectorClient(config)`, `toToolSchemas(tools?)`, `runAgent(options)`, plus the
35
- `LlmProvider` / `AgentMessage` / `AgentToolCall` / `ProviderResponse` types.
69
+ `readTools`, `coreReadTools`, `selectReadTools(kind)`, `filterReadTools(names)`,
70
+ `registryToTools(metrics?)`, `createCollectorClient(config)`, `toToolSchemas(tools?)`,
71
+ `runAgent(options)`, plus the `LlmProvider` / `AgentMessage` / `AgentToolCall` /
72
+ `ProviderResponse` types.
73
+
74
+ The catalog is ~69 tools. A small local model cannot hold every schema in its function-calling
75
+ prompt — hand a run `coreReadTools` or `filterReadTools([...])` rather than the full catalog.
36
76
 
37
77
  ## More
38
78
 
package/README.md CHANGED
@@ -61,23 +61,71 @@ console.log(result.content); // the model's final answer
61
61
 
62
62
  ## Tool catalog (read-only)
63
63
 
64
- `list_sessions`, `pointer_heatmap`, `world_heatmap`, `camera_heatmap`, `click_rays`, `flow_links`,
65
- `top_meshes`, `perf_summary`, `list_scenes`, `timeseries`, `event_counts`, `session_meta`,
66
- `scene_representation`, `funnel`, `aggregate_paths`, `rendering_technology`, `xr_rotation`,
67
- `xr_sources`, `xr_abandonment`, `xr_locomotion`. Most accept `since`/`until` (epoch ms) plus
68
- endpoint-specific filters (`scene`, `session`, `source`, `bins`, `cellSize`, `limit`, `cameraMode`,
69
- `rapidTurn`, `steps`). Each maps one-to-one to a documented
70
- collector query endpoint (see the [integration guide](https://github.com/RaananW/Uptimizr/blob/main/docs/integration.md)).
64
+ <!-- generated:registry-tool-names:start generated by `pnpm gen:docs`; edit the metric registry, not this table -->
65
+
66
+ `list_sessions`, `session_meta`, `scene_representation`, `list_scenes`, `timeseries`,
67
+ `event_counts`, `pointer_heatmap`, `mesh_uv_heatmap`, `world_heatmap`, `world_heatmap_stats`,
68
+ `gaze_heatmap`, `gaze_heatmap_stats`, `camera_heatmap`, `view_coverage_histogram`,
69
+ `position_heatmap`, `session_trajectory`, `aggregate_paths`, `scene_coverage`, `camera_distance`,
70
+ `click_rays`, `flow_links`, `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_dwell`,
71
+ `mesh_blind_spots`, `mesh_interaction_kinds`, `mesh_reachability`, `dead_clicks`, `rage_clicks`,
72
+ `hover_dwell`, `interaction_sources`, `top_input_actions`, `camera_gestures`, `navigation_stats`,
73
+ `backtrack_ratio`, `perf_summary`, `render_scale_truth`, `perf_distribution`, `fps_histogram`,
74
+ `frame_time_percentiles`, `jank_rate`, `perf_churn`, `perf_by_device`, `perf_by_scene`,
75
+ `perf_heatmap`, `compile_stalls`, `resource_summary`, `resource_percentiles`, `stability_counts`,
76
+ `graphics_diagnostics`, `error_heatmap`, `rendering_technology`, `capability_changes`,
77
+ `xr_rotation`, `xr_sources`, `xr_abandonment`, `xr_locomotion`, `xr_tracking_quality`,
78
+ `boundary_heatmap`, `boundary_heatmap_stats`, `xr_boundary_contacts`,
79
+ `ar_placement_time_to_place`, `ar_placement_attempts`, `ar_placement_surfaces`, `funnel`,
80
+ `scene_retention`, `load_bounce_funnel`, `variant_leaderboard`
81
+
82
+ <!-- generated:registry-tool-names:end -->
83
+
84
+ `readTools` is **generated** from the semantic metric registry in `@uptimizr/metrics`
85
+ ([ADR 0051](https://github.com/RaananW/Uptimizr/blob/main/docs/adr/0051-ai-first-analytics-layer.md) §1):
86
+ one tool per metric the collector serves on a read endpoint — **69** today, covering sessions and
87
+ scenes, pointer/world/gaze/camera heatmaps, mesh attention and blind spots, dead and rage clicks,
88
+ navigation and desire lines, performance (FPS distribution, jank, compile stalls, per-device and
89
+ per-scene), errors and stability, XR/AR comfort and placement, and conversion (funnel, scene
90
+ retention, load→bounce, variant leaderboard). The full table is in the
91
+ [MCP guide](https://uptimizr.com/docs/guides/mcp/), and each tool maps one-to-one to a documented
92
+ collector query endpoint (see the
93
+ [integration guide](https://github.com/RaananW/Uptimizr/blob/main/docs/integration.md)).
94
+
95
+ Each tool carries:
96
+
97
+ - a **name** that is the registry metric id (the 20 names shipped before the registry are
98
+ unchanged, and so are their argument schemas — a frozen-fixture test pins that);
99
+ - a **description** composed from the metric's description, how to read the result, and its
100
+ caveats (sample-size limits, which capture channel must be on);
101
+ - an **input schema** built from the endpoint's filters — most accept `since`/`until` (epoch ms)
102
+ plus `scene`, `session`, `source`, `bins`, `cellSize`, `limit`, `cameraMode`, `region`, …;
103
+ - an **output schema** (`{ rows: Row[] }`) derived from the metric's row schema, which
104
+ `@uptimizr/mcp` registers as the MCP `outputSchema`.
105
+
106
+ The registry lives in `@uptimizr/metrics`, a dependency-free package (`zod` +
107
+ `@uptimizr/schema`), so installing this one never downloads a database driver: `@uptimizr/db` and
108
+ its ~37 MB native DuckDB binding are **not** a dependency. Two tests keep that true — a bundle test
109
+ asserts no `node:` built-in or DuckDB driver can reach a browser build, and a manifest test fails
110
+ if any package with a native or optional binary dependency reappears.
71
111
 
72
112
  ## API
73
113
 
74
- | Export | Purpose |
75
- | ------------------------------ | ----------------------------------------------------------------- |
76
- | `readTools` | The read-only tool catalog (one entry per query endpoint). |
77
- | `createCollectorClient(cfg)` | Thin `GET`-only collector client (`fetch`-based, injectable). |
78
- | `toToolSchemas(tools?)` | Convert catalog tools to JSON-Schema tool descriptors for an LLM. |
79
- | `runAgent(options)` | The headless tool-calling loop. |
80
- | `LlmProvider` / `AgentMessage` | The provider-adapter interface and message types. |
114
+ | Export | Purpose |
115
+ | ------------------------------ | -------------------------------------------------------------------- |
116
+ | `readTools` | The read-only tool catalog (one entry per query endpoint). |
117
+ | `coreReadTools` | Focused subset for small local models (a filtered view, not a copy). |
118
+ | `selectReadTools(kind)` | Pick `"core"` or `"full"`. |
119
+ | `filterReadTools(names)` | Narrow the catalog to specific tool names, in catalog order. |
120
+ | `registryToTools(metrics?)` | Generate the catalog from metric-registry definitions. |
121
+ | `createCollectorClient(cfg)` | Thin `GET`-only collector client (`fetch`-based, injectable). |
122
+ | `toToolSchemas(tools?)` | Convert catalog tools to JSON-Schema tool descriptors for an LLM. |
123
+ | `runAgent(options)` | The headless tool-calling loop. |
124
+ | `LlmProvider` / `AgentMessage` | The provider-adapter interface and message types. |
125
+
126
+ A 69-tool catalog is more than a small local model can hold in its function-calling prompt — use
127
+ `coreReadTools` (what the `@uptimizr/react` assistant sends the WebLLM backend) or
128
+ `filterReadTools([...])` to hand a run a deliberate subset.
81
129
 
82
130
  The loop stops when the provider returns a final answer or after `maxSteps` turns
83
131
  (`DEFAULT_MAX_STEPS`, default 8). Unknown tools and invalid arguments are surfaced back to the model
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { createCollectorClient, CollectorError, type CollectorClient, type CollectorClientConfig, type QueryParams, } from "./client.js";
2
- export { readTools, coreReadTools, selectReadTools, CORE_READ_TOOL_NAMES, type ReadTool, type ReadToolRequest, type ReadToolSetKind, } from "./tools.js";
2
+ export { readTools, coreReadTools, selectReadTools, filterReadTools, CORE_READ_TOOL_NAMES, type ReadTool, type ReadToolRequest, type ReadToolSetKind, } from "./tools.js";
3
+ export { registryToTools, metricToTool, describeMetric } from "./registryTools.js";
3
4
  export type { AgentMessage, AgentToolCall, AgentToolSchema, LlmProvider, ProviderRequest, ProviderResponse, } from "./provider.js";
4
5
  export { runAgent, toToolSchemas, truncateToolResult, DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_RESULT_CHARS, type AgentStreamEvent, type RunAgentOptions, type RunAgentResult, } from "./loop.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,eAAe,EACf,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnF,YAAY,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,WAAW,EACX,eAAe,EACf,gBAAgB,GACjB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,EAC7B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { createCollectorClient, CollectorError, } from "./client.js";
2
- export { readTools, coreReadTools, selectReadTools, CORE_READ_TOOL_NAMES, } from "./tools.js";
2
+ export { readTools, coreReadTools, selectReadTools, filterReadTools, CORE_READ_TOOL_NAMES, } from "./tools.js";
3
+ export { registryToTools, metricToTool, describeMetric } from "./registryTools.js";
3
4
  export { runAgent, toToolSchemas, truncateToolResult, DEFAULT_MAX_STEPS, DEFAULT_MAX_TOOL_RESULT_CHARS, } from "./loop.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,GAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,oBAAoB,GAIrB,MAAM,YAAY,CAAC;AASpB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,GAI9B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,cAAc,GAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,aAAa,EACb,eAAe,EACf,eAAe,EACf,oBAAoB,GAIrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AASnF,OAAO,EACL,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,6BAA6B,GAI9B,MAAM,WAAW,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * **Generated tool catalog** (ADR 0051 §1, design sketch §A.2).
3
+ *
4
+ * `registryToTools()` turns the semantic metric registry in `@uptimizr/metrics`
5
+ * into the read-only {@link ReadTool} catalog this package exports. One registry
6
+ * entry with an `endpoint` becomes exactly one tool, so agent coverage of the
7
+ * collector's read surface is mechanical rather than hand-maintained: adding an
8
+ * aggregation + a registry entry adds the tool, and there is no second list to
9
+ * forget.
10
+ *
11
+ * What each part of a tool is derived from:
12
+ *
13
+ * | Tool field | Registry source |
14
+ * | -------------- | ---------------------------------------------------------- |
15
+ * | `name` | `id` (the 20 shipped tool names are registry ids verbatim) |
16
+ * | `title` | `title` |
17
+ * | `description` | `description` + `interpretation` + `caveats` |
18
+ * | `inputSchema` | `filters` + `endpoint.pathParams`, via {@link FILTER_FIELDS} |
19
+ * | `buildRequest` | `endpoint.path` (with `:param` substitution) + `filters` |
20
+ * | `outputSchema` | `row`, wrapped as `{ rows: Row[] }` |
21
+ *
22
+ * **Browser safety (ADR 0050).** This module imports `@uptimizr/metrics` — the
23
+ * registry's own dependency-free package, whose only runtime dependencies are
24
+ * `zod` and `@uptimizr/schema`. This package does not depend on `@uptimizr/db`
25
+ * at all: that package owns the DuckDB store and pulls in a ~37 MB native
26
+ * binding a browser can never use. `src/__tests__/browserSafety.test.ts` bundles
27
+ * this package for the browser and fails if any `node:` built-in or the DuckDB
28
+ * driver reaches the bundle, and `src/__tests__/dependencies.test.ts` fails if
29
+ * `@uptimizr/db` ever reappears in the manifest.
30
+ */
31
+ import { type MetricDefinition } from "@uptimizr/metrics";
32
+ import type { ReadTool } from "./tools.js";
33
+ /**
34
+ * Compose the agent-facing tool description: what the metric measures, how to
35
+ * read the result, and the caveats that decide how far to trust it. All three
36
+ * come from the registry, so the prose an agent sees and the prose the docs and
37
+ * the capabilities resource show are the same text.
38
+ */
39
+ export declare function describeMetric(metric: MetricDefinition): string;
40
+ /**
41
+ * Build the {@link ReadTool} for one registry metric. Returns `undefined` for a
42
+ * metric with no collector endpoint (the two daily rollups), which therefore
43
+ * cannot be called by an agent.
44
+ */
45
+ export declare function metricToTool(metric: MetricDefinition): ReadTool | undefined;
46
+ /**
47
+ * Generate the read-only tool catalog from the metric registry: one tool per
48
+ * registry entry that has a collector endpoint, in registry declaration order.
49
+ *
50
+ * Pure — it reads definitions only and never touches a collector — so the whole
51
+ * catalog is unit-testable without a live server.
52
+ */
53
+ export declare function registryToTools(metrics?: readonly MetricDefinition[]): readonly ReadTool[];
54
+ //# sourceMappingURL=registryTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registryTools.d.ts","sourceRoot":"","sources":["../src/registryTools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErF,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AAkT5D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAO/D;AAYD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,GAAG,SAAS,CA6D3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,GAAE,SAAS,gBAAgB,EAAiB,GAClD,SAAS,QAAQ,EAAE,CAOrB"}
@@ -0,0 +1,409 @@
1
+ /**
2
+ * **Generated tool catalog** (ADR 0051 §1, design sketch §A.2).
3
+ *
4
+ * `registryToTools()` turns the semantic metric registry in `@uptimizr/metrics`
5
+ * into the read-only {@link ReadTool} catalog this package exports. One registry
6
+ * entry with an `endpoint` becomes exactly one tool, so agent coverage of the
7
+ * collector's read surface is mechanical rather than hand-maintained: adding an
8
+ * aggregation + a registry entry adds the tool, and there is no second list to
9
+ * forget.
10
+ *
11
+ * What each part of a tool is derived from:
12
+ *
13
+ * | Tool field | Registry source |
14
+ * | -------------- | ---------------------------------------------------------- |
15
+ * | `name` | `id` (the 20 shipped tool names are registry ids verbatim) |
16
+ * | `title` | `title` |
17
+ * | `description` | `description` + `interpretation` + `caveats` |
18
+ * | `inputSchema` | `filters` + `endpoint.pathParams`, via {@link FILTER_FIELDS} |
19
+ * | `buildRequest` | `endpoint.path` (with `:param` substitution) + `filters` |
20
+ * | `outputSchema` | `row`, wrapped as `{ rows: Row[] }` |
21
+ *
22
+ * **Browser safety (ADR 0050).** This module imports `@uptimizr/metrics` — the
23
+ * registry's own dependency-free package, whose only runtime dependencies are
24
+ * `zod` and `@uptimizr/schema`. This package does not depend on `@uptimizr/db`
25
+ * at all: that package owns the DuckDB store and pulls in a ~37 MB native
26
+ * binding a browser can never use. `src/__tests__/browserSafety.test.ts` bundles
27
+ * this package for the browser and fails if any `node:` built-in or the DuckDB
28
+ * driver reaches the bundle, and `src/__tests__/dependencies.test.ts` fails if
29
+ * `@uptimizr/db` ever reappears in the manifest.
30
+ */
31
+ import { z } from "zod";
32
+ import { allMetrics } from "@uptimizr/metrics";
33
+ // ---------------------------------------------------------------------------
34
+ // Shared parameter definitions
35
+ // ---------------------------------------------------------------------------
36
+ //
37
+ // One Zod field per registry `FilterId`, defined **once** and reused by every
38
+ // tool that accepts that filter — the "a param means the same thing everywhere"
39
+ // rule the capabilities resource already assumes.
40
+ //
41
+ // The fields for the parameters the hand-written catalog shipped (`since`,
42
+ // `until`, `bins`, `limit`, `scene`, `session`, `cellSize`, `interval`, `type`,
43
+ // `source`, `cameraMode`, `rapidTurn`, `steps`) are carried over **verbatim**,
44
+ // so the 20 shipped tools' JSON Schemas are byte-identical after the migration
45
+ // (`src/__tests__/shippedToolCompat.test.ts` pins that against a frozen
46
+ // fixture). Bounds on the new fields mirror the collector's own Zod querystring
47
+ // in `oss/apps/collector-server/src/routes/query.ts`.
48
+ const since = z.number().int().optional().describe("Start of the time range, epoch milliseconds.");
49
+ const until = z.number().int().optional().describe("End of the time range, epoch milliseconds.");
50
+ const bins = z.number().int().positive().max(500).optional().describe("Grid resolution per axis.");
51
+ const limit = z.number().int().positive().max(1000).optional().describe("Maximum rows to return.");
52
+ const scene = z.string().optional().describe("Restrict to one developer-assigned scene id.");
53
+ const session = z.string().optional().describe("Scope the aggregate to a single session id.");
54
+ const cellSize = z.number().positive().max(1000).optional().describe("Voxel size in world units.");
55
+ const interval = z
56
+ .number()
57
+ .int()
58
+ .positive()
59
+ .optional()
60
+ .describe("Time-series bucket width, seconds.");
61
+ const eventType = z
62
+ .string()
63
+ .optional()
64
+ .describe("Restrict to a single event type, e.g. pointer_click.");
65
+ const source = z
66
+ .enum(["mouse", "touch", "stylus", "pen", "xr-controller", "hand", "gaze", "transient", "other"])
67
+ .optional()
68
+ .describe("Restrict a pointer/world heatmap to one input source.");
69
+ const cameraMode = z
70
+ .enum(["viewer", "first-person"])
71
+ .optional()
72
+ .describe("Camera navigation mode to scope to: 'viewer' (orbit) or 'first-person' (walkable).");
73
+ const rapidTurn = z
74
+ .number()
75
+ .nonnegative()
76
+ .max(Math.PI)
77
+ .optional()
78
+ .describe("Rapid-turn threshold in radians (0..π); view turns above this flag motion-sickness risk.");
79
+ const steps = z
80
+ .string()
81
+ .min(1)
82
+ .describe("Funnel steps as a JSON-encoded array of ordered step predicates (ADR 0038). Required. " +
83
+ 'Each step is `{ "type": <event_type>, ... }`; e.g. ' +
84
+ '`[{"type":"scene_change","to":"lobby"},{"type":"mesh_interaction","mesh":"buy"}]`.');
85
+ /**
86
+ * The Zod field each {@link FilterId} contributes to a tool's input schema.
87
+ *
88
+ * Every entry is **optional** except the two the collector declares required
89
+ * (see {@link REQUIRED_FILTERS}); `filterField()` re-derives requiredness per
90
+ * metric so one shared definition serves both cases.
91
+ */
92
+ const FILTER_FIELDS = {
93
+ since,
94
+ until,
95
+ scene,
96
+ session,
97
+ source,
98
+ mesh: z.string().min(1).max(256).optional().describe("Restrict to one mesh/object name."),
99
+ region: z
100
+ .string()
101
+ .optional()
102
+ .describe("World-space drill-down box as `minX,minY,minZ,maxX,maxY,maxZ` (ADR 0040 §4). " +
103
+ "Omit for the whole scene."),
104
+ cameraMode,
105
+ bins,
106
+ limit,
107
+ cellSize,
108
+ interval,
109
+ type: eventType,
110
+ bucket: z.number().int().positive().max(240).optional().describe("Histogram bin width in FPS."),
111
+ bucketMs: z
112
+ .number()
113
+ .int()
114
+ .positive()
115
+ .max(60_000)
116
+ .optional()
117
+ .describe("Histogram bin width in milliseconds."),
118
+ bucketSize: z
119
+ .number()
120
+ .positive()
121
+ .max(1000)
122
+ .optional()
123
+ .describe("Histogram bin width in world units."),
124
+ minRepeats: z
125
+ .number()
126
+ .int()
127
+ .min(2)
128
+ .max(100)
129
+ .optional()
130
+ .describe("Minimum clicks in a window before it counts as a rage cluster."),
131
+ windowMs: z
132
+ .number()
133
+ .int()
134
+ .positive()
135
+ .max(86_400_000)
136
+ .optional()
137
+ .describe("How long before a session's end a perf dip still counts as correlated."),
138
+ fpsThreshold: z
139
+ .number()
140
+ .positive()
141
+ .max(240)
142
+ .optional()
143
+ .describe("A frame-perf sample below this FPS counts as a dip."),
144
+ stallMs: z
145
+ .number()
146
+ .nonnegative()
147
+ .max(60_000)
148
+ .optional()
149
+ .describe("A shader-compile stall at least this long (ms) counts as a dip."),
150
+ moveThreshold: z
151
+ .number()
152
+ .nonnegative()
153
+ .max(1000)
154
+ .optional()
155
+ .describe("Inter-sample distance (world units) above which a segment counts as active travel."),
156
+ rapidTurn,
157
+ centerX: z.number().optional().describe("X of the reference point distances are measured from."),
158
+ centerY: z.number().optional().describe("Y of the reference point distances are measured from."),
159
+ centerZ: z.number().optional().describe("Z of the reference point distances are measured from."),
160
+ severity: z
161
+ .string()
162
+ .min(1)
163
+ .max(64)
164
+ .optional()
165
+ .describe("Graphics-diagnostic severity (info / warning / error / fatal). " +
166
+ "Setting it excludes JS runtime errors."),
167
+ category: z
168
+ .string()
169
+ .min(1)
170
+ .max(64)
171
+ .optional()
172
+ .describe("Graphics-diagnostic category (context-loss / validation / shader-compile / …). " +
173
+ "Setting it excludes JS runtime errors."),
174
+ errorKind: z
175
+ .string()
176
+ .min(1)
177
+ .max(64)
178
+ .optional()
179
+ .describe("Runtime-error kind (error / unhandledrejection). Setting it excludes engine diagnostics."),
180
+ groupByOrigin: z
181
+ .boolean()
182
+ .optional()
183
+ .describe("Add the click-time standpoint voxel as a grouping dimension."),
184
+ originVoxel: z
185
+ .string()
186
+ .regex(/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/)
187
+ .optional()
188
+ .describe("Restrict to clicks whose standpoint falls in this `vx,vy,vz` voxel."),
189
+ steps: steps.optional(),
190
+ bands: z
191
+ .string()
192
+ .max(256)
193
+ .optional()
194
+ .describe("Ascending, comma-separated load-time band boundaries in ms. " +
195
+ "Omit for the default `1000,3000,5000`."),
196
+ variant: z
197
+ .string()
198
+ .min(1)
199
+ .max(2048)
200
+ .optional()
201
+ .describe("JSON funnel-step predicate selecting the variant events. " +
202
+ "Omit to treat every custom event as a variant."),
203
+ conversion: z
204
+ .string()
205
+ .min(1)
206
+ .max(2048)
207
+ .optional()
208
+ .describe("JSON funnel-step predicate for the success event. Omit to report views only."),
209
+ // The shared result envelope (ADR 0051 §2). Declared literally rather than
210
+ // imported from `@uptimizr/db/summary`, which would put a database driver back
211
+ // on this package's dependency graph. `full` stays the default here: switching
212
+ // the generated tools to `table` is a separate, documented change (#299).
213
+ format: z
214
+ .enum(["full", "table", "summary"])
215
+ .optional()
216
+ .describe("Result envelope. `full` (default) returns the bare rows; `table` wraps them with a " +
217
+ "`meta` block; `summary` returns a bounded digest — top rows, a trend or merged " +
218
+ "spatial clusters — with shares, caveats and a plain-language reading. Prefer " +
219
+ "`summary` for a large result such as a heatmap or a long leaderboard."),
220
+ };
221
+ /**
222
+ * Filters the collector declares **required** in its querystring schema, by
223
+ * metric id. The registry records requiredness in prose (a `caveats` line) but
224
+ * not as data, so the two exceptions are listed here; everything else is
225
+ * optional. Path parameters are always required and are handled separately.
226
+ *
227
+ * Keep this in step with `oss/apps/collector-server/src/routes/query.ts`
228
+ * (`funnelQueryParams.steps`, `meshUvHeatmapQueryParams.mesh`). Promoting it
229
+ * into the registry itself is tracked as a follow-up.
230
+ */
231
+ const REQUIRED_FILTERS = {
232
+ funnel: ["steps"],
233
+ mesh_uv_heatmap: ["mesh"],
234
+ };
235
+ /**
236
+ * The **required** variant of each filter named in {@link REQUIRED_FILTERS} —
237
+ * the same field without the trailing `.optional()`. Declared rather than
238
+ * unwrapped so the shipped `steps` schema stays byte-identical.
239
+ */
240
+ const REQUIRED_FILTER_FIELDS = {
241
+ steps,
242
+ mesh: z.string().min(1).max(256).describe("The mesh/object name to bin. Required."),
243
+ };
244
+ /**
245
+ * Argument name for a filter that travels in the **path** rather than the
246
+ * querystring. The registry names such a parameter by the filter it binds
247
+ * (`session`, `scene`); the shipped tools call them `sessionId` / `sceneId` and
248
+ * those names are part of the public MCP contract, so they are preserved.
249
+ */
250
+ const PATH_PARAM_ARG_NAMES = {
251
+ session: "sessionId",
252
+ scene: "sceneId",
253
+ };
254
+ /** The Zod field a path parameter contributes — always a required, non-empty id. */
255
+ const PATH_PARAM_FIELDS = {
256
+ session: z.string().min(1).describe("The session id to describe."),
257
+ scene: z.string().min(1).describe("The scene id to fetch."),
258
+ };
259
+ // ---------------------------------------------------------------------------
260
+ // Generation
261
+ // ---------------------------------------------------------------------------
262
+ /** The field a metric contributes for one filter: required where the route says so. */
263
+ function filterField(metric, filter) {
264
+ if (REQUIRED_FILTERS[metric.id]?.includes(filter)) {
265
+ const required = REQUIRED_FILTER_FIELDS[filter];
266
+ if (!required)
267
+ throw new Error(`no required field defined for filter '${filter}'`);
268
+ return required;
269
+ }
270
+ return FILTER_FIELDS[filter];
271
+ }
272
+ /**
273
+ * The row schema a tool advertises, built from the registry's `row`.
274
+ *
275
+ * Two deliberate relaxations, both driven by what the collector really returns:
276
+ *
277
+ * - **Every column is nullable.** An aggregate over a range with no matching
278
+ * samples projects SQL `NULL` for its measures (`resource_summary`,
279
+ * `perf_churn`, … over an empty window). The registry's row schema describes
280
+ * the populated shape; a consumer that validates the advertised JSON Schema
281
+ * strictly — the MCP SDK's client does, with Ajv — would otherwise reject a
282
+ * perfectly ordinary "no data yet" answer. The column set and its types stay
283
+ * exactly as the registry declares them.
284
+ * - **Unknown columns are kept.** A few routes add a field of their own on top
285
+ * of the aggregation (the `*_stats` endpoints echo the resolved `cellSize`),
286
+ * and dropping it silently would be worse than passing it through.
287
+ *
288
+ * The schema still *coerces*: `@uptimizr/db` declares numeric columns with
289
+ * `z.coerce.number()` because ClickHouse renders 64-bit integers as strings over
290
+ * HTTP, so parsing a result with this schema normalises those strings to JSON
291
+ * numbers (ADR 0051 §2). `@uptimizr/mcp` parses with it before sending
292
+ * `structuredContent`, which is what makes the advertised schema true on every
293
+ * store engine.
294
+ */
295
+ function outputRowSchema(metric) {
296
+ const shape = {};
297
+ for (const [column, field] of Object.entries(metric.row.shape)) {
298
+ shape[column] = field.nullable();
299
+ }
300
+ return z.looseObject(shape);
301
+ }
302
+ /** `[":id"]` → the ordered `:param` placeholders of a Fastify path. */
303
+ function pathPlaceholders(path) {
304
+ return path
305
+ .split("/")
306
+ .filter((segment) => segment.startsWith(":"))
307
+ .map((segment) => segment.slice(1));
308
+ }
309
+ /**
310
+ * Compose the agent-facing tool description: what the metric measures, how to
311
+ * read the result, and the caveats that decide how far to trust it. All three
312
+ * come from the registry, so the prose an agent sees and the prose the docs and
313
+ * the capabilities resource show are the same text.
314
+ */
315
+ export function describeMetric(metric) {
316
+ const caveats = metric.caveats.map((caveat) => `- ${caveat}`).join("\n");
317
+ return (`${metric.description}\n\n` +
318
+ `How to read it: ${metric.interpretation}\n\n` +
319
+ `Caveats:\n${caveats}`);
320
+ }
321
+ /** The value a validated argument contributes to the collector querystring. */
322
+ function toQueryValue(value) {
323
+ if (value == null)
324
+ return undefined;
325
+ if (typeof value === "number" || typeof value === "string")
326
+ return value;
327
+ // `groupByOrigin` is a boolean in the tool schema and `"true"`/`"false"` on
328
+ // the wire (the collector's querystring enum).
329
+ if (typeof value === "boolean")
330
+ return String(value);
331
+ return undefined;
332
+ }
333
+ /**
334
+ * Build the {@link ReadTool} for one registry metric. Returns `undefined` for a
335
+ * metric with no collector endpoint (the two daily rollups), which therefore
336
+ * cannot be called by an agent.
337
+ */
338
+ export function metricToTool(metric) {
339
+ const endpoint = metric.endpoint;
340
+ if (!endpoint)
341
+ return undefined;
342
+ const pathParams = endpoint.pathParams ?? [];
343
+ const placeholders = pathPlaceholders(endpoint.path);
344
+ if (placeholders.length !== pathParams.length) {
345
+ throw new Error(`metric ${metric.id}: endpoint path has ${placeholders.length} path parameter(s) but ` +
346
+ `${pathParams.length} are declared`);
347
+ }
348
+ // `:param` placeholder (positional) → the tool argument that fills it.
349
+ const pathArgs = placeholders.map((placeholder, index) => {
350
+ const filter = pathParams[index];
351
+ const argName = PATH_PARAM_ARG_NAMES[filter];
352
+ const field = PATH_PARAM_FIELDS[filter];
353
+ if (!argName || !field) {
354
+ throw new Error(`metric ${metric.id}: no tool argument defined for path filter '${filter}'`);
355
+ }
356
+ return { placeholder, argName, field };
357
+ });
358
+ const inputSchema = {};
359
+ for (const { argName, field } of pathArgs)
360
+ inputSchema[argName] = field;
361
+ for (const filter of metric.filters)
362
+ inputSchema[filter] = filterField(metric, filter);
363
+ // Every row of the collector's response, in one bounded envelope. A single
364
+ // object result (a session descriptor, a one-row summary) is reported as a
365
+ // one-element `rows` array so the envelope is the same for every tool.
366
+ const outputSchema = {
367
+ rows: z
368
+ .array(outputRowSchema(metric))
369
+ .describe(`Result rows (one row per ${metric.grain}). A column is null when it has no data.`),
370
+ };
371
+ // The collector client strips a leading slash; keep paths root-relative so a
372
+ // tool's `path` reads the same as it always has (`api/v1/...`).
373
+ const template = endpoint.path.replace(/^\//, "");
374
+ return {
375
+ name: metric.id,
376
+ title: metric.title,
377
+ description: describeMetric(metric),
378
+ inputSchema,
379
+ outputSchema,
380
+ buildRequest: (args) => {
381
+ let path = template;
382
+ for (const { placeholder, argName } of pathArgs) {
383
+ const raw = args[argName];
384
+ path = path.replace(`:${placeholder}`, encodeURIComponent(typeof raw === "string" ? raw : ""));
385
+ }
386
+ const params = {};
387
+ for (const filter of metric.filters)
388
+ params[filter] = toQueryValue(args[filter]);
389
+ return { path, params };
390
+ },
391
+ };
392
+ }
393
+ /**
394
+ * Generate the read-only tool catalog from the metric registry: one tool per
395
+ * registry entry that has a collector endpoint, in registry declaration order.
396
+ *
397
+ * Pure — it reads definitions only and never touches a collector — so the whole
398
+ * catalog is unit-testable without a live server.
399
+ */
400
+ export function registryToTools(metrics = allMetrics()) {
401
+ const tools = [];
402
+ for (const metric of metrics) {
403
+ const tool = metricToTool(metric);
404
+ if (tool)
405
+ tools.push(tool);
406
+ }
407
+ return tools;
408
+ }
409
+ //# sourceMappingURL=registryTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registryTools.js","sourceRoot":"","sources":["../src/registryTools.ts"],"names":[],"mappings":"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"}
package/dist/tools.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import type { z } from "zod";
2
2
  import type { QueryParams } from "./client.js";
3
3
  /** A resolved read request: the collector path and its query parameters. */
4
4
  export interface ReadToolRequest {
@@ -16,22 +16,46 @@ export interface ReadTool {
16
16
  title: string;
17
17
  description: string;
18
18
  inputSchema: z.ZodRawShape;
19
+ /**
20
+ * Zod raw shape describing what the tool **returns**, derived from the metric
21
+ * registry's `row` schema (ADR 0051 §1). It is always the single-key envelope
22
+ * `{ rows: Row[] }`: a single-object result (a session descriptor, a one-row
23
+ * summary) is reported as a one-element array so every tool has the same
24
+ * shape. Consumers that speak MCP register it as the tool's `outputSchema`
25
+ * and return matching `structuredContent`; consumers that do not can ignore
26
+ * it. Optional so a hand-built tool stays valid.
27
+ */
28
+ outputSchema?: z.ZodRawShape;
19
29
  buildRequest: (args: Record<string, unknown>) => ReadToolRequest;
20
30
  }
21
31
  /**
22
- * The catalog of read-only tools. Each wraps one documented collector query
23
- * endpoint (docs/integration.md §Query). There are intentionally **no**
24
- * ingestion, mutation, or raw per-session event tools the surface is
25
- * aggregate, read-only, and privacy-preserving (ADR 0003 / ADR 0017).
32
+ * The catalog of read-only tools one per metric in the `@uptimizr/db`
33
+ * **semantic metric registry** that the collector serves on an endpoint
34
+ * (ADR 0051 §1, design sketch §A.2). It is **generated**, not hand-written: a
35
+ * new aggregation reaches agents by getting a registry entry, and there is no
36
+ * second list to keep in step. See `registryTools.ts` for how each field is
37
+ * derived.
38
+ *
39
+ * Every tool wraps one documented collector query endpoint (docs/integration.md
40
+ * §Query). There are intentionally **no** ingestion, mutation, or raw
41
+ * per-session event tools — the surface is aggregate, read-only, and
42
+ * privacy-preserving (ADR 0003 / ADR 0017); the registry's two builder-less
43
+ * resource entries (`session_meta`, `scene_representation`) are coarse
44
+ * descriptors, never an event stream.
45
+ *
46
+ * The 20 tool names the hand-written catalog shipped are registry ids verbatim
47
+ * and their argument schemas are unchanged — `__tests__/shippedToolCompat.test.ts`
48
+ * pins that against a frozen fixture, so an MCP client written against the old
49
+ * catalog keeps working.
26
50
  */
27
51
  export declare const readTools: readonly ReadTool[];
28
52
  /**
29
53
  * Names of the **core** read tools — a small, single-step-friendly subset of
30
54
  * {@link readTools} for small local models (ADR 0050). A 4-bit 7–8B model folds
31
- * every tool schema into its function-calling system prompt, so sending all 20
32
- * overwhelms it and degrades selection even for simple questions. This subset
33
- * covers the most common single-metric questions (recent sessions, active
34
- * scenes, top meshes, FPS, event counts, event volume over time, and one
55
+ * every tool schema into its function-calling system prompt, so sending the
56
+ * whole catalog overwhelms it and degrades selection even for simple questions.
57
+ * This subset covers the most common single-metric questions (recent sessions,
58
+ * active scenes, top meshes, FPS, event counts, event volume over time, and one
35
59
  * view-direction heatmap).
36
60
  *
37
61
  * Plain string membership only — used to FILTER {@link readTools} below, never to
@@ -51,4 +75,15 @@ export type ReadToolSetKind = "core" | "full";
51
75
  * catalog. Both are views of the same single tool definitions.
52
76
  */
53
77
  export declare function selectReadTools(kind: ReadToolSetKind): readonly ReadTool[];
78
+ /**
79
+ * Narrow the catalog to a caller-supplied set of tool names, preserving catalog
80
+ * order and identity. Unknown names are ignored, so a host app that pins a tool
81
+ * list cannot break when the registry renames or retires a metric — check the
82
+ * result's length if that matters to you.
83
+ *
84
+ * Use it when a model's context budget or a product decision calls for a
85
+ * deliberate subset (see {@link coreReadTools} for the built-in small-model one)
86
+ * rather than the full ~69-tool surface.
87
+ */
88
+ export declare function filterReadTools(names: readonly string[]): readonly ReadTool[];
54
89
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;IAC3B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,eAAe,CAAC;CAClE;AAqDD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,QAAQ,EAwRxC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAQjD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAE5C,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,QAAQ,EAAE,CAE1E"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;IAC3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC;IAC7B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,eAAe,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,QAAQ,EAAsB,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAQjD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAE5C,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAE9C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,QAAQ,EAAE,CAE1E;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,QAAQ,EAAE,CAG7E"}
package/dist/tools.js CHANGED
@@ -1,336 +1,32 @@
1
- import { z } from "zod";
2
- const num = (v) => (typeof v === "number" ? v : undefined);
3
- const str = (v) => (typeof v === "string" ? v : undefined);
4
- // Shared, reusable input fields (all optional unless a tool needs otherwise).
5
- const since = z.number().int().optional().describe("Start of the time range, epoch milliseconds.");
6
- const until = z.number().int().optional().describe("End of the time range, epoch milliseconds.");
7
- const bins = z.number().int().positive().max(500).optional().describe("Grid resolution per axis.");
8
- const limit = z.number().int().positive().max(1000).optional().describe("Maximum rows to return.");
9
- const scene = z.string().optional().describe("Restrict to one developer-assigned scene id.");
10
- const session = z.string().optional().describe("Scope the aggregate to a single session id.");
11
- const cellSize = z.number().positive().max(1000).optional().describe("Voxel size in world units.");
12
- const interval = z
13
- .number()
14
- .int()
15
- .positive()
16
- .optional()
17
- .describe("Time-series bucket width, seconds.");
18
- const eventType = z
19
- .string()
20
- .optional()
21
- .describe("Restrict to a single event type, e.g. pointer_click.");
22
- const source = z
23
- .enum(["mouse", "touch", "stylus", "pen", "xr-controller", "hand", "gaze", "transient", "other"])
24
- .optional()
25
- .describe("Restrict a pointer/world heatmap to one input source.");
26
- const cameraMode = z
27
- .enum(["viewer", "first-person"])
28
- .optional()
29
- .describe("Camera navigation mode to scope to: 'viewer' (orbit) or 'first-person' (walkable).");
30
- const rapidTurn = z
31
- .number()
32
- .nonnegative()
33
- .max(Math.PI)
34
- .optional()
35
- .describe("Rapid-turn threshold in radians (0..π); view turns above this flag motion-sickness risk.");
36
- const steps = z
37
- .string()
38
- .min(1)
39
- .describe("Funnel steps as a JSON-encoded array of ordered step predicates (ADR 0038). Required. " +
40
- 'Each step is `{ "type": <event_type>, ... }`; e.g. ' +
41
- '`[{"type":"scene_change","to":"lobby"},{"type":"mesh_interaction","mesh":"buy"}]`.');
42
- /** Build the common `{ since, until }` range params from validated args. */
43
- function range(args) {
44
- return { since: num(args.since), until: num(args.until) };
45
- }
1
+ import { registryToTools } from "./registryTools.js";
46
2
  /**
47
- * The catalog of read-only tools. Each wraps one documented collector query
48
- * endpoint (docs/integration.md §Query). There are intentionally **no**
49
- * ingestion, mutation, or raw per-session event tools the surface is
50
- * aggregate, read-only, and privacy-preserving (ADR 0003 / ADR 0017).
3
+ * The catalog of read-only tools one per metric in the `@uptimizr/db`
4
+ * **semantic metric registry** that the collector serves on an endpoint
5
+ * (ADR 0051 §1, design sketch §A.2). It is **generated**, not hand-written: a
6
+ * new aggregation reaches agents by getting a registry entry, and there is no
7
+ * second list to keep in step. See `registryTools.ts` for how each field is
8
+ * derived.
9
+ *
10
+ * Every tool wraps one documented collector query endpoint (docs/integration.md
11
+ * §Query). There are intentionally **no** ingestion, mutation, or raw
12
+ * per-session event tools — the surface is aggregate, read-only, and
13
+ * privacy-preserving (ADR 0003 / ADR 0017); the registry's two builder-less
14
+ * resource entries (`session_meta`, `scene_representation`) are coarse
15
+ * descriptors, never an event stream.
16
+ *
17
+ * The 20 tool names the hand-written catalog shipped are registry ids verbatim
18
+ * and their argument schemas are unchanged — `__tests__/shippedToolCompat.test.ts`
19
+ * pins that against a frozen fixture, so an MCP client written against the old
20
+ * catalog keeps working.
51
21
  */
52
- export const readTools = [
53
- {
54
- name: "list_sessions",
55
- title: "List recent sessions",
56
- description: "Recent sessions with id, visitor, event count, and start/end times.",
57
- inputSchema: { since, until, limit },
58
- buildRequest: (args) => ({
59
- path: "api/v1/sessions",
60
- params: { ...range(args), limit: num(args.limit) },
61
- }),
62
- },
63
- {
64
- name: "pointer_heatmap",
65
- title: "2D pointer heatmap",
66
- description: "Binned 2D pointer-position heatmap (screen-normalized).",
67
- inputSchema: { since, until, bins, scene, source, session },
68
- buildRequest: (args) => ({
69
- path: "api/v1/heatmaps/pointer",
70
- params: {
71
- ...range(args),
72
- bins: num(args.bins),
73
- scene: str(args.scene),
74
- source: str(args.source),
75
- session: str(args.session),
76
- },
77
- }),
78
- },
79
- {
80
- name: "world_heatmap",
81
- title: "3D world-space pointer heatmap",
82
- description: "Voxelized world-space pointer heatmap.",
83
- inputSchema: { since, until, cellSize, limit, scene, source },
84
- buildRequest: (args) => ({
85
- path: "api/v1/heatmaps/world",
86
- params: {
87
- ...range(args),
88
- cellSize: num(args.cellSize),
89
- limit: num(args.limit),
90
- scene: str(args.scene),
91
- source: str(args.source),
92
- },
93
- }),
94
- },
95
- {
96
- name: "camera_heatmap",
97
- title: "View-direction heatmap",
98
- description: "Camera view-direction distribution as spherical bins.",
99
- inputSchema: { since, until, bins, scene, session },
100
- buildRequest: (args) => ({
101
- path: "api/v1/heatmaps/camera",
102
- params: {
103
- ...range(args),
104
- bins: num(args.bins),
105
- scene: str(args.scene),
106
- session: str(args.session),
107
- },
108
- }),
109
- },
110
- {
111
- name: "click_rays",
112
- title: "View-gated click rays",
113
- description: "Clicks ASOF-joined to their nearest camera sample, per voxel and clicked mesh.",
114
- inputSchema: { since, until, cellSize, limit, scene, source, session },
115
- buildRequest: (args) => ({
116
- path: "api/v1/heatmaps/click-rays",
117
- params: {
118
- ...range(args),
119
- cellSize: num(args.cellSize),
120
- limit: num(args.limit),
121
- scene: str(args.scene),
122
- source: str(args.source),
123
- session: str(args.session),
124
- },
125
- }),
126
- },
127
- {
128
- name: "flow_links",
129
- title: "Gaze→mesh flow links",
130
- description: "Aggregate links from camera-direction bins to clicked meshes.",
131
- inputSchema: { since, until, bins, limit, scene, session },
132
- buildRequest: (args) => ({
133
- path: "api/v1/heatmaps/flow",
134
- params: {
135
- ...range(args),
136
- bins: num(args.bins),
137
- limit: num(args.limit),
138
- scene: str(args.scene),
139
- session: str(args.session),
140
- },
141
- }),
142
- },
143
- {
144
- name: "top_meshes",
145
- title: "Most-interacted meshes",
146
- description: "Meshes ranked by interaction count.",
147
- inputSchema: { since, until, limit, session },
148
- buildRequest: (args) => ({
149
- path: "api/v1/meshes/top",
150
- params: { ...range(args), limit: num(args.limit), session: str(args.session) },
151
- }),
152
- },
153
- {
154
- name: "perf_summary",
155
- title: "Rendering performance summary",
156
- description: "Sample count and avg/min/p50 FPS over the range.",
157
- inputSchema: { since, until, session },
158
- buildRequest: (args) => ({
159
- path: "api/v1/perf",
160
- params: { ...range(args), session: str(args.session) },
161
- }),
162
- },
163
- {
164
- name: "list_scenes",
165
- title: "List active scenes",
166
- description: "Distinct developer-assigned scenes with activity.",
167
- inputSchema: { since, until, limit },
168
- buildRequest: (args) => ({
169
- path: "api/v1/scenes",
170
- params: { ...range(args), limit: num(args.limit) },
171
- }),
172
- },
173
- {
174
- name: "timeseries",
175
- title: "Event-volume time series",
176
- description: "Event-volume buckets over time, with average FPS per bucket.",
177
- inputSchema: { since, until, interval, scene, type: eventType },
178
- buildRequest: (args) => ({
179
- path: "api/v1/timeseries",
180
- params: {
181
- ...range(args),
182
- interval: num(args.interval),
183
- scene: str(args.scene),
184
- type: str(args.type),
185
- },
186
- }),
187
- },
188
- {
189
- name: "event_counts",
190
- title: "Per-event-type counts",
191
- description: "Counts per event type over the range (scene-health panel).",
192
- inputSchema: { since, until, scene },
193
- buildRequest: (args) => ({
194
- path: "api/v1/event-counts",
195
- params: { ...range(args), scene: str(args.scene) },
196
- }),
197
- },
198
- {
199
- name: "session_meta",
200
- title: "Session descriptor",
201
- description: "Coarse descriptor for one session (device/scene/user). No raw event stream.",
202
- inputSchema: { sessionId: z.string().min(1).describe("The session id to describe.") },
203
- buildRequest: (args) => ({
204
- path: `api/v1/sessions/${encodeURIComponent(str(args.sessionId) ?? "")}/meta`,
205
- params: {},
206
- }),
207
- },
208
- {
209
- name: "scene_representation",
210
- title: "Scene representation",
211
- description: "Registered proxy geometry (bounds/meshes) for one scene, if any.",
212
- inputSchema: { sceneId: z.string().min(1).describe("The scene id to fetch.") },
213
- buildRequest: (args) => ({
214
- path: `api/v1/scenes/${encodeURIComponent(str(args.sceneId) ?? "")}/representation`,
215
- params: {},
216
- }),
217
- },
218
- {
219
- name: "funnel",
220
- title: "Conversion funnel",
221
- description: "Ordered, per-session conversion funnel (ADR 0038): how many sessions reach each " +
222
- "caller-supplied step. Steps are a JSON array (see the `steps` argument).",
223
- inputSchema: { since, until, scene, cameraMode, steps },
224
- buildRequest: (args) => ({
225
- path: "api/v1/funnel",
226
- params: {
227
- ...range(args),
228
- scene: str(args.scene),
229
- cameraMode: str(args.cameraMode),
230
- steps: str(args.steps),
231
- },
232
- }),
233
- },
234
- {
235
- name: "aggregate_paths",
236
- title: "Aggregate desire-line paths",
237
- description: "Crowd-level movement routes (ADR 0037): every session's camera path binned onto the " +
238
- "ground grid and returned as ordered, session-keyed points for an overlaid route map.",
239
- inputSchema: { since, until, cellSize, limit, scene, cameraMode },
240
- buildRequest: (args) => ({
241
- path: "api/v1/paths",
242
- params: {
243
- ...range(args),
244
- cellSize: num(args.cellSize),
245
- limit: num(args.limit),
246
- scene: str(args.scene),
247
- cameraMode: str(args.cameraMode),
248
- },
249
- }),
250
- },
251
- {
252
- name: "rendering_technology",
253
- title: "Rendering-technology breakdown",
254
- description: "Rendering-technology mix from session_start.graphics (ADR 0046): session count per " +
255
- "(api, backend, api_version, shading_language) — WebGPU vs WebGL2 and shading language.",
256
- inputSchema: { since, until, scene, session },
257
- buildRequest: (args) => ({
258
- path: "api/v1/rendering-technology",
259
- params: { ...range(args), scene: str(args.scene), session: str(args.session) },
260
- }),
261
- },
262
- {
263
- name: "xr_rotation",
264
- title: "XR head-rotation rate",
265
- description: "XR head/view rotation rate (ADR 0048), a motion-sickness proxy: per-session rapid-turn " +
266
- "counts over the camera pose stream.",
267
- inputSchema: { since, until, rapidTurn, limit, scene, session },
268
- buildRequest: (args) => ({
269
- path: "api/v1/xr/rotation",
270
- params: {
271
- ...range(args),
272
- rapidTurn: num(args.rapidTurn),
273
- limit: num(args.limit),
274
- scene: str(args.scene),
275
- session: str(args.session),
276
- },
277
- }),
278
- },
279
- {
280
- name: "xr_sources",
281
- title: "XR input-source usage",
282
- description: "XR input-source split (ADR 0048): hand vs. controller vs. gaze usage.",
283
- inputSchema: { since, until, limit, scene, session },
284
- buildRequest: (args) => ({
285
- path: "api/v1/xr/sources",
286
- params: {
287
- ...range(args),
288
- limit: num(args.limit),
289
- scene: str(args.scene),
290
- session: str(args.session),
291
- },
292
- }),
293
- },
294
- {
295
- name: "xr_abandonment",
296
- title: "XR session abandonment",
297
- description: "XR session abandonment (ADR 0048): per XR session, its time bounds and event/interaction " +
298
- "counts; a short span signals headset drop-off.",
299
- inputSchema: { since, until, limit, scene, session },
300
- buildRequest: (args) => ({
301
- path: "api/v1/xr/abandonment",
302
- params: {
303
- ...range(args),
304
- limit: num(args.limit),
305
- scene: str(args.scene),
306
- session: str(args.session),
307
- },
308
- }),
309
- },
310
- {
311
- name: "xr_locomotion",
312
- title: "XR locomotion & comfort",
313
- description: "XR locomotion & comfort (ADR 0048): per XR session, its locomotion-style mix " +
314
- "(fly / navigate / teleport + duration) and wall-clock span — a discomfort proxy.",
315
- inputSchema: { since, until, limit, scene, session },
316
- buildRequest: (args) => ({
317
- path: "api/v1/xr/locomotion",
318
- params: {
319
- ...range(args),
320
- limit: num(args.limit),
321
- scene: str(args.scene),
322
- session: str(args.session),
323
- },
324
- }),
325
- },
326
- ];
22
+ export const readTools = registryToTools();
327
23
  /**
328
24
  * Names of the **core** read tools — a small, single-step-friendly subset of
329
25
  * {@link readTools} for small local models (ADR 0050). A 4-bit 7–8B model folds
330
- * every tool schema into its function-calling system prompt, so sending all 20
331
- * overwhelms it and degrades selection even for simple questions. This subset
332
- * covers the most common single-metric questions (recent sessions, active
333
- * scenes, top meshes, FPS, event counts, event volume over time, and one
26
+ * every tool schema into its function-calling system prompt, so sending the
27
+ * whole catalog overwhelms it and degrades selection even for simple questions.
28
+ * This subset covers the most common single-metric questions (recent sessions,
29
+ * active scenes, top meshes, FPS, event counts, event volume over time, and one
334
30
  * view-direction heatmap).
335
31
  *
336
32
  * Plain string membership only — used to FILTER {@link readTools} below, never to
@@ -358,4 +54,18 @@ export const coreReadTools = readTools.filter((tool) => CORE_READ_TOOL_NAMES.inc
358
54
  export function selectReadTools(kind) {
359
55
  return kind === "core" ? coreReadTools : readTools;
360
56
  }
57
+ /**
58
+ * Narrow the catalog to a caller-supplied set of tool names, preserving catalog
59
+ * order and identity. Unknown names are ignored, so a host app that pins a tool
60
+ * list cannot break when the registry renames or retires a metric — check the
61
+ * result's length if that matters to you.
62
+ *
63
+ * Use it when a model's context budget or a product decision calls for a
64
+ * deliberate subset (see {@link coreReadTools} for the built-in small-model one)
65
+ * rather than the full ~69-tool surface.
66
+ */
67
+ export function filterReadTools(names) {
68
+ const wanted = new Set(names);
69
+ return readTools.filter((tool) => wanted.has(tool.name));
70
+ }
361
71
  //# sourceMappingURL=tools.js.map
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAgCrD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAwB,eAAe,EAAE,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,eAAe;IACf,aAAa;IACb,YAAY;IACZ,cAAc;IACd,cAAc;IACd,YAAY;IACZ,gBAAgB;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAwB,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAC1E,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CACzC,CAAC;AAKF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAqB;IACnD,OAAO,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC"}
package/llms.txt CHANGED
@@ -11,9 +11,36 @@
11
11
  - [Integration & API reference](https://github.com/RaananW/Uptimizr/blob/main/docs/integration.md): the underlying query endpoints.
12
12
  - [Architecture Decision Records](https://github.com/RaananW/Uptimizr/tree/main/docs/adr): in-browser assistant (0050), privacy model (0003), thin backends (0005), consumer-facing agents (0017).
13
13
 
14
+ ## Tools (read-only)
15
+
16
+ <!-- generated:registry-tool-names:start — generated by `pnpm gen:docs`; edit the metric registry, not this list -->
17
+
18
+ `list_sessions`, `session_meta`, `scene_representation`, `list_scenes`, `timeseries`,
19
+ `event_counts`, `pointer_heatmap`, `mesh_uv_heatmap`, `world_heatmap`, `world_heatmap_stats`,
20
+ `gaze_heatmap`, `gaze_heatmap_stats`, `camera_heatmap`, `view_coverage_histogram`,
21
+ `position_heatmap`, `session_trajectory`, `aggregate_paths`, `scene_coverage`, `camera_distance`,
22
+ `click_rays`, `flow_links`, `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_dwell`,
23
+ `mesh_blind_spots`, `mesh_interaction_kinds`, `mesh_reachability`, `dead_clicks`, `rage_clicks`,
24
+ `hover_dwell`, `interaction_sources`, `top_input_actions`, `camera_gestures`, `navigation_stats`,
25
+ `backtrack_ratio`, `perf_summary`, `render_scale_truth`, `perf_distribution`, `fps_histogram`,
26
+ `frame_time_percentiles`, `jank_rate`, `perf_churn`, `perf_by_device`, `perf_by_scene`,
27
+ `perf_heatmap`, `compile_stalls`, `resource_summary`, `resource_percentiles`, `stability_counts`,
28
+ `graphics_diagnostics`, `error_heatmap`, `rendering_technology`, `capability_changes`,
29
+ `xr_rotation`, `xr_sources`, `xr_abandonment`, `xr_locomotion`, `xr_tracking_quality`,
30
+ `boundary_heatmap`, `boundary_heatmap_stats`, `xr_boundary_contacts`,
31
+ `ar_placement_time_to_place`, `ar_placement_attempts`, `ar_placement_surfaces`, `funnel`,
32
+ `scene_retention`, `load_bounce_funnel`, `variant_leaderboard`
33
+
34
+ <!-- generated:registry-tool-names:end -->
35
+
14
36
  ## Key exports
15
37
 
16
- - `readTools` — the read-only tool catalog (one entry per query endpoint).
38
+ - `readTools` — the read-only tool catalog (one entry per query endpoint), generated from the
39
+ `@uptimizr/metrics` metric registry: 69 tools, each with an input schema, an output schema and the
40
+ metric's interpretation notes and caveats in its description (ADR 0051).
41
+ - `coreReadTools` / `selectReadTools(kind)` / `filterReadTools(names)` — narrowed views of the
42
+ catalog for models that cannot carry every tool schema.
43
+ - `registryToTools(metrics?)` — generate the catalog from metric-registry definitions.
17
44
  - `createCollectorClient(config)` — the thin GET-only collector client.
18
45
  - `runAgent(options)` — the headless tool-calling loop (LLM ↔ tools ↔ collector).
19
46
  - `toToolSchemas(tools?)` — convert catalog tools to JSON-Schema tool descriptors for an LLM.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uptimizr/agent-core",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Framework-agnostic, browser-safe core for Uptimizr analytics agents — the single read-only tool catalog over the collector query API, a headless LLM provider-adapter interface, and the tool-calling loop.",
5
5
  "keywords": [
6
6
  "uptimizr",
@@ -58,7 +58,8 @@
58
58
  ],
59
59
  "sideEffects": false,
60
60
  "dependencies": {
61
- "zod": "^4.5.4"
61
+ "zod": "^4.5.4",
62
+ "@uptimizr/metrics": "0.1.0"
62
63
  },
63
64
  "peerDependencies": {
64
65
  "@mlc-ai/web-llm": "^0.2.0"
@@ -70,6 +71,7 @@
70
71
  },
71
72
  "devDependencies": {
72
73
  "@mlc-ai/web-llm": "^0.2.84",
74
+ "esbuild": "^0.28.2",
73
75
  "vitest": "^4.1.11"
74
76
  },
75
77
  "engines": {