@fallen-8/studio 0.0.36 → 0.0.38

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 (47) hide show
  1. package/dist-lib/{Canvas3D-BXYc6PEP.js → Canvas3D-DEWoiNMD.js} +1 -1
  2. package/dist-lib/{F8GraphCanvas-Ckq0NuuE.js → F8GraphCanvas-Cu6dtIgq.js} +981 -965
  3. package/dist-lib/canvas.js +1 -1
  4. package/dist-lib/{cssMode-nGncvC5m.js → cssMode-1gdBAwNQ.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-CP74sa8J.js → freemarker2-DOQZLtnt.js} +1 -1
  8. package/dist-lib/{handlebars-QALLOIn0.js → handlebars-CIXlymxU.js} +1 -1
  9. package/dist-lib/{html-85a-cm74.js → html--Bi9VDgI.js} +1 -1
  10. package/dist-lib/{htmlMode-BgQACh7e.js → htmlMode-BqCrpeeP.js} +1 -1
  11. package/dist-lib/{index-CQF9rZdm.js → index-0ioFtrZM.js} +24510 -23934
  12. package/dist-lib/{javascript-C5gSrEJX.js → javascript-BL3tIzUw.js} +1 -1
  13. package/dist-lib/{jsonMode-CPyHCN9i.js → jsonMode-FxM7KRm5.js} +1 -1
  14. package/dist-lib/{liquid-C-WFafiu.js → liquid-wB7unZht.js} +1 -1
  15. package/dist-lib/{mdx-Cqij6eG9.js → mdx-DmS41r19.js} +1 -1
  16. package/dist-lib/{python-DxKmSiUE.js → python-C24igqMV.js} +1 -1
  17. package/dist-lib/{razor-C_PJXRiv.js → razor-BRvioLVk.js} +1 -1
  18. package/dist-lib/{tsMode-BPfWv0l3.js → tsMode-zMn1qnUE.js} +1 -1
  19. package/dist-lib/types/api/client.d.ts +49 -0
  20. package/dist-lib/types/api/endpoints.d.ts +49 -3
  21. package/dist-lib/types/api/types.d.ts +65 -3
  22. package/dist-lib/types/app/nav.d.ts +2 -7
  23. package/dist-lib/types/app/routes.d.ts +7 -2
  24. package/dist-lib/types/components/ConfigurationSurface.d.ts +23 -2
  25. package/dist-lib/types/components/ErrorBox.d.ts +6 -0
  26. package/dist-lib/types/components/SemanticBlockEditor.d.ts +4 -1
  27. package/dist-lib/types/components/SemanticQueryEditor.d.ts +8 -1
  28. package/dist-lib/types/components/SettingRow.d.ts +14 -0
  29. package/dist-lib/types/components/StoredQueriesPanel.d.ts +16 -11
  30. package/dist-lib/types/components/StoredQueryControls.d.ts +3 -4
  31. package/dist-lib/types/delegate/nl/NlDraftStats.d.ts +13 -0
  32. package/dist-lib/types/delegate/nl/config.d.ts +5 -4
  33. package/dist-lib/types/delegate/nl/generate.d.ts +6 -0
  34. package/dist-lib/types/lib/fieldHelp.d.ts +3 -1
  35. package/dist-lib/types/lib/fileLimits.d.ts +69 -0
  36. package/dist-lib/types/lib/format.d.ts +8 -0
  37. package/dist-lib/types/lib/modelProvenance.d.ts +26 -0
  38. package/dist-lib/types/lib/storedQueries.d.ts +10 -0
  39. package/dist-lib/types/lib/vectorIndexCreate.d.ts +49 -0
  40. package/dist-lib/types/screens/PathScreen.d.ts +3 -0
  41. package/dist-lib/types/screens/TraverseScreen.d.ts +1 -0
  42. package/dist-lib/types/state/instanceStore.d.ts +49 -2
  43. package/dist-lib/types/state/integrations.d.ts +11 -1
  44. package/dist-lib/{typescript-CmUu7z19.js → typescript-BIjKKvsW.js} +1 -1
  45. package/dist-lib/{xml-BID2APnO.js → xml-CT-uMOiT.js} +1 -1
  46. package/dist-lib/{yaml-CpQ-mN6F.js → yaml-Dezcc_VH.js} +1 -1
  47. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
- import type { ApiError } from "../api/client";
2
- import type { ObservabilityConfigREST, PendingRestartREST, SettingREST } from "../api/types";
1
+ import { ApiError } from "../api/client";
2
+ import type { InstanceConfig } from "../instances/types";
3
+ import type { ChatProviderStatsREST, ObservabilityConfigREST, PendingRestartREST, SettingREST } from "../api/types";
3
4
  /**
4
5
  * The configuration surface (feature configuration-surface): one dialog holding everything this
5
6
  * instance binds, reached from the single Configure button on the Connect screen's configuration card.
@@ -14,12 +15,24 @@ import type { ObservabilityConfigREST, PendingRestartREST, SettingREST } from ".
14
15
  * a value under a half-typed field here, which is exactly what the poll suspension exists to prevent.
15
16
  * What this component does own is where you are looking: the section, the query and the filter. Those
16
17
  * live under Dialog.Content, which Radix unmounts on close, so they reset without an effect.
18
+ *
19
+ * The ONE server read it does own is the chat model catalog (feature chat-model-catalog), because it
20
+ * only makes sense once the operator has navigated to one particular section: it sits on its own cache
21
+ * key, is never polled, fetches at most once per visit and unmounts with this subtree. The draft still
22
+ * belongs to the card, so this cannot replace a value under a half-typed field.
17
23
  */
