@datalayer/core 1.1.66 → 1.2.12

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.
Files changed (237) hide show
  1. package/README.md +43 -20
  2. package/lib/api/constants.d.ts +1 -1
  3. package/lib/api/constants.js +1 -1
  4. package/lib/api/contents/attachments.js +3 -7
  5. package/lib/api/contents/datasets.d.ts +48 -0
  6. package/lib/api/contents/datasets.js +44 -7
  7. package/lib/api/contents/runtimeMounts.js +1 -1
  8. package/lib/api/contents/sandboxUid.d.ts +13 -45
  9. package/lib/api/contents/sandboxUid.js +14 -65
  10. package/lib/api/evals/client.d.ts +402 -0
  11. package/lib/api/evals/client.js +359 -0
  12. package/lib/api/evals/index.d.ts +10 -0
  13. package/lib/api/evals/index.js +18 -0
  14. package/lib/api/evals/request.d.ts +43 -0
  15. package/lib/api/evals/request.js +67 -0
  16. package/lib/api/evals/status.d.ts +27 -0
  17. package/lib/api/evals/status.js +122 -0
  18. package/lib/api/evals/types.d.ts +1335 -0
  19. package/lib/api/evals/types.js +5 -0
  20. package/lib/api/iam/authentication.js +6 -4
  21. package/lib/api/iam/connectedAgents.d.ts +29 -0
  22. package/lib/api/iam/connectedAgents.js +35 -0
  23. package/lib/api/iam/healthz.js +2 -2
  24. package/lib/api/iam/identityProviders.d.ts +76 -0
  25. package/lib/api/iam/identityProviders.js +187 -0
  26. package/lib/api/iam/index.d.ts +1 -0
  27. package/lib/api/iam/index.js +1 -0
  28. package/lib/api/iam/mcpPolicy.d.ts +102 -1
  29. package/lib/api/iam/mcpPolicy.js +38 -2
  30. package/lib/api/iam/oauth2.js +18 -12
  31. package/lib/api/iam/profile.d.ts +17 -1
  32. package/lib/api/iam/profile.js +27 -0
  33. package/lib/api/iam/scimTokens.d.ts +79 -0
  34. package/lib/api/iam/scimTokens.js +141 -0
  35. package/lib/api/iam/secrets.js +10 -23
  36. package/lib/api/iam/trials.d.ts +38 -0
  37. package/lib/api/iam/trials.js +66 -0
  38. package/lib/api/index.d.ts +4 -0
  39. package/lib/api/index.js +4 -0
  40. package/lib/api/mcp/observability.d.ts +34 -11
  41. package/lib/api/mcp/observability.js +97 -59
  42. package/lib/api/orchestration/client.d.ts +53 -0
  43. package/lib/api/orchestration/client.js +105 -0
  44. package/lib/api/orchestration/events.d.ts +88 -0
  45. package/lib/api/orchestration/events.js +245 -0
  46. package/lib/api/orchestration/generated.d.ts +693 -0
  47. package/lib/api/orchestration/generated.js +687 -0
  48. package/lib/api/orchestration/index.d.ts +30 -0
  49. package/lib/api/orchestration/index.js +34 -0
  50. package/lib/api/orchestration/lifecycle.d.ts +39 -0
  51. package/lib/api/orchestration/lifecycle.js +57 -0
  52. package/lib/api/orchestration/measures.d.ts +55 -0
  53. package/lib/api/orchestration/measures.js +99 -0
  54. package/lib/api/otel/dashboards.d.ts +56 -0
  55. package/lib/api/otel/dashboards.js +50 -0
  56. package/lib/api/otel/index.d.ts +1 -0
  57. package/lib/api/otel/index.js +1 -0
  58. package/lib/api/otel/metrics.d.ts +16 -0
  59. package/lib/api/otel/metrics.js +15 -0
  60. package/lib/api/scheduler/client.d.ts +32 -0
  61. package/lib/api/scheduler/client.js +42 -0
  62. package/lib/api/scheduler/index.d.ts +8 -0
  63. package/lib/api/scheduler/index.js +16 -0
  64. package/lib/api/scheduler/request.d.ts +28 -0
  65. package/lib/api/scheduler/request.js +50 -0
  66. package/lib/api/scheduler/types.d.ts +88 -0
  67. package/lib/api/scheduler/types.js +5 -0
  68. package/lib/api/spacer/comments.d.ts +97 -0
  69. package/lib/api/spacer/comments.js +45 -0
  70. package/lib/api/spacer/index.d.ts +9 -0
  71. package/lib/api/spacer/index.js +17 -0
  72. package/lib/api/spacer/notebooks.d.ts +33 -0
  73. package/lib/api/spacer/notebooks.js +39 -0
  74. package/lib/api/spacer/request.d.ts +25 -0
  75. package/lib/api/spacer/request.js +46 -0
  76. package/lib/api/spacer/spaces.d.ts +68 -0
  77. package/lib/api/spacer/spaces.js +45 -0
  78. package/lib/api/utils/validation.d.ts +4 -4
  79. package/lib/api/utils/validation.js +10 -7
  80. package/lib/client/auth/strategies.js +1 -1
  81. package/lib/client/constants.d.ts +1 -0
  82. package/lib/client/constants.js +1 -0
  83. package/lib/client/mixins/IAMMixin.js +2 -2
  84. package/lib/components/animation/AnimatedText.d.ts +1 -44
  85. package/lib/components/animation/AnimatedText.js +6 -122
  86. package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
  87. package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
  88. package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
  89. package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
  90. package/lib/components/anonymous/index.d.ts +7 -0
  91. package/lib/components/anonymous/index.js +15 -0
  92. package/lib/components/avatars/UserAvatar.d.ts +7 -1
  93. package/lib/components/avatars/UserAvatar.js +15 -1
  94. package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
  95. package/lib/components/billing/BillingEntitySelect.js +49 -10
  96. package/lib/components/billing/eligibility.d.ts +22 -0
  97. package/lib/components/billing/eligibility.js +27 -0
  98. package/lib/components/billing/index.d.ts +1 -0
  99. package/lib/components/billing/index.js +1 -0
  100. package/lib/components/checkout/StripeCheckout.d.ts +1 -1
  101. package/lib/components/checkout/StripeCheckout.js +1 -1
  102. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
  103. package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
  104. package/lib/components/display/DatalayerBox.d.ts +2 -3
  105. package/lib/components/display/DatalayerBox.js +1 -1
  106. package/lib/components/display/NavLink.js +3 -2
  107. package/lib/components/display/VisuallyHidden.d.ts +1 -2
  108. package/lib/components/labels/StatusLabels.d.ts +2 -10
  109. package/lib/components/labels/StatusLabels.js +2 -26
  110. package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
  111. package/lib/components/principal/PrincipalAppearance.js +232 -174
  112. package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
  113. package/lib/components/principal/PrincipalAvatar.js +2 -2
  114. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
  115. package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
  116. package/lib/components/screencapture/Screencapture.js +46 -3
  117. package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
  118. package/lib/components/sharing/ShareAccessComponent.js +110 -78
  119. package/lib/components/sharing/SharingEditor.d.ts +5 -1
  120. package/lib/components/sharing/SharingEditor.js +9 -4
  121. package/lib/components/sharing/index.d.ts +1 -0
  122. package/lib/components/sharing/index.js +1 -0
  123. package/lib/components/sharing/sandboxSharing.d.ts +26 -0
  124. package/lib/components/sharing/sandboxSharing.js +47 -0
  125. package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
  126. package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
  127. package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
  128. package/lib/components/spaces/SpaceDisplay.js +92 -0
  129. package/lib/components/spaces/index.d.ts +4 -0
  130. package/lib/components/spaces/index.js +7 -0
  131. package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
  132. package/lib/components/spaces/spaceDisplayModel.js +170 -0
  133. package/lib/config/Configuration.d.ts +4 -4
  134. package/lib/config/Configuration.js +7 -7
  135. package/lib/config/index.d.ts +1 -0
  136. package/lib/config/index.js +1 -0
  137. package/lib/config/planes.d.ts +45 -0
  138. package/lib/config/planes.js +53 -0
  139. package/lib/hooks/cacheConverters.d.ts +0 -7
  140. package/lib/hooks/cacheConverters.js +0 -25
  141. package/lib/hooks/index.d.ts +1 -0
  142. package/lib/hooks/index.js +1 -0
  143. package/lib/hooks/useBackdrop.d.ts +4 -5
  144. package/lib/hooks/useBillingEntityStore.js +3 -0
  145. package/lib/hooks/useCache.d.ts +197 -44
  146. package/lib/hooks/useCache.js +1586 -494
  147. package/lib/hooks/useContents.d.ts +22 -1
  148. package/lib/hooks/useContents.js +90 -21
  149. package/lib/hooks/useMcp.d.ts +87 -1
  150. package/lib/hooks/useMcp.js +248 -13
  151. package/lib/hooks/useNavigate.d.ts +41 -3
  152. package/lib/hooks/useNavigate.js +116 -52
  153. package/lib/hooks/usePrincipalCacheStore.js +3 -0
  154. package/lib/hooks/usePrincipalStore.js +3 -0
  155. package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
  156. package/lib/hooks/useSpaceCacheStore.js +85 -0
  157. package/lib/hooks/useWindowSize.js +1 -1
  158. package/lib/models/CreditsDTO.d.ts +6 -5
  159. package/lib/models/CreditsDTO.js +7 -5
  160. package/lib/models/IAMProvidersSpecs.d.ts +10 -5
  161. package/lib/models/IAMProvidersSpecs.js +0 -23
  162. package/lib/models/McpBinding.d.ts +6 -0
  163. package/lib/models/Organization.d.ts +69 -0
  164. package/lib/models/Organization.js +96 -0
  165. package/lib/models/Secret.d.ts +1 -2
  166. package/lib/models/Secret.js +2 -18
  167. package/lib/models/StartedBy.d.ts +34 -0
  168. package/lib/models/StartedBy.js +36 -0
  169. package/lib/models/Team.d.ts +2 -0
  170. package/lib/models/Team.js +2 -0
  171. package/lib/models/User.d.ts +4 -0
  172. package/lib/models/User.js +3 -0
  173. package/lib/models/UserSettings.d.ts +13 -0
  174. package/lib/models/UserSettings.js +9 -0
  175. package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
  176. package/lib/navigation/adapters/react-router.d.ts +1 -1
  177. package/lib/navigation/adapters/react-router.js +3 -0
  178. package/lib/navigation/components.js +2 -3
  179. package/lib/routes/publicPaths.js +4 -0
  180. package/lib/state/index.d.ts +1 -0
  181. package/lib/state/index.js +1 -0
  182. package/lib/state/sessionEnd.d.ts +55 -0
  183. package/lib/state/sessionEnd.js +162 -0
  184. package/lib/state/substates/CoreState.js +3 -16
  185. package/lib/state/substates/IAMState.d.ts +3 -3
  186. package/lib/state/substates/IAMState.js +7 -0
  187. package/lib/state/substates/LayoutState.js +12 -0
  188. package/lib/state/substates/NavigationState.d.ts +82 -0
  189. package/lib/state/substates/NavigationState.js +255 -0
  190. package/lib/state/substates/ProfileState.d.ts +1 -0
  191. package/lib/state/substates/ProfileState.js +1 -0
  192. package/lib/state/substates/index.d.ts +1 -0
  193. package/lib/state/substates/index.js +1 -0
  194. package/lib/utils/Lazy.d.ts +20 -0
  195. package/lib/utils/Lazy.js +32 -6
  196. package/lib/utils/Screencapture.d.ts +15 -0
  197. package/lib/utils/Screencapture.js +26 -20
  198. package/lib/utils/WithSuspense.d.ts +11 -1
  199. package/lib/utils/WithSuspense.js +11 -1
  200. package/lib/views/mcp/AdmittedClients.d.ts +44 -0
  201. package/lib/views/mcp/AdmittedClients.js +59 -0
  202. package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
  203. package/lib/views/mcp/ApprovalQueue.js +95 -0
  204. package/lib/views/mcp/ConnectedAgents.js +38 -3
  205. package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
  206. package/lib/views/mcp/EnterpriseConsole.js +23 -1
  207. package/lib/views/mcp/IdentityProviders.d.ts +33 -0
  208. package/lib/views/mcp/IdentityProviders.js +299 -0
  209. package/lib/views/mcp/McpDashboard.js +90 -7
  210. package/lib/views/mcp/McpHome.js +1 -1
  211. package/lib/views/mcp/McpObservability.d.ts +30 -1
  212. package/lib/views/mcp/McpObservability.js +105 -19
  213. package/lib/views/mcp/NotebookRuns.d.ts +39 -0
  214. package/lib/views/mcp/NotebookRuns.js +44 -0
  215. package/lib/views/mcp/OrganizationPolicy.js +2 -1
  216. package/lib/views/mcp/PersonalPolicy.js +2 -1
  217. package/lib/views/mcp/PolicyForm.d.ts +17 -1
  218. package/lib/views/mcp/PolicyForm.js +25 -3
  219. package/lib/views/mcp/PolicyHistory.d.ts +13 -0
  220. package/lib/views/mcp/PolicyHistory.js +14 -1
  221. package/lib/views/mcp/RunDetail.d.ts +87 -0
  222. package/lib/views/mcp/RunDetail.js +186 -0
  223. package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
  224. package/lib/views/mcp/ScimProvisioning.js +173 -0
  225. package/lib/views/mcp/TeamPolicies.js +66 -5
  226. package/lib/views/mcp/ToolAccess.d.ts +60 -0
  227. package/lib/views/mcp/ToolAccess.js +101 -0
  228. package/lib/views/mcp/TraceTimeline.d.ts +81 -0
  229. package/lib/views/mcp/TraceTimeline.js +132 -0
  230. package/lib/views/mcp/index.d.ts +5 -0
  231. package/lib/views/mcp/index.js +5 -0
  232. package/lib/views/otel/simpleAuthStore.js +3 -0
  233. package/lib/views/secrets/SecretEdit.js +3 -2
  234. package/lib/views/secrets/SecretNew.js +5 -1
  235. package/package.json +271 -264
  236. package/scripts/generate-mcp-types.py +16 -10
  237. package/scripts/generate-orchestration-types.py +920 -0
