@theoremjs/studio 0.3.4-next.456.gff60088 → 0.3.4-next.460.g4444a29

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 (26) hide show
  1. package/package.json +4 -4
  2. package/page/assets/{Banner-DBzTZFXK.js → Banner-BXLdz4y2.js} +2 -2
  3. package/page/assets/{ConsoleFrame-xxYOJ87g.js → ConsoleFrame-DJ2vIGy8.js} +1 -1
  4. package/page/assets/{ContextMenu-BeVF9aNZ.js → ContextMenu-DnU_R5on.js} +2 -2
  5. package/page/assets/{ToolResultCharts-DBMZY7TW.js → ToolResultCharts-BFLDoF4L.js} +1 -1
  6. package/page/assets/{TraceInspector-CzHEXIY1.js → TraceInspector-CLL7OG3M.js} +1 -1
  7. package/page/assets/{TraceOverview-Bxg_mg5E.js → TraceOverview-BUqgljgU.js} +1 -1
  8. package/page/assets/{browser-engine-9AzaOhwz.js → browser-engine-zievI8f-.js} +1 -1
  9. package/page/assets/{browser-transport-C4SkWngw.js → browser-transport-ArRkOmu8.js} +3 -3
  10. package/page/assets/{export-agent-Bp0s2CsN.js → export-agent-Dz3Y7tO7.js} +1 -1
  11. package/page/assets/{guardrail-tester-CS65cwR5.js → guardrail-tester-D-hsX8gK.js} +1 -1
  12. package/page/assets/{index--GBhZcW8.js → index-DGzlieAM.js} +6 -6
  13. package/page/assets/{studio-code-pane-B5U9m4Ds.js → studio-code-pane-BNwB_may.js} +1 -1
  14. package/page/assets/{studio-console-UkWyi9VN.js → studio-console-gYuEwLzY.js} +1 -1
  15. package/page/assets/{studio-decision-CCqMemnt.js → studio-decision-BenlP-cQ.js} +1 -1
  16. package/page/assets/{studio-embedding-RTptdueU.js → studio-embedding-ChUIvwWb.js} +1 -1
  17. package/page/assets/{studio-host-console-4UbIwUY0.js → studio-host-console-Dg6LezAO.js} +2 -2
  18. package/page/assets/{studio-labels-I9r-0TcO.js → studio-labels-YnrLEnjn.js} +1 -1
  19. package/page/assets/{studio-live-Cn-wK5-R.js → studio-live-CaYSM1iE.js} +1 -1
  20. package/page/assets/{studio-map-BWTX2beg.js → studio-map-BYqiUV_l.js} +1 -1
  21. package/page/assets/{studio-trace-replay-BaTeqFr0.js → studio-trace-replay-DDcuo5Zv.js} +1 -1
  22. package/page/assets/{use-one-call-C0-dw_94.js → use-one-call-DLdyrBVf.js} +1 -1
  23. package/page/index.html +5 -5
  24. package/ui/tree-map.css +82 -0
  25. package/ui/tree-map.d.ts +7 -1
  26. package/ui/tree-map.js +78 -20
package/ui/tree-map.css CHANGED
@@ -13,3 +13,85 @@
13
13
  .studio-tree-map-lines .map-line {
14
14
  stroke: color-mix(in srgb, var(--color-border-emphasized) 60%, var(--color-background-surface));
15
15
  }
