@fallen-8/studio 0.0.38 → 0.0.40

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 (35) hide show
  1. package/dist-lib/{Canvas3D-DEWoiNMD.js → Canvas3D-CafFy8T8.js} +1 -1
  2. package/dist-lib/{F8GraphCanvas-Cu6dtIgq.js → F8GraphCanvas-CMXizZ4K.js} +705 -674
  3. package/dist-lib/canvas.js +1 -1
  4. package/dist-lib/{cssMode-1gdBAwNQ.js → cssMode-DcJKqlDO.js} +1 -1
  5. package/dist-lib/f8-studio.css +1 -1
  6. package/dist-lib/f8-studio.js +2 -2
  7. package/dist-lib/{freemarker2-DOQZLtnt.js → freemarker2-CqsXfxrG.js} +1 -1
  8. package/dist-lib/{handlebars-CIXlymxU.js → handlebars-CWuq8civ.js} +1 -1
  9. package/dist-lib/{html--Bi9VDgI.js → html-DXVjXiYh.js} +1 -1
  10. package/dist-lib/{htmlMode-BqCrpeeP.js → htmlMode-vc43Xi32.js} +1 -1
  11. package/dist-lib/{index-0ioFtrZM.js → index-bm1ERcEP.js} +23117 -22432
  12. package/dist-lib/{javascript-BL3tIzUw.js → javascript-BAw14QCv.js} +1 -1
  13. package/dist-lib/{jsonMode-FxM7KRm5.js → jsonMode-BgO9x6Pt.js} +1 -1
  14. package/dist-lib/{liquid-wB7unZht.js → liquid-BORLQ9T_.js} +1 -1
  15. package/dist-lib/{mdx-DmS41r19.js → mdx-DjAZ-OHO.js} +1 -1
  16. package/dist-lib/{python-C24igqMV.js → python-DSG-Ns6E.js} +1 -1
  17. package/dist-lib/{razor-BRvioLVk.js → razor-BhXgviY9.js} +1 -1
  18. package/dist-lib/{tsMode-zMn1qnUE.js → tsMode--dsrDMOH.js} +1 -1
  19. package/dist-lib/types/api/endpoints.d.ts +7 -7
  20. package/dist-lib/types/api/types.d.ts +18 -1
  21. package/dist-lib/types/canvas/InteractPanel.d.ts +19 -0
  22. package/dist-lib/types/lib/canvasCap.d.ts +10 -0
  23. package/dist-lib/types/lib/canvasInteract.d.ts +174 -0
  24. package/dist-lib/types/lib/configCatalog.d.ts +12 -0
  25. package/dist-lib/types/lib/fieldHelp.d.ts +7 -0
  26. package/dist-lib/types/lib/format.d.ts +1 -1
  27. package/dist-lib/types/lib/listCaps.d.ts +16 -2
  28. package/dist-lib/types/lib/neighborhood.d.ts +1 -0
  29. package/dist-lib/types/lib/vectorSearch.d.ts +19 -0
  30. package/dist-lib/types/state/instanceStore.d.ts +31 -2
  31. package/dist-lib/types/state/integrations.d.ts +10 -0
  32. package/dist-lib/{typescript-BIjKKvsW.js → typescript-CN4PnAKf.js} +1 -1
  33. package/dist-lib/{xml-CT-uMOiT.js → xml-BgTKhrv7.js} +1 -1
  34. package/dist-lib/{yaml-Dezcc_VH.js → yaml-CDTzHXpW.js} +1 -1
  35. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { conf as t, language as e } from "./typescript-BIjKKvsW.js";
1
+ import { conf as t, language as e } from "./typescript-CN4PnAKf.js";
2
2
  var i = t, o = {
3
3
  // Set defaultToken to invalid to see what you do not tokenize yet
4
4
  defaultToken: "invalid",
@@ -1,4 +1,4 @@
1
- import { m as Et } from "./index-0ioFtrZM.js";
1
+ import { m as Et } from "./index-bm1ERcEP.js";
2
2
  var Lt = Object.defineProperty, Ot = Object.getOwnPropertyDescriptor, Nt = Object.getOwnPropertyNames, Rt = Object.prototype.hasOwnProperty, Mt = (e, r, i, n) => {
3
3
  if (r && typeof r == "object" || typeof r == "function")
4
4
  for (let t of Nt(r))
@@ -1,4 +1,4 @@
1
- import { m as l } from "./index-0ioFtrZM.js";
1
+ import { m as l } from "./index-bm1ERcEP.js";
2
2
  var d = Object.defineProperty, s = Object.getOwnPropertyDescriptor, c = Object.getOwnPropertyNames, u = Object.prototype.hasOwnProperty, m = (t, e, r, n) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let i of c(e))
@@ -1,4 +1,4 @@
1
- import { m as s } from "./index-0ioFtrZM.js";
1
+ import { m as s } from "./index-bm1ERcEP.js";
2
2
  var d = Object.defineProperty, c = Object.getOwnPropertyDescriptor, p = Object.getOwnPropertyNames, a = Object.prototype.hasOwnProperty, k = (n, e, i, r) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let o of p(e))
