@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.
- package/README.md +43 -20
- package/lib/api/constants.d.ts +1 -1
- package/lib/api/constants.js +1 -1
- package/lib/api/contents/attachments.js +3 -7
- package/lib/api/contents/datasets.d.ts +48 -0
- package/lib/api/contents/datasets.js +44 -7
- package/lib/api/contents/runtimeMounts.js +1 -1
- package/lib/api/contents/sandboxUid.d.ts +13 -45
- package/lib/api/contents/sandboxUid.js +14 -65
- package/lib/api/evals/client.d.ts +402 -0
- package/lib/api/evals/client.js +359 -0
- package/lib/api/evals/index.d.ts +10 -0
- package/lib/api/evals/index.js +18 -0
- package/lib/api/evals/request.d.ts +43 -0
- package/lib/api/evals/request.js +67 -0
- package/lib/api/evals/status.d.ts +27 -0
- package/lib/api/evals/status.js +122 -0
- package/lib/api/evals/types.d.ts +1335 -0
- package/lib/api/evals/types.js +5 -0
- package/lib/api/iam/authentication.js +6 -4
- package/lib/api/iam/connectedAgents.d.ts +29 -0
- package/lib/api/iam/connectedAgents.js +35 -0
- package/lib/api/iam/healthz.js +2 -2
- package/lib/api/iam/identityProviders.d.ts +76 -0
- package/lib/api/iam/identityProviders.js +187 -0
- package/lib/api/iam/index.d.ts +1 -0
- package/lib/api/iam/index.js +1 -0
- package/lib/api/iam/mcpPolicy.d.ts +102 -1
- package/lib/api/iam/mcpPolicy.js +38 -2
- package/lib/api/iam/oauth2.js +18 -12
- package/lib/api/iam/profile.d.ts +17 -1
- package/lib/api/iam/profile.js +27 -0
- package/lib/api/iam/scimTokens.d.ts +79 -0
- package/lib/api/iam/scimTokens.js +141 -0
- package/lib/api/iam/secrets.js +10 -23
- package/lib/api/iam/trials.d.ts +38 -0
- package/lib/api/iam/trials.js +66 -0
- package/lib/api/index.d.ts +4 -0
- package/lib/api/index.js +4 -0
- package/lib/api/mcp/observability.d.ts +34 -11
- package/lib/api/mcp/observability.js +97 -59
- package/lib/api/orchestration/client.d.ts +53 -0
- package/lib/api/orchestration/client.js +105 -0
- package/lib/api/orchestration/events.d.ts +88 -0
- package/lib/api/orchestration/events.js +245 -0
- package/lib/api/orchestration/generated.d.ts +693 -0
- package/lib/api/orchestration/generated.js +687 -0
- package/lib/api/orchestration/index.d.ts +30 -0
- package/lib/api/orchestration/index.js +34 -0
- package/lib/api/orchestration/lifecycle.d.ts +39 -0
- package/lib/api/orchestration/lifecycle.js +57 -0
- package/lib/api/orchestration/measures.d.ts +55 -0
- package/lib/api/orchestration/measures.js +99 -0
- package/lib/api/otel/dashboards.d.ts +56 -0
- package/lib/api/otel/dashboards.js +50 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/api/otel/metrics.d.ts +16 -0
- package/lib/api/otel/metrics.js +15 -0
- package/lib/api/scheduler/client.d.ts +32 -0
- package/lib/api/scheduler/client.js +42 -0
- package/lib/api/scheduler/index.d.ts +8 -0
- package/lib/api/scheduler/index.js +16 -0
- package/lib/api/scheduler/request.d.ts +28 -0
- package/lib/api/scheduler/request.js +50 -0
- package/lib/api/scheduler/types.d.ts +88 -0
- package/lib/api/scheduler/types.js +5 -0
- package/lib/api/spacer/comments.d.ts +97 -0
- package/lib/api/spacer/comments.js +45 -0
- package/lib/api/spacer/index.d.ts +9 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/notebooks.d.ts +33 -0
- package/lib/api/spacer/notebooks.js +39 -0
- package/lib/api/spacer/request.d.ts +25 -0
- package/lib/api/spacer/request.js +46 -0
- package/lib/api/spacer/spaces.d.ts +68 -0
- package/lib/api/spacer/spaces.js +45 -0
- package/lib/api/utils/validation.d.ts +4 -4
- package/lib/api/utils/validation.js +10 -7
- package/lib/client/auth/strategies.js +1 -1
- package/lib/client/constants.d.ts +1 -0
- package/lib/client/constants.js +1 -0
- package/lib/client/mixins/IAMMixin.js +2 -2
- package/lib/components/animation/AnimatedText.d.ts +1 -44
- package/lib/components/animation/AnimatedText.js +6 -122
- package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
- package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
- package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
- package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
- package/lib/components/anonymous/index.d.ts +7 -0
- package/lib/components/anonymous/index.js +15 -0
- package/lib/components/avatars/UserAvatar.d.ts +7 -1
- package/lib/components/avatars/UserAvatar.js +15 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
- package/lib/components/billing/BillingEntitySelect.js +49 -10
- package/lib/components/billing/eligibility.d.ts +22 -0
- package/lib/components/billing/eligibility.js +27 -0
- package/lib/components/billing/index.d.ts +1 -0
- package/lib/components/billing/index.js +1 -0
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/checkout/StripeCheckout.js +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
- package/lib/components/display/DatalayerBox.d.ts +2 -3
- package/lib/components/display/DatalayerBox.js +1 -1
- package/lib/components/display/NavLink.js +3 -2
- package/lib/components/display/VisuallyHidden.d.ts +1 -2
- package/lib/components/labels/StatusLabels.d.ts +2 -10
- package/lib/components/labels/StatusLabels.js +2 -26
- package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
- package/lib/components/principal/PrincipalAppearance.js +232 -174
- package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
- package/lib/components/principal/PrincipalAvatar.js +2 -2
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
- package/lib/components/screencapture/Screencapture.js +46 -3
- package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
- package/lib/components/sharing/ShareAccessComponent.js +110 -78
- package/lib/components/sharing/SharingEditor.d.ts +5 -1
- package/lib/components/sharing/SharingEditor.js +9 -4
- package/lib/components/sharing/index.d.ts +1 -0
- package/lib/components/sharing/index.js +1 -0
- package/lib/components/sharing/sandboxSharing.d.ts +26 -0
- package/lib/components/sharing/sandboxSharing.js +47 -0
- package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
- package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
- package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
- package/lib/components/spaces/SpaceDisplay.js +92 -0
- package/lib/components/spaces/index.d.ts +4 -0
- package/lib/components/spaces/index.js +7 -0
- package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
- package/lib/components/spaces/spaceDisplayModel.js +170 -0
- package/lib/config/Configuration.d.ts +4 -4
- package/lib/config/Configuration.js +7 -7
- package/lib/config/index.d.ts +1 -0
- package/lib/config/index.js +1 -0
- package/lib/config/planes.d.ts +45 -0
- package/lib/config/planes.js +53 -0
- package/lib/hooks/cacheConverters.d.ts +0 -7
- package/lib/hooks/cacheConverters.js +0 -25
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useBackdrop.d.ts +4 -5
- package/lib/hooks/useBillingEntityStore.js +3 -0
- package/lib/hooks/useCache.d.ts +197 -44
- package/lib/hooks/useCache.js +1586 -494
- package/lib/hooks/useContents.d.ts +22 -1
- package/lib/hooks/useContents.js +90 -21
- package/lib/hooks/useMcp.d.ts +87 -1
- package/lib/hooks/useMcp.js +248 -13
- package/lib/hooks/useNavigate.d.ts +41 -3
- package/lib/hooks/useNavigate.js +116 -52
- package/lib/hooks/usePrincipalCacheStore.js +3 -0
- package/lib/hooks/usePrincipalStore.js +3 -0
- package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
- package/lib/hooks/useSpaceCacheStore.js +85 -0
- package/lib/hooks/useWindowSize.js +1 -1
- package/lib/models/CreditsDTO.d.ts +6 -5
- package/lib/models/CreditsDTO.js +7 -5
- package/lib/models/IAMProvidersSpecs.d.ts +10 -5
- package/lib/models/IAMProvidersSpecs.js +0 -23
- package/lib/models/McpBinding.d.ts +6 -0
- package/lib/models/Organization.d.ts +69 -0
- package/lib/models/Organization.js +96 -0
- package/lib/models/Secret.d.ts +1 -2
- package/lib/models/Secret.js +2 -18
- package/lib/models/StartedBy.d.ts +34 -0
- package/lib/models/StartedBy.js +36 -0
- package/lib/models/Team.d.ts +2 -0
- package/lib/models/Team.js +2 -0
- package/lib/models/User.d.ts +4 -0
- package/lib/models/User.js +3 -0
- package/lib/models/UserSettings.d.ts +13 -0
- package/lib/models/UserSettings.js +9 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
- package/lib/navigation/adapters/react-router.d.ts +1 -1
- package/lib/navigation/adapters/react-router.js +3 -0
- package/lib/navigation/components.js +2 -3
- package/lib/routes/publicPaths.js +4 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +1 -0
- package/lib/state/sessionEnd.d.ts +55 -0
- package/lib/state/sessionEnd.js +162 -0
- package/lib/state/substates/CoreState.js +3 -16
- package/lib/state/substates/IAMState.d.ts +3 -3
- package/lib/state/substates/IAMState.js +7 -0
- package/lib/state/substates/LayoutState.js +12 -0
- package/lib/state/substates/NavigationState.d.ts +82 -0
- package/lib/state/substates/NavigationState.js +255 -0
- package/lib/state/substates/ProfileState.d.ts +1 -0
- package/lib/state/substates/ProfileState.js +1 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/utils/Lazy.d.ts +20 -0
- package/lib/utils/Lazy.js +32 -6
- package/lib/utils/Screencapture.d.ts +15 -0
- package/lib/utils/Screencapture.js +26 -20
- package/lib/utils/WithSuspense.d.ts +11 -1
- package/lib/utils/WithSuspense.js +11 -1
- package/lib/views/mcp/AdmittedClients.d.ts +44 -0
- package/lib/views/mcp/AdmittedClients.js +59 -0
- package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
- package/lib/views/mcp/ApprovalQueue.js +95 -0
- package/lib/views/mcp/ConnectedAgents.js +38 -3
- package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
- package/lib/views/mcp/EnterpriseConsole.js +23 -1
- package/lib/views/mcp/IdentityProviders.d.ts +33 -0
- package/lib/views/mcp/IdentityProviders.js +299 -0
- package/lib/views/mcp/McpDashboard.js +90 -7
- package/lib/views/mcp/McpHome.js +1 -1
- package/lib/views/mcp/McpObservability.d.ts +30 -1
- package/lib/views/mcp/McpObservability.js +105 -19
- package/lib/views/mcp/NotebookRuns.d.ts +39 -0
- package/lib/views/mcp/NotebookRuns.js +44 -0
- package/lib/views/mcp/OrganizationPolicy.js +2 -1
- package/lib/views/mcp/PersonalPolicy.js +2 -1
- package/lib/views/mcp/PolicyForm.d.ts +17 -1
- package/lib/views/mcp/PolicyForm.js +25 -3
- package/lib/views/mcp/PolicyHistory.d.ts +13 -0
- package/lib/views/mcp/PolicyHistory.js +14 -1
- package/lib/views/mcp/RunDetail.d.ts +87 -0
- package/lib/views/mcp/RunDetail.js +186 -0
- package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
- package/lib/views/mcp/ScimProvisioning.js +173 -0
- package/lib/views/mcp/TeamPolicies.js +66 -5
- package/lib/views/mcp/ToolAccess.d.ts +60 -0
- package/lib/views/mcp/ToolAccess.js +101 -0
- package/lib/views/mcp/TraceTimeline.d.ts +81 -0
- package/lib/views/mcp/TraceTimeline.js +132 -0
- package/lib/views/mcp/index.d.ts +5 -0
- package/lib/views/mcp/index.js +5 -0
- package/lib/views/otel/simpleAuthStore.js +3 -0
- package/lib/views/secrets/SecretEdit.js +3 -2
- package/lib/views/secrets/SecretNew.js +5 -1
- package/package.json +271 -264
- package/scripts/generate-mcp-types.py +16 -10
- 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
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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 {
|
|
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
|
-
/**
|
|
37
|
-
|
|
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') ||
|
|
111
|
-
|
|
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
|
|
143
|
+
* The SLIs from the service levels dashboard — the platform-wide reading.
|
|
116
144
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
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
|
|
122
|
-
const
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
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:
|
|
151
|
-
taskSuccessRate:
|
|
165
|
+
p95CallDurationMs: p95Seconds === undefined ? null : p95Seconds * 1000,
|
|
166
|
+
taskSuccessRate: terminal > 0 ? (tasks.completed ?? 0) / terminal : null,
|
|
152
167
|
p95SandboxLaunchSeconds,
|
|
153
|
-
samples: {
|
|
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
|
|
177
|
-
|
|
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
|
|
194
|
-
|
|
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
|
-
|
|
223
|
+
reporting: MCP_METRIC_CATALOG.filter(name => reported.has(name)),
|
|
199
224
|
spans,
|
|
200
|
-
slis:
|
|
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
|
|
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 {
|
|
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, {
|
|
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 {};
|