@theoremjs/studio 0.3.4-next.458.gbf7b487 → 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-C4MPbvft.js → Banner-BXLdz4y2.js} +2 -2
  3. package/page/assets/{ConsoleFrame-BkzieVRC.js → ConsoleFrame-DJ2vIGy8.js} +1 -1
  4. package/page/assets/{ContextMenu-BGP2gdee.js → ContextMenu-DnU_R5on.js} +2 -2
  5. package/page/assets/{ToolResultCharts-xDwNDd-T.js → ToolResultCharts-BFLDoF4L.js} +1 -1
  6. package/page/assets/{TraceInspector-CHpdhiVX.js → TraceInspector-CLL7OG3M.js} +1 -1
  7. package/page/assets/{TraceOverview-DCGew7UN.js → TraceOverview-BUqgljgU.js} +1 -1
  8. package/page/assets/{browser-engine-Ca2pvYX0.js → browser-engine-zievI8f-.js} +1 -1
  9. package/page/assets/{browser-transport-DYgEItHi.js → browser-transport-ArRkOmu8.js} +3 -3
  10. package/page/assets/{export-agent-5rXmF-g1.js → export-agent-Dz3Y7tO7.js} +1 -1
  11. package/page/assets/{guardrail-tester-B-ZfQFVu.js → guardrail-tester-D-hsX8gK.js} +1 -1
  12. package/page/assets/{index-Dajtrq_Z.js → index-DGzlieAM.js} +6 -6
  13. package/page/assets/{studio-code-pane-CKYRitdD.js → studio-code-pane-BNwB_may.js} +1 -1
  14. package/page/assets/{studio-console-DwhqnNyw.js → studio-console-gYuEwLzY.js} +1 -1
  15. package/page/assets/{studio-decision-Ckj4UNNt.js → studio-decision-BenlP-cQ.js} +1 -1
  16. package/page/assets/{studio-embedding-8qL_dVlz.js → studio-embedding-ChUIvwWb.js} +1 -1
  17. package/page/assets/{studio-host-console-BXwwloN4.js → studio-host-console-Dg6LezAO.js} +2 -2
  18. package/page/assets/{studio-labels-C1pvg0JC.js → studio-labels-YnrLEnjn.js} +1 -1
  19. package/page/assets/{studio-live-26srJ74m.js → studio-live-CaYSM1iE.js} +1 -1
  20. package/page/assets/{studio-map-C5zsJusF.js → studio-map-BYqiUV_l.js} +1 -1
  21. package/page/assets/{studio-trace-replay-B38TicvO.js → studio-trace-replay-DDcuo5Zv.js} +1 -1
  22. package/page/assets/{use-one-call-DjVkallj.js → use-one-call-DLdyrBVf.js} +1 -1
  23. package/page/index.html +5 -5
  24. package/ui/tree-map.css +66 -27
  25. package/ui/tree-map.d.ts +5 -5
  26. package/ui/tree-map.js +77 -24
package/ui/tree-map.css CHANGED
@@ -15,44 +15,83 @@
15
15
  }
16
16
 
17
17
  /*
18
- * Feeds draw in as the loader's map draws (read-map.css), one after another: the line from the
19
- * tree, then the token at its end. Hidden, they leave in the reverse order.
20
- * invariant: Transitions, not keyframes, so drawing and leaving both ease, and a turn mid-draw
21
- * goes back from where it is.
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.
22
23
  */
23
24
  .studio-tree-map {
24
- --feed-step: 70ms;
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);
25
31
  }
26
32
 