16
+
17
+ /*
18
+ * Detail adds nodes. What is drawn moves to make room first, then each added node draws in after
19
+ * the one before, as the loader's map draws (read-map.css): its line, then its token. Without
20
+ * detail, the added ones leave in the reverse order, then the rest moves back.
21
+ * invariant: Transitions, not keyframes, so both ways ease, and a turn mid-way goes back from
22
+ * where it is. An added node only ever jumps to its place while it is not drawn.
23
+ */
24
+ .studio-tree-map {
25
+ --added-step: 40ms;
26
+ --added-draw: var(--duration-medium, 240ms);
27
+ --map-move: var(--duration-slow, 400ms);
28
+ /* How long the added nodes take to leave, before the rest moves back. */
29
+ --map-leave: calc(var(--added-n) * var(--added-step) + 2 * var(--added-draw));
30
+ --map-ease: var(--ease-standard, ease-out);
31
+ }
32
+
33
+ .studio-tree-map > [data-added] {
34
+ opacity: 0;
35
+ }
36
+
37
+ .studio-tree-map-lines [data-added] {
38
+ stroke-dasharray: 1;
39
+ stroke-dashoffset: var(--added-from);
40
+ }
41
+
42
+ .studio-tree-map[data-detail] > [data-added] {
43
+ opacity: 1;
44
+ }
45
+
46
+ .studio-tree-map[data-detail] .studio-tree-map-lines [data-added] {
47
+ stroke-dashoffset: 0;
48
+ }
49
+
50
+ /* invariant: With reduced motion, nothing moves: each node is at once where it ends. */
51
+ @media (prefers-reduced-motion: no-preference) {
52
+ .studio-tree-map > .map-token,
53
+ .studio-tree-map-lines .map-line {
54
+ transition:
55
+ top var(--map-move) var(--map-ease) var(--map-leave),
56
+ left var(--map-move) var(--map-ease) var(--map-leave),
57
+ d var(--map-move) var(--map-ease) var(--map-leave);
58
+ }
59
+
60
+ .studio-tree-map > [data-added] {
61
+ transition:
62
+ opacity var(--added-draw) var(--map-ease)
63
+ calc((var(--added-n) - var(--added-i)) * var(--added-step)),
64
+ top 0s var(--map-leave),
65
+ left 0s var(--map-leave);
66
+ }
67
+
68
+ .studio-tree-map-lines [data-added] {
69
+ transition:
70
+ stroke-dashoffset var(--added-draw) var(--map-ease)
71
+ calc((var(--added-n) - var(--added-i)) * var(--added-step) + var(--added-draw)),
72
+ d 0s var(--map-leave);
73
+ }
74
+
75
+ .studio-tree-map[data-detail] > .map-token {
76
+ transition-delay: 0s;
77
+ }
78
+
79
+ .studio-tree-map[data-detail] > [data-added] {
80
+ transition:
81
+ opacity var(--added-draw) var(--map-ease)
82
+ calc(var(--map-move) + var(--added-i) * var(--added-step) + var(--added-draw)),
83
+ top 0s,
84
+ left 0s;
85
+ }
86
+
87
+ .studio-tree-map[data-detail] .studio-tree-map-lines .map-line {
88
+ transition-delay: 0s;
89
+ }
90
+
91
+ .studio-tree-map[data-detail] .studio-tree-map-lines [data-added] {
92
+ transition:
93
+ stroke-dashoffset var(--added-draw) var(--map-ease)
94
+ calc(var(--map-move) + var(--added-i) * var(--added-step)),
95
+ d 0s;
96
+ }
97
+ }
package/ui/tree-map.d.ts CHANGED
@@ -3,5 +3,11 @@ export interface StudioTreeMapProps {
3
3
  workspace: StudioWorkspace;
4
4
  /** The keys of the agents to draw, in the workspace's order; every agent when unset. */
5
5
  agents?: readonly string[] | undefined;
6
+ /**
7
+ * Every tool in the registry, not a few, and each turn runner opened into the steps of a turn. Turned on, what is drawn moves to make room, then each
8
+ * node it adds draws in after the one before, its line first, as the loader's map draws; turned
9
+ * off, they leave in the reverse order and the rest moves back.
10
+ */
11
+ detail?: boolean | undefined;
6
12
  }
7
- export declare function StudioTreeMap({ workspace, agents }: StudioTreeMapProps): import("react").JSX.Element;
13
+ export declare function StudioTreeMap({ workspace, agents, detail }: StudioTreeMapProps): import("react").JSX.Element;
package/ui/tree-map.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconCloud, IconEngine, IconSettingsAutomation, IconTool } from '@tabler/icons-react';
2
+ import { IconAdjustments, IconArrowsMinimize, IconChecks, IconCloud, IconEngine, IconFlag, IconKey, IconRepeat, IconSettingsAutomation, IconShieldCheck, IconTimeline, IconTool, } from '@tabler/icons-react';
3
3
  import { useRef } from 'react';