@@ -13,17 +13,21 @@
13
13
  * Audit answers *who did what, and was it allowed*; this answers *how did
14
14
  * it run*. A task carries its `trace_id`, so "show me this run" is the
15
15
  * task's spans; its logs are the log records of that trace; and the four
16
- * SLIs are read from the gateway's metric catalog. Metrics carry no user,
17
- * agent or organization label by design, so a per-agent reading is
18
- * computed from the `mcp.request` spans, which do carry `client.id` and
19
- * `org.uid`.
16
+ * SLIs are read from the OTEL service's service levels dashboard, which
17
+ * computes them from the metrics as they were exported — a counter's
18
+ * increase, a percentile from a histogram's buckets. Nothing here adds
19
+ * metric points up: the gateway reports running totals, and adding those
20
+ * counts every earlier report again. Metrics carry no user, agent or
21
+ * organization label by design, so a per-agent reading is computed from the
22
+ * `mcp.request` spans, which do carry `client.id` and `org.uid`.
20
23
  *
21
24
  * @module api/mcp/observability
22
25
  */
23
26
  import { DEFAULT_SERVICE_URLS } from '../constants.js';
24
27
  import { getTrace, listTraces } from '../otel/traces.js';
25
- import { queryMetrics } from '../otel/metrics.js';
28
+ import { listMetricNames } from '../otel/metrics.js';
26
29
  import { queryLogs } from '../otel/logs.js';