27
- .studio-tree-map-lines [data-feed] {
28
- stroke-dasharray: 1;
29
- stroke-dashoffset: 0;
30
- transition: stroke-dashoffset var(--duration-medium, 240ms) var(--ease-standard, ease-out)
31
- calc(var(--feed-i) * var(--feed-step));
33
+ .studio-tree-map > [data-added] {
34
+ opacity: 0;
32
35
  }
33
36
 
34
- .studio-tree-map > [data-feed] {
35
- transition: opacity var(--duration-medium, 240ms) var(--ease-standard, ease-out)
36
- calc(var(--feed-i) * var(--feed-step) + var(--duration-medium, 240ms));
37
+ .studio-tree-map-lines [data-added] {
38
+ stroke-dasharray: 1;
39
+ stroke-dashoffset: var(--added-from);
37
40
  }
38
41
 
39
- .studio-tree-map[data-feeds="hidden"] > [data-feed] {
40
- opacity: 0;
41
- transition-delay: calc((var(--feed-n) - var(--feed-i)) * var(--feed-step));
42
+ .studio-tree-map[data-detail] > [data-added] {
43
+ opacity: 1;
42
44
  }
43
45
 
44
- .studio-tree-map[data-feeds="hidden"] .studio-tree-map-lines [data-feed] {
45
- stroke-dashoffset: var(--feed-from);
46
- transition-delay: calc(
47
- (var(--feed-n) - var(--feed-i)) *
48
- var(--feed-step) +
49
- var(--duration-medium, 240ms)
50
- );
46
+ .studio-tree-map[data-detail] .studio-tree-map-lines [data-added] {
47
+ stroke-dashoffset: 0;
51
48
  }
52
49
 
53
- @media (prefers-reduced-motion: reduce) {
54
- .studio-tree-map-lines [data-feed],
55
- .studio-tree-map > [data-feed] {
56
- transition: none;
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;
57
96
  }
58
97
  }
package/ui/tree-map.d.ts CHANGED
@@ -4,10 +4,10 @@ export interface StudioTreeMapProps {
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
6
  /**
7
- * Whether what feeds the tree is drawn beside it. Turned on, each feed draws in after the one
8
- * before, its line from the tree first, as the loader's map draws; turned off, they leave in the
9
- * reverse order. Shown when unset.
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
10
  */
11
- feeds?: 'shown' | 'hidden' | undefined;
11
+ detail?: boolean | undefined;
12
12
  }
13
- export declare function StudioTreeMap({ workspace, agents, feeds: shown }: 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,12 +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
- /** The order a feed draws in, and which end its line starts from: 1 the path's start, -1 its end. */
146
- const feedStyle = (index, from = 1) => ({ '--feed-i': index, '--feed-from': from });
147
- export function StudioTreeMap({ workspace, agents, feeds: shown = 'shown' }) {
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 }) {
148
181
  const root = useRef(null);
149
182
  const rows = rowsOf(workspace, agents);
150
- 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;
151
189
  const widths = useTokenWidths(root, workspace);
152
190
  const drafts = new Map(workspace.agents.map((agent) => [
153
191
  agent.key,
@@ -157,6 +195,7 @@ export function StudioTreeMap({ workspace, agents, feeds: shown = 'shown' }) {
157
195
  const feedX = Math.max(0, ...rows.map(right)) + GAP;
158
196
  const byId = new Map(rows.map((row) => [rowId(row), row]));
159
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 };
160
199
  const height = PAD * 2 + Math.max(rows.length * ROW, ...feeds.map((feed) => feed.y + HALF - PAD));
161
200
  const feedLeft = (feed) => feedX + feed.depth * INDENT;
162
201
  const feedRight = (feed) => feedLeft(feed) + (widths[feed.id] ?? GUESS);
@@ -168,28 +207,42 @@ export function StudioTreeMap({ workspace, agents, feeds: shown = 'shown' }) {
168
207
  return above && feed.depth <= above.depth ? [railFor(feed, above)] : [];
169
208
  });
170
209
  const width = Math.max(GUESS, ...feeds.map(feedRight), ...rails) + PAD;
171
- const order = new Map(feeds.map((feed, index) => [feed.id, index]));
172
- return (_jsxs("div", { ref: root, className: "studio-tree-map", "data-feeds": shown, style: { width, height, '--feed-n': feeds.length }, 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) => {
173
- const row = byId.get(id);
174
- if (!row)
175
- return null;
176
- const { d } = mapCurve({ x: feedX - LINE_GAP, y: feed.y }, { x: right(row) + LINE_GAP, y: row.y });
177
- // The line runs from the feed to the row; it draws from the row.
178
- return (_jsx("path", { className: "map-line", d: d, pathLength: 1, "data-feed": "", style: feedStyle(order.get(feed.id) ?? 0, -1) }, `${feed.id}>${id}`));
179
- })), 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);
180
228
  const above = feed.under === undefined ? undefined : feedById.get(feed.under);
181
229
  if (above === undefined)
182
230
  return null;
183
231
  const from = { x: feedLeft(above), y: above.y };
184
232
  // One of its own turns in from the trunk, as a tree row does; one level with it comes round
185
233
  // the right of what lies between, so it reads as joining the feed, not as one of its own.
186
- const d = feed.depth > above.depth
234
+ const isOwn = feed.depth > above.depth;
235
+ const d = isOwn
187
236
  ? linePath(from, { x: feedLeft(feed), y: feed.y })
188
237
  : sidePath({ x: feedRight(feed) + LINE_GAP, y: feed.y }, { x: feedRight(above) + LINE_GAP, y: above.y }, railFor(feed, above));
189
238
  // A turn in runs from the feed above; a line round the side runs from this one.
190
- return (_jsx("path", { className: "map-line", d: d, pathLength: 1, "data-feed": "", style: feedStyle(order.get(feed.id) ?? 0, feed.depth > above.depth ? 1 : -1) }, `${feed.id}^`));
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}^`));
191
241
  })] }), rows.map((row) => {
192
242
  const draft = drafts.get(row.agent) ?? createBlankDraft();
193
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)));
194
- }), feeds.map((feed) => (_jsx(MapToken, { id: feed.id, label: feed.label, icon: feed.icon, x: feedLeft(feed), y: feed.y, "data-feed": "", style: feedStyle(order.get(feed.id) ?? 0) }, 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
+ })] }));
195
248
  }