@corbits/react-ui 0.1.0 → 0.2.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/LICENSE +174 -499
- package/README.md +228 -85
- package/dist/blocks/login/auth-layout.d.ts +1 -1
- package/dist/blocks/login/auth-layout.js +3 -33
- package/dist/blocks/login/login-form.js +6 -119
- package/dist/hooks/use-command-palette-navigation.js +18 -17
- package/dist/hooks/use-controllable-state.d.ts +2 -2
- package/dist/hooks/use-controllable-state.js +23 -15
- package/dist/hooks/use-delayed-autofocus.js +10 -11
- package/dist/hooks/use-dismissable-popover.d.ts +2 -2
- package/dist/hooks/use-dismissable-popover.js +21 -29
- package/dist/hooks/use-list-selection.js +54 -85
- package/dist/hooks/use-prefers-reduced-motion.js +8 -4
- package/dist/hooks/use-scroll-current-into-view.js +5 -7
- package/dist/index.d.ts +0 -11
- package/dist/index.js +10 -19
- package/dist/lib/artifact.js +16 -35
- package/dist/lib/chart-geometry.js +33 -20
- package/dist/lib/chart-palette.js +17 -31
- package/dist/lib/chat-message.js +32 -13
- package/dist/lib/chat-parts.js +2 -1
- package/dist/lib/csv.js +42 -26
- package/dist/lib/metrics.js +30 -48
- package/dist/lib/now-item.js +26 -25
- package/dist/lib/relative-time.js +14 -29
- package/dist/lib/theme.js +32 -30
- package/dist/lib/url.js +9 -8
- package/dist/lib/workflow-display-flow.js +37 -33
- package/dist/lib/workflow-registry.d.ts +0 -41
- package/dist/lib/workflow-registry.js +13 -23
- package/dist/lib/workflow-run-error.js +16 -20
- package/dist/lib/workflow-run-progress.js +94 -52
- package/dist/lib/workflow-run.js +17 -13
- package/dist/styles.css +11 -11
- package/dist/test/render-hook.js +11 -12
- package/dist/theme.css +51 -14
- package/dist/ui/agent-turn.d.ts +1 -1
- package/dist/ui/agent-turn.js +4 -37
- package/dist/ui/animated-number.js +15 -28
- package/dist/ui/approval-card.js +5 -90
- package/dist/ui/artifact-body.js +47 -125
- package/dist/ui/artifact-notice.d.ts +1 -1
- package/dist/ui/artifact-notice.js +9 -16
- package/dist/ui/avatar.d.ts +1 -1
- package/dist/ui/avatar.js +11 -48
- package/dist/ui/badge.js +4 -12
- package/dist/ui/bar-chart.d.ts +1 -1
- package/dist/ui/bar-chart.js +22 -74
- package/dist/ui/block-card.js +7 -45
- package/dist/ui/boot-screen.d.ts +1 -1
- package/dist/ui/boot-screen.js +4 -33
- package/dist/ui/bulk-action-bar.d.ts +1 -1
- package/dist/ui/bulk-action-bar.js +14 -33
- package/dist/ui/button.js +10 -24
- package/dist/ui/card.js +5 -25
- package/dist/ui/category-bars.js +14 -59
- package/dist/ui/chart-frame.d.ts +2 -2
- package/dist/ui/chart-frame.js +6 -85
- package/dist/ui/chat-composer.js +4 -16
- package/dist/ui/chat-dock-timing.js +7 -3
- package/dist/ui/chat-input.js +20 -100
- package/dist/ui/chat-panel.d.ts +1 -1
- package/dist/ui/chat-panel.js +7 -41
- package/dist/ui/chat-thread.js +13 -31
- package/dist/ui/checkbox.js +10 -52
- package/dist/ui/command-palette.js +71 -246
- package/dist/ui/compare-body.d.ts +1 -1
- package/dist/ui/compare-body.js +28 -98
- package/dist/ui/confirm-button.js +8 -15
- package/dist/ui/corbits-mark.js +7 -16
- package/dist/ui/csv-table.d.ts +1 -1
- package/dist/ui/csv-table.js +8 -50
- package/dist/ui/dialog.d.ts +1 -1
- package/dist/ui/dialog.js +32 -62
- package/dist/ui/dictation-status-line.js +7 -25
- package/dist/ui/dither-canvas.d.ts +1 -1
- package/dist/ui/dither-canvas.js +31 -56
- package/dist/ui/embed-body.d.ts +1 -1
- package/dist/ui/embed-body.js +7 -56
- package/dist/ui/empty-state.d.ts +1 -1
- package/dist/ui/empty-state.js +3 -26
- package/dist/ui/file-input.js +17 -37
- package/dist/ui/filter-bar.d.ts +1 -1
- package/dist/ui/filter-bar.js +11 -71
- package/dist/ui/filter-chip.d.ts +1 -1
- package/dist/ui/filter-chip.js +7 -15
- package/dist/ui/gate-block.d.ts +2 -1
- package/dist/ui/gate-block.js +4 -29
- package/dist/ui/horizontal-stepper.d.ts +1 -1
- package/dist/ui/horizontal-stepper.js +18 -45
- package/dist/ui/input.js +1 -6
- package/dist/ui/inspector-shell.d.ts +5 -5
- package/dist/ui/inspector-shell.js +14 -81
- package/dist/ui/intake-form.d.ts +1 -1
- package/dist/ui/intake-form.js +21 -97
- package/dist/ui/kind-card-grid.js +9 -31
- package/dist/ui/library-page-header.js +4 -32
- package/dist/ui/list-detail.js +5 -35
- package/dist/ui/live-run-banner.d.ts +1 -1
- package/dist/ui/live-run-banner.js +5 -15
- package/dist/ui/live-status-line.js +6 -24
- package/dist/ui/menu.js +7 -24
- package/dist/ui/message-bubble.d.ts +3 -3
- package/dist/ui/message-bubble.js +5 -44
- package/dist/ui/mic-button.d.ts +1 -1
- package/dist/ui/mic-button.js +15 -21
- package/dist/ui/mic-permission-dialog.js +5 -41
- package/dist/ui/notifications-bell.js +9 -43
- package/dist/ui/now-cards.d.ts +2 -2
- package/dist/ui/now-cards.js +16 -94
- package/dist/ui/page-panel.js +11 -11
- package/dist/ui/page-shell.js +4 -11
- package/dist/ui/parts-renderer.js +51 -149
- package/dist/ui/profile-card.js +7 -111
- package/dist/ui/progress-checklist.js +11 -49
- package/dist/ui/provider-mark.d.ts +2 -2
- package/dist/ui/provider-mark.js +9 -16
- package/dist/ui/quick-reply-chips.js +6 -14
- package/dist/ui/quote-card.js +12 -32
- package/dist/ui/reasoning-block.d.ts +1 -1
- package/dist/ui/reasoning-block.js +14 -33
- package/dist/ui/research-body.js +32 -213
- package/dist/ui/rich-empty-state.js +6 -48
- package/dist/ui/run-now-button.js +14 -15
- package/dist/ui/section.d.ts +1 -1
- package/dist/ui/section.js +4 -40
- package/dist/ui/select.js +1 -15
- package/dist/ui/selection-checkbox.d.ts +1 -1
- package/dist/ui/selection-checkbox.js +11 -29
- package/dist/ui/settings-panel.js +7 -50
- package/dist/ui/shimmer-text.js +3 -6
- package/dist/ui/sidebar-item-row.d.ts +1 -1
- package/dist/ui/sidebar-item-row.js +9 -39
- package/dist/ui/sidebar-panel.js +15 -40
- package/dist/ui/sidebar.js +15 -76
- package/dist/ui/skeleton.js +3 -7
- package/dist/ui/sortable-table.js +29 -72
- package/dist/ui/sparkline.js +14 -38
- package/dist/ui/stat-grid.js +17 -52
- package/dist/ui/status-dot.d.ts +1 -1
- package/dist/ui/status-dot.js +8 -20
- package/dist/ui/step-list.d.ts +1 -0
- package/dist/ui/step-list.js +11 -50
- package/dist/ui/switch.js +4 -16
- package/dist/ui/table.js +7 -32
- package/dist/ui/tabs.js +39 -54
- package/dist/ui/textarea.js +10 -19
- package/dist/ui/theme-provider.js +54 -78
- package/dist/ui/theme-toggle.js +13 -16
- package/dist/ui/thinking-indicator.js +3 -15
- package/dist/ui/thinking-label.js +16 -35
- package/dist/ui/thinking-mark.d.ts +1 -1
- package/dist/ui/thinking-mark.js +4 -145
- package/dist/ui/time-series-chart.js +43 -174
- package/dist/ui/toast.js +12 -20
- package/dist/ui/token-mosaic.js +5 -43
- package/dist/ui/tool-block.js +18 -70
- package/dist/ui/tool-narrative.d.ts +1 -1
- package/dist/ui/tool-narrative.js +10 -57
- package/dist/ui/tool-picker.js +57 -145
- package/dist/ui/tooltip.d.ts +1 -1
- package/dist/ui/tooltip.js +4 -33
- package/dist/ui/top-bar.js +14 -72
- package/dist/ui/trace-waterfall.d.ts +1 -1
- package/dist/ui/trace-waterfall.js +21 -93
- package/dist/ui/typing-indicator.d.ts +1 -1
- package/dist/ui/typing-indicator.js +4 -18
- package/dist/ui/view-toggle.js +10 -29
- package/dist/ui/voice-waveform.js +3 -11
- package/package.json +94 -535
package/dist/lib/theme.js
CHANGED
|
@@ -6,15 +6,12 @@
|
|
|
6
6
|
* opt-out and only works on `documentElement`. This module owns the pure
|
|
7
7
|
* resolution rules; ThemeProvider applies them to the document and persists
|
|
8
8
|
* the choice.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
"light",
|
|
12
|
-
"dark"
|
|
13
|
-
];
|
|
9
|
+
*/
|
|
10
|
+
export const THEME_MODES = ["system", "light", "dark"];
|
|
14
11
|
export const THEME_PRESETS = [
|
|
15
12
|
"default",
|
|
16
13
|
"warm",
|
|
17
|
-
"cool"
|
|
14
|
+
"cool",
|
|
18
15
|
];
|
|
19
16
|
export const DEFAULT_THEME_STORAGE_KEY = "corbits-theme";
|
|
20
17
|
export function isThemeMode(value) {
|
|
@@ -23,44 +20,48 @@ export function isThemeMode(value) {
|
|
|
23
20
|
export function isThemePreset(value) {
|
|
24
21
|
return value === "default" || value === "warm" || value === "cool";
|
|
25
22
|
}
|
|
26
|
-
/** Resolve light/dark after consulting the system preference when mode is system. */
|
|
27
|
-
|
|
28
|
-
if (mode === "
|
|
23
|
+
/** Resolve light/dark after consulting the system preference when mode is system. */
|
|
24
|
+
export function resolveThemeMode(mode, systemPrefersDark) {
|
|
25
|
+
if (mode === "light")
|
|
26
|
+
return "light";
|
|
27
|
+
if (mode === "dark")
|
|
28
|
+
return "dark";
|
|
29
29
|
return systemPrefersDark ? "dark" : "light";
|
|
30
30
|
}
|
|
31
31
|
export function parseThemePreference(raw, fallback) {
|
|
32
|
-
if (raw === null || raw.length === 0)
|
|
32
|
+
if (raw === null || raw.length === 0)
|
|
33
|
+
return fallback;
|
|
33
34
|
try {
|
|
34
35
|
const parsed = JSON.parse(raw);
|
|
35
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
36
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
37
|
+
return fallback;
|
|
36
38
|
const record = parsed;
|
|
37
39
|
const mode = isThemeMode(record.mode) ? record.mode : fallback.mode;
|
|
38
|
-
const preset = isThemePreset(record.preset)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
const preset = isThemePreset(record.preset)
|
|
41
|
+
? record.preset
|
|
42
|
+
: fallback.preset;
|
|
43
|
+
return { mode, preset };
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
44
46
|
// Legacy: a bare mode string from an earlier client.
|
|
45
|
-
if (isThemeMode(raw))
|
|
46
|
-
mode: raw,
|
|
47
|
-
preset: fallback.preset
|
|
48
|
-
};
|
|
47
|
+
if (isThemeMode(raw))
|
|
48
|
+
return { mode: raw, preset: fallback.preset };
|
|
49
49
|
return fallback;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
export function serializeThemePreference(preference) {
|
|
53
|
-
return JSON.stringify({
|
|
54
|
-
mode: preference.mode,
|
|
55
|
-
preset: preference.preset
|
|
56
|
-
});
|
|
53
|
+
return JSON.stringify({ mode: preference.mode, preset: preference.preset });
|
|
57
54
|
}
|
|
58
|
-
/** Cycle system → light → dark → system for a one-control toggle. */
|
|
59
|
-
|
|
60
|
-
if (mode === "
|
|
55
|
+
/** Cycle system → light → dark → system for a one-control toggle. */
|
|
56
|
+
export function nextThemeMode(mode) {
|
|
57
|
+
if (mode === "system")
|
|
58
|
+
return "light";
|
|
59
|
+
if (mode === "light")
|
|
60
|
+
return "dark";
|
|
61
61
|
return "system";
|
|
62
62
|
}
|
|
63
|
-
/** Apply resolved mode + preset to a root element (usually documentElement). */
|
|
63
|
+
/** Apply resolved mode + preset to a root element (usually documentElement). */
|
|
64
|
+
export function applyThemeToRoot(root, resolved, preset) {
|
|
64
65
|
root.classList.toggle("dark", resolved === "dark");
|
|
65
66
|
// `.light` is the explicit-light escape hatch from the `prefers-color-scheme`
|
|
66
67
|
// media query in theme.css — without it, "light" mode chosen on a dark-OS
|
|
@@ -68,7 +69,8 @@ export function serializeThemePreference(preference) {
|
|
|
68
69
|
root.classList.toggle("light", resolved === "light");
|
|
69
70
|
if (preset === "default") {
|
|
70
71
|
root.removeAttribute("data-theme");
|
|
71
|
-
}
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
72
74
|
root.setAttribute("data-theme", preset);
|
|
73
75
|
}
|
|
74
76
|
if (root instanceof HTMLElement) {
|
package/dist/lib/url.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
const DEFAULT_ALLOWED_PROTOCOLS = [
|
|
2
|
-
"http:",
|
|
3
|
-
"https:"
|
|
4
|
-
];
|
|
1
|
+
const DEFAULT_ALLOWED_PROTOCOLS = ["http:", "https:"];
|
|
5
2
|
/**
|
|
6
3
|
* Is `url` safe to hand to a live sink — `href`, `src`, `window.open` — as-is?
|
|
7
4
|
*
|
|
@@ -17,10 +14,12 @@ const DEFAULT_ALLOWED_PROTOCOLS = [
|
|
|
17
14
|
* sink this guards links to a third-party resource — a citation, a download,
|
|
18
15
|
* an embed — so there is no in-app page a bare path could sensibly mean, and
|
|
19
16
|
* inventing a base to resolve against would only guess wrong.
|
|
20
|
-
*/
|
|
17
|
+
*/
|
|
18
|
+
export function isSafeUrl(url, allowedProtocols = DEFAULT_ALLOWED_PROTOCOLS) {
|
|
21
19
|
try {
|
|
22
20
|
return allowedProtocols.includes(new URL(url).protocol);
|
|
23
|
-
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
24
23
|
return false;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
@@ -31,7 +30,9 @@ const DEFAULT_ALLOWED_PROTOCOLS = [
|
|
|
31
30
|
* into `href`/`src` when present, and a clean signal to fall back to plain
|
|
32
31
|
* text when not. Never returns a placeholder like `"#"` — a disabled-looking
|
|
33
32
|
* link that is secretly still a link is its own trap.
|
|
34
|
-
*/
|
|
35
|
-
|
|
33
|
+
*/
|
|
34
|
+
export function toSafeHref(url, allowedProtocols = DEFAULT_ALLOWED_PROTOCOLS) {
|
|
35
|
+
if (url === undefined)
|
|
36
|
+
return undefined;
|
|
36
37
|
return isSafeUrl(url, allowedProtocols) ? url : undefined;
|
|
37
38
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function characterOf(primitive) {
|
|
2
|
-
switch(primitive.kind){
|
|
2
|
+
switch (primitive.kind) {
|
|
3
3
|
case "step":
|
|
4
4
|
case "map":
|
|
5
5
|
return primitive.deterministic === true ? "deterministic" : "reasoning";
|
|
@@ -25,14 +25,15 @@ function characterOf(primitive) {
|
|
|
25
25
|
* author-tagging convention (a legacy tag, a metadata field) out of a
|
|
26
26
|
* published library, where the tag vocabulary would become part of the
|
|
27
27
|
* public surface.
|
|
28
|
-
*/
|
|
28
|
+
*/
|
|
29
|
+
export function deriveDisplayFlow(primitives) {
|
|
29
30
|
return {
|
|
30
|
-
steps: primitives.map((primitive)=>({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
steps: primitives.map((primitive) => ({
|
|
32
|
+
stepId: primitive.stepId,
|
|
33
|
+
label: primitive.label ?? primitive.stepId,
|
|
34
|
+
character: characterOf(primitive),
|
|
35
|
+
after: primitive.after ?? [],
|
|
36
|
+
})),
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
@@ -40,7 +41,8 @@ function characterOf(primitive) {
|
|
|
40
41
|
* with different characters — the strongest signal wins so a group never
|
|
41
42
|
* under-represents itself (a group containing one human `await` step reads
|
|
42
43
|
* as `await` even if every other step in it is `deterministic`).
|
|
43
|
-
*/
|
|
44
|
+
*/
|
|
45
|
+
const CHARACTER_PRIORITY = [
|
|
44
46
|
"await",
|
|
45
47
|
"gate",
|
|
46
48
|
"child",
|
|
@@ -48,11 +50,12 @@ function characterOf(primitive) {
|
|
|
48
50
|
"reasoning",
|
|
49
51
|
"sleep",
|
|
50
52
|
"deterministic",
|
|
51
|
-
"other"
|
|
53
|
+
"other",
|
|
52
54
|
];
|
|
53
55
|
function aggregateCharacter(characters) {
|
|
54
|
-
for (const candidate of CHARACTER_PRIORITY){
|
|
55
|
-
if (characters.includes(candidate))
|
|
56
|
+
for (const candidate of CHARACTER_PRIORITY) {
|
|
57
|
+
if (characters.includes(candidate))
|
|
58
|
+
return candidate;
|
|
56
59
|
}
|
|
57
60
|
return "other";
|
|
58
61
|
}
|
|
@@ -61,14 +64,12 @@ function aggregateCharacter(characters) {
|
|
|
61
64
|
* group's `steps` is validated against the flow's actual step ids — an
|
|
62
65
|
* unknown id throws immediately rather than silently producing an empty or
|
|
63
66
|
* partial group.
|
|
64
|
-
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
]));
|
|
69
|
-
const groups = overlay.groups.map((group)=>{
|
|
67
|
+
*/
|
|
68
|
+
export function applyDisplayOverlay(flow, overlay) {
|
|
69
|
+
const byId = new Map(flow.steps.map((step) => [step.stepId, step]));
|
|
70
|
+
const groups = overlay.groups.map((group) => {
|
|
70
71
|
const characters = [];
|
|
71
|
-
for (const stepId of group.steps){
|
|
72
|
+
for (const stepId of group.steps) {
|
|
72
73
|
const step = byId.get(stepId);
|
|
73
74
|
if (step === undefined) {
|
|
74
75
|
throw new Error(`display overlay group ${JSON.stringify(group.key)} references unknown step ${JSON.stringify(stepId)}`);
|
|
@@ -80,25 +81,28 @@ function aggregateCharacter(characters) {
|
|
|
80
81
|
label: group.label,
|
|
81
82
|
character: aggregateCharacter(characters),
|
|
82
83
|
stepIds: group.steps,
|
|
83
|
-
...group.activityLabel !== undefined
|
|
84
|
-
activityLabel: group.activityLabel
|
|
85
|
-
|
|
84
|
+
...(group.activityLabel !== undefined
|
|
85
|
+
? { activityLabel: group.activityLabel }
|
|
86
|
+
: {}),
|
|
86
87
|
};
|
|
87
88
|
});
|
|
88
|
-
return {
|
|
89
|
-
groups
|
|
90
|
-
};
|
|
89
|
+
return { groups };
|
|
91
90
|
}
|
|
92
91
|
/**
|
|
93
92
|
* Maps pure display-flow steps into `StepList` items, all `pending` unless a
|
|
94
93
|
* status lookup is given — the host overlays real run state on top once it
|
|
95
94
|
* has any.
|
|
96
|
-
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
95
|
+
*/
|
|
96
|
+
export function stepListFromDisplayFlow(steps, statusById) {
|
|
97
|
+
const lookup = statusById instanceof Map
|
|
98
|
+
? (id) => statusById.get(id)
|
|
99
|
+
: statusById !== undefined
|
|
100
|
+
? (id) => statusById[id]
|
|
101
|
+
: () => undefined;
|
|
102
|
+
return steps.map((step) => ({
|
|
103
|
+
id: step.stepId,
|
|
104
|
+
name: step.label,
|
|
105
|
+
status: lookup(step.stepId) ?? "pending",
|
|
106
|
+
character: step.character,
|
|
107
|
+
}));
|
|
104
108
|
}
|
|
@@ -30,33 +30,6 @@ export declare function workflowScopeLabel(scope: WorkflowScope): string;
|
|
|
30
30
|
* as shared infrastructure; `personal` gets the accent tone that marks
|
|
31
31
|
* "yours" everywhere else in the registry. */
|
|
32
32
|
export declare const WORKFLOW_SCOPE_BADGE_TONE: Record<WorkflowScope, BadgeTone>;
|
|
33
|
-
/** A live run's phase as an inspector or list row reports it — a coarser
|
|
34
|
-
* vocabulary than `RunStatus` in `workflow-run.ts` (no `provisioning`), for
|
|
35
|
-
* surfaces that only distinguish what a reader can act on. */
|
|
36
|
-
export type LiveRunPhase = "running" | "awaiting" | "completed" | "failed" | "cancelled";
|
|
37
|
-
export declare const LIVE_RUN_PHASE_TONE: Record<LiveRunPhase, WorkflowStatusTone>;
|
|
38
|
-
export declare const LIVE_RUN_PHASE_LABEL: Record<LiveRunPhase, string>;
|
|
39
|
-
export type WorkflowListItemKind = "run" | "schedule";
|
|
40
|
-
/** One dense row in the combined live-runs-and-schedules list. */
|
|
41
|
-
export type WorkflowListItem = {
|
|
42
|
-
readonly id: string;
|
|
43
|
-
readonly itemKind: WorkflowListItemKind;
|
|
44
|
-
/** Primary label — the workflow's kind, already humanised. */
|
|
45
|
-
readonly title: string;
|
|
46
|
-
/** Secondary line under the title: an alias, an origin tag. */
|
|
47
|
-
readonly subtitle?: string;
|
|
48
|
-
/** The "when" column: origin phrase for a run, cadence for a schedule. */
|
|
49
|
-
readonly when: string;
|
|
50
|
-
readonly scope: WorkflowScope;
|
|
51
|
-
readonly statusTone: WorkflowStatusTone;
|
|
52
|
-
readonly statusLabel: string;
|
|
53
|
-
/** Next-fire or elapsed text, already formatted by the caller. */
|
|
54
|
-
readonly nextOrElapsed: string;
|
|
55
|
-
/** Highlights `nextOrElapsed` — the next fire is close, or the run is fresh. */
|
|
56
|
-
readonly nextSoon?: boolean;
|
|
57
|
-
/** A live run parked on a human decision gets a subtle accent stripe. */
|
|
58
|
-
readonly needsYou?: boolean;
|
|
59
|
-
};
|
|
60
33
|
export type GateKind = "reviewList" | "choice" | "form" | "multiSelect";
|
|
61
34
|
export declare const GATE_KIND_LABEL: Record<GateKind, string>;
|
|
62
35
|
/** Shell model for a pending gate; the interactive payload is the caller's. */
|
|
@@ -65,20 +38,6 @@ export type GateShellModel = {
|
|
|
65
38
|
readonly title: string;
|
|
66
39
|
readonly prompt?: string;
|
|
67
40
|
};
|
|
68
|
-
/** One offering in a workflow-kind picker (distinct from `WorkflowOffering` in
|
|
69
|
-
* `workflow-catalog.tsx`, which drives the run-once grid): this shape adds
|
|
70
|
-
* category grouping and an "already on" badge for a picker that lists kinds
|
|
71
|
-
* to attach to a schedule or an automation rather than to run once. */
|
|
72
|
-
export type KindPickerItem = {
|
|
73
|
-
readonly id: string;
|
|
74
|
-
readonly label: string;
|
|
75
|
-
readonly description: string;
|
|
76
|
-
/** Grouping key. Omit when every item shares one category. */
|
|
77
|
-
readonly category?: string;
|
|
78
|
-
readonly categoryLabel?: string;
|
|
79
|
-
readonly alreadyOn?: boolean;
|
|
80
|
-
readonly alreadyOnLabel?: string;
|
|
81
|
-
};
|
|
82
41
|
export type StepDisplayStatus = "pending" | "active" | "done" | "failed";
|
|
83
42
|
/** One step row in the live inspector's step list. */
|
|
84
43
|
export type StepListItem = {
|
|
@@ -3,26 +3,29 @@ export const WORKFLOW_STATUS_LABEL = {
|
|
|
3
3
|
awaiting: "Needs you",
|
|
4
4
|
done: "Done",
|
|
5
5
|
paused: "Paused",
|
|
6
|
-
fail: "Failed"
|
|
6
|
+
fail: "Failed",
|
|
7
7
|
};
|
|
8
|
-
/** Badge tone for a status chip composed as `<Badge tone={...}><StatusDot .../>{label}</Badge>`. */
|
|
8
|
+
/** Badge tone for a status chip composed as `<Badge tone={...}><StatusDot .../>{label}</Badge>`. */
|
|
9
|
+
export const WORKFLOW_STATUS_BADGE_TONE = {
|
|
9
10
|
running: "info",
|
|
10
11
|
awaiting: "accent",
|
|
11
12
|
done: "success",
|
|
12
13
|
paused: "neutral",
|
|
13
|
-
fail: "danger"
|
|
14
|
+
fail: "danger",
|
|
14
15
|
};
|
|
15
|
-
/** Dot tone for the same chip — see `status-dot.tsx` for why only three exist. */
|
|
16
|
+
/** Dot tone for the same chip — see `status-dot.tsx` for why only three exist. */
|
|
17
|
+
export const WORKFLOW_STATUS_DOT_TONE = {
|
|
16
18
|
running: "emphasis",
|
|
17
19
|
awaiting: "emphasis",
|
|
18
20
|
done: "neutral",
|
|
19
21
|
paused: "neutral",
|
|
20
|
-
fail: "danger"
|
|
22
|
+
fail: "danger",
|
|
21
23
|
};
|
|
22
24
|
/** Whether a status tone's dot pulses by default — the two tones that are
|
|
23
25
|
* still moving or still waiting on someone. A caller composing `Badge` +
|
|
24
26
|
* `StatusDot` directly (there is no `StatusChip` component) passes this as
|
|
25
|
-
* `StatusDot`'s `live` prop unless it has a more specific signal. */
|
|
27
|
+
* `StatusDot`'s `live` prop unless it has a more specific signal. */
|
|
28
|
+
export function workflowStatusLive(tone) {
|
|
26
29
|
return tone === "running" || tone === "awaiting";
|
|
27
30
|
}
|
|
28
31
|
export function workflowScopeLabel(scope) {
|
|
@@ -30,27 +33,14 @@ export function workflowScopeLabel(scope) {
|
|
|
30
33
|
}
|
|
31
34
|
/** Badge tone for a workflow's scope. `tenant` gets the info tone so it reads
|
|
32
35
|
* as shared infrastructure; `personal` gets the accent tone that marks
|
|
33
|
-
* "yours" everywhere else in the registry. */
|
|
36
|
+
* "yours" everywhere else in the registry. */
|
|
37
|
+
export const WORKFLOW_SCOPE_BADGE_TONE = {
|
|
34
38
|
tenant: "info",
|
|
35
|
-
personal: "accent"
|
|
36
|
-
};
|
|
37
|
-
export const LIVE_RUN_PHASE_TONE = {
|
|
38
|
-
running: "running",
|
|
39
|
-
awaiting: "awaiting",
|
|
40
|
-
completed: "done",
|
|
41
|
-
failed: "fail",
|
|
42
|
-
cancelled: "fail"
|
|
43
|
-
};
|
|
44
|
-
export const LIVE_RUN_PHASE_LABEL = {
|
|
45
|
-
running: "Running",
|
|
46
|
-
awaiting: "Needs you",
|
|
47
|
-
completed: "Done",
|
|
48
|
-
failed: "Failed",
|
|
49
|
-
cancelled: "Cancelled"
|
|
39
|
+
personal: "accent",
|
|
50
40
|
};
|
|
51
41
|
export const GATE_KIND_LABEL = {
|
|
52
42
|
reviewList: "Needs you · review",
|
|
53
43
|
choice: "Needs you · choice",
|
|
54
44
|
form: "Needs you · form",
|
|
55
|
-
multiSelect: "Needs you · select"
|
|
45
|
+
multiSelect: "Needs you · select",
|
|
56
46
|
};
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* plain-language messages, and defaults everything unrecognized to a
|
|
9
9
|
* generic-but-honest internal message. The raw text survives on the result
|
|
10
10
|
* for an operator surface or a log; it must never reach an end-user panel.
|
|
11
|
-
*/
|
|
11
|
+
*/
|
|
12
|
+
const PROVIDER_API_ERROR = /^([A-Za-z][A-Za-z0-9]*(?: [A-Za-z0-9]+){0,2}) API error: (\d{3})/;
|
|
12
13
|
const ANY_API_ERROR = /\bAPI error: (\d{3})/;
|
|
13
14
|
const GENERIC_PROVIDER_LABEL = "An external service";
|
|
14
15
|
const NETWORK_PATTERNS = [
|
|
@@ -19,37 +20,39 @@ const NETWORK_PATTERNS = [
|
|
|
19
20
|
/\bEAI_AGAIN\b/,
|
|
20
21
|
/\bsocket\b.*\b(closed|hang ?up|reset)\b/i,
|
|
21
22
|
/\b(request|fetch|connect(?:ion)?|socket)\b.*\btimed out\b/i,
|
|
22
|
-
/\bnetwork (error|request failed)\b/i
|
|
23
|
+
/\bnetwork (error|request failed)\b/i,
|
|
23
24
|
];
|
|
24
25
|
const INTERNAL_MESSAGE = "Something went wrong inside this workflow run. Try running it again; if it keeps failing, contact your workspace admin.";
|
|
25
26
|
const NETWORK_MESSAGE = "A service this workflow depends on couldn't be reached. Try running it again in a moment.";
|
|
26
27
|
function classifyProviderError(provider, status, raw) {
|
|
27
|
-
const credentialRef = provider === GENERIC_PROVIDER_LABEL
|
|
28
|
+
const credentialRef = provider === GENERIC_PROVIDER_LABEL
|
|
29
|
+
? "credential's"
|
|
30
|
+
: `${provider} credential's`;
|
|
28
31
|
if (status === 401 || status === 403) {
|
|
29
32
|
return {
|
|
30
33
|
kind: "external-auth",
|
|
31
34
|
userMessage: `${provider} declined the request (${status}). Check the connected ${credentialRef} access and try again.`,
|
|
32
|
-
raw
|
|
35
|
+
raw,
|
|
33
36
|
};
|
|
34
37
|
}
|
|
35
38
|
if (status === 429) {
|
|
36
39
|
return {
|
|
37
40
|
kind: "external-rate-limit",
|
|
38
41
|
userMessage: `${provider} is rate-limiting requests right now. Wait a few minutes and run this again.`,
|
|
39
|
-
raw
|
|
42
|
+
raw,
|
|
40
43
|
};
|
|
41
44
|
}
|
|
42
45
|
if (status >= 500) {
|
|
43
46
|
return {
|
|
44
47
|
kind: "external-unavailable",
|
|
45
48
|
userMessage: `${provider} had a problem on its end (${status}). Try running this again shortly.`,
|
|
46
|
-
raw
|
|
49
|
+
raw,
|
|
47
50
|
};
|
|
48
51
|
}
|
|
49
52
|
return {
|
|
50
53
|
kind: "external-rejected",
|
|
51
54
|
userMessage: `${provider} rejected the request (${status}). Try again, and contact your workspace admin if it keeps failing.`,
|
|
52
|
-
raw
|
|
55
|
+
raw,
|
|
53
56
|
};
|
|
54
57
|
}
|
|
55
58
|
export function classifyRunError(raw) {
|
|
@@ -61,18 +64,10 @@ export function classifyRunError(raw) {
|
|
|
61
64
|
if (anyApiErrorMatch?.[1] !== undefined) {
|
|
62
65
|
return classifyProviderError(GENERIC_PROVIDER_LABEL, Number(anyApiErrorMatch[1]), raw);
|
|
63
66
|
}
|
|
64
|
-
if (NETWORK_PATTERNS.some((pattern)=>pattern.test(raw))) {
|
|
65
|
-
return {
|
|
66
|
-
kind: "network",
|
|
67
|
-
userMessage: NETWORK_MESSAGE,
|
|
68
|
-
raw
|
|
69
|
-
};
|
|
67
|
+
if (NETWORK_PATTERNS.some((pattern) => pattern.test(raw))) {
|
|
68
|
+
return { kind: "network", userMessage: NETWORK_MESSAGE, raw };
|
|
70
69
|
}
|
|
71
|
-
return {
|
|
72
|
-
kind: "internal",
|
|
73
|
-
userMessage: INTERNAL_MESSAGE,
|
|
74
|
-
raw
|
|
75
|
-
};
|
|
70
|
+
return { kind: "internal", userMessage: INTERNAL_MESSAGE, raw };
|
|
76
71
|
}
|
|
77
72
|
/**
|
|
78
73
|
* Plain-language line for a step's live inference issue — a still-running
|
|
@@ -83,8 +78,9 @@ export function classifyRunError(raw) {
|
|
|
83
78
|
* runtime's error types. The step keeps running for every category except
|
|
84
79
|
* `context_overflow`, where the input itself must shrink before a retry can
|
|
85
80
|
* help — its message is the one that omits the retry claim.
|
|
86
|
-
*/
|
|
87
|
-
|
|
81
|
+
*/
|
|
82
|
+
export function describeLiveInferenceIssue(category) {
|
|
83
|
+
switch (category) {
|
|
88
84
|
case "timeout":
|
|
89
85
|
return "Model provider timed out — retrying";
|
|
90
86
|
case "retryable":
|