@@ -1,4 +1,4 @@
1
- import { m as o } from "./index-0ioFtrZM.js";
1
+ import { m as o } from "./index-bm1ERcEP.js";
2
2
  var a = Object.defineProperty, l = Object.getOwnPropertyDescriptor, p = Object.getOwnPropertyNames, c = Object.prototype.hasOwnProperty, g = (t, e, n, s) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let r of p(e))
@@ -1,4 +1,4 @@
1
- import { m } from "./index-0ioFtrZM.js";
1
+ import { m } from "./index-bm1ERcEP.js";
2
2
  var s = Object.defineProperty, c = Object.getOwnPropertyDescriptor, l = Object.getOwnPropertyNames, d = Object.prototype.hasOwnProperty, p = (t, e, o, n) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let r of l(e))
@@ -1,4 +1,4 @@
1
- import { t as O, m as I } from "./index-0ioFtrZM.js";
1
+ import { t as O, m as I } from "./index-bm1ERcEP.js";
2
2
  var N = Object.defineProperty, M = Object.getOwnPropertyDescriptor, R = Object.getOwnPropertyNames, K = Object.prototype.hasOwnProperty, E = (e, t, i, o) => {
3
3
  if (t && typeof t == "object" || typeof t == "function")
4
4
  for (let n of R(t))
@@ -112,12 +112,12 @@ export declare const getGraphElement: (i: InstanceConfig, id: number, signal?: A
112
112
  * which re-reads those singly.
113
113
  */
114
114
  export declare const getGraphElements: (i: InstanceConfig, ids: number[], signal?: AbortSignal) => Promise<GraphElementBatchREST | null>;
115
- export declare const getOutEdgeProperties: (i: InstanceConfig, id: number) => Promise<string[] | null>;
116
- export declare const getInEdgeProperties: (i: InstanceConfig, id: number) => Promise<string[] | null>;
117
- export declare const getOutEdges: (i: InstanceConfig, id: number, edgePropertyId: string) => Promise<number[] | null>;
118
- export declare const getInEdges: (i: InstanceConfig, id: number, edgePropertyId: string) => Promise<number[] | null>;
119
- export declare const getInDegree: (i: InstanceConfig, id: number) => Promise<number | null>;
120
- export declare const getOutDegree: (i: InstanceConfig, id: number) => Promise<number | null>;
115
+ export declare const getOutEdgeProperties: (i: InstanceConfig, id: number, signal?: AbortSignal) => Promise<string[] | null>;
116
+ export declare const getInEdgeProperties: (i: InstanceConfig, id: number, signal?: AbortSignal) => Promise<string[] | null>;
117
+ export declare const getOutEdges: (i: InstanceConfig, id: number, edgePropertyId: string, signal?: AbortSignal) => Promise<number[] | null>;
118
+ export declare const getInEdges: (i: InstanceConfig, id: number, edgePropertyId: string, signal?: AbortSignal) => Promise<number[] | null>;
119
+ export declare const getInDegree: (i: InstanceConfig, id: number, signal?: AbortSignal) => Promise<number | null>;
120
+ export declare const getOutDegree: (i: InstanceConfig, id: number, signal?: AbortSignal) => Promise<number | null>;
121
121
  export declare const getEdgePropertyDegree: (i: InstanceConfig, id: number, direction: "in" | "out", edgePropertyId: string) => Promise<number | null>;
122
122
  export declare const getEdgeSource: (i: InstanceConfig, id: number) => Promise<number | null>;
123
123
  export declare const getEdgeTarget: (i: InstanceConfig, id: number) => Promise<number | null>;
@@ -135,7 +135,7 @@ export declare const deleteElementEmbedding: (i: InstanceConfig, id: number, nam
135
135
  /** Embed text and store it as the element's named embedding (+ model stamp), one txn. */
136
136
  export declare const embedElement: (i: InstanceConfig, spec: EmbedElementSpecification) => Promise<boolean | null>;
137
137
  /** Semantic search: embed the query text once, then kNN — same result shape as scanVector. */
138
- export declare const embeddingSearch: (i: InstanceConfig, spec: EmbeddingSearchSpecification) => Promise<VectorSearchResultREST | null>;
138
+ export declare const embeddingSearch: (i: InstanceConfig, spec: EmbeddingSearchSpecification, signal?: AbortSignal) => Promise<VectorSearchResultREST | null>;
139
139
  export declare const createIndex: (i: InstanceConfig, spec: PluginSpecification) => Promise<boolean | null>;
140
140
  export declare const addToIndex: (i: InstanceConfig, indexId: string, spec: IndexAddToSpecification) => Promise<boolean | null>;
141
141
  export declare const removeIndexKey: (i: InstanceConfig, indexId: string, key: IndexKeySpecification) => Promise<boolean | null>;
@@ -438,8 +438,18 @@ export interface ChatProviderStatsREST {
438
438
  /**
439
439
  * From the configured options, not from a probe target: reported for EVERY backend, including
440
440
  * the ones with no residency API.
441
+ *
442
+ * The ASSIST purpose's model. It keeps the bare name `model` deliberately: every reader of it
443
+ * predates the purposes, and renaming it would have changed a contract to add one.
441
444
  */
442
445
  model: string | null;
446
+ /**
447
+ * The AGENT purpose's model (feature agent-host), or null when the selected backend names none,
448
+ * which is the shipped state for OpenAI and Anthropic. Distinct from `model` because the two are
449
+ * configured by different people for different reasons: the assist model is the fine-tune, the
450
+ * agent model is a general one that can call tools.
451
+ */
452
+ agentModel?: string | null;
443
453
  loaded: boolean;
444
454
  resident?: boolean | null;
445
455
  gpu?: boolean | null;
@@ -1035,6 +1045,13 @@ export interface IntegrationProvider {
1035
1045
  id: string;
1036
1046
  displayName: string;
1037
1047
  description: string;
1048
+ /**
1049
+ * Absolute http(s) URL of the integration's own documentation, when it declares one. It is what
1050
+ * keeps `description` a sentence instead of a reference manual in a table cell. Optional: an
1051
+ * older runtime, or a provider whose author wrote no page, sends none. Render it only through
1052
+ * `docsHref` in state/integrations.ts, which refuses a scheme a browser should not follow.
1053
+ */
1054
+ docsUrl?: string | null;
1038
1055
  settings: IntegrationSetting[];
1039
1056
  entityKinds: string[];
1040
1057
  claimTypes: string[];
@@ -1117,7 +1134,7 @@ export interface IntegrationDiagnostic {
1117
1134
  * A `File` and NOT its bytes, which is the whole of feature integration-file-transport on this side.
1118
1135
  * The version this replaced carried `contentBase64`, so the tab had to hold every file's bytes, the
1119
1136
  * base64 expansion of them and the serialised request all at once; a set of AUTOSAR extracts left
1120
- * 5.84 GiB resident before the send even started, and the encoder failed outright at about 384 MiB
1137
+ * gigabytes resident before the send even started, and the encoder failed outright at about 384 MiB
1121
1138
  * of input because a JavaScript string caps at 512 MiB. A handle costs nothing until the browser
1122
1139
  * streams it off disk.
1123
1140
  *
@@ -0,0 +1,19 @@
1
+ import type { ElementRef } from "./GraphCanvas";
2
+ /**
3
+ * Canvas "Interact" tab (feature canvas-interact): filters build a MATCH SET over the canvas
4
+ * vertices, and two view-only verbs apply to it - expand every match's neighborhood, or remove
5
+ * every match from the view. With no filter active the match set is every canvas vertex, which is
6
+ * how "expand all" is expressed rather than as a separate button.
7
+ *
8
+ * Label, property and on-canvas degree are cheap, so they evaluate live on every render. Database
9
+ * degree and the semantic threshold cost server round trips, so they run behind Preview, and any
10
+ * filter edit or canvas change INVALIDATES that result: acting on a stale match set is the bug
11
+ * this lifecycle exists to prevent. Nothing here touches the database.
12
+ */
13
+ export declare function InteractPanel({ selected, onSelect, onHover, }: {
14
+ /** What the Detail panel currently shows, so a bulk remove can retire a selection it took. */
15
+ selected: ElementRef | null;
16
+ onSelect: (ref: ElementRef | null) => void;
17
+ /** Spotlight a previewed vertex on the canvas, the Find tab's affordance. */
18
+ onHover?: (ref: ElementRef | null) => void;
19
+ }): import("react").JSX.Element;
@@ -5,3 +5,13 @@
5
5
  * sample-graph loaders and the Canvas screen's "Show whole graph" load.
6
6
  */
7
7
  export declare const CANVAS_ELEMENT_CAP = 20000;
8
+ /**
9
+ * The most elements (vertices PLUS edges) a bulk expand will grow the canvas to before it stops
10
+ * and says so (feature canvas-interact).
11
+ *
12
+ * A separate number from `CANVAS_ELEMENT_CAP` on purpose: that one bounds each KIND of a fetch, so
13
+ * "Show whole graph" can legitimately leave 20,000 vertices AND 20,000 edges on the canvas. A
14
+ * sweep refusing to grow a canvas the app itself just filled would be enforcing a ceiling nothing
15
+ * else in the product has, which is why this is the sum and twice the size.
16
+ */
17
+ export declare const CANVAS_EXPAND_CEILING: number;
@@ -0,0 +1,174 @@
1
+ import type { EdgeREST, VectorSearchResultREST, VertexREST } from "../api/types";
2
+ import type { InstanceConfig } from "../instances/types";
3
+ import type { CanvasEdge, CanvasNode } from "../state/instanceStore";
4
+ /**
5
+ * Pure logic for the Canvas "Interact" tab (feature canvas-interact): filters build a MATCH SET
6
+ * over the canvas vertices, and two view-only verbs (expand, remove) apply to it. Kept DOM-free
7
+ * so every decision below is unit-tested without a render.
8
+ *
9
+ * The verbs are also the single home for expand-on-demand: the Detail panel's "Expand neighbors"
10
+ * runs `expandVertices` over one id, the tab runs it over the match set. See
11
+ * features/open/canvas-interact/spec.md.
12
+ */
13
+ /**
14
+ * The most candidates a DATABASE-degree evaluation will sweep. Two requests per candidate, so the
15
+ * cap is about bounding a click, not about correctness; above it the run is refused rather than
16
+ * partially evaluated, and the cheap filters are the narrowing tool. One tuning home.
17
+ */
18
+ export declare const DEGREE_SWEEP_CAP = 1000;
19
+ /**
20
+ * The most matched vertices one Expand may sweep. A single vertex's expand is already several
21
+ * requests (both adjacency listings, then every edge and endpoint), so this is the difference
22
+ * between a click and a thousand-request storm.
23
+ */
24
+ export declare const EXPAND_SWEEP_CAP = 100;
25
+ /** How many vertices are expanded (or degree-probed) concurrently in one batched round. */
26
+ export declare const INTERACT_BATCH_SIZE = 8;
27
+ /** Which edges a degree comparison counts. */
28
+ export type DegreeSource = "database" | "canvas";
29
+ export type DegreeDirection = "in" | "out" | "total";
30
+ export type DegreeOp = "over" | "under";
31
+ export type SemanticDirection = "closer" | "farther";
32
+ /**
33
+ * The filters that need no server round trip, so they evaluate live on every render: label and
34
+ * property read the canvas snapshot, and on-canvas degree counts the edges actually loaded.
35
+ * A field is INACTIVE when empty, which is why the degree value is a string - "" has to mean
36
+ * "not filtering", and 0 is a legitimate threshold.
37
+ */
38
+ export interface CheapFilters {
39
+ label: string;
40
+ propKey: string;
41
+ propTerm: string;
42
+ degreeSource: DegreeSource;
43
+ degreeDirection: DegreeDirection;
44
+ degreeOp: DegreeOp;
45
+ /** The comparison value as typed; "" (or unparseable) leaves the degree filter inactive. */
46
+ degreeValue: string;
47
+ }
48
+ /** A degree filter that is actually on: parsed, and known to be the canvas-counted source. */
49
+ export interface ActiveDegree {
50
+ direction: DegreeDirection;
51
+ op: DegreeOp;
52
+ value: number;
53
+ }
54
+ /**
55
+ * The degree filter as a number, or null when it is not filtering at all. A blank or
56
+ * unparseable value is inactive rather than 0: typing "over 0" is a real filter and must not be
57
+ * what an empty box means.
58
+ */
59
+ export declare function activeDegree(filters: CheapFilters): ActiveDegree | null;
60
+ /** Whether any cheap filter is on, which is what makes an empty match set meaningful. */
61
+ export declare function anyCheapActive(filters: CheapFilters): boolean;
62
+ /** `over` and `under` are strict, so "over 50" excludes a vertex of exactly 50. */
63
+ export declare function compareDegree(degree: number, op: DegreeOp, value: number): boolean;
64
+ /**
65
+ * The canvas vertices surviving every ACTIVE cheap filter, AND-composed.
66
+ *
67
+ * A stub vertex (merged as an edge's unloaded endpoint: no `props`, null label) matches no label
68
+ * and no property filter, because nothing was ever read about it - but an on-canvas degree filter
69
+ * counts its loaded edges like any other vertex's, since that is a fact about the view rather
70
+ * than about the element.
71
+ *
72
+ * On-canvas degree delegates to the style engine's `visibleDegrees`, which is what degree-based
73
+ * node sizing already reads: one home for counting the view's edges.
74
+ */
75
+ export declare function matchCheap(nodes: CanvasNode[], edges: CanvasEdge[], filters: CheapFilters): CanvasNode[];
76
+ /** The ids whose fetched degree satisfies the comparison; an id with no score is not matched. */
77
+ export declare function applyDegree(degrees: ReadonlyMap<number, number>, op: DegreeOp, value: number): Set<number>;
78
+ /** What a semantic threshold decided, including how much of the input it could not judge. */
79
+ export interface SemanticVerdict {
80
+ matched: Set<number>;
81
+ /** Candidates the search returned no score for. They match NOTHING, in either direction. */
82
+ unscored: number;
83
+ }
84
+ /**
85
+ * The candidates a semantic threshold keeps, oriented by the search's own metric.
86
+ *
87
+ * `higherIsBetter` comes from the server (Cosine/DotProduct: higher is closer; L2: lower is), and
88
+ * the threshold is in that metric's RAW units - the client never re-derives a similarity.
89
+ *
90
+ * A candidate the result carries no score for is UNSCORED and matches neither direction. It has
91
+ * no embedding, or it fell outside the search window, and either way nothing measured it: "I
92
+ * could not look" must never become "it is far", least of all in front of a bulk remove.
93
+ */
94
+ export declare function applySemantic(candidateIds: number[], result: VectorSearchResultREST | null, direction: SemanticDirection, threshold: number): SemanticVerdict;
95
+ /** How far a batched sweep has got, for the panel's progress line. */
96
+ export interface SweepProgress {
97
+ done: number;
98
+ total: number;
99
+ }
100
+ /** A degree sweep's answer: what it read, and what it could NOT read. */
101
+ export interface DegreeSweepResult {
102
+ degrees: Map<number, number>;
103
+ /**
104
+ * Candidates whose degree the server would not answer. They are absent from `degrees`, so they
105
+ * match nothing - and the caller must SAY so, because "0 of 500 match" is otherwise
106
+ * indistinguishable from "500 vertices measured and none qualified".
107
+ */
108
+ unreadable: number;
109
+ }
110
+ /**
111
+ * Every candidate's DATABASE degree in one direction, batched and abortable.
112
+ *
113
+ * `total` costs both requests per vertex; a direction costs one. A vertex whose degree cannot be
114
+ * read is left OUT of the map rather than recorded as 0, so it fails the comparison instead of
115
+ * being swept up by "under x" by a bulk remove - and it is COUNTED, which is the half that makes
116
+ * the rule honest rather than merely safe (the semantic filter's unscored count is the precedent).
117
+ */
118
+ export declare function degreeSweep(instance: InstanceConfig, ids: number[], options: {
119
+ direction: DegreeDirection;
120
+ signal?: AbortSignal;
121
+ onProgress?: (progress: SweepProgress) => void;
122
+ }): Promise<DegreeSweepResult>;
123
+ /** What an expand sweep actually did, which is never assumed to be "all of it". */
124
+ export interface ExpandOutcome {
125
+ /** Vertices the sweep ATTEMPTED (its progress position), failures included. */
126
+ attempted: number;
127
+ /** Vertices whose neighborhood came back and was merged. `expanded + failed === attempted`. */
128
+ expanded: number;
129
+ total: number;
130
+ /** True when the canvas element ceiling stopped the sweep before the last vertex. */
131
+ stoppedAtCeiling: boolean;
132
+ cancelled: boolean;
133
+ /**
134
+ * Vertices whose neighborhood fetch threw. NOTE the honest limitation: the neighborhood
135
+ * primitive swallows per-request HTTP failures and returns empty arrays, so a vertex whose
136
+ * adjacency the server refused looks exactly like a vertex with no neighbors. This counts only
137
+ * what reaches us as an exception (a malformed answer), which is why the panel never presents
138
+ * it as "everything that went wrong" - and why an ABORT is handled by discarding its batch
139
+ * rather than by counting it here, since an aborted fetch does not throw out of the primitive
140
+ * either.
141
+ */
142
+ failed: number;
143
+ /**
144
+ * Vertices where the per-vertex edge cap cut the neighborhood short, so the canvas holds only
145
+ * part of what they touch. Reported, because the alternative is a hub that looks fully expanded.
146
+ */
147
+ truncated: number;
148
+ }
149
+ /**
150
+ * Expand a set of vertices: one hop each, merged as every batch lands.
151
+ *
152
+ * The one home for expand-on-demand. `onMerge` is called per batch rather than once at the end,
153
+ * so a long sweep grows the canvas visibly and a cancel keeps what already landed. `skip` is
154
+ * re-read per batch through `liveElementCount`/`skipIds` callbacks rather than captured once,
155
+ * because each merge changes what the next batch would re-fetch.
156
+ *
157
+ * The sweep stops when the canvas reaches `elementCeiling` and SAYS so (`stoppedAtCeiling`), the
158
+ * same honesty as the whole-graph truncation notice - silently expanding half a match set would
159
+ * look identical to a graph that simply has fewer neighbors. The signal reaches the fetches
160
+ * themselves, so a cancel stops issuing requests rather than only stopping the next batch.
161
+ */
162
+ export declare function expandVertices(instance: InstanceConfig, ids: number[], options: {
163
+ /** Ids not to re-hydrate, re-read before each batch (the live canvas). */
164
+ skipIds: () => ReadonlySet<number>;
165
+ /** Current canvas element count, re-read before each batch. */
166
+ liveElementCount?: () => number;
167
+ /** Stop once the canvas holds this many elements. Omitted = no ceiling. */
168
+ elementCeiling?: number;
169
+ onMerge: (vertices: VertexREST[], edges: EdgeREST[]) => void;
170
+ onProgress?: (progress: SweepProgress) => void;
171
+ signal?: AbortSignal;
172
+ /** Per-vertex edge cap; defaults to the standing expand cap. */
173
+ cap?: number;
174
+ }): Promise<ExpandOutcome>;
@@ -62,6 +62,18 @@ export interface SectionGroup {
62
62
  /** The sub-groups, direct keys first; a single unlabelled group when the section renders flat. */
63
63
  groups: SettingGroup[];
64
64
  }
65
+ /**
66
+ * The purposes a chat completion can name, as they are spelled in a settings key
67
+ * (`Fallen8:Chat:<Backend>:Models:<Purpose>`). ONE list, so a surface that offers something per
68
+ * purpose cannot offer it for a subset: the server resolves the model per purpose and refuses a
69
+ * completion whose purpose names none, which is a state an operator has to be able to see and fix
70
+ * for every purpose that exists.
71
+ *
72
+ * Order is the order they are shown in, and `Assist` is first because it is the purpose a
73
+ * completion gets when it names none. Not because it is the one an instance has configured: the
74
+ * two Ollama-protocol backends default BOTH purposes and the two metered ones default neither.
75
+ */
76
+ export declare const CHAT_PURPOSES: readonly string[];
65
77
  /**
66
78
  * Buckets the published settings into the ordered sections, preserving the server's order within a
67
79
  * raw section: the catalog authors related keys adjacently (an index switch is followed by the index
@@ -110,6 +110,13 @@ export declare const FIELD_HELP: {
110
110
  readonly canvasEdgeLabels: "Show edge-container names on edges (2D: always visible, 3D: on hover). Subject to the same 5,000-element degrade threshold as node labels.";
111
111
  readonly canvasEdgeArrows: "Draw arrowheads pointing at each edge's target vertex, making direction visible in both 2D and 3D.";
112
112
  readonly saveGameDeleteFiles: "Also delete the checkpoint's files on the server's disk, not just its registry entry. The data is then unrecoverable.";
113
+ readonly interactLabel: "Match only vertices carrying exactly this label. A vertex the canvas holds only as an edge's endpoint has no label read yet, so it never matches a label filter.";
114
+ readonly interactProperty: "Match vertices carrying this property key; add a term to require the value to contain it (case-insensitive). This reads the canvas snapshot, which holds scalars only and caps strings at 200 characters, so a term that occurs only past that cap will not match. The Find tab is the server-side search.";
115
+ readonly interactDegreeSource: "Which edges the degree counts. 'the database' asks the server for the vertex's true degree, one small request per candidate, so it needs Preview. 'edges on canvas' counts only the edges currently loaded: instant, and the number you see, but a vertex you never expanded reads 0 there whatever the database knows.";
116
+ readonly interactDegree: "Keep vertices whose degree is strictly over (or under) this number, counted in the chosen direction. Leave the number empty to switch the filter off; 0 is a real bound, not 'off'.";
117
+ readonly interactSemantic: "Keep vertices whose stored embedding is closer (or farther) than a threshold from this text. The provider embeds the text once, then the bound vector index ranks your elements. The threshold is in the index metric's RAW units, exactly as the search reports them: with Cosine/DotProduct a higher score is closer, with L2 a lower one is.";
118
+ readonly interactDegreeUnreadable: "Vertices whose degree the server would not answer (deleted since they landed on the canvas, or an instance that stopped answering). They are left OUT of the match set rather than counted as 0, so 'under x' cannot sweep up a vertex nobody measured, and they are counted here so a shrunken match set is never mistaken for a measurement.";
119
+ readonly interactSemanticUnscored: "A canvas vertex the search returned no score for (no embedding stored, or outside the search window) matches NEITHER direction, and the preview counts it. Nothing measured it, so calling it 'far' would remove vertices on no evidence.";
113
120
  readonly feedKinds: "Event kinds to show and count. Dimensions combine like the REST filter grammar: AND across dimensions, OR within one. Resync events are exempt and always shown, because they mean continuity was lost.";
114
121
  readonly feedElements: "Restrict to vertex or edge events: the elements dimension of the REST filter grammar.";
115
122
  readonly feedLabels: "Exact, case-sensitive labels to match (Enter or comma adds one). An element without a label never matches a labels filter, the same rule the server applies.";
@@ -6,7 +6,7 @@ export declare function formatExact(value: number): string;
6
6
  * A size in bytes, in binary units up to GiB ("0 B", "512 B", "1.5 KiB", "5.8 GiB").
7
7
  *
8
8
  * GiB and not MiB because two callers need it: a save-game registry, and the refusal that tells
9
- * someone their 5983 MiB of files is over the ceiling. Reporting that as "5983.0 MiB" is arithmetic
9
+ * someone their several gibibytes of files are over the ceiling. Reporting that in mebibytes is arithmetic
10
10
  * the reader should not have to do while being told no.
11
11
  */
12
12
  export declare function formatBytes(bytes: number): string;
@@ -41,8 +41,22 @@ export declare function capList<T>(items: readonly T[], max?: number): {
41
41
  shown: T[];
42
42
  total: number;
43
43
  };
44
+ /**
45
+ * How tall ONE row is, in rem, for a list whose rows are not a single line. The cap is a row
46
+ * COUNT, so it needs a height per row to work with; the CSS default (2.5rem, see index.css) is a
47
+ * one-line table row, and a list of wrapped prose hits that ceiling several rows early and scrolls
48
+ * a list far shorter than its threshold. Add an entry only for a list that reads that way.
49
+ */
50
+ export declare const SCROLL_ROW_REM: {
51
+ /**
52
+ * Available integrations (IntegrationsScreen): each row is a sentence describing what the
53
+ * integration reads, and it wraps to three or four lines on a narrow window.
54
+ */
55
+ readonly integrations: 5;
56
+ };
44
57
  /**
45
58
  * Inline style that tells a `.scroll-list` wrapper how many rows to show before it caps its
46
- * height and scrolls. Custom CSS properties need the cast; this keeps it in one place.
59
+ * height and scrolls, and optionally how tall to assume one row is (see {@link SCROLL_ROW_REM};
60
+ * omitted, the CSS default applies). Custom CSS properties need the cast; this keeps it in one place.
47
61
  */
48
- export declare function scrollRows(rows: number): CSSProperties;
62
+ export declare function scrollRows(rows: number, rowRem?: number): CSSProperties;
@@ -25,6 +25,7 @@ export interface Neighborhood {
25
25
  export declare function fetchVertexNeighborhood(instance: InstanceConfig, vertexId: number, options: {
26
26
  cap: number;
27
27
  skipNeighborIds?: ReadonlySet<number>;
28
+ signal?: AbortSignal;
28
29
  }): Promise<Neighborhood>;
29
30
  /**
30
31
  * An edge's endpoint vertices plus EVERY edge between them, both directions — found by
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The engine's own ceiling on a kNN `k`, mirrored client-side.
3
+ *
4
+ * ONE home, because every caller of `/scan/index/vector` and `/embedding/search` has to agree with
5
+ * the server or the request is refused outright: `VectorIndex.MaxK` is 1024 and
6
+ * `VectorIndex.TryNearestNeighbors` rejects anything above it, which the embedding controller
7
+ * turns into a 400 AFTER the provider has already embedded the query text. So a k picked from some
8
+ * other quantity does not degrade, it fails, and it fails having spent a model call.
9
+ *
10
+ * That is not hypothetical: the canvas Interact tab first shipped this asking for the canvas
11
+ * element cap (20,000) worth of neighbours, which made its semantic filter unusable on every real
12
+ * instance while every mocked test passed.
13
+ */
14
+ export declare const MAX_K = 1024;
15
+ /**
16
+ * A kNN window that cannot exceed the engine's ceiling, for a caller who wants "as many as I might
17
+ * need" rather than a number a person typed. `wanted` is what the caller would ideally ask for.
18
+ */
19
+ export declare function boundedK(wanted: number): number;
@@ -220,9 +220,17 @@ export declare const DEFAULT_ANALYTICS_DRAFT: AnalyticsDraft;
220
220
  * state (re-run on demand), exactly like every other result in the studio - only the inputs here
221
221
  * persist.
222
222
  */
223
+ /**
224
+ * The tabs of the canvas tool strip, in strip order. ONE home for the ids: the strip renders them
225
+ * and the persisted `canvasToolsDraft.tab` is validated against them on rehydration.
226
+ */
227
+ export declare const CANVAS_TABS: readonly ["style", "find", "connect", "interact"];
228
+ export type CanvasTab = (typeof CANVAS_TABS)[number];
229
+ /** Guard for the untrusted source of a canvas tab id: persisted storage. */
230
+ export declare const isCanvasTab: (value: unknown) => value is CanvasTab;
223
231
  export interface CanvasToolsDraft {
224
- /** Which right-panel tab is active: styling, element search, or path connecting. */
225
- tab: "style" | "find" | "connect";
232
+ /** Which right-panel tab is active: styling, element search, path connecting, or interacting. */
233
+ tab: CanvasTab;
226
234
  /** Find: the all-property contains term (fed to POST /scan/graph/properties). */
227
235
  findTerm: string;
228
236
  /** Find: optional exact-match label restrictor; empty searches every label. */
@@ -233,6 +241,25 @@ export interface CanvasToolsDraft {
233
241
  connectMaxDepth: number;
234
242
  /** Connect: use every canvas vertex, or only a picked subset, as the pair endpoints. */
235
243
  connectScope: "all" | "pick";
244
+ /**
245
+ * Interact (feature canvas-interact): the filter rows that build the match set the tab's two
246
+ * verbs act on. Every one is INACTIVE when blank - which is why the two numeric thresholds are
247
+ * strings, since 0 is a legitimate degree bound and "" has to mean "not filtering" - and with
248
+ * none of them active the match set is every canvas vertex, i.e. "expand all".
249
+ */
250
+ interactLabel: string;
251
+ interactPropKey: string;
252
+ interactPropTerm: string;
253
+ /** Which edges the degree comparison counts: the database's answer, or the loaded ones. */
254
+ interactDegreeSource: "database" | "canvas";
255
+ interactDegreeDirection: "in" | "out" | "total";
256
+ interactDegreeOp: "over" | "under";
257
+ interactDegreeValue: string;
258
+ interactSemanticText: string;
259
+ interactSemanticIndexId: string;
260
+ interactSemanticDirection: "closer" | "farther";
261
+ /** The threshold in the metric's RAW units, as typed (blank = the filter is off). */
262
+ interactSemanticThreshold: string;
236
263
  }
237
264
  export declare const DEFAULT_CANVAS_TOOLS_DRAFT: CanvasToolsDraft;
238
265
  /** One-shot navigation intent: "open Query with this index preselected" (cleared on consume). */
@@ -295,6 +322,8 @@ export interface WorkspaceState {
295
322
  scanPrefill: ScanPrefill | null;
296
323
  mergeIntoCanvas: (vertices: VertexREST[], edges: EdgeREST[]) => void;
297
324
  removeFromCanvas: (kind: "node" | "edge", id: number) => void;
325
+ /** Removes a SET of vertices (and their incident edges) in one write - see the implementation. */
326
+ removeManyFromCanvas: (ids: readonly number[]) => void;
298
327
  clearCanvas: () => void;
299
328
  setWholeGraphTruncation: (truncation: WholeGraphTruncation | null) => void;
300
329
  setStyleConfig: (patch: Partial<StyleConfig>) => void;
@@ -27,6 +27,16 @@ export declare function useIntegrationProviders(instance: InstanceConfig | null)
27
27
  export declare function useIntegrationLimits(instance: InstanceConfig | null): import("@tanstack/react-query").UseQueryResult<NoInfer<FileLimits | null>, unknown>;
28
28
  /** Whether a failure is the capability being off rather than the instance being unwell. */
29
29
  export declare function isCapabilityRefusal(error: unknown): boolean;
30
+ /**
31
+ * The href for a provider's documentation link, or null when there is nothing safe to link.
32
+ *
33
+ * The runtime refuses anything but an absolute http(s) URL when it builds its catalog, so this is
34
+ * the second half of that check rather than the only one: the descriptor arrives over the network
35
+ * from a deployable Studio does not ship with, and a `javascript:` href here would run in the
36
+ * operator's browser. Anything else is dropped silently - the row simply carries no link, which is
37
+ * the same state as a provider that declares no documentation.
38
+ */
39
+ export declare function docsHref(provider: Pick<IntegrationProvider, "docsUrl">): string | null;
30
40
  /** The capability verdict of a providers query, for the rail and for a deep link. */
31
41
  export declare function capabilityOf(query: {
32
42
  isError: boolean;
@@ -1,4 +1,4 @@
1
- import { m as s } from "./index-0ioFtrZM.js";
1
+ import { m as s } from "./index-bm1ERcEP.js";
2
2
  var c = Object.defineProperty, a = Object.getOwnPropertyDescriptor, p = Object.getOwnPropertyNames, g = Object.prototype.hasOwnProperty, l = (t, e, o, i) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let n of p(e))
@@ -1,4 +1,4 @@
1
- import { m as r } from "./index-0ioFtrZM.js";
1
+ import { m as r } from "./index-bm1ERcEP.js";
2
2
  var m = Object.defineProperty, c = Object.getOwnPropertyDescriptor, l = Object.getOwnPropertyNames, d = Object.prototype.hasOwnProperty, p = (t, e, o, i) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let n of l(e))
@@ -1,4 +1,4 @@
1
- import { m as l } from "./index-0ioFtrZM.js";
1
+ import { m as l } from "./index-bm1ERcEP.js";
2
2
  var i = Object.defineProperty, c = Object.getOwnPropertyDescriptor, u = Object.getOwnPropertyNames, s = Object.prototype.hasOwnProperty, d = (n, e, r, o) => {
3
3
  if (e && typeof e == "object" || typeof e == "function")
4
4
  for (let t of u(e))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fallen-8/studio",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "F8 Studio - browser frontend for Fallen-8 instances, and its graph canvas as a standalone component",
5
5
  "license": "MIT",
6
6
  "author": "Henning Rauch",