30
+ import { getDashboardData } from '../otel/dashboards.js';
27
31
  /**
28
32
  * The `service.name` the gateway exports under, and the one its workers use.
29
33
  *
@@ -33,8 +37,15 @@ import { queryLogs } from '../otel/logs.js';
33
37
  * queryable after the process is gone.
34
38
  */
35
39
  export const MCP_GATEWAY_SERVICE_NAME = 'jupyter-mcp-server';
36
- /** The `service.name` a worker's relayed output is filed under. */
37
- export const MCP_WORKER_SERVICE_NAME = 'jupyter-mcp-worker';
40
+ /**
41
+ * The `service.name` a worker's relayed output is filed under.
42
+ *
43
+ * `mcp-worker` since the service was renamed to `datalayer-mcp-server`: the
44
+ * gateway names its workers, and a name carrying `jupyter` said the wrong
45
+ * thing about a process that serves Datalayer sandboxes as readily as a
46
+ * Jupyter server.
47
+ */
48
+ export const MCP_WORKER_SERVICE_NAME = 'mcp-worker';
38
49
  /**
39
50
  * The `service.name` the durable execution service exports under.
40
51
  *
@@ -94,6 +105,21 @@ export const MCP_SLI_METRICS = {
94
105
  taskSuccess: 'mcp.tasks',
95
106
  sandboxLaunch: 'sandbox.launch_seconds',
96
107
  };
108
+ /** The OTEL service's built-in dashboard the four SLIs are read from. */
109
+ export const MCP_SERVICE_LEVELS_DASHBOARD = 'mcp-service-levels';
110
+ /**
111
+ * Its panels, by the ids the OTEL service gives them. A contract test there
112
+ * holds them, so a panel renamed on the service fails a test rather than
113
+ * reading here as nothing measured.
114
+ */
115
+ export const MCP_SERVICE_LEVEL_PANELS = {
116
+ callsByOutcome: 'mcp-calls-by-outcome',
117
+ callDurationP95: 'mcp-call-duration-p95',
118
+ tasksByStatus: 'mcp-tasks-by-status',
119
+ sandboxLaunchP95: 'sandbox-launch_seconds-by-provider-p95',
120
+ sandboxLaunches: 'sandbox-launch_seconds-by-provider-count',
121
+ };
122
+ const TERMINAL_STATUSES = ['completed', 'failed', 'cancelled'];
97
123
  /** The nearest-rank percentile of a sample; `null` for an empty one. */