4
4
  import { mapCurve } from "../map-line.js";
5
5
  import { createBlankDraft, libraryDraft, workspaceTree, } from "../mod.js";
@@ -72,7 +72,26 @@ function runnerLabel(type) {
72
72
  return 'Embedding runner';
73
73
  return 'Turn runner';
74
74
  }
75
- function feedsOf(workspace, rows) {
75
+ /**
76
+ * What a turn runner does in one turn, in order.
77
+ * why: The kernel contract's turn lifecycle (docs/contracts/kernel.md, "Turn lifecycle"), step for
78
+ * step; a decision and a session have no such list there, so their runners open into nothing.
79
+ */
80
+ const TURN_STEPS = [
81
+ { id: 'resolve', label: 'Resolve', icon: IconAdjustments },
82
+ { id: 'sanitize', label: 'Sanitize', icon: IconShieldCheck },
83
+ { id: 'compaction', label: 'Compaction', icon: IconArrowsMinimize },
84
+ { id: 'canary', label: 'Canary bind', icon: IconKey },
85
+ { id: 'pre_turn', label: 'pre_turn', icon: IconFlag },
86
+ { id: 'stream', label: 'Provider stream', icon: IconCloud },
87
+ { id: 'tools', label: 'Tool loop', icon: IconRepeat },
88
+ { id: 'before_end', label: 'before_end', icon: IconFlag },
89
+ { id: 'validation', label: 'Validation', icon: IconChecks },
90
+ { id: 'egress', label: 'Egress', icon: IconShieldCheck },
91
+ { id: 'trace', label: 'Trace', icon: IconTimeline },
92
+ { id: 'post_turn', label: 'post_turn', icon: IconFlag },
93
+ ];
94
+ function feedsOf(workspace, rows, detail) {
76
95
  const feeds = [];
77
96
  const add = (id, label, icon, into, under, depth = 0) => {
78
97
  const below = (feeds.at(-1)?.y ?? Number.NEGATIVE_INFINITY) + ROW;
@@ -93,8 +112,13 @@ function feedsOf(workspace, rows) {
93
112
  if (!name)
94
113
  continue;
95
114
  const runner = runnerLabel(agent.identity.profileType);
96
- if (runner)
97
- add(`${agent.key}/runner`, runner, IconEngine, [name]);
115
+ if (runner) {
116
+ const id = `${agent.key}/runner`;
117
+ add(id, runner, IconEngine, [name]);
118
+ const steps = detail && runner === 'Turn runner' ? TURN_STEPS : [];
119
+ for (const step of steps)
120
+ add(`${id}/${step.id}`, step.label, step.icon, [], id, 1);
121
+ }
98
122
  const providers = new Map();
99
123
  for (const binding of agent.modelBindings) {
100
124
  const row = mine.find((each) => each.node.ref.facet === 'modelBinding' && each.node.ref.key === binding.key);
@@ -113,7 +137,7 @@ function feedsOf(workspace, rows) {
113
137
  else if (tools && workspace.toolSpecs.length > 0) {
114
138
  const registry = REGISTRY;
115
139
  add(registry, 'Tool registry', IconTool, [tools]);
116
- for (const tool of shownTools(workspace.toolSpecs)) {
140
+ for (const tool of listedTools(workspace.toolSpecs, detail)) {
117
141
  const icon = toolTypeIcon(tool.toolType);
118
142
  add(`${registry}/${tool.key}`, tool.toolName, icon, [], registry, 1);
119
143
  }
@@ -122,14 +146,18 @@ function feedsOf(workspace, rows) {
122
146
  }
123
147
  return feeds;
124
148
  }
125
- /** A few of the registry's tools: the first of each type, then the next ones, in the registry's order. */
126
- function shownTools(tools) {
149
+ /**
150
+ * The registry's tools: the first of each type, then the rest in the registry's order. A few of
151
+ * them, or with `detail` every one.
152
+ */
153
+ function listedTools(tools, detail) {
127
154
  const firsts = TOOL_TYPES.flatMap((type) => {
128
155
  const tool = tools.find((each) => each.toolType === type);
129
156
  return tool ? [tool] : [];
130
157
  });
131
158
  const rest = tools.filter((tool) => !firsts.includes(tool));
132
- return [...firsts, ...rest].slice(0, SHOWN_TOOLS);
159
+ const listed = [...firsts, ...rest];
160
+ return detail ? listed : listed.slice(0, SHOWN_TOOLS);
133
161
  }
134
162
  /** Right from `from` to `rail`, up or down it, and back left to `to`, its corners turned. */
135
163
  function sidePath(from, to, rail) {
@@ -142,10 +170,22 @@ function linePath(from, to) {
142
170
  const x = from.x + TRUNK;
143
171
  return `M ${x} ${from.y + HALF} V ${to.y - TURN} Q ${x} ${to.y} ${x + TURN} ${to.y} H ${to.x - LINE_GAP}`;
144
172
  }
145
- export function StudioTreeMap({ workspace, agents }) {
173
+ /** The order an added node draws in, and which end its line starts from: 1 the path's start, -1 its end. */
174
+ const addedStyle = (index, from = 1) => ({ '--added-i': index, '--added-from': from });
175
+ /**
176
+ * A line's path as a style too, so a line that moves eases to its new shape where the browser
177
+ * eases `d`; the attribute draws it where it does not.
178
+ */
179
+ const pathStyle = (d, style) => ({ ...style, d: `path("${d}")` });
180
+ export function StudioTreeMap({ workspace, agents, detail = false }) {
146
181
  const root = useRef(null);
147
182
  const rows = rowsOf(workspace, agents);
148
- const feeds = feedsOf(workspace, rows);
183
+ const few = feedsOf(workspace, rows, false);
184
+ const full = feedsOf(workspace, rows, true);
185
+ const fewIds = new Set(few.map((feed) => feed.id));
186
+ const addedIndex = new Map(full.filter((feed) => !fewIds.has(feed.id)).map((feed, index) => [feed.id, index]));
187
+ /** The feeds laid out; without detail, an added one waits on the feed it comes under. */
188
+ const feeds = detail ? full : few;
149
189
  const widths = useTokenWidths(root, workspace);
150
190
  const drafts = new Map(workspace.agents.map((agent) => [
151
191
  agent.key,
@@ -155,6 +195,7 @@ export function StudioTreeMap({ workspace, agents }) {
155
195
  const feedX = Math.max(0, ...rows.map(right)) + GAP;
156
196
  const byId = new Map(rows.map((row) => [rowId(row), row]));
157
197
  const feedById = new Map(feeds.map((feed) => [feed.id, feed]));
198
+ const placed = (feed) => feedById.get(feed.id) ?? { ...feed, y: feedById.get(feed.under ?? '')?.y ?? feed.y };
158
199
  const height = PAD * 2 + Math.max(rows.length * ROW, ...feeds.map((feed) => feed.y + HALF - PAD));
159
200
  const feedLeft = (feed) => feedX + feed.depth * INDENT;
160
201
  const feedRight = (feed) => feedLeft(feed) + (widths[feed.id] ?? GUESS);
@@ -166,25 +207,42 @@ export function StudioTreeMap({ workspace, agents }) {
166
207
  return above && feed.depth <= above.depth ? [railFor(feed, above)] : [];
167
208
  });
168
209
  const width = Math.max(GUESS, ...feeds.map(feedRight), ...rails) + PAD;
169
- return (_jsxs("div", { ref: root, className: "studio-tree-map", style: { width, height }, children: [_jsxs("svg", { className: "studio-tree-map-lines", width: width, height: height, "aria-hidden": "true", children: [rows.map((row) => row.parent && (_jsx("path", { className: "map-line", d: linePath(row.parent, row) }, rowId(row)))), feeds.flatMap((feed) => feed.into.map((id) => {
170
- const row = byId.get(id);
171
- if (!row)
172
- return null;
173
- const { d } = mapCurve({ x: feedX - LINE_GAP, y: feed.y }, { x: right(row) + LINE_GAP, y: row.y });
174
- return _jsx("path", { className: "map-line", d: d }, `${feed.id}>${id}`);
175
- })), feeds.map((feed) => {
210
+ /** What marks a node or line detail adds: its turn to draw, and the end its line draws from. */
211
+ const addedProps = (id, from = 1) => {
212
+ const index = addedIndex.get(id);
213
+ return index === undefined ? {} : { 'data-added': '', style: addedStyle(index, from) };
214
+ };
215
+ return (_jsxs("div", { ref: root, className: "studio-tree-map", "data-detail": detail ? '' : undefined, style: { width, height, '--added-n': addedIndex.size }, children: [_jsxs("svg", { className: "studio-tree-map-lines", width: width, height: height, "aria-hidden": "true", children: [rows.map((row) => row.parent && (_jsx("path", { className: "map-line", d: linePath(row.parent, row), style: pathStyle(linePath(row.parent, row)) }, rowId(row)))), full.flatMap((each) => {
216
+ const feed = placed(each);
217
+ return feed.into.map((id) => {
218
+ const row = byId.get(id);
219
+ if (!row)
220
+ return null;
221
+ const { d } = mapCurve({ x: feedX - LINE_GAP, y: feed.y }, { x: right(row) + LINE_GAP, y: row.y });
222
+ // The line runs from the feed to the row; it draws from the row.
223
+ const { style, ...added } = addedProps(feed.id, -1);
224
+ return (_jsx("path", { className: "map-line", d: d, pathLength: 1, style: pathStyle(d, style), ...added }, `${feed.id}>${id}`));
225
+ });
226
+ }), full.map((each) => {
227
+ const feed = placed(each);
176
228
  const above = feed.under === undefined ? undefined : feedById.get(feed.under);
177
229
  if (above === undefined)
178
230
  return null;
179
231
  const from = { x: feedLeft(above), y: above.y };
180
232
  // One of its own turns in from the trunk, as a tree row does; one level with it comes round
181
233
  // the right of what lies between, so it reads as joining the feed, not as one of its own.
182
- const d = feed.depth > above.depth
234
+ const isOwn = feed.depth > above.depth;
235
+ const d = isOwn
183
236
  ? linePath(from, { x: feedLeft(feed), y: feed.y })
184
237
  : sidePath({ x: feedRight(feed) + LINE_GAP, y: feed.y }, { x: feedRight(above) + LINE_GAP, y: above.y }, railFor(feed, above));
185
- return _jsx("path", { className: "map-line", d: d }, `${feed.id}^`);
238
+ // A turn in runs from the feed above; a line round the side runs from this one.
239
+ const { style, ...added } = addedProps(feed.id, isOwn ? 1 : -1);
240
+ return (_jsx("path", { className: "map-line", d: d, pathLength: 1, style: pathStyle(d, style), ...added }, `${feed.id}^`));
186
241
  })] }), rows.map((row) => {
187
242
  const draft = drafts.get(row.agent) ?? createBlankDraft();
188
243
  return (_jsx(MapToken, { id: rowId(row), label: row.node.label, icon: nodeIcon(draft, row.node.ref), x: row.x, y: row.y }, rowId(row)));
189
- }), feeds.map((feed) => (_jsx(MapToken, { id: feed.id, label: feed.label, icon: feed.icon, x: feedLeft(feed), y: feed.y }, feed.id)))] }));
244
+ }), full.map((each) => {
245
+ const feed = placed(each);
246
+ return (_jsx(MapToken, { id: feed.id, label: feed.label, icon: feed.icon, x: feedLeft(feed), y: feed.y, ...addedProps(feed.id) }, feed.id));
247
+ })] }));
190
248
  }