18
24
  export interface ConfigurationSurfaceProps {
19
25
  open: boolean;
20
26
  onClose: () => void;
21
27
  /** Named in the header, because the settings behind it belong to one instance and not the next. */
22
28
  instanceName: string;
29
+ /**
30
+ * The instance the catalog read addresses (feature chat-model-catalog). A PROP rather than a
31
+ * registry subscription: everything else here is prop-driven, and subscribing re-rendered this
32
+ * subtree during an instance switch instead of letting it unmount, so it could paint one pass
33
+ * addressing the new instance while every other prop still described the old one.
34
+ */
35
+ instance: InstanceConfig | null;
23
36
  settings: readonly SettingREST[];
24
37
  pendingRestart: readonly PendingRestartREST[];
25
38
  observability: ObservabilityConfigREST;
@@ -38,5 +51,13 @@ export interface ConfigurationSurfaceProps {
38
51
  isRowDisabled: (key: string) => boolean;
39
52
  /** A blanked numeric field the server would refuse the whole batch over, if there is one. */
40
53
  blankNumericKey?: string;
54
+ /**
55
+ * The chat gateway's RUNNING state (feature chat-model-catalog), absent or null when the instance
56
+ * reports none. Two facts live only here: whether chat is on at all, and which backend is actually
57
+ * serving. Neither is derivable from the inventory - Fallen8:Chat:Enabled is never-writable so its
58
+ * value is withheld, and the Backend descriptor publishes the STORED value, which after a write is
59
+ * the pending one. The picker follows what is running.
60
+ */
61
+ chat?: ChatProviderStatsREST | null;
41
62
  }
42
63
  export declare function ConfigurationSurface(props: ConfigurationSurfaceProps): import("react").JSX.Element;
@@ -1,6 +1,12 @@
1
1
  /**
2
2
  * Every failed request shows HTTP status + server message (NFR: never a silent console
3
3
  * error). A network-level failure renders as the disconnected state with a retry.
4
+ *
5
+ * The fallback title is deliberately NOT about requests. This box also renders throws from the
6
+ * client side of a mutation, where no request was made at all: an integration submit that could
7
+ * not build its body reported "Request failed / Invalid string length", which sent the reader
8
+ * looking for a server fault that did not exist. A title is a claim, so the generic one claims
9
+ * only what is always true.
4
10
  */
5
11
  export declare function ErrorBox({ error, onRetry }: {
6
12
  error: unknown;
@@ -1,4 +1,5 @@
1
1
  import { type SemanticDraft } from "../lib/semantic";
2
+ import type { EmbeddingProviderStatsREST } from "../api/types";
2
3
  /**
3
4
  * The Path screen's declarative semantic block (feature element-embeddings): the shared
4
5
  * query core (SemanticQueryEditor) plus the block-local minScore filter and
@@ -11,7 +12,7 @@ import { type SemanticDraft } from "../lib/semantic";
11
12
  * Controlled: the parent owns the SemanticDraft and derives which delegate slots to
12
13
  * disable from semanticOwnsVertex{Filter,Cost}.
13
14
  */
14
- export declare function SemanticBlockEditor({ draft, onChange, allowCost, costDisabledReason, providerEnabled, embeddingNames, idPrefix, disabled, disabledReason, }: {
15
+ export declare function SemanticBlockEditor({ draft, onChange, allowCost, costDisabledReason, providerEnabled, provider, embeddingNames, idPrefix, disabled, disabledReason, }: {
15
16
  draft: SemanticDraft;
16
17
  onChange: (patch: Partial<SemanticDraft>) => void;
17
18
  /** costBySimilarity is a path concept; false disables the cost slot entirely. */
@@ -21,6 +22,8 @@ export declare function SemanticBlockEditor({ draft, onChange, allowCost, costDi
21
22
  costDisabledReason?: string;
22
23
  /** Resolved provider state; null = unknown (no graph shape computed yet). */
23
24
  providerEnabled: boolean | null;
25
+ /** Passed straight to SemanticQueryEditor, which documents it. */
26
+ provider?: EmbeddingProviderStatsREST | null;
24
27
  embeddingNames: string[];
25
28
  idPrefix: string;
26
29
  /** e.g. a stored template is selected — the block cannot apply. */
@@ -1,15 +1,22 @@
1
1
  import type { SemanticQueryDraft } from "../lib/semantic";
2
+ import type { EmbeddingProviderStatsREST } from "../api/types";
2
3
  /**
3
4
  * The semantic QUERY fields (source, vector/text, embedding name, metric) — the one query
4
5
  * every semantic decision of a request scores against. Extracted so the Path screen's
5
6
  * block editor and the Subgraph screen's per-request query section render exactly one
6
7
  * implementation. Pure data — it compiles no C#.
7
8
  */
8
- export declare function SemanticQueryEditor({ query, onChange, providerEnabled, embeddingNames, idPrefix, }: {
9
+ export declare function SemanticQueryEditor({ query, onChange, providerEnabled, provider, embeddingNames, idPrefix, }: {
9
10
  query: SemanticQueryDraft;
10
11
  onChange: (patch: Partial<SemanticQueryDraft>) => void;
11
12
  /** Resolved provider state; null = unknown (no graph shape computed yet). */
12
13
  providerEnabled: boolean | null;
14
+ /**
15
+ * The provider snapshot behind {@link providerEnabled}, when the caller holds it: it names the
16
+ * backend and embedding function that will turn the text into a vector. Optional, so a call
17
+ * site that cannot answer that question simply says nothing.
18
+ */
19
+ provider?: EmbeddingProviderStatsREST | null;
13
20
  embeddingNames: string[];
14
21
  idPrefix: string;
15
22
  }): import("react").JSX.Element;
@@ -1,4 +1,10 @@
1
1
  import type { SettingREST } from "../api/types";
2
+ /** One value a string row can OFFER without requiring it (feature chat-model-catalog). */
3
+ export interface SettingSuggestion {
4
+ value: string;
5
+ /** What is known about it, shown beside the value; omitted when nothing is known. */
6
+ label?: string;
7
+ }
2
8
  export declare const SettingRow: import("react").NamedExoticComponent<{
3
9
  setting: SettingREST;
4
10
  /** The unsaved value, or undefined when this row is untouched. */
@@ -7,4 +13,12 @@ export declare const SettingRow: import("react").NamedExoticComponent<{
7
13
  onClear: (key: string) => void;
8
14
  /** True when the whole editable region is gated off (an embed host locked it). */
9
15
  disabled?: boolean;
16
+ /**
17
+ * Values to offer on a `string` row, as a native combobox. OFFER is the whole contract: a typed
18
+ * value outside the list is not an error, because for a model name the list is not the whole
19
+ * resolvable set. Absent (or empty) leaves the row exactly as it was.
20
+ */
21
+ suggestions?: readonly SettingSuggestion[];
22
+ /** One line under the control, for whoever supplied the suggestions to say why it could not. */
23
+ note?: string;
10
24
  }>;
@@ -1,14 +1,19 @@
1
- import type { StoredQueryKind } from "../api/types";
1
+ import type { StoredQuerySummaryREST } from "../api/types";
2
2
  /**
3
- * Kind-scoped stored-query management (concept spec §5.3): a stored query is unique to its
4
- * scenario — Path or SubGraph — so its management home lives on that scenario's screen, next
5
- * to the fragments it captures. The panel lists ONLY entries of `kind`, with read-only source,
6
- * recompile diagnostics, delete (immutable entries: delete + re-register is the edit flow),
7
- * and a **Use** action that selects the entry into this screen's own filter picker. Capture
8
- * ("Save as stored query…") lives in the inline advanced tier of the same screen.
3
+ * The stored-query library (concept spec §5.3): the WHOLE `/storedquery` collection of the
4
+ * namespace in one table, with a **kind** column naming each entry's scenario. It was always
5
+ * one server-side collection; until feature studio-traverse-merge the Studio rendered it as
6
+ * two kind-scoped panels, one per scenario screen, which hid that fact and split the view.
7
+ *
8
+ * Read-only source, recompile diagnostics, delete (entries are immutable, so delete plus
9
+ * re-register is the edit flow), and a **Use** action that hands the entry back to the host,
10
+ * which selects it into the matching scenario's filter picker. Capture ("Save as stored
11
+ * query…") stays in each scenario's inline advanced tier, next to the fragments it captures.
9
12
  */
10
- export declare function StoredQueriesPanel({ kind, onUse, }: {
11
- kind: StoredQueryKind;
12
- /** Select this entry into the host screen's filter picker (stored source + name). */
13
- onUse: (name: string) => void;
13
+ export declare function StoredQueriesPanel({ onUse, }: {
14
+ /**
15
+ * Select this entry into its scenario's filter picker (stored source + name). The whole
16
+ * entry is handed over, not just the name, because the host has to route it by `kind`.
17
+ */
18
+ onUse: (entry: StoredQuerySummaryREST) => void;
14
19
  }): import("react").JSX.Element;
@@ -2,11 +2,10 @@ import type { StoredPathQueryBlock, StoredQueryKind, StoredSubGraphQueryBlock }
2
2
  import type { InstanceConfig } from "../instances/types";
3
3
  import type { FilterSource } from "../state/instanceStore";
4
4
  /**
5
- * Stored-query surfaces shared by Path and Subgraph (concept spec §5.1/5.2): the
6
- * inline|stored source toggle, the kind-filtered picker with a read-only fragment
5
+ * Stored-query surfaces shared by the two Traverse scenario tabs (concept spec §5.1/5.2):
6
+ * the inline|stored source toggle, the kind-filtered picker with a read-only fragment
7
7
  * preview, and the "Save as stored query…" capture dialog. Management (list, source,
8
- * delete) lives in the kind-scoped Stored queries panel below on the same screen — the
9
- * picker only points there.
8
+ * delete) lives in the Traverse screen's Stored queries tab; the picker only points there.
10
9
  */
11
10
  export declare const REGISTRATION_401 = "registration requires the instance's API key \u2014 configure it on the Connect screen";
12
11
  export declare function FilterSourceToggle({ value, onChange, }: {
@@ -0,0 +1,13 @@
1
+ import type { NlGenerationStats } from "./generate";
2
+ /**
3
+ * One draft's generation stats (nl-assist-ux FR-5), the row UNDER the draft label: the summary
4
+ * line plus the provider's raw fields on demand. Both NL panels render this one component, so
5
+ * the formatter and the markup have a single home.
6
+ *
7
+ * The backend segment is whatever the stats object captured with THIS draft carries, never the
8
+ * live configuration (see lib/modelProvenance.ts). The row sits BELOW the label, not beside it:
9
+ * a same-row block costs the label width the panel's 288px sidebar does not have.
10
+ */
11
+ export declare function NlDraftStats({ stats }: {
12
+ stats: NlGenerationStats;
13
+ }): import("react").JSX.Element;
@@ -26,10 +26,11 @@ export interface NlAssistConfig {
26
26
  maxRetries: number;
27
27
  }
28
28
  /**
29
- * The default model the compose stack pulls for the instance's chat backend (produced by
30
- * nl-assist-finetune). Shown as a hint only; in instance mode the server owns the model, and
31
- * in custom mode the user picks one (see NL_PRESETS). If the chosen model is absent on the
32
- * backend, calls 404 - create it with the training pipeline or pick the stock phi4-mini preset.
29
+ * CUSTOM-MODE ONLY: the prefill for the model field, and the fine-tune the compose stack pulls
30
+ * (produced by nl-assist-finetune). It says nothing about instance mode - the server owns that
31
+ * model and reports it on /status, which is where the panels read it from. If the chosen model is
32
+ * absent on the endpoint, calls 404 - create it with the training pipeline or pick the stock
33
+ * phi4-mini preset.
33
34
  */
34
35
  export declare const DEFAULT_NL_MODEL = "phi4-f8-mini";
35
36
  export declare const DEFAULT_NL_CONFIG: NlAssistConfig;
@@ -34,6 +34,12 @@ export interface NlGenerationStats {
34
34
  completionTokens?: number;
35
35
  durationMs?: number;
36
36
  tokensPerSecond?: number;
37
+ /**
38
+ * Which server-side backend produced THIS draft, from that call's own response. Undefined in
39
+ * custom mode, deliberately: a browser-direct call reaches no Fallen-8, so there is no server
40
+ * selector to report and inventing one would sit a fabricated name beside real ones.
41
+ */
42
+ backend?: string;
37
43
  /** The provider's stats fields verbatim, for the expandable raw view. */
38
44
  raw: Record<string, unknown>;
39
45
  }
@@ -20,7 +20,7 @@ export declare const FIELD_HELP: {
20
20
  readonly lookupKind: "What the id refers to: vertex, edge, or graphelement (either — the server figures out which).";
21
21
  readonly maxElements: "Upper bound on how many elements the bulk view loads from GET /graph. Keep it modest on big graphs — this is a browser, not an export (use JSONL export for that).";
22
22
  readonly bulkFilter: "Client-side filter over the loaded elements: matches an exact id or a substring of the label.";
23
- readonly scanKind: "Property scan walks all elements (no index needed); 'ask an index' picks a registered index and offers the query forms its type answers.";
23
+ readonly scanKind: "Property scan walks all elements (no index needed); 'ask an index' picks a registered index and offers the query forms its type answers; 'semantic search' types words instead, and the embedding provider turns them into the query vector.";
24
24
  readonly propertyScope: "Specific key: scan one named property with an operator and typed literal. Any property: a case-insensitive substring search across EVERY property value (numbers and dates included, compared as text) - a cold, un-indexed full-graph discovery scan.";
25
25
  readonly searchTerm: "The substring to look for across every property value, case-insensitively. An element matches when any of its values contains it.";
26
26
  readonly searchLabel: "Optional: restrict the search to elements with exactly this label. Leave empty to search every label.";
@@ -50,6 +50,8 @@ export declare const FIELD_HELP: {
50
50
  readonly vectorBindEmbeddingName: "Optional: bind this vector index to a named element embedding. A bound index maintains itself as a projection of that embedding — you write embeddings on the elements and the index follows; explicit vector-adds are rejected. Leave empty for a raw (bring-your-own-vector) index.";
51
51
  readonly vectorModel: "Optional model-identity string this index expects its vectors to come from (e.g. 'bge-micro-v2#384#Cosine'). The embedding provider refuses to write mismatched vectors; a search whose provider identity differs answers 409. Diagnostic only for a raw index.";
52
52
  readonly embeddingSearchText: "Search text. The embedding provider embeds it once (server-side), then runs kNN — you never handle the vector. Needs the provider enabled on this instance.";
53
+ readonly semanticIndexId: "The vector index the search ranks against. The list is narrowed to the indices that report the vector family, since only they hold vectors to rank; one bound to an embedding name projects that embedding off your elements and maintains itself.";
54
+ readonly semanticBindEmbedding: "Required here, unlike on the Indexes screen: this index exists so a typed query can rank the embeddings ALREADY on your elements, and only a bound index projects them. Name the embedding they carry ('default' unless you chose otherwise). An unbound index would hold nothing until you pasted vectors into it by hand.";
53
55
  readonly embeddingName: "Name of the embedding to read/write on this element, e.g. 'default'. Letters, digits, underscore, dash; max 64 chars. Different names hold independent vectors (and may differ in dimension).";
54
56
  readonly embeddingVectorPaste: "The embedding vector, pasted as a JSON array or comma-separated floats. The element is the source of truth; any vector index bound to this name updates automatically on save.";
55
57
  readonly embeddingText: "Text to embed onto this element via the server's embedding provider (stored with a model-identity stamp). Needs the provider enabled; otherwise paste a vector.";
@@ -0,0 +1,69 @@
1
+ import type { FileLimits } from "../api/types";
2
+ /**
3
+ * Whether a job's files fit what THIS instance accepts, checked at pick time (feature
4
+ * integration-file-transport).
5
+ *
6
+ * This module is the only place in Studio allowed to reason about file ceilings, and it holds no
7
+ * numbers of its own. Every ceiling arrives from `GET /integrations/limits` already reconciled with
8
+ * the proxy's transport bound, so there is one number per question and nothing to combine. That
9
+ * matters because the version this replaced had a ceiling of its own, about 384 MiB, which sat
10
+ * BELOW the instance's: jobs the instance would have accepted were refused in the browser, and no
11
+ * amount of configuration could fix it.
12
+ *
13
+ * The corollary is the rule for the unknown case. An instance too old to serve the route, or one
14
+ * whose integrations capability is off, leaves the limits undefined, and then NOTHING is checked
15
+ * and nothing is guessed: the send goes ahead and the instance refuses it if it must. A default
16
+ * substituted here would be the same bug again.
17
+ */
18
+ /** Enough of a file to check it, whichever transport carries it later. */
19
+ export interface SizedFile {
20
+ name: string;
21
+ size: number;
22
+ }
23
+ /**
24
+ * The ceilings, or their absence. Absence has three spellings and they all mean the same thing
25
+ * here: the query has not answered yet, it failed, or the instance answered with no body.
26
+ */
27
+ export type MaybeLimits = FileLimits | null | undefined;
28
+ /**
29
+ * What one file setting is being asked to hold, and what the rest of the job already holds.
30
+ *
31
+ * Generic over the incoming type, so a caller passing real `File` handles gets `File`s back with no
32
+ * cast. That is not cosmetic: it is what makes "this only ever filters, it never constructs" a fact
33
+ * the compiler holds rather than a comment somebody has to keep true.
34
+ */
35
+ export interface StagingRequest<T extends SizedFile = SizedFile> {
36
+ /** The ceilings this instance published, or absent when they could not be read. */
37
+ limits: MaybeLimits;
38
+ /** The files being added to ONE file setting, in the order they were picked. */
39
+ incoming: T[];
40
+ /** What that setting already holds. Kept whatever this verdict says. */
41
+ staged?: SizedFile[];
42
+ /** What every OTHER file setting of the same job holds: the total and the count are job-wide. */
43
+ elsewhere?: SizedFile[];
44
+ /** True when the setting declares `multiple`, so its files are read as ONE claimed set. */
45
+ claimedSet?: boolean;
46
+ }
47
+ export interface StagingVerdict<T extends SizedFile = SizedFile> {
48
+ /** The incoming files that may be staged, in pick order. */
49
+ accepted: T[];
50
+ /** One message for the setting's problem channel, or null when there is nothing to say. */
51
+ problem: string | null;
52
+ }
53
+ /**
54
+ * The refusal that keeps a set out of the tab before it is ever sent.
55
+ *
56
+ * Granularity differs between the three ceilings on purpose. A file over the per-file ceiling is
57
+ * individually too big, so it is refused individually and its siblings still stage. A broken TOTAL
58
+ * or COUNT is a property of the whole job, so no single file is at fault and none of the incoming
59
+ * batch is accepted: picking some arbitrary prefix that fits would drop the tail on a decision the
60
+ * person picking never made, and for a claimed set it would silently split the set.
61
+ */
62
+ export declare function checkStaging<T extends SizedFile>(request: StagingRequest<T>): StagingVerdict<T>;
63
+ /**
64
+ * What the form says when it could not read the ceilings. Its job is to stop someone reading the
65
+ * absence of refusals as approval, without naming a number Studio does not know.
66
+ */
67
+ export declare const LIMITS_UNKNOWN_NOTE: string;
68
+ /** The ceilings in one line, for the form to state up front rather than only when refusing. */
69
+ export declare function describeLimits(limits: MaybeLimits): string;
@@ -2,6 +2,14 @@
2
2
  export declare function formatCompact(value: number): string;
3
3
  /** Full number with grouping, for exact values ("10,001,000"). */
4
4
  export declare function formatExact(value: number): string;
5
+ /**
6
+ * A size in bytes, in binary units up to GiB ("0 B", "512 B", "1.5 KiB", "5.8 GiB").
7
+ *
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
10
+ * the reader should not have to do while being told no.
11
+ */
12
+ export declare function formatBytes(bytes: number): string;
5
13
  /**
6
14
  * The one glyph this UI renders for a value the server does not have, so a row cannot mix two
7
15
  * spellings of "absent" in one table and read as two different states.
@@ -0,0 +1,26 @@
1
+ import type { ChatProviderStatsREST, EmbeddingProviderStatsREST } from "../api/types";
2
+ /**
3
+ * How Studio names the model backend that serves a request (feature model-providers).
4
+ *
5
+ * Two kinds of label, and the distinction is the feature:
6
+ * - AMBIENT ("requests will go to X") reads the polled /status block, which describes the
7
+ * CURRENT configuration. {@link chatAmbientLabel} is named so a call site cannot use it by
8
+ * accident where a per-call answer belongs.
9
+ * - PER-CALL reads the `backend` field carried on that call's own response. A draft produced
10
+ * under one backend must keep saying so after the operator switches, so nothing per-call may
11
+ * be derived from here.
12
+ *
13
+ * Neither function invents a name it cannot know: an absent field yields a sentence saying the
14
+ * value is absent, never a plausible default.
15
+ */
16
+ /**
17
+ * The ambient chat destination: `"{backend} · {model}"`, or the reason there is no pair to show.
18
+ * `undefined` means /status has not answered yet, which is a different thing from chat being off.
19
+ */
20
+ export declare function chatAmbientLabel(chat: ChatProviderStatsREST | null | undefined): string;
21
+ /**
22
+ * The embedding function's identity as a reader recognises it: `modelName[@modelVersion]`.
23
+ * A provider that reports no model name is described by its dimension instead, because that is
24
+ * the one property of the vector space still known to be true.
25
+ */
26
+ export declare function embeddingStamp(provider: EmbeddingProviderStatsREST): string;
@@ -8,6 +8,16 @@ import type { PathDraft, SubgraphPatternDraft } from "../state/instanceStore";
8
8
  */
9
9
  /** Server-side name rule: always a safe URL path segment, compared case-sensitively. */
10
10
  export declare const STORED_QUERY_NAME: RegExp;
11
+ /**
12
+ * The draft patch that points a scenario at a stored entry. Every gesture that hands a name
13
+ * back ("Save as stored query…" succeeding, "Use" in the library) means the same two things:
14
+ * switch the source to stored, and select this name. Both path and subgraph drafts carry
15
+ * those two fields, so one home instead of a copy per call site.
16
+ */
17
+ export declare const selectStoredQuery: (name: string) => {
18
+ readonly filterSource: "stored";
19
+ readonly storedQuery: string;
20
+ };
11
21
  /**
12
22
  * The whole spec from a draft — stored and inline fragments never travel together. The
13
23
  * semantic block (feature element-embeddings) attaches regardless of the filter source
@@ -0,0 +1,49 @@
1
+ import type { EmbeddingProviderStatsREST, PropertySpecification } from "../api/types";
2
+ /**
3
+ * What a NEW vector index is created with, in one place: two screens create one (the Indexes
4
+ * screen's create panel and the Query screen's semantic on-ramp, feature
5
+ * semantic-search-onramp) and the numbers are not a preference. A bound index whose dimension
6
+ * or metric disagrees with the model writing into it is refused on every later embed and every
7
+ * later search, so the provider is the authority and guessing it twice is how the two copies
8
+ * would drift.
9
+ */
10
+ /**
11
+ * Fallbacks for a server that reports no usable provider. Not a recommendation: a shape the
12
+ * engine accepts, so the form has something to submit while saying (at the call site) that
13
+ * these are defaults rather than the instance's own numbers.
14
+ */
15
+ export declare const VECTOR_INDEX_FALLBACK: {
16
+ readonly dimension: "384";
17
+ readonly metric: "Cosine";
18
+ };
19
+ export interface VectorIndexDefaults {
20
+ /** The provider is on AND names a dimension, so its numbers are the authoritative ones. */
21
+ providerReady: boolean;
22
+ dimension: string;
23
+ metric: string;
24
+ }
25
+ /** The dimension + metric a new vector index should default to on this instance. */
26
+ export declare function vectorIndexDefaults(provider: EmbeddingProviderStatsREST | null | undefined): VectorIndexDefaults;
27
+ /** The engine's own bounds on a vector index's dimension (VectorIndex.Initialize). */
28
+ export declare const VECTOR_DIMENSION_RANGE: {
29
+ readonly min: 1;
30
+ readonly max: 4096;
31
+ };
32
+ /**
33
+ * Whether this dimension is one the engine will take. The number input's `min`/`max` are not
34
+ * enough on their own: neither attribute blocks an EMPTY field, and neither is consulted at all
35
+ * unless the button is a submit. An empty value travels as `propertyValue: ""` against
36
+ * `System.Int32`, which the server cannot convert, so the round trip is spent to be told so.
37
+ */
38
+ export declare function isValidVectorDimension(dimension: string): boolean;
39
+ /**
40
+ * The `pluginOptions` of POST /index for a vector index. Options travel as typed literals
41
+ * (vector-index README §creation), and embeddingName/model are emitted only when set, so a raw
42
+ * index keeps exactly the two-option shape (pinned by index-management.test.tsx).
43
+ */
44
+ export declare function vectorIndexPluginOptions(options: {
45
+ dimension: string;
46
+ metric: string;
47
+ embeddingName?: string;
48
+ model?: string;
49
+ }): Record<string, PropertySpecification>;
@@ -5,5 +5,8 @@
5
5
  * editor - /path swallows compile errors, so an empty result here is "no paths found",
6
6
  * never an error (FR-13). Filters come from inline fragments or a stored query — the
7
7
  * source toggle keeps the two mutually exclusive (concept spec §5.1).
8
+ *
9
+ * Rendered as the "Path finding" tab of the Traverse screen (feature studio-traverse-merge),
10
+ * which also owns the stored-query library this screen used to host at its foot.
8
11
  */
9
12
  export declare function PathScreen(): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function TraverseScreen(): import("react").JSX.Element;
@@ -67,6 +67,19 @@ export interface ResultSet {
67
67
  }
68
68
  /** Where a path/subgraph run takes its fragments from (concept spec §5.1). */
69
69
  export type FilterSource = "inline" | "stored";
70
+ /**
71
+ * The tabs of the merged Traverse screen (feature studio-traverse-merge), in strip order.
72
+ * ONE home for the ids: the tab strip renders them, the route validates `?tab=` against them,
73
+ * and the persisted `traverseTab` remembers the last one per instance-and-namespace.
74
+ */
75
+ export declare const TRAVERSE_TABS: readonly ["path", "subgraph", "stored"];
76
+ export type TraverseTab = (typeof TRAVERSE_TABS)[number];
77
+ /** The tab a fresh workspace opens on: path finding is the more frequent scenario. */
78
+ export declare const DEFAULT_TRAVERSE_TAB: TraverseTab;
79
+ /** Guard for the two untrusted sources of a tab id: the `?tab=` search param and storage. */
80
+ export declare const isTraverseTab: (value: unknown) => value is TraverseTab;
81
+ /** The scenario tab a stored query of this kind belongs to (its `kind` is `string | null`). */
82
+ export declare const traverseTabForKind: (kind: string | null | undefined) => TraverseTab;
70
83
  export interface PathDraft {
71
84
  from: string;
72
85
  to: string;
@@ -85,13 +98,23 @@ export interface PathDraft {
85
98
  semantic: SemanticDraft;
86
99
  }
87
100
  export declare const DEFAULT_PATH_DRAFT: PathDraft;
101
+ /** The Query screen's three ways of asking (feature index-workspace / semantic-search-onramp). */
102
+ export declare const QUERY_MODES: readonly ["property", "index", "semantic"];
103
+ export type QueryMode = (typeof QUERY_MODES)[number];
88
104
  /**
89
105
  * The Query screen's whole input form (feature index-workspace). Persisted per instance
90
106
  * so leaving for the Canvas and coming back restores it exactly — results are re-run on
91
107
  * demand (kept out of the lean persisted store). Reset via the screen's Clear button.
92
108
  */
93
109
  export interface QueryDraft {
94
- mode: "property" | "index";
110
+ /**
111
+ * "semantic" is text-in kNN (feature semantic-search-onramp): its own mode rather than a
112
+ * source toggle inside the index mode's vector form, because a capability reachable only
113
+ * after picking the right index is one nobody finds. It shares the kNN parameters below
114
+ * with that form - same question, different query source - but NOT the index, which is
115
+ * drawn from a different set (see semanticIndexId).
116
+ */
117
+ mode: QueryMode;
95
118
  /** Property-scan scope: one named "key" (typed operator) or "any" property (contains search). */
96
119
  propertyScope: "key" | "any";
97
120
  propertyId: string;
@@ -100,6 +123,13 @@ export interface QueryDraft {
100
123
  /** All-property search label restrictor (propertyScope === "any"); empty scans every label. */
101
124
  searchLabel: string;
102
125
  indexId: string;
126
+ /**
127
+ * The semantic mode's index, kept apart from `indexId` because the two modes choose from
128
+ * different sets: every registered index there, only the ones that can rank a vector here.
129
+ * Sharing one field meant picking a vector index for a semantic search silently replaced the
130
+ * operator's index-mode selection AND the query form that went with it.
131
+ */
132
+ semanticIndexId: string;
103
133
  form: IndexCapability;
104
134
  operator: BinaryOperatorName;
105
135
  resultType: "Vertices" | "Edges" | "Both";
@@ -111,14 +141,23 @@ export interface QueryDraft {
111
141
  fulltextQuery: string;
112
142
  spatialElementId: string;
113
143
  spatialDistance: string;
144
+ /** The pasted query vector (index mode, vector form); the semantic mode never uses it. */
114
145
  vectorText: string;
115
146
  vectorK: string;
116
147
  vectorKind: "any" | "vertex" | "edge";
117
148
  vectorLabel: string;
118
- vectorSource: "vector" | "text";
149
+ /** The query text of the semantic mode, embedded once server-side. */
119
150
  vectorSearchText: string;
120
151
  }
121
152
  export declare const DEFAULT_QUERY_DRAFT: QueryDraft;
153
+ /**
154
+ * Rehydrates a persisted Query draft. Text-in kNN used to be a `vectorSource` toggle INSIDE the
155
+ * index mode's vector form; feature semantic-search-onramp made it its own mode, so a draft
156
+ * written by an older build is LIFTED rather than dropped: the text, k, kind and label are the
157
+ * same question asked the same way, and only the route to the form changed. The stale key is
158
+ * stripped instead of spread through, so nothing carries a field this build has no meaning for.
159
+ */
160
+ export declare function migrateQueryDraft(persisted: Partial<QueryDraft> | undefined): QueryDraft;
122
161
  /**
123
162
  * One pattern row of the subgraph builder: a pattern spec plus a stable list key and the
124
163
  * step's vertex-slot state (feature subgraph-semantic-thresholds) — the slot MODE and the
@@ -246,6 +285,13 @@ export interface WorkspaceState {
246
285
  browserDraft: BrowserDraft;
247
286
  analyticsDraft: AnalyticsDraft;
248
287
  canvasToolsDraft: CanvasToolsDraft;
288
+ /**
289
+ * The Traverse tab last left open (feature studio-traverse-merge). Persisted rather than
290
+ * URL-only because switching namespace or instance rewrites the leaf WITHOUT the search
291
+ * param (see app/scopedRoute.ts), and being dumped on another tab by a context switch is
292
+ * the same "lose what you were looking at" the switchers exist to avoid.
293
+ */
294
+ traverseTab: TraverseTab;
249
295
  scanPrefill: ScanPrefill | null;
250
296
  mergeIntoCanvas: (vertices: VertexREST[], edges: EdgeREST[]) => void;
251
297
  removeFromCanvas: (kind: "node" | "edge", id: number) => void;
@@ -266,6 +312,7 @@ export interface WorkspaceState {
266
312
  setAnalyticsDraft: (patch: Partial<AnalyticsDraft>) => void;
267
313
  resetAnalyticsDraft: () => void;
268
314
  setCanvasToolsDraft: (patch: Partial<CanvasToolsDraft>) => void;
315
+ setTraverseTab: (tab: TraverseTab) => void;
269
316
  setScanPrefill: (prefill: ScanPrefill | null) => void;
270
317
  setFeedFilter: (patch: Partial<FeedFilterDraft>) => void;
271
318
  setInspectPrefill: (id: number | null) => void;
@@ -1,5 +1,5 @@
1
1
  import type { InstanceConfig } from "../instances/types";
2
- import type { IntegrationProvider } from "../api/types";
2
+ import type { FileLimits, IntegrationProvider } from "../api/types";
3
3
  /**
4
4
  * The integrations capability of one instance (feature integrations), read from the one route that
5
5
  * answers it: the provider catalog.
@@ -15,6 +15,16 @@ import type { IntegrationProvider } from "../api/types";
15
15
  */
16
16
  export type IntegrationsCapability = "checking" | "available" | "absent" | "unreachable";
17
17
  export declare function useIntegrationProviders(instance: InstanceConfig | null): import("@tanstack/react-query").UseQueryResult<NoInfer<IntegrationProvider[] | null>, unknown>;
18
+ /**
19
+ * What a job may carry on this instance (feature integration-file-transport). Read once per
20
+ * instance and held for the session: the ceilings come from configuration, so they change when the
21
+ * instance is redeployed and never while a screen is open.
22
+ *
23
+ * It fails softly on purpose. An instance too old to serve the route answers 404, and a form that
24
+ * cannot read the ceilings must check NOTHING rather than fall back to a number of its own - see
25
+ * `lib/fileLimits.ts`, which is the only place allowed to interpret the absence.
26
+ */
27
+ export declare function useIntegrationLimits(instance: InstanceConfig | null): import("@tanstack/react-query").UseQueryResult<NoInfer<FileLimits | null>, unknown>;
18
28
  /** Whether a failure is the capability being off rather than the instance being unwell. */
19
29
  export declare function isCapabilityRefusal(error: unknown): boolean;
20
30
  /** The capability verdict of a providers query, for the rail and for a deep link. */
@@ -1,4 +1,4 @@
1
- import { m as s } from "./index-CQF9rZdm.js";
1
+ import { m as s } from "./index-0ioFtrZM.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-CQF9rZdm.js";
1
+ import { m as r } from "./index-0ioFtrZM.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-CQF9rZdm.js";
1
+ import { m as l } from "./index-0ioFtrZM.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.36",
3
+ "version": "0.0.38",
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",