@theoremjs/studio 0.3.4-next.474.gdb1d5d7 → 0.3.4-next.482.g7e608f2
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 +1 -1
- package/draft.js +1 -1
- package/package.json +4 -4
- package/page/assets/{Banner-TdHtbVjU.js → Banner-CrUhb26_.js} +2 -2
- package/page/assets/{ConsoleFrame-DgjR7mxh.js → ConsoleFrame-6cEEvO4i.js} +1 -1
- package/page/assets/{ContextMenu-D-6K0Fs2.js → ContextMenu-WnsgC14_.js} +2 -2
- package/page/assets/{ToolResultCharts-0ddlwgFH.js → ToolResultCharts-BEhuo0Z4.js} +1 -1
- package/page/assets/{TraceInspector-egLHbVIj.js → TraceInspector-k1w1q0XO.js} +1 -1
- package/page/assets/{TraceOverview-CRTN7VoT.js → TraceOverview-Crxd-sTS.js} +1 -1
- package/page/assets/{_virtual_studio-type-sources-DdSjKnMh.js → _virtual_studio-type-sources-DAabvYbE.js} +16 -6
- package/page/assets/{browser-engine-tXDx3yU4.js → browser-engine-C78edv3x.js} +7 -7
- package/page/assets/{browser-transport-ffGDz5MD.js → browser-transport-mGxdvtBL.js} +4 -4
- package/page/assets/{crypto-C5mfRMPv.js → crypto-iT_LZ8Et.js} +1 -1
- package/page/assets/encode-files-8AFMw7Er.js +1 -0
- package/page/assets/{export-agent-Y58EdieU.js → export-agent-BedkRp13.js} +1 -1
- package/page/assets/{guardrail-tester-CDawxhDM.js → guardrail-tester-XwnZWNsg.js} +1 -1
- package/page/assets/{index-DtLCmecg.js → index-BVHT-9mR.js} +9 -9
- package/page/assets/{live-messages-CcUq850L.js → live-messages-B65rUlNM.js} +1 -1
- package/page/assets/{reader-DkhgU7-Z.js → reader-XebgyCzF.js} +4 -4
- package/page/assets/{shaped-data-Hq2l-bCM.js → shaped-data-Bc6u4pow.js} +2 -2
- package/page/assets/{stub-9noS56tk.js → stub-DG5wxM-A.js} +1 -1
- package/page/assets/{studio-code-pane-CTGeGFc3.js → studio-code-pane-p4fjtQhL.js} +3 -3
- package/page/assets/{studio-console-bsXe3dk3.js → studio-console-BtZY4aUM.js} +1 -1
- package/page/assets/{studio-decision-CEcqOCMb.js → studio-decision-BovTBIwV.js} +1 -1
- package/page/assets/{studio-embedding-C1KeE3S4.js → studio-embedding-BY6UQk0k.js} +1 -1
- package/page/assets/{studio-host-console-mg-gOPJs.js → studio-host-console-D9NFWXxV.js} +2 -2
- package/page/assets/{studio-labels-DyUKoK3A.js → studio-labels-C3yQoEd0.js} +1 -1
- package/page/assets/{studio-live-D4qKxLHi.js → studio-live-B_cVDiqs.js} +1 -1
- package/page/assets/{studio-map-CsQoRSdx.js → studio-map-iN6-MOzK.js} +1 -1
- package/page/assets/studio-trace-replay-B3k21TSg.js +2 -0
- package/page/assets/{studio-type-checker-Ch0YO2TO.js → studio-type-checker-Bljo3amv.js} +1 -1
- package/page/assets/{tool-schema-DUAd6AXZ.js → tool-schema-BmScISma.js} +8 -8
- package/page/assets/{trace-record-Dfx7WS9n.js → trace-record-D4xAUHLZ.js} +1 -1
- package/page/assets/{tree-q4zfZBm3.js → tree-BiZScKs7.js} +2 -2
- package/page/assets/{turn-client-BHueOGtF.js → turn-client-CBWNoFgo.js} +2 -2
- package/page/assets/types-zRlFhC9U.js +1 -0
- package/page/assets/{use-one-call-BF7eEAPL.js → use-one-call-rh-5EjBB.js} +1 -1
- package/page/assets/{workspace-D8wB8WWL.js → workspace-kAEf4Zn4.js} +1 -1
- package/page/index.html +15 -15
- package/policy.js +2 -2
- package/replay.js +2 -3
- package/server/draft-decide.d.ts +4 -1
- package/server/draft-decide.js +1 -1
- package/ui/lib/tree-map-layout.d.ts +38 -14
- package/ui/lib/tree-map-layout.js +210 -142
- package/ui/tree-map.d.ts +10 -9
- package/ui/tree-map.js +60 -40
- package/page/assets/encode-files-CZXrfYAp.js +0 -1
- package/page/assets/studio-trace-replay-aP7TzJuO.js +0 -2
- package/page/assets/types-CbxtWiCN.js +0 -1
package/ui/tree-map.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { IconAdjustments, IconArrowsMinimize, IconChecks, IconCloud, IconEngine,
|
|
2
|
+
import { IconAdjustments, IconArrowsMinimize, IconChecks, IconCloud, IconEngine, IconKey, IconLock, IconPlugConnected, IconRepeat, IconSettingsAutomation, IconShieldCheck, IconStack2, IconTimeline, IconWorldCheck, } from '@tabler/icons-react';
|
|
3
3
|
import { useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { mapCurve } from "../map-line.js";
|
|
5
5
|
import { createBlankDraft, libraryDraft } from "../mod.js";
|
|
6
6
|
import { drawnAt, HALF, INDENT, PAD, placeAt, rowId, treeMapLayout, } from "./lib/tree-map-layout.js";
|
|
7
|
-
import { toolTypeIcon } from "./lib/type-icons.js";
|
|
7
|
+
import { AGENT_ICON, profileTypeIcon, toolTypeIcon } from "./lib/type-icons.js";
|
|
8
8
|
import { MapToken, useTokenWidths } from "./map-token.js";
|
|
9
9
|
import { nodeIcon } from "./node-icon.js";
|
|
10
10
|
import { drags, follow } from "./pan.js";
|
|
@@ -15,7 +15,7 @@ const TRUNK = 13;
|
|
|
15
15
|
const TURN = 8;
|
|
16
16
|
/** Between a token's side and its line. */
|
|
17
17
|
const LINE_GAP = 4;
|
|
18
|
-
/** How far right of
|
|
18
|
+
/** How far right of what it passes a line coming round a column runs. */
|
|
19
19
|
const RAIL = 20;
|
|
20
20
|
/** A token's width until it is measured. */
|
|
21
21
|
const GUESS = 120;
|
|
@@ -23,28 +23,37 @@ const STEP_ICONS = {
|
|
|
23
23
|
resolve: IconAdjustments,
|
|
24
24
|
sanitize: IconShieldCheck,
|
|
25
25
|
compaction: IconArrowsMinimize,
|
|
26
|
-
canary: IconKey,
|
|
27
|
-
pre_turn: IconFlag,
|
|
28
26
|
stream: IconCloud,
|
|
29
27
|
tools: IconRepeat,
|
|
30
|
-
before_end: IconFlag,
|
|
31
28
|
validation: IconChecks,
|
|
32
29
|
egress: IconShieldCheck,
|
|
33
30
|
trace: IconTimeline,
|
|
34
|
-
|
|
31
|
+
};
|
|
32
|
+
const CHECK_ICONS = {
|
|
33
|
+
permission: IconLock,
|
|
34
|
+
'sign-in': IconKey,
|
|
35
|
+
network: IconWorldCheck,
|
|
36
|
+
result: IconShieldCheck,
|
|
35
37
|
};
|
|
36
38
|
function feedIcon(feed) {
|
|
39
|
+
const of = feed.of ?? '';
|
|
37
40
|
if (feed.kind === 'runner')
|
|
38
41
|
return IconEngine;
|
|
42
|
+
if (feed.kind === 'step')
|
|
43
|
+
return STEP_ICONS[of] ?? IconRepeat;
|
|
39
44
|
if (feed.kind === 'provider')
|
|
40
45
|
return IconCloud;
|
|
46
|
+
if (feed.kind === 'protocol')
|
|
47
|
+
return IconPlugConnected;
|
|
41
48
|
if (feed.kind === 'tool')
|
|
42
|
-
return toolTypeIcon(
|
|
49
|
+
return toolTypeIcon(of);
|
|
50
|
+
if (feed.kind === 'branch')
|
|
51
|
+
return IconStack2;
|
|
52
|
+
if (feed.kind === 'subagent')
|
|
53
|
+
return profileTypeIcon(of) ?? AGENT_ICON;
|
|
43
54
|
if (feed.kind === 'tool-runner')
|
|
44
55
|
return IconSettingsAutomation;
|
|
45
|
-
|
|
46
|
-
return STEP_ICONS[feed.of ?? ''] ?? IconFlag;
|
|
47
|
-
return IconTool;
|
|
56
|
+
return CHECK_ICONS[of] ?? IconShieldCheck;
|
|
48
57
|
}
|
|
49
58
|
/** Right from `from` to `rail`, up or down it, and back left to `to`, its corners turned. */
|
|
50
59
|
function sidePath(from, to, rail) {
|
|
@@ -77,7 +86,8 @@ export function StudioTreeMap({ workspace, agents, grow = 0, fit, draggable = fa
|
|
|
77
86
|
const [dragging, setDragging] = useState(false);
|
|
78
87
|
// why: Every token is drawn from the start, the undrawn ones unseen, so each is measured before it shows.
|
|
79
88
|
const widths = useTokenWidths(root, workspace);
|
|
80
|
-
const
|
|
89
|
+
const { width: fitWidth, height: fitHeight } = fit ?? { width: 0, height: 0 };
|
|
90
|
+
const layout = useMemo(() => treeMapLayout(workspace, agents, (id) => widths[id] ?? GUESS, fitWidth > 0 && fitHeight > 0 ? { width: fitWidth, height: fitHeight } : undefined), [workspace, agents, widths, fitWidth, fitHeight]);
|
|
81
91
|
const width = (id) => widths[id] ?? GUESS;
|
|
82
92
|
const drafts = new Map(workspace.agents.map((agent) => [
|
|
83
93
|
agent.key,
|
|
@@ -91,46 +101,65 @@ export function StudioTreeMap({ workspace, agents, grow = 0, fit, draggable = fa
|
|
|
91
101
|
};
|
|
92
102
|
const drawn = (id) => drawnAt(layout, id, grow);
|
|
93
103
|
const feedById = new Map(feeds.map((feed) => [feed.id, feed]));
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
/** A line draws in its first half of the later of its two ends drawing, its token in the second. */
|
|
105
|
+
const lineDrawn = (...ids) => {
|
|
106
|
+
const parts = ids.flatMap((id) => drawn(id) ?? []);
|
|
107
|
+
if (parts.length === 0)
|
|
108
|
+
return {};
|
|
109
|
+
const part = Math.min(...parts);
|
|
110
|
+
return { pathLength: 1, style: { strokeDasharray: 1, strokeDashoffset: 1 - clamp(part * 2) } };
|
|
99
111
|
};
|
|
100
112
|
const shown = feeds.filter((feed) => (drawn(feed.id) ?? 1) > 0);
|
|
101
113
|
const right = (id) => at(id).x + width(id);
|
|
102
|
-
/** Right of every feed from `
|
|
103
|
-
const railFor = (feed,
|
|
104
|
-
const [top, bottom] = [at(
|
|
114
|
+
/** Right of every feed in its column from `to` to `feed`, where each stands now. */
|
|
115
|
+
const railFor = (feed, to) => {
|
|
116
|
+
const [top, bottom] = [at(to.id).y, at(feed.id).y].sort((a, b) => a - b);
|
|
105
117
|
const lying = shown.filter((each) => {
|
|
106
118
|
const { y } = at(each.id);
|
|
107
|
-
return y >= (top ?? 0) && y <= (bottom ?? 0)
|
|
119
|
+
return each.column === feed.column && y >= (top ?? 0) && y <= (bottom ?? 0);
|
|
108
120
|
});
|
|
109
|
-
return Math.max(
|
|
121
|
+
return Math.max(...lying.map((each) => right(each.id))) + RAIL;
|
|
110
122
|
};
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return above && feed.depth <= above.depth ? [railFor(feed, above)] : [];
|
|
123
|
+
const joins = shown.flatMap((feed) => {
|
|
124
|
+
const to = feed.joins === undefined ? undefined : feedById.get(feed.joins);
|
|
125
|
+
return to && (drawn(to.id) ?? 1) > 0 ? [{ feed, to }] : [];
|
|
115
126
|
});
|
|
127
|
+
/** A join to a feed further right runs across to it; to one in its own column, round their right. */
|
|
128
|
+
const joinPath = (feed, to) => {
|
|
129
|
+
const from = { x: right(feed.id) + LINE_GAP, y: at(feed.id).y };
|
|
130
|
+
if (to.column > feed.column) {
|
|
131
|
+
return mapCurve(from, { x: at(to.id).x - LINE_GAP, y: at(to.id).y }).d;
|
|
132
|
+
}
|
|
133
|
+
return sidePath(from, { x: right(to.id) + LINE_GAP, y: at(to.id).y }, railFor(feed, to));
|
|
134
|
+
};
|
|
135
|
+
const places = [...rows.map(rowId), ...shown.map((feed) => feed.id)];
|
|
136
|
+
const rails = joins.flatMap(({ feed, to }) => to.column === feed.column ? [railFor(feed, to)] : []);
|
|
116
137
|
const mapWidth = Math.max(GUESS, ...places.map(right), ...rails) + PAD;
|
|
117
138
|
const height = Math.max(...places.map((id) => at(id).y)) + HALF + PAD;
|
|
118
139
|
const grown = useMemo(() => {
|
|
119
140
|
const ids = [...layout.rows.map(rowId), ...layout.feeds.map((feed) => feed.id)];
|
|
120
141
|
const ends = ids.map((id) => ({ id, ...placeAt(layout, id, 1) }));
|
|
121
142
|
return {
|
|
122
|
-
width: Math.max(...ends.map((end) => end.x + (widths[end.id] ?? GUESS))) +
|
|
143
|
+
width: Math.max(...ends.map((end) => end.x + (widths[end.id] ?? GUESS))) + PAD,
|
|
123
144
|
height: Math.max(...ends.map((end) => end.y)) + HALF + PAD,
|
|
124
145
|
};
|
|
125
146
|
}, [layout, widths]);
|
|
126
147
|
const fits = fit ? Math.min(1, fit.width / grown.width, fit.height / grown.height) : 1;
|
|
127
148
|
const scale = 1 + (fits - 1) * clamp(grow);
|
|
149
|
+
// why: Grown, the map stands in the middle of the box it fills; closed, at its top left.
|
|
150
|
+
const centre = fit
|
|
151
|
+
? {
|
|
152
|
+
x: (Math.max(0, fit.width - grown.width * fits) / 2) * clamp(grow),
|
|
153
|
+
y: (Math.max(0, fit.height - grown.height * fits) / 2) * clamp(grow),
|
|
154
|
+
}
|
|
155
|
+
: NONE;
|
|
128
156
|
// why: The pointer moves in the page's pixels; the map is scaled, so a move is divided back into its own.
|
|
129
157
|
const drag = (event) => {
|
|
130
158
|
if (!draggable || !drags(event))
|
|
131
159
|
return;
|
|
132
160
|
event.preventDefault();
|
|
133
|
-
const token = event.target.closest('[data-map-token]')?.dataset
|
|
161
|
+
const token = event.target.closest('[data-map-token]')?.dataset
|
|
162
|
+
.mapToken;
|
|
134
163
|
const from = token === undefined ? field : (moved[token] ?? NONE);
|
|
135
164
|
const put = (to) => {
|
|
136
165
|
if (token === undefined)
|
|
@@ -147,7 +176,8 @@ export function StudioTreeMap({ workspace, agents, grow = 0, fit, draggable = fa
|
|
|
147
176
|
setDragging(false);
|
|
148
177
|
});
|
|
149
178
|
};
|
|
150
|
-
const
|
|
179
|
+
const shift = { x: field.x + centre.x, y: field.y + centre.y };
|
|
180
|
+
const translate = shift.x || shift.y ? { translate: `${shift.x}px ${shift.y}px` } : {};
|
|
151
181
|
return (_jsxs("div", { ref: root, className: "studio-tree-map", style: {
|
|
152
182
|
width: mapWidth,
|
|
153
183
|
height,
|
|
@@ -157,17 +187,7 @@ export function StudioTreeMap({ workspace, agents, grow = 0, fit, draggable = fa
|
|
|
157
187
|
const from = at(feed.id);
|
|
158
188
|
const { d } = mapCurve({ x: from.x - LINE_GAP, y: from.y }, { x: right(id) + LINE_GAP, y: at(id).y });
|
|
159
189
|
return _jsx("path", { className: "map-line", d: d }, `${feed.id}>${id}`);
|
|
160
|
-
})), shown.map((feed) => {
|
|
161
|
-
const above = feed.under === undefined ? undefined : feedById.get(feed.under);
|
|
162
|
-
if (above === undefined)
|
|
163
|
-
return null;
|
|
164
|
-
// One of its own comes down from it, as a tree row does; one level with it comes round
|
|
165
|
-
// the right of what lies between, so it reads as joining the feed, not as one of its own.
|
|
166
|
-
const d = feed.depth > above.depth
|
|
167
|
-
? underPath(at(above.id), at(feed.id))
|
|
168
|
-
: sidePath({ x: right(feed.id) + LINE_GAP, y: at(feed.id).y }, { x: right(above.id) + LINE_GAP, y: at(above.id).y }, railFor(feed, above));
|
|
169
|
-
return _jsx("path", { className: "map-line", d: d, ...lineDrawn(feed.id) }, `${feed.id}^`);
|
|
170
|
-
})] }), rows.map((row) => {
|
|
190
|
+
})), shown.map((feed) => feed.under !== undefined && (_jsx("path", { className: "map-line", d: underPath(at(feed.under), at(feed.id)), ...lineDrawn(feed.id) }, `${feed.id}^`))), joins.map(({ feed, to }) => (_jsx("path", { className: "map-line", d: joinPath(feed, to), ...lineDrawn(feed.id, to.id) }, `${feed.id}~${to.id}`)))] }), rows.map((row) => {
|
|
171
191
|
const draft = drafts.get(row.agent) ?? createBlankDraft();
|
|
172
192
|
const { x, y } = at(rowId(row));
|
|
173
193
|
return (_jsx(MapToken, { id: rowId(row), label: row.node.label, icon: nodeIcon(draft, row.node.ref), x: x, y: y }, rowId(row)));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{fn as e,pn as t}from"./shaped-data-Hq2l-bCM.js";function n(e){return e.map(e=>({name:e.name,mimeType:e.type||`application/octet-stream`,sizeBytes:e.size}))}function r(t){let n=[];for(let r of t){if(typeof r.data!=`string`||r.data.length===0)continue;let t=e(r.data),i=t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength);n.push(new File([i],r.name,{type:r.mimeType||`application/octet-stream`}))}return n}async function i(e){let n=[];for(let r of e)n.push({name:r.name,mimeType:r.type||`application/octet-stream`,data:t(new Uint8Array(await r.arrayBuffer()))});return n}function a(e,t,n){let r=0,i=0;return e.map(e=>{if(e.kind===`user-attachment`){let n=t?.[r]?.data;return r+=1,n===void 0?e:{...e,data:n}}if(e.kind===`user-voice`){let t=n?.[i]?.data;return i+=1,t===void 0?e:{...e,data:t}}return e})}export{r as i,i as n,n as r,a as t};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./rolldown-runtime-hePW80VL.js";import{c as t,u as n}from"./themeProps-3IqahpCr.js";import{n as r,t as i}from"./SegmentedControlItem-BLuJOusN.js";import{t as a}from"./VStack-CkVMcNiK.js";import{A as o,_ as s,a as c,o as l,s as u,v as d}from"./browser-transport-ffGDz5MD.js";import{r as f}from"./IconButton-CG5klqF1.js";import{t as p}from"./Text-BsiAsowd.js";import{n as m,t as h}from"./labels-provider-BSiD6Lrb.js";import{a as g,t as _}from"./Banner-TdHtbVjU.js";import{t as v,v as ee}from"./studio-labels-DyUKoK3A.js";import{c as y}from"./host-patterns-C9RMP16Q.js";import{n as b}from"./trace-record-Dfx7WS9n.js";import{n as x}from"./trace-schema-9CdEyG6Q.js";import{_ as S}from"./turn-client-BHueOGtF.js";import{a as C,i as w,o as T,t as E}from"./ConsoleFrame-DgjR7mxh.js";import{C as D,a as O,b as k,g as te,x as ne}from"./index-DtLCmecg.js";var A=e=>typeof e==`object`&&!!e&&!Array.isArray(e),j=(e,t)=>e.attributes[t],M=(e,t)=>{let n=j(e,t);return typeof n==`string`?n:void 0};function N(e,t,n){let r=j(t,n);return r===void 0?void 0:b(e,r)}function P(e,t,n){let r=N(e,t,n);return r===void 0?``:typeof r==`string`?r:JSON.stringify(r)}function F(e,t,n){let r=N(e,t,n);return Array.isArray(r)?r.filter(A):[]}var I=e=>Array.isArray(e.parts)?e.parts.filter(A):[],L=e=>BigInt(String(e.startTimeUnixNano)),R=(e,t)=>{let n=L(e)-L(t);return n===0n?0:n<0n?-1:1},re=e=>`content_sha256`in e||`json_sha256`in e;function z(e){let t=e.arguments;if(A(t))return t;if(typeof t!=`string`)return{};try{let e=JSON.parse(t);return A(e)?e:{}}catch{return{}}}function B(e){if(typeof e.content==`string`){if(e.type===`reasoning`)return{type:`thought`,text:e.content};if(e.type===`text`)return{type:`text`,text:e.content}}}function ie(e){let t=[],n=[],r=!1;for(let i of e){let e=I(i),a=e.some(e=>e.type===`text`);for(let i of e){let e=B(i);re(i)?r=!0:e?t.push(e):i.type===`structured`&&!a?t.push({type:`text`,text:JSON.stringify(i.content)}):i.type===`tool_call`&&typeof i.name==`string`?(n.push(i.name),t.push({type:`tool`,tool:{name:i.name,callId:typeof i.id==`string`?i.id:`replay-${String(n.length)}`,arguments:z(i)}})):(i.type===`blob`||i.type===`uri`)&&(r=!0)}}return{events:t,calls:n,missing:r}}function ae(e,t){for(let n=e;n;n=t.get(n.parentSpanId??``)){let e=M(n,`gen_ai.agent.name`);if(M(n,`gen_ai.operation.name`)===`invoke_agent`&&e)return e}return``}var V=e=>M(e,`gen_ai.operation.name`);function oe(e){let t=new Map(e.spans.map(e=>[e.spanId,e]));return e.spans.filter(e=>V(e)===`chat`).toSorted(R).map(n=>{let r=ie(F(e,n,`gen_ai.output.messages`)),i=M(n,`theorem.stop.kind`)??`completed`;return{agent:ae(n,t),...r,events:[...r.events,{type:`done`,stop:{kind:i}}]}})}function se(e){return e.spans.filter(e=>V(e)===`execute_tool`).toSorted(R).map(t=>({name:M(t,`gen_ai.tool.name`)??``,result:P(e,t,`gen_ai.tool.call.result`),failed:M(t,`theorem.tool.outcome`)===`error`}))}function ce(e,t){let n=F(e,t,`gen_ai.input.messages`).findLast(e=>e.role===`user`),r=n?I(n):[];return{text:r.flatMap(e=>e.type===`text`&&typeof e.content==`string`?[e.content]:[]).join(`
|
|
2
|
-
`),attachments:r.filter(e=>e.type===`blob`||e.type===`uri`).length}}function le(e,t){let n=e.spans.filter(e=>V(e)===`execute_tool`).toSorted(R),r=new Set,i=(e,t)=>{let i=n.find(t=>M(t,`gen_ai.tool.call.id`)===e)??n.find(e=>!r.has(e)&&M(e,`gen_ai.tool.name`)===t);return i&&r.add(i),i},a=[];for(let n of F(e,t,`gen_ai.output.messages`))for(let t of I(n)){let n=B(t);if(n)a.push(n);else if(t.type===`tool_call`&&typeof t.name==`string`){let n=typeof t.id==`string`?t.id:`call-${String(a.length)}`;a.push(...ue(e,t.name,n,z(t),i))}}let o=P(e,t,`theorem.error.public`);t.status.code===`ERROR`&&a.push({type:`error`,errorKind:`internal`,error:o||t.status.message});let s=M(t,`theorem.stop.kind`)??`completed`;return a.push({type:`done`,stop:{kind:s}}),a}function ue(e,t,n,r,i){let a=i(n,t),o={type:`tool`,tool:{name:t,callId:n,arguments:r}};if(!a)return[o];let s=Number(L(a)/1000000n),c=P(e,a,`gen_ai.tool.call.result`);return[o,{type:`tool`,tool:{name:t,callId:n,at:s,...M(a,`theorem.tool.outcome`)===`error`?{phase:`error`,failure:{code:M(a,`theorem.tool.failure.code`)??`failed`,kind:`internal`,message:c}}:{phase:`complete`,output:H(c)}}}]}function H(e){try{return JSON.parse(e)}catch{return e}}var de=e=>e.spans.find(e=>!e.parentSpanId);function fe(e){let t=``,n,r=[];return e.forEach((e,i)=>{let a=de(e);if(!a||V(a)!==`invoke_agent`)return;let o=M(a,`gen_ai.agent.name`)??``;t||=o;let s=oe(e),c=se(e),l=r.at(-1);if(o!==t&&l){l.calls.push(...s),l.results.push(...c);return}n??=Number(L(a)/1000000n);let u=ce(e,a);r.push({...u,calls:s,results:c,blocks:S({text:u.text},le(e,a),{idPrefix:`recorded-${String(i)}`})})}),{agent:t,turns:r,...n===void 0?{}:{recordedAt:n}}}function pe(e){if(e.failed)throw Error(e.result);let t=H(e.result);return A(t)?t:{result:t}}var me=e=>{let t=e%100,n=t>=11&&t<=13?`th`:{1:`st`,2:`nd`,3:`rd`}[e%10]??`th`;return`${String(e)}${n}`};function he(e,t,n){if(!e)return`The profile asked the model a ${me(t+1)} time this turn; the recording answered ${String(t)}.`;if(e.missing)return`The recording does not hold all of this reply.`;let r=new Set((n.wireTools??[]).map(e=>e.name)),i=e.calls.find(e=>!r.has(e));return i&&`The recording calls ${i}, which the profile no longer offers.`}function ge(e,t,n){let r=0,i=new Map,a=new Map,o=t=>{let n=a.get(t);if(!n){n=new Map;for(let r of e.turns[t]?.results??[])n.set(r.name,[...n.get(r.name)??[],r]);a.set(t,n)}return n},s=t=>({async*complete(a){let o=e.turns[r]?.calls.filter(e=>e.agent===t)??[],s=`${String(r)} ${t}`,c=i.get(s)??0;i.set(s,c+1);let l=he(o[c],o.length,a);if(l)throw n({turn:r,call:c+1,reason:l}),new y(`request`,`Replay stopped: ${l}`);yield*o[c]?.events??[]}}),c=e=>()=>{let t=o(r).get(e)?.shift();if(!t)throw Error(`The recording has no further result for ${e}.`);return pe(t)},l=new Set(e.turns.flatMap(e=>e.results.map(e=>e.name)));return{provider:n=>s(n.id===t?e.agent:n.id),toolHandlers:Object.fromEntries([...l].map(e=>[e,c(e)])),startTurn:e=>{r=e}}}function U(e){return e.map(e=>{if(e.type===`agent`)return e;let{name:t,description:n,category:r,access:i,permission:a,loadTier:o,paths:s}=e;return{type:`function`,name:t,description:n,category:r,access:i,permission:a,loadTier:o,paths:s,inputSchema:e.inputSchema,outputSchema:e.outputSchema,...e.labels?{labels:e.labels}:{}}})}function _e(e){return{...e,customTools:U(e.customTools),...e.dependencies?{dependencies:e.dependencies.map(e=>({...e,customTools:U(e.customTools)}))}:{}}}function W(e){return e.turns.flatMap(e=>e.blocks)}function ve(e){let t;try{t=JSON.parse(e)}catch{throw new y(`request`,`This file is not JSON.`)}let n=Array.isArray(t)?t:[t];return n.map((e,t)=>{let r=x.safeParse(e);if(r.success)return r.data;let i=n.length>1?` (record ${String(t+1)})`:``;throw new y(`request`,`This file is not a Theorem trace${i}.`)})}var G=e(n(),1),K=t();function ye(e,t,n){return t?l(e,t,{conversationKey:O(),blocks:n}):s(e,n)}var q=e=>`turn ${String(e+1)}`;function J({iface:e,feed:t,trace:n,card:r,conversation:i}){let a=g(e,t,n);return(0,K.jsxs)(E,{inspector:a,maxWidth:`960px`,requestLabel:`Trace`,children:[r,i]})}function Y({iface:e,blocks:t,banner:n,chat:r}){let i=m();return(0,K.jsxs)(C,{label:`Conversation`,children:[n,(0,K.jsx)(D,{blocks:t,handle:i(`@theorem.agent.handle`,{handle:e.identity.handle}),labels:e.labels,streaming:r?.streaming,delivery:r?.delivery,answering:r?.answering,onToolDecision:r&&((e,t)=>{r.handleToolDecision(e,t)}),onAuthenticated:r&&((e,t)=>{r.handleAuthenticated(e,t)})})]})}function be({onImport:e}){let[t,n]=(0,G.useState)(),[r,i]=(0,G.useState)(!1);return(0,K.jsxs)(a,{gap:2,children:[(0,K.jsx)(ne,{label:`Trace file`,isLabelHidden:!0,mode:`dropzone`,accept:`application/json,.json`,isLoading:r,placeholder:`Drop a trace (.json) or choose a file`,value:null,changeAction:async t=>{let r=Array.isArray(t)?t[0]:t;if(r){i(!0);try{e({name:r.name,records:ve(await r.text())}),n(void 0)}catch(e){n(e instanceof Error?e.message:String(e))}finally{i(!1)}}},onChange:()=>void 0}),t?(0,K.jsx)(_,{status:`error`,title:t}):null]})}var xe=e=>e.recordedAt===void 0?void 0:new Intl.DateTimeFormat(void 0,{dateStyle:`medium`,timeStyle:`short`}).format(e.recordedAt);function Se({shown:e,onShown:t}){return(0,K.jsxs)(r,{label:`Show`,size:`sm`,value:e,onChange:e=>{t(e===`replayed`?`replayed`:`recorded`)},children:[(0,K.jsx)(i,{value:`recorded`,label:`Recorded`}),(0,K.jsx)(i,{value:`replayed`,label:`Replayed`})]})}function X({controls:e}){let{script:t,payload:n}=e,r=t.turns.length,i=[t.agent||`No agent`,`${String(r)} ${r===1?`turn`:`turns`}`,xe(t)];return(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(a,{gap:0,children:[(0,K.jsx)(p,{type:`label`,maxLines:1,children:e.opened.name}),(0,K.jsx)(p,{type:`supporting`,color:`secondary`,maxLines:1,children:i.filter(Boolean).join(` · `)})]}),t.agent&&t.agent!==n.profile.id?(0,K.jsx)(_,{status:`info`,title:`Recorded with ${t.agent}; a replay runs through ${n.profile.id}.`}):null,r===0?(0,K.jsx)(_,{status:`info`,title:`This trace holds no conversation to replay.`}):null,(0,K.jsx)(k,{label:`Live tools`,description:`Run the profile's tools instead of answering them from the recording.`,value:e.liveTools,onChange:e.onLiveTools})]})}var Z=()=>void 0;function Q({onImport:e,controls:t}){let n=t?.onReplay??Z;return(0,K.jsxs)(w,{title:`Trace`,onRun:n,actions:t?.shown?(0,K.jsx)(Se,{shown:t.shown,onShown:t.onShown}):null,children:[(0,K.jsx)(be,{onImport:e}),t?(0,K.jsx)(X,{controls:t}):null,(0,K.jsx)(T,{note:t?`Answers each model call from the recording, so it needs no keys.`:null,isReady:(t?.script.turns.length??0)>0,isRunning:t?.isRunning??!1,runLabel:t?.shown?`Replay again`:`Replay`,runningLabel:`Replaying`,stopLabel:`Stop`,onRun:n,onStop:t?.onStop??Z})]})}function Ce({status:e,turns:t,onContinue:n,onLive:r}){let[i,o]=(0,G.useState)(!1),[s,c]=(0,G.useState)(),l=e=>(0,K.jsx)(f,{label:`Continue live`,variant:`secondary`,size:`sm`,isLoading:i,onClick:async()=>{o(!0),c(void 0);try{await r(e)}catch(e){c(e instanceof Error?e.message:String(e)),o(!1)}}}),u=(()=>{switch(e.kind){case`running`:return(0,K.jsx)(_,{status:`info`,title:`Replaying ${q(e.turn)} of ${String(t)}`});case`waiting`:return(0,K.jsx)(_,{status:`info`,title:`${q(e.turn-1)} waits on you`,description:`Answer it in the conversation, then continue the replay.`,endContent:(0,K.jsx)(f,{label:`Continue replay`,variant:`secondary`,size:`sm`,onClick:()=>{n(e.turn)}})});case`missing`:return(0,K.jsx)(_,{status:`warning`,title:`Replay stopped before ${q(e.turn)}`,description:`It was sent with files, and a trace never holds a file's bytes. Continue live to send it again with yours.`,endContent:l(e.turn)});case`diverged`:{let{turn:t,call:n,reason:r}=e.divergence;return(0,K.jsx)(_,{status:`warning`,title:`Replay stopped at ${q(t)}, model call ${String(n)}`,description:r,endContent:l(t)})}case`failed`:return(0,K.jsx)(_,{status:`error`,title:`Replay stopped at ${q(e.turn)}`,description:e.message,endContent:l(e.turn)});case`done`:return(0,K.jsx)(_,{status:`success`,title:`Replayed ${String(t)} ${t===1?`turn`:`turns`}`,description:`Every model call this profile made was one the recording answered.`})}})();return(0,K.jsxs)(a,{gap:1,children:[u,s?(0,K.jsx)(_,{status:`error`,title:s}):null]})}function $(e){let t=o();for(let n of e)t.push(n);return t}function we({payload:e,iface:t,trace:n,card:r,opened:i,script:a,shown:s,liveTools:l,runtime:u,onLive:d}){let f=(0,G.useRef)(void 0),[p,m]=(0,G.useState)({kind:`running`,turn:0}),[h]=(0,G.useState)(o),g=(0,G.useMemo)(()=>$(i.records),[i.records]),_=(0,G.useMemo)(()=>ge(a,e.profile.id,e=>{f.current??=e}),[a,e.profile.id]),v=(0,G.useMemo)(()=>c(l?e:_e(e),{mode:`byok`,provider:_.provider,...l?{}:{toolHandlers:_.toolHandlers}},{conversationKey:O(),traces:h}),[e,_,l,h]),y=(0,G.useMemo)(()=>l?ee(e):void 0,[l,e]),b=te({transport:v,iface:t,pageTools:y}),{sendText:x,handleStop:S}=b,C=(0,G.useRef)(b.phase);C.current=b.phase;let[w,T]=(0,G.useState)(0);(0,G.useEffect)(()=>{let e=!1,t=async()=>{for(;!e&&C.current===`streaming`;)await new Promise(e=>requestAnimationFrame(e))};return(async()=>{for(let n=w;n<a.turns.length;n+=1){if(await t(),e)return;if(C.current===`gated`)return _.startTurn(n-1),m({kind:`waiting`,turn:n});let{text:r,attachments:i}=a.turns[n];if(i>0)return m({kind:`missing`,turn:n});_.startTurn(n),m({kind:`running`,turn:n});try{let t=await x(r);if(e)return;if(f.current)return m({kind:`diverged`,divergence:f.current});t||--n}catch(e){let t=e instanceof Error?e.message:String(e);return m({kind:`failed`,turn:n,message:t})}}m({kind:`done`})})(),()=>{e=!0,S()}},[w,_,a,x,S]);let E=async t=>{d({...await ye(e,u,a.turns.slice(0,t).flatMap(e=>e.blocks)),text:a.turns[t]?.text??``})},D=s===`replayed`;return(0,K.jsx)(J,{iface:t,feed:D?h:g,trace:n,card:r({isRunning:p.kind===`running`,onStop:()=>{S(),m({kind:`done`})}}),conversation:(0,K.jsx)(Y,{iface:t,blocks:D?[...b.blocks,...b.streamBlocks]:W(a),chat:D?b:void 0,banner:D?(0,K.jsx)(Ce,{status:p,turns:a.turns.length,onContinue:T,onLive:E}):void 0})})}function Te(e){return(0,K.jsx)(u,{children:(0,K.jsx)(h,{labels:v,children:(0,K.jsx)(Ee,{...e})})})}function Ee({payload:e,trace:t,runtime:n,onLive:r}){let i=(0,G.useMemo)(()=>d(e),[e]),[a,o]=(0,G.useState)(),s=(0,G.useMemo)(()=>a&&fe(a.records),[a]),c=(0,G.useMemo)(()=>$(a?.records??[]),[a]),[l,u]=(0,G.useState)(0),[f,p]=(0,G.useState)(`recorded`),[m,h]=(0,G.useState)(!1),g=e=>{o(e),u(0),p(`recorded`)},_=()=>{u(e=>e+1),p(`replayed`)};if(i.type===`live`)return null;if(!a||!s)return(0,K.jsx)(J,{iface:i,feed:c,trace:t,card:(0,K.jsx)(Q,{onImport:g}),conversation:null});let v=({isRunning:t,onStop:n})=>(0,K.jsx)(Q,{onImport:g,controls:{opened:a,script:s,payload:e,shown:l>0?f:null,onShown:p,liveTools:m,onLiveTools:e=>{h(e),l>0&&_()},isRunning:t,onReplay:_,onStop:n}});return l===0?(0,K.jsx)(J,{iface:i,feed:c,trace:t,card:v({isRunning:!1,onStop:()=>void 0}),conversation:(0,K.jsx)(Y,{iface:i,blocks:W(s)})}):(0,K.jsx)(we,{payload:e,iface:i,trace:t,card:v,opened:a,script:s,shown:f,liveTools:m,runtime:n,onLive:r},l)}export{Te as TraceReplay};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ur as e}from"./tool-schema-DUAd6AXZ.js";var t=e.filter(e=>e!==`builtin`),n=`Tool type must be ${t.join(`, `).replace(/, ([^,]+)$/,`, or $1`)}.`;export{n,t};
|