98
124
  export const percentile = (values, fraction) => {
99
125
  if (values.length === 0) {
@@ -107,50 +133,43 @@ const attribute = (holder, name) => String(holder.attributes?.[name] ?? '');
107
133
  const notBefore = (timestamp, since) => !since || !timestamp || timestamp >= since;
108
134
  /** Whether an `mcp.request` span is a failed call in the availability sense. */
109
135
  const isUnavailable = (span) => {
110
- const status = attribute(span, 'http.response.status_code') || attribute(span, 'http.status_code');
111
- const rpc = attribute(span, 'rpc.jsonrpc.error_code') || attribute(span, 'mcp.error.code');
136
+ const status = attribute(span, 'http.response.status_code') ||
137
+ attribute(span, 'http.status_code');
138
+ const rpc = attribute(span, 'rpc.jsonrpc.error_code') ||
139
+ attribute(span, 'mcp.error.code');
112
140
  return status.startsWith('5') || rpc === '-32001';
113
141
  };
114
142
  /**
115
- * The SLIs over catalog points — the platform-wide reading.
143
+ * The SLIs from the service levels dashboard — the platform-wide reading.
116
144
  *
117
- * `mcp.calls{outcome}` gives availability, `mcp.call.duration{tool}` the
118
- * latency, `mcp.tasks{status}` the task success rate and
119
- * `sandbox.launch_seconds{provider}` the launches.
145
+ * Its panels arrive summarised: calls and tasks as how much each counter grew
146
+ * over the window, the two p95s from their histograms' buckets. The call
147
+ * duration is recorded in seconds and shown in milliseconds. A panel with
148
+ * nothing in it reads as not measured, never as a zero.
120
149
  */
121
- export const summarizeMetricPoints = (metrics, filters = {}) => {
122
- const within = (point) => notBefore(point.timestamp, filters.since);
123
- const calls = (metrics['mcp.calls'] ?? []).filter(within);
124
- const totalCalls = calls.reduce((sum, point) => sum + point.value, 0);
125
- const failedCalls = calls
126
- .filter(point => ['error', 'unavailable'].includes(attribute(point, 'outcome')))
127
- .reduce((sum, point) => sum + point.value, 0);
128
- const durations = (metrics['mcp.call.duration'] ?? []).filter(within).map(point => point.value);
129
- const tasks = (metrics['mcp.tasks'] ?? []).filter(within);
130
- const terminal = tasks.filter(point => ['completed', 'failed', 'cancelled'].includes(attribute(point, 'status')));
131
- const totalTerminal = terminal.reduce((sum, point) => sum + point.value, 0);
132
- const completed = terminal
133
- .filter(point => attribute(point, 'status') === 'completed')
134
- .reduce((sum, point) => sum + point.value, 0);
135
- const launches = (metrics['sandbox.launch_seconds'] ?? []).filter(within);
136
- const byProvider = new Map();
137
- for (const point of launches) {
138
- const provider = attribute(point, 'provider') || 'unknown';
139
- byProvider.set(provider, [...(byProvider.get(provider) ?? []), point.value]);
140
- }
141
- const p95SandboxLaunchSeconds = {};
142
- for (const [provider, values] of byProvider) {
143
- const p95 = percentile(values, 0.95);
144
- if (p95 !== null) {
145
- p95SandboxLaunchSeconds[provider] = p95;
146
- }
147
- }
150
+ export const summarizeServiceLevels = (data) => {
151
+ const panels = new Map(data.panels.map(panel => [panel.id, panel]));
152
+ const byLabel = (id) => Object.fromEntries((panels.get(id)?.series ?? [])
153
+ .filter(entry => entry.summary !== null)
154
+ .map(entry => [entry.label, entry.summary]));
155
+ const total = (values) => Object.values(values).reduce((sum, value) => sum + value, 0);
156
+ const calls = byLabel(MCP_SERVICE_LEVEL_PANELS.callsByOutcome);
157
+ const totalCalls = total(calls);
158
+ const failedCalls = (calls.error ?? 0) + (calls.unavailable ?? 0);
159
+ const tasks = byLabel(MCP_SERVICE_LEVEL_PANELS.tasksByStatus);
160
+ const terminal = TERMINAL_STATUSES.reduce((sum, status) => sum + (tasks[status] ?? 0), 0);
161
+ const p95Seconds = byLabel(MCP_SERVICE_LEVEL_PANELS.callDurationP95)[''];
162
+ const p95SandboxLaunchSeconds = Object.fromEntries(Object.entries(byLabel(MCP_SERVICE_LEVEL_PANELS.sandboxLaunchP95)).map(([provider, seconds]) => [provider || 'unknown', seconds]));
148
163
  return {
149
164
  availability: totalCalls > 0 ? (totalCalls - failedCalls) / totalCalls : null,
150
- p95CallDurationMs: percentile(durations, 0.95),
151
- taskSuccessRate: totalTerminal > 0 ? completed / totalTerminal : null,
165
+ p95CallDurationMs: p95Seconds === undefined ? null : p95Seconds * 1000,
166
+ taskSuccessRate: terminal > 0 ? (tasks.completed ?? 0) / terminal : null,
152
167
  p95SandboxLaunchSeconds,
153
- samples: { calls: totalCalls, tasks: totalTerminal, launches: launches.length },
168
+ samples: {
169
+ calls: totalCalls,
170
+ tasks: terminal,
171
+ launches: total(byLabel(MCP_SERVICE_LEVEL_PANELS.sandboxLaunches)),
172
+ },
154
173
  };
155
174
  };
156
175
  /**
@@ -173,8 +192,12 @@ export const summarizeRequestSpans = (spans, filters = {}) => {
173
192
  const terminal = [...tasks.values()].filter(status => ['completed', 'failed', 'cancelled'].includes(status));
174
193
  const completed = terminal.filter(status => status === 'completed').length;
175
194
  return {
176
- availability: selected.length > 0 ? (selected.length - unavailable) / selected.length : null,
177
- p95CallDurationMs: percentile(selected.filter(span => !attribute(span, 'mcp.task.id')).map(span => span.duration_ms), 0.95),
195
+ availability: selected.length > 0
196
+ ? (selected.length - unavailable) / selected.length
197
+ : null,
198
+ p95CallDurationMs: percentile(selected
199
+ .filter(span => !attribute(span, 'mcp.task.id'))
200
+ .map(span => span.duration_ms), 0.95),
178
201
  taskSuccessRate: terminal.length > 0 ? completed / terminal.length : null,
179
202
  p95SandboxLaunchSeconds: {},
180
203
  samples: { calls: selected.length, tasks: terminal.length, launches: 0 },
@@ -183,21 +206,25 @@ export const summarizeRequestSpans = (spans, filters = {}) => {
183
206
  /** The four SLIs and the catalog, for everyone or for one agent or organization. */
184
207
  export const fetchMcpMetrics = async (token, filters = {}, otelUrl = DEFAULT_SERVICE_URLS.OTEL) => {
185
208
  const limit = filters.limit ?? 500;
186
- const names = Object.values(MCP_SLI_METRICS);
187
- const pages = await Promise.all(names.map(name => queryMetrics(token, { metricName: name, serviceName: serviceNameFor(name), limit }, otelUrl)));
188
- const metrics = {};
189
- names.forEach((name, index) => {
190
- metrics[name] = pages[index].data ?? [];
191
- });
192
209
  const scoped = Boolean(filters.agent || filters.org);
193
- const spans = scoped
194
- ? (await listTraces(token, { serviceName: MCP_GATEWAY_SERVICE_NAME, limit }, otelUrl)).data ?? []
195
- : [];
210
+ const [levels, names, traces] = await Promise.all([
211
+ scoped
212
+ ? undefined
213
+ : getDashboardData(token, MCP_SERVICE_LEVELS_DASHBOARD, { since: filters.since ? new Date(filters.since) : undefined }, otelUrl),
214
+ listMetricNames(token, otelUrl),
215
+ scoped
216
+ ? listTraces(token, { serviceName: MCP_GATEWAY_SERVICE_NAME, limit }, otelUrl)
217
+ : undefined,
218
+ ]);
219
+ const reported = new Set((names.data ?? []).map(row => row.metric_name));
220
+ const spans = traces?.data ?? [];
196
221
  return {
197
222
  filters,
198
- metrics,
223
+ reporting: MCP_METRIC_CATALOG.filter(name => reported.has(name)),
199
224
  spans,
200
- slis: scoped ? summarizeRequestSpans(spans, filters) : summarizeMetricPoints(metrics, filters),
225
+ slis: levels
226
+ ? summarizeServiceLevels(levels)
227
+ : summarizeRequestSpans(spans, filters),
201
228
  readAt: new Date().toISOString(),
202
229
  };
203
230
  };
@@ -209,7 +236,9 @@ export const spanTree = (spans) => {
209
236
  }
210
237
  const roots = [];
211
238
  for (const node of nodes.values()) {
212
- const parent = node.span.parent_span_id ? nodes.get(node.span.parent_span_id) : undefined;
239
+ const parent = node.span.parent_span_id
240
+ ? nodes.get(node.span.parent_span_id)
241
+ : undefined;
213
242
  (parent ? parent.children : roots).push(node);
214
243
  }
215
244
  const byStart = (a, b) => a.span.start_time.localeCompare(b.span.start_time);
@@ -227,7 +256,12 @@ export const fetchRunTrace = async (token, task, otelUrl = DEFAULT_SERVICE_URLS.
227
256
  }
228
257
  const trace = await getTrace(token, task.traceId, otelUrl);
229
258
  const spans = trace.data ?? [];
230
- return { taskUid: task.uid, traceId: task.traceId, spans, tree: spanTree(spans) };
259
+ return {
260
+ taskUid: task.uid,
261
+ traceId: task.traceId,
262
+ spans,
263
+ tree: spanTree(spans),
264
+ };
231
265
  };
232
266
  /**
233
267
  * The spans of one trace, named directly.
@@ -249,6 +283,10 @@ export const fetchMcpLogs = async (token, task, options = {}, otelUrl = DEFAULT_
249
283
  if (!task.traceId) {
250
284
  return { taskUid: task.uid, traceId: '', records: [] };
251
285
  }
252
- const page = await queryLogs(token, { traceId: task.traceId, limit: options.limit ?? 200, severity: options.severity }, otelUrl);
286
+ const page = await queryLogs(token, {
287
+ traceId: task.traceId,
288
+ limit: options.limit ?? 200,
289
+ severity: options.severity,
290
+ }, otelUrl);
253
291
  return { taskUid: task.uid, traceId: task.traceId, records: page.data ?? [] };
254
292
  };
@@ -0,0 +1,53 @@
1
+ import { type EvalsClientOptions, type EvalsQuery } from '../evals/request';
2
+ import { type AgentsAttach, type AgentsCreate, type AgentsDiscover, type CancelAnswer, type CollectAnswer, type CommandAnswer, type DelegateAnswer, type DiscoverAnswer, type ExecutionAnswer, type ExecutionState, type ExecutionsAnswer, type ExecutionsCancel, type ExecutionsCheckpoint, type ExecutionsCollect, type ExecutionsDelegate, type ExecutionsPause, type ExecutionsResume, type ExecutionsSteer, type ExecutionsTerminate, type OrchestrationOperation, type ReportAnswer, type WorkerAnswer } from './generated';
3
+ /** Who calls: the service origin, the caller's token, and the account the executions belong to. */
4
+ export type OrchestrationClientOptions = EvalsClientOptions;
5
+ /**
6
+ * One operation's method and path under `/api/ai-agents/v1`, with its
7
+ * parameters filled in and encoded.
8
+ *
9
+ * @throws Error when the control plane has no such operation, or a
10
+ * parameter the path names is missing.
11
+ */
12
+ export declare const operationPath: (operation: string, parameters?: Record<string, string>) => {
13
+ method: OrchestrationOperation["method"];
14
+ path: string;
15
+ };
16
+ /** The full URL of one operation, with the account scope and a query. */
17
+ export declare const operationUrl: (options: OrchestrationClientOptions, operation: string, parameters?: Record<string, string>, query?: EvalsQuery) => string;
18
+ /** `agents.discover`: the workers meeting every constraint the command states. */
19
+ export declare const discoverAgents: (options: OrchestrationClientOptions, command: AgentsDiscover) => Promise<DiscoverAnswer>;
20
+ /** `agents.create`: bring a worker's compute up. */
21
+ export declare const createAgent: (options: OrchestrationClientOptions, command: AgentsCreate) => Promise<WorkerAnswer>;
22
+ /** `agents.attach`: a worker or a session that is already there. */
23
+ export declare const attachAgent: (options: OrchestrationClientOptions, command: AgentsAttach) => Promise<WorkerAnswer>;
24
+ /** `executions.delegate`: an objective and its context, to a worker. */
25
+ export declare const delegateExecution: (options: OrchestrationClientOptions, command: ExecutionsDelegate) => Promise<DelegateAnswer>;
26
+ /** `executions.steer`: instructions added while the work runs. */
27
+ export declare const steerExecution: (options: OrchestrationClientOptions, command: ExecutionsSteer) => Promise<CommandAnswer>;
28
+ /** `executions.pause`, where the worker's protocol can pause. */
29
+ export declare const pauseExecution: (options: OrchestrationClientOptions, command: ExecutionsPause) => Promise<CommandAnswer>;
30
+ /** `executions.resume`, from where it stopped or from a checkpoint. */
31
+ export declare const resumeExecution: (options: OrchestrationClientOptions, command: ExecutionsResume) => Promise<CommandAnswer>;
32
+ /** `executions.cancel`: stop the work, and by default everything below it. */
33
+ export declare const cancelExecution: (options: OrchestrationClientOptions, command: ExecutionsCancel) => Promise<CancelAnswer>;
34
+ /** `executions.checkpoint`, where the worker's protocol keeps state. */
35
+ export declare const checkpointExecution: (options: OrchestrationClientOptions, command: ExecutionsCheckpoint) => Promise<CommandAnswer>;
36
+ /** `executions.collect`: the artifacts of an execution and of its children. */
37
+ export declare const collectExecution: (options: OrchestrationClientOptions, command: ExecutionsCollect) => Promise<CollectAnswer>;
38
+ /** `executions.terminate`: release the worker, where its protocol can. */
39
+ export declare const terminateExecution: (options: OrchestrationClientOptions, command: ExecutionsTerminate) => Promise<CommandAnswer>;
40
+ /** One execution, its attempts, and the milestones it reached. */
41
+ export declare const getExecution: (options: OrchestrationClientOptions, executionId: string) => Promise<ExecutionAnswer>;
42
+ /**
43
+ * `executions.report`: the execution's live report, a document in the
44
+ * account's orchestration space, written the first time it is asked for and
45
+ * the same one after that.
46
+ */
47
+ export declare const openExecutionReport: (options: OrchestrationClientOptions, executionId: string) => Promise<ReportAnswer>;
48
+ /** The account's executions, oldest first: a tree by its root, a level by its parent. */
49
+ export declare const listExecutions: (options: OrchestrationClientOptions, filter?: {
50
+ rootExecutionId?: string;
51
+ parentExecutionId?: string;
52
+ status?: ExecutionState;
53
+ }) => Promise<ExecutionsAnswer>;
@@ -0,0 +1,105 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /*
6
+ * Copyright (c) 2023-2026 Datalayer, Inc.
7
+ * Distributed under the terms of the Modified BSD License.
8
+ */
9
+ /**
10
+ * The orchestration control plane, as a caller reaches it.
11
+ *
12
+ * Every path comes from `ORCHESTRATION_API`, which is generated from the
13
+ * control plane's own OpenAPI document: this module spells no URL itself, so
14
+ * a route that moves on the service moves here when the types are
15
+ * regenerated — or fails the check that they were not. A view calls these
16
+ * functions and never builds an orchestration path of its own.
17
+ *
18
+ * Bodies are the canonical commands as they are and answers the envelopes
19
+ * the service returns; the wire is camel case on both sides, so nothing is
20
+ * converted.
21
+ *
22
+ * @module api/orchestration/client
23
+ */
24
+ import { API_BASE_PATHS } from '../constants.js';
25
+ import { aiAgentsRequest, aiAgentsUrl, } from '../evals/request.js';
26
+ import { ORCHESTRATION_API, } from './generated.js';
27
+ /**
28
+ * One operation's method and path under `/api/ai-agents/v1`, with its
29
+ * parameters filled in and encoded.
30
+ *
31
+ * @throws Error when the control plane has no such operation, or a
32
+ * parameter the path names is missing.
33
+ */
34
+ export const operationPath = (operation, parameters = {}) => {
35
+ const found = ORCHESTRATION_API.find(one => one.operation === operation);
36
+ if (!found) {
37
+ throw new Error(`The control plane has no operation '${operation}'.`);
38
+ }
39
+ const path = found.path.replace(/\{([^}]+)\}/g, (_, name) => {
40
+ const value = parameters[name];
41
+ if (value === undefined || value === '') {
42
+ throw new Error(`'${operation}' needs '${name}'.`);
43
+ }
44
+ return encodeURIComponent(value);
45
+ });
46
+ if (!path.startsWith(API_BASE_PATHS.AI_AGENTS)) {
47
+ throw new Error(`'${operation}' is not under ${API_BASE_PATHS.AI_AGENTS}: ${found.path}`);
48
+ }
49
+ return {
50
+ method: found.method,
51
+ path: path.slice(API_BASE_PATHS.AI_AGENTS.length),
52
+ };
53
+ };
54
+ /** The full URL of one operation, with the account scope and a query. */
55
+ export const operationUrl = (options, operation, parameters = {}, query = {}) => aiAgentsUrl(options, operationPath(operation, parameters).path, query);
56
+ const call = (options, operation, init = {}) => {
57
+ const { method, path } = operationPath(operation, init.parameters);
58
+ return aiAgentsRequest(options, path, {
59
+ method,
60
+ body: init.body,
61
+ query: init.query,
62
+ });
63
+ };
64
+ /** `agents.discover`: the workers meeting every constraint the command states. */
65
+ export const discoverAgents = (options, command) => call(options, 'agents.discover', { body: command });
66
+ /** `agents.create`: bring a worker's compute up. */
67
+ export const createAgent = (options, command) => call(options, 'agents.create', { body: command });
68
+ /** `agents.attach`: a worker or a session that is already there. */
69
+ export const attachAgent = (options, command) => call(options, 'agents.attach', { body: command });
70
+ /** `executions.delegate`: an objective and its context, to a worker. */
71
+ export const delegateExecution = (options, command) => call(options, 'executions.delegate', { body: command });
72
+ /** `executions.steer`: instructions added while the work runs. */
73
+ export const steerExecution = (options, command) => call(options, 'executions.steer', { body: command });
74
+ /** `executions.pause`, where the worker's protocol can pause. */
75
+ export const pauseExecution = (options, command) => call(options, 'executions.pause', { body: command });
76
+ /** `executions.resume`, from where it stopped or from a checkpoint. */
77
+ export const resumeExecution = (options, command) => call(options, 'executions.resume', { body: command });
78
+ /** `executions.cancel`: stop the work, and by default everything below it. */
79
+ export const cancelExecution = (options, command) => call(options, 'executions.cancel', { body: command });
80
+ /** `executions.checkpoint`, where the worker's protocol keeps state. */
81
+ export const checkpointExecution = (options, command) => call(options, 'executions.checkpoint', { body: command });
82
+ /** `executions.collect`: the artifacts of an execution and of its children. */
83
+ export const collectExecution = (options, command) => call(options, 'executions.collect', { body: command });
84
+ /** `executions.terminate`: release the worker, where its protocol can. */
85
+ export const terminateExecution = (options, command) => call(options, 'executions.terminate', { body: command });
86
+ /** One execution, its attempts, and the milestones it reached. */
87
+ export const getExecution = (options, executionId) => call(options, 'executions.get', {
88
+ parameters: { execution_id: executionId },
89
+ });
90
+ /**
91
+ * `executions.report`: the execution's live report, a document in the
92
+ * account's orchestration space, written the first time it is asked for and
93
+ * the same one after that.
94
+ */
95
+ export const openExecutionReport = (options, executionId) => call(options, 'executions.report', {
96
+ parameters: { execution_id: executionId },
97
+ });
98
+ /** The account's executions, oldest first: a tree by its root, a level by its parent. */
99
+ export const listExecutions = (options, filter = {}) => call(options, 'executions.list', {
100
+ query: {
101
+ rootExecutionId: filter.rootExecutionId,
102
+ parentExecutionId: filter.parentExecutionId,
103
+ status: filter.status,
104
+ },
105
+ });
@@ -0,0 +1,88 @@
1
+ import { type OrchestrationClientOptions } from './client';
2
+ import type { ExecutionEvent, LifecycleEvent, TreeSummary } from './generated';
3
+ /** The user channel's event for a tree that moved, and the stream's roll-up. */
4
+ export declare const TREE_EVENT = "orchestration.tree";
5
+ /** One Server-Sent Event, as it was framed. */
6
+ export interface ServerSentEvent {
7
+ id?: string;
8
+ event: string;
9
+ data: string;
10
+ }
11
+ /**
12
+ * Split what has arrived into the complete events and what is left over,
13
+ * which is the beginning of an event still arriving.
14
+ */
15
+ export declare const readServerSentEvents: (buffer: string) => {
16
+ events: ServerSentEvent[];
17
+ rest: string;
18
+ };
19
+ /** The service refused the subscription; asking again would be refused again. */
20
+ export declare class SubscriptionRefused extends Error {
21
+ readonly status: number;
22
+ readonly detail: string;
23
+ constructor(status: number, detail: string);
24
+ }
25
+ /** What `fetch` answers, as much of it as a subscription reads. */
26
+ interface StreamedResponse {
27
+ ok: boolean;
28
+ status: number;
29
+ body: ReadableStream<Uint8Array> | null;
30
+ text(): Promise<string>;
31
+ }
32
+ export interface SubscribeOptions {
33
+ /** Every event of the tree below the execution too; the service's default. */
34
+ includeChildren?: boolean;
35
+ /** Replay the execution's own events after this sequence. */
36
+ fromSequence?: number;
37
+ /** Only these lifecycle events; every event when empty. */
38
+ events?: LifecycleEvent[];
39
+ /** The id of the last event already received, to resume after it. */
40
+ lastEventId?: string;
41
+ /** Each event once, in the order the service sent them, with the cursor it moved the subscription to. */
42
+ onEvent: (event: ExecutionEvent, cursor: string) => void;
43
+ /** What the executions the subscription covers are doing, after each batch of events that changed it. */
44
+ onTree?: (tree: TreeSummary, cursor: string) => void;
45
+ /** The subscription ended because every execution it covers is over. */
46
+ onEnd?: () => void;
47
+ /** How many drops in a row, with no event between them, before giving up. */
48
+ maxReconnects?: number;
49
+ /** How long to wait before reconnecting, in milliseconds. */
50
+ reconnectDelayMs?: number;
51
+ signal?: AbortSignal;
52
+ /** The `fetch` to use; the global one by default. */
53
+ fetch?: (url: string, init: RequestInit) => Promise<StreamedResponse>;
54
+ }
55
+ export interface Subscription {
56
+ /** Settles when the stream ends, is aborted, or cannot be resumed. */
57
+ done: Promise<void>;
58
+ /** The id a later subscription resumes from. */
59
+ lastEventId: () => string | undefined;
60
+ }
61
+ /**
62
+ * Subscribe to an execution — and its tree — until it is over.
63
+ *
64
+ * A dropped connection, before the service answered or in the middle of the
65
+ * stream, is resumed from the last event received. A refusal is not: it
66
+ * rejects `done` with `SubscriptionRefused`. An abort ends the subscription
67
+ * quietly, because stopping is the caller's decision rather than a failure.
68
+ */
69
+ export declare const subscribeToExecution: (options: OrchestrationClientOptions, executionId: string, subscribe: SubscribeOptions) => Subscription;
70
+ /**
71
+ * What a tree is doing, worked out from its canonical events alone (O2-03).
72
+ *
73
+ * The same summary the subscription sends as `orchestration.tree`: each
74
+ * execution's latest state, its parent, its worker and its goal — the message
75
+ * of the event that created it — and its depth below the first execution the
76
+ * events cover. Each execution's events are read in their own sequence,
77
+ * whatever order they arrived in.
78
+ */
79
+ export declare const treeFromEvents: (events: readonly ExecutionEvent[]) => TreeSummary;
80
+ /** A message of the app's user channel announcing that a tree moved. */
81
+ export interface TreeAnnouncement {
82
+ channel: string;
83
+ event: typeof TREE_EVENT;
84
+ data: TreeSummary;
85
+ }
86
+ /** Whether a user-channel message is a tree announcement. */
87
+ export declare const isTreeAnnouncement: (message: unknown) => message is TreeAnnouncement;
88
+ export {};