@theoremjs/studio 0.3.4-next.484.g20d8b9d → 0.3.4-next.522.g9e684cd
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 +3 -3
- package/compile.d.ts +1 -1
- package/compile.js +44 -2
- package/draft.d.ts +55 -2
- package/draft.js +14 -0
- package/example.js +5 -2
- package/map-line.d.ts +12 -0
- package/map-line.js +98 -0
- package/map.d.ts +1 -1
- package/map.js +0 -1
- package/mod.d.ts +1 -1
- package/mod.js +1 -1
- package/package.json +4 -4
- package/page/assets/{Banner-G4u0gVOw.js → Banner-UZW6WFTG.js} +2 -2
- package/page/assets/{ConsoleFrame-BZqxUndX.js → ConsoleFrame-C6ZxuLse.js} +3 -3
- package/page/assets/{ContextMenu-DEnGmVYR.js → ContextMenu-ClIUDzvK.js} +2 -2
- package/page/assets/{ToolResultCharts-BWBYDar4.js → ToolResultCharts-COgqvWEu.js} +1 -1
- package/page/assets/{TraceInspector-B0cUdNg5.js → TraceInspector-D2unePaa.js} +1 -1
- package/page/assets/{TraceOverview-Bjqg7laD.js → TraceOverview-CCA1iUNg.js} +2 -2
- package/page/assets/{_virtual_studio-type-sources-DBS0HldZ.js → _virtual_studio-type-sources-DfyVGpe8.js} +93 -61
- package/page/assets/browser-engine-CRGnAh9x.js +11 -0
- package/page/assets/browser-transport-CgmN-3Ia.js +47 -0
- package/page/assets/{compile-egress-BSxOdX4K.js → compile-egress-BRGW9qfO.js} +2 -2
- package/page/assets/{crypto-iT_LZ8Et.js → crypto-BoqeX_71.js} +1 -1
- package/page/assets/{egress-automata-B5ZGE1mT.js → egress-automata-SiHQTP1i.js} +1 -1
- package/page/assets/{encode-files-8AFMw7Er.js → encode-files-DFrbgXms.js} +1 -1
- package/page/assets/{export-agent-Cxamh6fg.js → export-agent-U8qRBuhg.js} +3 -3
- package/page/assets/{guardrail-tester-Lubrp5dY.js → guardrail-tester-DASanQyo.js} +2 -2
- package/page/assets/host-patterns-cSf1U25G.js +1 -0
- package/page/assets/index-C9rhrCGT.css +1 -0
- package/page/assets/index-CGN6iWF2.js +101 -0
- package/page/assets/{labels-provider-BSiD6Lrb.js → labels-provider-Gus3heEH.js} +1 -1
- package/page/assets/{live-ingress-lDUGPwth.js → live-ingress-qi-y5uvH.js} +1 -1
- package/page/assets/{live-messages-BwMauTVi.js → live-messages-cl-CI8gZ.js} +1 -1
- package/page/assets/reader-IkImpzZF.js +7 -0
- package/page/assets/shaped-data-CITXsEfw.js +21 -0
- package/page/assets/{stub-_DAX3TnJ.js → stub-Ccyi1ZiM.js} +2 -2
- package/page/assets/studio-code-pane-AoMu0cGy.js +8 -0
- package/page/assets/{studio-console-C-rWlbSY.js → studio-console-JNYkyQ0E.js} +1 -1
- package/page/assets/{studio-decision-CCpYdeOV.js → studio-decision-BRJuvgS3.js} +1 -1
- package/page/assets/{studio-embedding-BM1yTK8B.js → studio-embedding-D-r2kuz3.js} +1 -1
- package/page/assets/studio-host-console-HoLSpRVk.js +2 -0
- package/page/assets/{studio-labels-CBBymwHa.js → studio-labels-CBcjlfH4.js} +1 -1
- package/page/assets/studio-live-DtywUIK2.js +5 -0
- package/page/assets/studio-map-BIJ-S7br.js +1 -0
- package/page/assets/studio-trace-replay-BuOKQwlj.js +2 -0
- package/page/assets/{studio-type-checker-B4qvn-WC.js → studio-type-checker-C8qG2W9D.js} +1 -1
- package/page/assets/tool-schema-DDkOMTMz.js +17 -0
- package/page/assets/{trace-record-D4xAUHLZ.js → trace-record-Dqvj9bhx.js} +1 -1
- package/page/assets/tree-jmLWUWxQ.js +3 -0
- package/page/assets/{turn-client-D_bUUpER.js → turn-client-DSatougR.js} +2 -2
- package/page/assets/types-4jMDDudJ.js +1 -0
- package/page/assets/{use-one-call-DWpPEFdQ.js → use-one-call-BcTU9gJ9.js} +1 -1
- package/page/assets/workspace-B2bnm5qv.js +1 -0
- package/page/index.html +19 -19
- package/read-source.js +10 -1
- package/registrations.d.ts +6 -0
- package/run-payload.d.ts +1 -1
- package/runtime.d.ts +1 -1
- package/runtime.js +1 -1
- package/server/draft-decide.d.ts +1 -4
- package/server/draft-decide.js +1 -1
- package/server/draft-replies.js +2 -2
- package/source.js +1 -1
- package/tools.js +3 -0
- package/types.d.ts +6 -0
- package/ui/brand-icons.d.ts +2 -2
- package/ui/brand-icons.js +6 -4
- package/ui/lib/tree-map-layout.d.ts +120 -18
- package/ui/lib/tree-map-layout.js +1292 -190
- package/ui/map-token.css +25 -0
- package/ui/node-icon.js +1 -4
- package/ui/profile-editor.js +22 -6
- package/ui/read-map.css +1 -24
- package/ui/read-map.js +52 -4
- package/ui/studio-map.js +1 -3
- package/ui/tree-map.css +9 -0
- package/ui/tree-map.d.ts +27 -6
- package/ui/tree-map.js +215 -75
- package/page/assets/browser-engine-CaPsakbj.js +0 -11
- package/page/assets/browser-transport-BEha0XY8.js +0 -47
- package/page/assets/host-patterns-C9RMP16Q.js +0 -1
- package/page/assets/index-C3n9ogf7.js +0 -101
- package/page/assets/index-Cbs7B46A.css +0 -1
- package/page/assets/reader-oVJF5Iqk.js +0 -7
- package/page/assets/shaped-data-Bc6u4pow.js +0 -16
- package/page/assets/studio-code-pane-BqHsqd7P.js +0 -8
- package/page/assets/studio-host-console-D8_OCbZG.js +0 -2
- package/page/assets/studio-live-CgYci_ts.js +0 -5
- package/page/assets/studio-map-QDBMJ6x3.js +0 -1
- package/page/assets/studio-trace-replay-BIRuiVjZ.js +0 -2
- package/page/assets/tool-schema-CvHbJyis.js +0 -18
- package/page/assets/tree-DtF83caH.js +0 -3
- package/page/assets/types-Bc3MMW0P.js +0 -1
- package/page/assets/workspace-ILHOuESH.js +0 -1
package/ui/map-token.css
CHANGED
|
@@ -9,3 +9,28 @@
|
|
|
9
9
|
stroke: var(--color-border-emphasized);
|
|
10
10
|
stroke-width: 1.5;
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
/* A line drawing in runs out from the node it leaves, as the loader's map draws: its own pace, not
|
|
14
|
+
the scroll's. */
|
|
15
|
+
.map-line-drawing {
|
|
16
|
+
stroke-dasharray: 1;
|
|
17
|
+
stroke-dashoffset: 1;
|
|
18
|
+
animation: map-line-draw var(--duration-medium, 240ms) var(--ease-standard, ease-out) forwards;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* A token drawing in shows over the same span. */
|
|
22
|
+
.map-token-drawing {
|
|
23
|
+
animation: map-draw-in var(--duration-medium, 240ms) var(--ease-standard, ease-out) both;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@keyframes map-line-draw {
|
|
27
|
+
to {
|
|
28
|
+
stroke-dashoffset: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@keyframes map-draw-in {
|
|
33
|
+
from {
|
|
34
|
+
opacity: 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/ui/node-icon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IconTool } from '@tabler/icons-react';
|
|
2
|
-
import {
|
|
2
|
+
import { modelFamilyMark } from "./brand-icons.js";
|
|
3
3
|
import { FACET_ICON } from "./lib/facet-icons.js";
|
|
4
4
|
import { PROFILE_TYPE_ICON, toolTypeIcon } from "./lib/type-icons.js";
|
|
5
5
|
/** A node's icon; Identity shows the profile type's once one is picked. */
|
|
@@ -11,9 +11,6 @@ export function nodeIcon(draft, ref) {
|
|
|
11
11
|
const binding = draft.modelBindings.find((each) => each.key === ref.key);
|
|
12
12
|
if (!binding)
|
|
13
13
|
return FACET_ICON.modelBinding;
|
|
14
|
-
const definition = draft.providers.find((each) => each.id === binding.provider)?.definition;
|
|
15
|
-
if (definition === 'typesafe')
|
|
16
|
-
return IconTypeSafe;
|
|
17
14
|
return modelFamilyMark(binding.apiId) ?? FACET_ICON.modelBinding;
|
|
18
15
|
}
|
|
19
16
|
if (ref.facet !== 'toolSpec')
|
package/ui/profile-editor.js
CHANGED
|
@@ -27,7 +27,7 @@ import { IconAbc, IconAdjustmentsHorizontal, IconAlertTriangle, IconAlignLeft, I
|
|
|
27
27
|
import { ATTACHMENT_ACCEPT_MIMES, CONTINUE_STOP_KINDS, fieldMeta, GOOGLE_BUILTIN_TOOLS, GOOGLE_IMAGE_ASPECT_RATIOS, GOOGLE_IMAGE_OUTPUT_MIMES, GOOGLE_IMAGE_RESOLUTIONS, GOOGLE_SPEECH_VOICES, HTTP_METHODS, IMAGE_ATTACHMENT_ACCEPT_MIMES, LABEL_KEYS, labelDefault, PROFILE_HANDLE_MAX_CHARS, PROFILE_ID_MAX_CHARS, profileGraphFacet, THINKING_LEVELS, VOICE_ACCEPT_MIMES, } from '@theoremjs/agents';
|
|
28
28
|
import { BOUNDARIES, BOUNDARY_META, DETECT_ACTION_META, DETECT_ACTIONS, DETECTOR_BOUNDARIES, DETECTOR_GROUP_META, DETECTOR_GROUPS, DETECTOR_META, DETECTORS, TOOL_BOUNDARIES, TOOL_KINDS, } from '@theoremjs/agents/guardrails';
|
|
29
29
|
import { createContext, lazy, Suspense, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore, } from 'react';
|
|
30
|
-
import { acceptSections, agentToolTarget, bindingSlots, COMPACTION_DRAFT_DEFAULTS, defaultEffortRequired, defaultModelRequired, definitionOf, draftAllows, draftKey, expandAccept, INLINE_LABELS, includableFacets, includeFacet, inputLimitsRequired, isGoogleRoute, isOpenRouterRoute, kernelDefinitions, LOCAL_PROVIDER_ID, lentCompression, modelBindingNodeId, modelRoute, modelSlots, newCriteria, newDecisionImage, newDecisionQuestion, newModelBinding, newOwnDetector, newPattern, newToolSpec, nextAccept, onStudioLocal, optionAt, plantsCanary, protocolOptionFields, removeModelBinding, STUDIO_TRACE_DESTINATION, sampleToolInput, sectionNote, servedProtocols, servesProfileType, setProfileType, studioNetworkNote, studioNodeRef, studioRunsProvider, studioTaintNote, takesContinueInstruction, toolSpecNodeId, updateModelBinding, withOption, writeAsk, } from "../mod.js";
|
|
30
|
+
import { acceptSections, agentToolTarget, bindingSlots, COMPACTION_DRAFT_DEFAULTS, defaultEffortRequired, defaultModelRequired, definitionOf, draftAllows, draftKey, expandAccept, INLINE_LABELS, includableFacets, includeFacet, inputLimitsRequired, isGoogleRoute, isOpenRouterRoute, kernelDefinitions, LOCAL_PROVIDER_ID, lentCompression, MODEL_LIMITS, modelBindingNodeId, modelRoute, modelSlots, newCriteria, newDecisionImage, newDecisionQuestion, newModelBinding, newOwnDetector, newPattern, newToolSpec, nextAccept, onStudioLocal, optionAt, plantsCanary, protocolOptionFields, removeModelBinding, STUDIO_TRACE_DESTINATION, sampleToolInput, sectionNote, servedProtocols, servesProfileType, setProfileType, studioNetworkNote, studioNodeRef, studioRunsProvider, studioTaintNote, TIMER_MAX_MS, takesContinueInstruction, toolSpecNodeId, updateModelBinding, withOption, writeAsk, } from "../mod.js";
|
|
31
31
|
import { AddProviderButton } from "./add-provider.js";
|
|
32
32
|
import { IconGoogle, IconOpenAi, IconOpenRouter, IconTypeSafe } from "./brand-icons.js";
|
|
33
33
|
import { ChoiceRow, InspectorGroupTitle, InspectorRow, InspectorSection, ListRow, NamesRow, NumberRow, OriginLine, SegmentedRow, SetInCode, SliderRow, SwitchRow, TextAreaRow, TextRow, } from "./inspector.js";
|
|
@@ -245,6 +245,11 @@ function DecisionModelEditor({ draft, setDraft, bindingKey, }) {
|
|
|
245
245
|
set({ timeoutMs });
|
|
246
246
|
} })] }));
|
|
247
247
|
}
|
|
248
|
+
function LimitsSection({ binding, set }) {
|
|
249
|
+
return (_jsx(InspectorSection, { title: "Limits", path: "models.*.limits", children: MODEL_LIMITS.map(({ name, label, units, isTimer }) => (_jsx(NumberRow, { label: label, path: `models.*.limits.${name}`, units: units, field: `limits.${name}`, value: binding.limits?.[name] ?? null, min: 1, max: isTimer ? TIMER_MAX_MS : undefined, isIntegerOnly: true, onChange: (value) => {
|
|
250
|
+
set({ limits: { ...binding.limits, [name]: value } });
|
|
251
|
+
} }, name))) }));
|
|
252
|
+
}
|
|
248
253
|
/** A key slot, chosen from the slots the keys panel holds; each says which service its key is for. */
|
|
249
254
|
export function SlotRow({ label, path, field, value, isRequired, given, onChange, }) {
|
|
250
255
|
const connection = useContext(LocalConnection);
|
|
@@ -550,7 +555,7 @@ function ModelBindingEditor({ draft, setDraft, bindingKey, onSelect, }) {
|
|
|
550
555
|
const set = (change) => {
|
|
551
556
|
setDraft((current) => updateModelBinding(current, bindingKey, change));
|
|
552
557
|
};
|
|
553
|
-
return (_jsxs(_Fragment, { children: [_jsx(ModelSection, { draft: draft, binding: binding, type: type, set: set }), type !== 'embedding' && _jsx(GenerationSection, { binding: binding, set: set }), _jsx(ProtocolOptionsSection, { providers: draft.providers, binding: binding, type: type, set: set }), type === 'text' && _jsx(CompactionSection, { binding: binding, set: set }), type !== 'embedding' && _jsx(EffortsSection, { binding: binding, set: set }), draft.modelBindings.length > 1 && (_jsx(Section, { variant: "transparent", padding: 3, children: _jsx(Button, { label: "Remove model", variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconTrash, size: "sm" }), onClick: () => {
|
|
558
|
+
return (_jsxs(_Fragment, { children: [_jsx(ModelSection, { draft: draft, binding: binding, type: type, set: set }), type !== 'embedding' && _jsx(GenerationSection, { binding: binding, set: set }), _jsx(ProtocolOptionsSection, { providers: draft.providers, binding: binding, type: type, set: set }), _jsx(LimitsSection, { binding: binding, set: set }), type === 'text' && _jsx(CompactionSection, { binding: binding, set: set }), type !== 'embedding' && _jsx(EffortsSection, { binding: binding, set: set }), draft.modelBindings.length > 1 && (_jsx(Section, { variant: "transparent", padding: 3, children: _jsx(Button, { label: "Remove model", variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconTrash, size: "sm" }), onClick: () => {
|
|
554
559
|
setDraft((current) => removeModelBinding(current, bindingKey));
|
|
555
560
|
onSelect('models');
|
|
556
561
|
} }) }))] }));
|
|
@@ -1966,7 +1971,9 @@ function HttpRequestSection({ tool, set }) {
|
|
|
1966
1971
|
set({ endpoint });
|
|
1967
1972
|
} }), _jsx(SegmentedRow, { label: "Method", path: "registerTool.method", field: "method", value: tool.method ?? HTTP_METHODS[0], segments: METHOD_SEGMENTS, onChange: (method) => {
|
|
1968
1973
|
set({ method });
|
|
1969
|
-
} }), _jsx(HeadersRow, { tool: tool, set: set })
|
|
1974
|
+
} }), _jsx(HeadersRow, { tool: tool, set: set }), _jsx(NumberRow, { label: "Max response", path: "registerTool.maxResponseBytes", units: "bytes", field: "maxResponseBytes", value: tool.maxResponseBytes ?? null, min: 1, isIntegerOnly: true, onChange: (maxResponseBytes) => {
|
|
1975
|
+
set({ maxResponseBytes });
|
|
1976
|
+
} })] }));
|
|
1970
1977
|
}
|
|
1971
1978
|
function HttpMappingSection({ tool, set }) {
|
|
1972
1979
|
return (_jsxs(InspectorSection, { title: "Mapping", path: "registerTool.mapping", children: [_jsx(NamesRow, { label: "Path", path: "registerTool.mapping.pathParams", field: "pathParams", value: tool.pathParams ?? [], placeholder: "Names in {braces}", onChange: (pathParams) => {
|
|
@@ -1992,7 +1999,16 @@ function McpServerSection({ tool, set }) {
|
|
|
1992
1999
|
set({ serverUrl });
|
|
1993
2000
|
} }), _jsx(TextRow, { label: "Remote tool", path: "registerTool.mcpToolName", field: "mcpToolName", isRequired: true, value: tool.mcpToolName ?? '', placeholder: "search_flights", onChange: (mcpToolName) => {
|
|
1994
2001
|
set({ mcpToolName });
|
|
1995
|
-
} }), _jsx(HeadersRow, { tool: tool, set: set })
|
|
2002
|
+
} }), _jsx(HeadersRow, { tool: tool, set: set }), _jsx(NumberRow, { label: "Max response", path: "registerTool.maxResponseBytes", units: "bytes", field: "maxResponseBytes", value: tool.maxResponseBytes ?? null, min: 1, isIntegerOnly: true, onChange: (maxResponseBytes) => {
|
|
2003
|
+
set({ maxResponseBytes });
|
|
2004
|
+
} })] }));
|
|
2005
|
+
}
|
|
2006
|
+
function McpSessionSection({ tool, set }) {
|
|
2007
|
+
return (_jsxs(InspectorSection, { title: "Session", path: "registerTool.session", children: [_jsx(NumberRow, { label: "Idle", path: "registerTool.session.idleMs", units: "ms", field: "sessionIdleMs", value: tool.sessionIdleMs ?? null, min: 1, isIntegerOnly: true, onChange: (sessionIdleMs) => {
|
|
2008
|
+
set({ sessionIdleMs });
|
|
2009
|
+
} }), _jsx(NumberRow, { label: "Max", path: "registerTool.session.max", units: "sessions", field: "sessionMax", value: tool.sessionMax ?? null, min: 1, isIntegerOnly: true, onChange: (sessionMax) => {
|
|
2010
|
+
set({ sessionMax });
|
|
2011
|
+
} })] }));
|
|
1996
2012
|
}
|
|
1997
2013
|
/** Where an authenticated tool's credential comes from, how it's sent, and what signed out does. */
|
|
1998
2014
|
function AuthCredentialRows({ tool, authType, set, }) {
|
|
@@ -2067,7 +2083,7 @@ function ToolSpecEditor({ draft, setDraft, toolKey, onSelect, }) {
|
|
|
2067
2083
|
}));
|
|
2068
2084
|
};
|
|
2069
2085
|
const remote = tool.toolType === 'http' || tool.toolType === 'mcp';
|
|
2070
|
-
return (_jsxs(_Fragment, { children: [_jsx(ToolSection, { draft: draft, setDraft: setDraft, tool: tool, set: set }), _jsx(ContractSection, { tool: tool, set: set }), _jsx(ActivitySection, { tool: tool, set: set }), tool.toolType === 'function' && _jsx(StubSection, { tool: tool, set: set }), tool.toolType === 'http' && _jsx(HttpSections, { tool: tool, set: set }), tool.toolType === 'agent' && workspace && (_jsx(AgentSection, { tool: tool, set: set, workspace: workspace })), tool.toolType === 'mcp' && _jsx(McpServerSection, { tool: tool, set: set }), remote && _jsx(AuthSection, { tool: tool, set: set }), remote && _jsx(ToolTest, { tool: tool, guardrails: draft.guardrails }, tool.key), _jsx(PolicySection, { draft: draft, tool: tool, set: set }), _jsx(Section, { variant: "transparent", padding: 3, children: _jsx(Button, { label: "Remove tool", variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconTrash, size: "sm" }), onClick: () => {
|
|
2086
|
+
return (_jsxs(_Fragment, { children: [_jsx(ToolSection, { draft: draft, setDraft: setDraft, tool: tool, set: set }), _jsx(ContractSection, { tool: tool, set: set }), _jsx(ActivitySection, { tool: tool, set: set }), tool.toolType === 'function' && _jsx(StubSection, { tool: tool, set: set }), tool.toolType === 'http' && _jsx(HttpSections, { tool: tool, set: set }), tool.toolType === 'agent' && workspace && (_jsx(AgentSection, { tool: tool, set: set, workspace: workspace })), tool.toolType === 'mcp' && _jsx(McpServerSection, { tool: tool, set: set }), tool.toolType === 'mcp' && _jsx(McpSessionSection, { tool: tool, set: set }), remote && _jsx(AuthSection, { tool: tool, set: set }), remote && _jsx(ToolTest, { tool: tool, guardrails: draft.guardrails }, tool.key), _jsx(PolicySection, { draft: draft, tool: tool, set: set }), _jsx(Section, { variant: "transparent", padding: 3, children: _jsx(Button, { label: "Remove tool", variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconTrash, size: "sm" }), onClick: () => {
|
|
2071
2087
|
setDraft((current) => removeToolSpec(current, toolKey, tool.toolName));
|
|
2072
2088
|
onSelect('tools');
|
|
2073
2089
|
} }) })] }));
|
|
@@ -2531,7 +2547,7 @@ function DecisionImageRow({ image, index, onRename, onRemove, }) {
|
|
|
2531
2547
|
const reference = `<${image.name}>`;
|
|
2532
2548
|
return (_jsxs(InspectorRow, { label: label, path: "decision.images.name", hasIssue: status !== undefined, children: [_jsx(Thumbnail, { src: `data:${image.mimeType};base64,${image.data}`, label: `Questions write it as ${reference}` }), _jsx(StackItem, { size: "fill", children: _jsx(TextInput, { label: `${label} name`, isLabelHidden: true, size: "sm", status: status, value: image.name, onChange: onRename }) }), _jsx(Tooltip, { content: `Remove ${reference}. A question that names it then has no image to read.`, children: _jsx(IconButton, { label: `Remove ${reference}`, variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconX, size: "sm" }), onClick: onRemove }) })] }));
|
|
2533
2549
|
}
|
|
2534
|
-
/** The pictures
|
|
2550
|
+
/** The pictures a decision can send, each under the name its questions write, and a drop to add more. */
|
|
2535
2551
|
function DecisionImagesSection({ draft, setDraft }) {
|
|
2536
2552
|
const keys = useLentKeys();
|
|
2537
2553
|
const { reading, changeAction } = useFilesRead(async (picked) => {
|
package/ui/read-map.css
CHANGED
|
@@ -11,20 +11,9 @@
|
|
|
11
11
|
pointer-events: none;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/* The line draws in from the node it leaves. */
|
|
15
|
-
.read-map-line {
|
|
16
|
-
stroke-dasharray: 1;
|
|
17
|
-
stroke-dashoffset: 1;
|
|
18
|
-
animation: read-map-line-in var(--duration-medium, 240ms) var(--ease-standard, ease-out) forwards;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
14
|
.read-map-dot {
|
|
22
15
|
fill: var(--color-text-secondary);
|
|
23
|
-
animation:
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.read-map-node {
|
|
27
|
-
animation: read-map-in var(--duration-medium, 240ms) var(--ease-standard, ease-out) both;
|
|
16
|
+
animation: map-draw-in var(--duration-fast, 120ms) var(--ease-standard, ease-out) both;
|
|
28
17
|
}
|
|
29
18
|
|
|
30
19
|
.read-map-foot {
|
|
@@ -34,15 +23,3 @@
|
|
|
34
23
|
gap: 16px;
|
|
35
24
|
justify-content: space-between;
|
|
36
25
|
}
|
|
37
|
-
|
|
38
|
-
@keyframes read-map-line-in {
|
|
39
|
-
to {
|
|
40
|
-
stroke-dashoffset: 0;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@keyframes read-map-in {
|
|
45
|
-
from {
|
|
46
|
-
opacity: 0;
|
|
47
|
-
}
|
|
48
|
-
}
|
package/ui/read-map.js
CHANGED
|
@@ -4,6 +4,7 @@ import { IconFileCode, IconFolder } from '@tabler/icons-react';
|
|
|
4
4
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
5
5
|
import { mapCurve } from "../map-line.js";
|
|
6
6
|
import { readMap } from "./lib/read-map.js";
|
|
7
|
+
import { ease } from "./lib/tree-map-layout.js";
|
|
7
8
|
import { AGENT_ICON, profileTypeIcon, toolTypeIcon } from "./lib/type-icons.js";
|
|
8
9
|
import { MapToken, useTokenWidths } from "./map-token.js";
|
|
9
10
|
import './read-map.css';
|
|
@@ -15,6 +16,8 @@ const LAG_MS = 500;
|
|
|
15
16
|
const CATCH_UP_MS = 900;
|
|
16
17
|
/** The map shows for at least this long, so a quick read can still be seen. */
|
|
17
18
|
const SHOWN_MS = 2000;
|
|
19
|
+
/** How long a node already drawn takes to glide to where a new folder moves it. */
|
|
20
|
+
const GLIDE_MS = 240;
|
|
18
21
|
/** The panel's own padding, step 4. */
|
|
19
22
|
const PAD = 16;
|
|
20
23
|
const ROW = 30;
|
|
@@ -127,6 +130,50 @@ function lineTo(from, fromWidth, to, dots) {
|
|
|
127
130
|
dots: Array.from({ length: dots }, (_, index) => curve.at((index + 1) / (dots + 1))),
|
|
128
131
|
};
|
|
129
132
|
}
|
|
133
|
+
/** Where a glide stands at a time: eased from where it was to where it goes. */
|
|
134
|
+
function glideAt({ from, to, at }, now) {
|
|
135
|
+
const part = ease(Math.min(1, (now - at) / GLIDE_MS));
|
|
136
|
+
return { x: from.x + (to.x - from.x) * part, y: from.y + (to.y - from.y) * part };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The nodes where they stand now: a node drawn shows where it is laid out, and one a later folder
|
|
140
|
+
* moves glides there from where it stood, its lines with it, rather than jumping.
|
|
141
|
+
*/
|
|
142
|
+
function useGlided(placed) {
|
|
143
|
+
const glides = useRef(new Map());
|
|
144
|
+
const [now, setNow] = useState(() => performance.now());
|
|
145
|
+
useLayoutEffect(() => {
|
|
146
|
+
const at = performance.now();
|
|
147
|
+
let moving = false;
|
|
148
|
+
for (const { node, x, y } of placed) {
|
|
149
|
+
const last = glides.current.get(node.id);
|
|
150
|
+
if (last && last.to.x === x && last.to.y === y) {
|
|
151
|
+
moving ||= at - last.at < GLIDE_MS;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
glides.current.set(node.id, {
|
|
155
|
+
from: last ? glideAt(last, at) : { x, y },
|
|
156
|
+
to: { x, y },
|
|
157
|
+
at: last ? at : 0,
|
|
158
|
+
});
|
|
159
|
+
moving ||= last !== undefined;
|
|
160
|
+
}
|
|
161
|
+
if (!moving)
|
|
162
|
+
return;
|
|
163
|
+
let frame = 0;
|
|
164
|
+
const tick = (time) => {
|
|
165
|
+
setNow(time);
|
|
166
|
+
if (time - at < GLIDE_MS)
|
|
167
|
+
frame = requestAnimationFrame(tick);
|
|
168
|
+
};
|
|
169
|
+
frame = requestAnimationFrame(tick);
|
|
170
|
+
return () => cancelAnimationFrame(frame);
|
|
171
|
+
}, [placed]);
|
|
172
|
+
return placed.map((each) => {
|
|
173
|
+
const glide = glides.current.get(each.node.id);
|
|
174
|
+
return glide ? { ...each, ...glideAt(glide, now) } : each;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
130
177
|
export function ReadMap({ reading, onDrawn }) {
|
|
131
178
|
const drawn = useDrawn(reading, onDrawn);
|
|
132
179
|
const { ref, size } = useSize();
|
|
@@ -149,8 +196,9 @@ export function ReadMap({ reading, onDrawn }) {
|
|
|
149
196
|
}));
|
|
150
197
|
}, [map, size, drawn.steps]);
|
|
151
198
|
const widths = useTokenWidths(ref, placed);
|
|
152
|
-
const
|
|
153
|
-
|
|
199
|
+
const shown = useGlided(placed);
|
|
200
|
+
const byId = new Map(shown.map((each) => [each.node.id, each]));
|
|
201
|
+
return (_jsxs("div", { ref: ref, className: "read-map", "aria-hidden": "true", children: [_jsx("svg", { className: "read-map-lines", "aria-hidden": "true", width: size?.width ?? 0, height: size?.height ?? 0, children: shown.map((to) => {
|
|
154
202
|
const from = to.node.parent === undefined ? undefined : byId.get(to.node.parent);
|
|
155
203
|
const width = from && widths[from.node.id];
|
|
156
204
|
if (!from || width === undefined)
|
|
@@ -158,6 +206,6 @@ export function ReadMap({ reading, onDrawn }) {
|
|
|
158
206
|
const read = to.node.own.filter((step) => step < drawn.steps).length;
|
|
159
207
|
const dots = Math.ceil((Math.min(DOTS, to.node.own.length) * read) / Math.max(1, to.node.own.length));
|
|
160
208
|
const line = lineTo(from, width, to, Math.min(DOTS, to.node.own.length));
|
|
161
|
-
return (_jsxs("g", { children: [_jsx("path", { className: "map-line
|
|
162
|
-
}) }),
|
|
209
|
+
return (_jsxs("g", { children: [_jsx("path", { className: "map-line map-line-drawing", d: line.d, pathLength: 1 }), line.dots.slice(0, dots).map(({ x, y }, index) => (_jsx("circle", { className: "read-map-dot", cx: x, cy: y, r: 2.5 }, index)))] }, to.node.id));
|
|
210
|
+
}) }), shown.map(({ node, x, y }) => (_jsx(MapToken, { className: "map-token-drawing", id: node.id, label: short(node.label), icon: nodeIcon(node), x: x, y: y }, node.id))), _jsxs("div", { className: "read-map-foot", children: [_jsx(Text, { type: "supporting", color: "secondary", maxLines: 1, children: saying(steps, drawn.steps) }), _jsx(Text, { type: "supporting", color: "secondary", maxLines: 1, children: tally(steps, drawn.steps) })] })] }));
|
|
163
211
|
}
|
package/ui/studio-map.js
CHANGED
|
@@ -19,7 +19,7 @@ import { TextInput } from '@astryxdesign/core/TextInput';
|
|
|
19
19
|
import { IconArrowsMaximize, IconArrowsMinimize, IconCloud, IconCode, IconExternalLink, IconEye, IconFocus2, IconLayoutGrid, IconSearch, IconX, } from '@tabler/icons-react';
|
|
20
20
|
import { useEffect, useMemo, useRef, useState, } from 'react';
|
|
21
21
|
import { mapFamily, mapFound, mapLayout, mapLinkWords, mapNoteLines, workspaceMap, } from "../mod.js";
|
|
22
|
-
import {
|
|
22
|
+
import { modelFamilyMark } from "./brand-icons.js";
|
|
23
23
|
import { FACET_ICON } from "./lib/facet-icons.js";
|
|
24
24
|
import { readKeptMap, writeKeptMap } from "./lib/studio-map-kept.js";
|
|
25
25
|
import { useProject } from "./lib/studio-project.js";
|
|
@@ -53,8 +53,6 @@ function nodeIcon({ kind, type, note }) {
|
|
|
53
53
|
if (kind === 'tool')
|
|
54
54
|
return toolTypeIcon(type ?? '');
|
|
55
55
|
// A model's note is its API model id, which names the family.
|
|
56
|
-
if (kind === 'model' && type === 'typesafe')
|
|
57
|
-
return IconTypeSafe;
|
|
58
56
|
if (kind === 'model')
|
|
59
57
|
return modelFamilyMark(note) ?? FACET_ICON.modelBinding;
|
|
60
58
|
if (kind === 'provider')
|
package/ui/tree-map.css
CHANGED
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
stroke: color-mix(in srgb, var(--color-border-emphasized) 60%, var(--color-background-surface));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/* Grown, a title over each column, and what the column is under it. */
|
|
20
|
+
.studio-tree-map-heading {
|
|
21
|
+
position: absolute;
|
|
22
|
+
display: flex;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
white-space: nowrap;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
.studio-tree-map[data-draggable] {
|
|
20
29
|
cursor: grab;
|
|
21
30
|
touch-action: none;
|
package/ui/tree-map.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type MapPlace } from '../map-line.ts';
|
|
1
2
|
import { type StudioWorkspace } from '../mod.ts';
|
|
2
3
|
import { type Box } from './lib/tree-map-layout.ts';
|
|
3
4
|
export interface StudioTreeMapProps {
|
|
@@ -5,18 +6,38 @@ export interface StudioTreeMapProps {
|
|
|
5
6
|
/** The keys of the agents to draw, in the workspace's order; every agent when unset. */
|
|
6
7
|
agents?: readonly string[] | undefined;
|
|
7
8
|
/**
|
|
8
|
-
* How far the tree has grown, from 0 to 1. As it grows
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* How far the tree has grown, from 0 to 1. As it grows the map grows to its size, then draws out
|
|
10
|
+
* from the tree's agents as one pen would, at an even pace: each line runs out from the node it
|
|
11
|
+
* leaves, and the node at its end shows as the line reaches it, drifting the last of the way along
|
|
12
|
+
* it. Nothing moves before the drawing comes to it: what the map shows closed glides into place
|
|
13
|
+
* once its line reaches it, its line with it, or, where something would show where it stands, sets
|
|
14
|
+
* off just before that shows and goes slower, so its line catches it as it lands.
|
|
15
|
+
* Shrinking takes it all back the same way.
|
|
12
16
|
*/
|
|
13
17
|
grow?: number | undefined;
|
|
14
18
|
/**
|
|
15
19
|
* The box the map fills grown: its rows and gaps stretch to fill it, and it stands in the middle
|
|
16
|
-
* of it.
|
|
20
|
+
* of it.
|
|
17
21
|
*/
|
|
18
22
|
fit?: Box | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The box the map stands in now, when it changes as the map grows: closed and grown, the map
|
|
25
|
+
* stands in the middle of it, eased smaller where it would not fit. `fit` by default.
|
|
26
|
+
*/
|
|
27
|
+
room?: Box | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* The keys of the agents the map shows closed, when not `agents`. Growing takes away what the
|
|
30
|
+
* tree does not draw, and an agent the tree draws as an agent tool's agent glides into it.
|
|
31
|
+
*/
|
|
32
|
+
still?: readonly string[] | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Where the tokens the map shows closed stand, by id, in the map's own pixels, for a map that
|
|
35
|
+
* grows out of something else: closed, the map stands at its own size from the top left of what
|
|
36
|
+
* holds it, these tokens where they are given and nothing else; growing, the tree draws out round
|
|
37
|
+
* them, and each glides to where it stands grown as the drawing comes to it. In place of `still`.
|
|
38
|
+
*/
|
|
39
|
+
closed?: ReadonlyMap<string, MapPlace> | undefined;
|
|
19
40
|
/** A token dragged moves to where it is dropped, its lines with it; the field dragged moves the whole map. */
|
|
20
41
|
draggable?: boolean | undefined;
|
|
21
42
|
}
|
|
22
|
-
export declare function StudioTreeMap({ workspace, agents, grow, fit, draggable, }: StudioTreeMapProps): import("react").JSX.Element;
|
|
43
|
+
export declare function StudioTreeMap({ workspace, agents, grow, fit, room, still, closed: given, draggable, }: StudioTreeMapProps): import("react").JSX.Element;
|