@intentface/ui 0.0.0 → 0.7.0

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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -2
  3. package/dist/ask-user/ask-user.d.ts +104 -0
  4. package/dist/ask-user/ask-user.js +245 -0
  5. package/dist/ask-user/index.d.ts +3 -0
  6. package/dist/ask-user/index.js +3 -0
  7. package/dist/ask-user/index.parts.d.ts +1 -0
  8. package/dist/ask-user/index.parts.js +5 -0
  9. package/dist/attachments/attachments.d.ts +73 -0
  10. package/dist/attachments/attachments.js +121 -0
  11. package/dist/attachments/index.d.ts +3 -0
  12. package/dist/attachments/index.js +3 -0
  13. package/dist/attachments/index.parts.d.ts +1 -0
  14. package/dist/attachments/index.parts.js +5 -0
  15. package/dist/chip/chip.d.ts +45 -0
  16. package/dist/chip/chip.js +43 -0
  17. package/dist/chip/index.d.ts +2 -0
  18. package/dist/chip/index.js +2 -0
  19. package/dist/chip/index.parts.d.ts +1 -0
  20. package/dist/chip/index.parts.js +5 -0
  21. package/dist/chip-markdown.d.ts +25 -0
  22. package/dist/chip-markdown.js +54 -0
  23. package/dist/composer/actions.d.ts +35 -0
  24. package/dist/composer/actions.js +76 -0
  25. package/dist/composer/ask-user-machine.d.ts +52 -0
  26. package/dist/composer/ask-user-machine.js +164 -0
  27. package/dist/composer/attachments-machine.d.ts +34 -0
  28. package/dist/composer/attachments-machine.js +91 -0
  29. package/dist/composer/attachments.d.ts +16 -0
  30. package/dist/composer/attachments.js +32 -0
  31. package/dist/composer/command-list.d.ts +49 -0
  32. package/dist/composer/command-list.js +360 -0
  33. package/dist/composer/commands.d.ts +28 -0
  34. package/dist/composer/commands.js +56 -0
  35. package/dist/composer/container.d.ts +3 -0
  36. package/dist/composer/container.js +32 -0
  37. package/dist/composer/controller.d.ts +3 -0
  38. package/dist/composer/controller.js +6 -0
  39. package/dist/composer/editor-dom.d.ts +57 -0
  40. package/dist/composer/editor-dom.js +517 -0
  41. package/dist/composer/fuzzy.d.ts +4 -0
  42. package/dist/composer/fuzzy.js +49 -0
  43. package/dist/composer/index.d.ts +25 -0
  44. package/dist/composer/index.js +13 -0
  45. package/dist/composer/index.parts.d.ts +11 -0
  46. package/dist/composer/index.parts.js +15 -0
  47. package/dist/composer/internals.d.ts +30 -0
  48. package/dist/composer/internals.js +102 -0
  49. package/dist/composer/keyboard.d.ts +61 -0
  50. package/dist/composer/keyboard.js +75 -0
  51. package/dist/composer/panel.d.ts +28 -0
  52. package/dist/composer/panel.js +76 -0
  53. package/dist/composer/placeholder.d.ts +10 -0
  54. package/dist/composer/placeholder.js +8 -0
  55. package/dist/composer/popover.d.ts +12 -0
  56. package/dist/composer/popover.js +62 -0
  57. package/dist/composer/prefix-detection.d.ts +23 -0
  58. package/dist/composer/prefix-detection.js +67 -0
  59. package/dist/composer/root.d.ts +21 -0
  60. package/dist/composer/root.js +124 -0
  61. package/dist/composer/segments.d.ts +108 -0
  62. package/dist/composer/segments.js +366 -0
  63. package/dist/composer/store.d.ts +98 -0
  64. package/dist/composer/store.js +457 -0
  65. package/dist/composer/textarea.d.ts +39 -0
  66. package/dist/composer/textarea.js +64 -0
  67. package/dist/composer/trigger-tracker.d.ts +12 -0
  68. package/dist/composer/trigger-tracker.js +90 -0
  69. package/dist/composer/types.d.ts +127 -0
  70. package/dist/composer/types.js +4 -0
  71. package/dist/composer/use-composer-editor.d.ts +43 -0
  72. package/dist/composer/use-composer-editor.js +653 -0
  73. package/dist/generative/catalog.d.ts +177 -0
  74. package/dist/generative/catalog.js +20 -0
  75. package/dist/generative/index.d.ts +26 -0
  76. package/dist/generative/index.js +20 -0
  77. package/dist/generative/json-schema.d.ts +45 -0
  78. package/dist/generative/json-schema.js +216 -0
  79. package/dist/generative/markdown.d.ts +21 -0
  80. package/dist/generative/markdown.js +76 -0
  81. package/dist/generative/tree.d.ts +56 -0
  82. package/dist/generative/tree.js +365 -0
  83. package/dist/generative/use-tree.d.ts +12 -0
  84. package/dist/generative/use-tree.js +64 -0
  85. package/dist/internal/change-event-details.d.ts +12 -0
  86. package/dist/internal/change-event-details.js +16 -0
  87. package/dist/internal/collapsible.d.ts +22 -0
  88. package/dist/internal/collapsible.js +94 -0
  89. package/dist/internal/collection.d.ts +32 -0
  90. package/dist/internal/collection.js +72 -0
  91. package/dist/internal/iso-layout-effect.d.ts +2 -0
  92. package/dist/internal/iso-layout-effect.js +6 -0
  93. package/dist/internal/portal.d.ts +6 -0
  94. package/dist/internal/portal.js +18 -0
  95. package/dist/internal/primitive-props.d.ts +4 -0
  96. package/dist/internal/primitive-props.js +3 -0
  97. package/dist/internal/render/baseTypes.d.ts +18 -0
  98. package/dist/internal/render/baseTypes.js +4 -0
  99. package/dist/internal/render/empty.d.ts +3 -0
  100. package/dist/internal/render/empty.js +5 -0
  101. package/dist/internal/render/getReactElementRef.d.ts +5 -0
  102. package/dist/internal/render/getReactElementRef.js +15 -0
  103. package/dist/internal/render/getStateAttributesProps.d.ts +4 -0
  104. package/dist/internal/render/getStateAttributesProps.js +23 -0
  105. package/dist/internal/render/mergeObjects.d.ts +1 -0
  106. package/dist/internal/render/mergeObjects.js +14 -0
  107. package/dist/internal/render/mergeProps.d.ts +55 -0
  108. package/dist/internal/render/mergeProps.js +183 -0
  109. package/dist/internal/render/positioning.d.ts +33 -0
  110. package/dist/internal/render/positioning.js +112 -0
  111. package/dist/internal/render/reactVersion.d.ts +3 -0
  112. package/dist/internal/render/reactVersion.js +7 -0
  113. package/dist/internal/render/resolveClassName.d.ts +8 -0
  114. package/dist/internal/render/resolveClassName.js +12 -0
  115. package/dist/internal/render/resolveStyle.d.ts +8 -0
  116. package/dist/internal/render/resolveStyle.js +12 -0
  117. package/dist/internal/render/transition.d.ts +47 -0
  118. package/dist/internal/render/transition.js +259 -0
  119. package/dist/internal/render/types.d.ts +74 -0
  120. package/dist/internal/render/types.js +3 -0
  121. package/dist/internal/render/useMergedRefs.d.ts +21 -0
  122. package/dist/internal/render/useMergedRefs.js +102 -0
  123. package/dist/internal/render/useRefWithInit.d.ts +10 -0
  124. package/dist/internal/render/useRefWithInit.js +12 -0
  125. package/dist/internal/render/useRender.d.ts +71 -0
  126. package/dist/internal/render/useRender.js +12 -0
  127. package/dist/internal/render/useRenderElement.d.ts +62 -0
  128. package/dist/internal/render/useRenderElement.js +157 -0
  129. package/dist/internal/render/warn.d.ts +1 -0
  130. package/dist/internal/render/warn.js +15 -0
  131. package/dist/internal/safe-polygon.d.ts +21 -0
  132. package/dist/internal/safe-polygon.js +179 -0
  133. package/dist/internal/scroll-into-view-within.d.ts +1 -0
  134. package/dist/internal/scroll-into-view-within.js +26 -0
  135. package/dist/internal/standard-schema.d.ts +38 -0
  136. package/dist/internal/standard-schema.js +4 -0
  137. package/dist/internal/state-mappings.d.ts +8 -0
  138. package/dist/internal/state-mappings.js +17 -0
  139. package/dist/internal/use-controlled.d.ts +19 -0
  140. package/dist/internal/use-controlled.js +33 -0
  141. package/dist/message/index.d.ts +3 -0
  142. package/dist/message/index.js +3 -0
  143. package/dist/message/index.parts.d.ts +1 -0
  144. package/dist/message/index.parts.js +5 -0
  145. package/dist/message/message.d.ts +58 -0
  146. package/dist/message/message.js +93 -0
  147. package/dist/message-utils.d.ts +55 -0
  148. package/dist/message-utils.js +79 -0
  149. package/dist/nav/index.d.ts +4 -0
  150. package/dist/nav/index.js +5 -0
  151. package/dist/nav/index.parts.d.ts +3 -0
  152. package/dist/nav/index.parts.js +7 -0
  153. package/dist/nav/nav.d.ts +152 -0
  154. package/dist/nav/nav.js +660 -0
  155. package/dist/nav/store.d.ts +50 -0
  156. package/dist/nav/store.js +95 -0
  157. package/dist/reasoning/index.d.ts +3 -0
  158. package/dist/reasoning/index.js +3 -0
  159. package/dist/reasoning/index.parts.d.ts +1 -0
  160. package/dist/reasoning/index.parts.js +5 -0
  161. package/dist/reasoning/reasoning.d.ts +38 -0
  162. package/dist/reasoning/reasoning.js +67 -0
  163. package/dist/shell/index.d.ts +5 -0
  164. package/dist/shell/index.js +5 -0
  165. package/dist/shell/index.parts.d.ts +3 -0
  166. package/dist/shell/index.parts.js +7 -0
  167. package/dist/shell/shell.d.ts +108 -0
  168. package/dist/shell/shell.js +390 -0
  169. package/dist/shell/store.d.ts +112 -0
  170. package/dist/shell/store.js +134 -0
  171. package/dist/steps/index.d.ts +2 -0
  172. package/dist/steps/index.js +2 -0
  173. package/dist/steps/index.parts.d.ts +1 -0
  174. package/dist/steps/index.parts.js +5 -0
  175. package/dist/steps/steps.d.ts +90 -0
  176. package/dist/steps/steps.js +116 -0
  177. package/dist/tabs/anchored.d.ts +59 -0
  178. package/dist/tabs/anchored.js +109 -0
  179. package/dist/tabs/hover.d.ts +33 -0
  180. package/dist/tabs/hover.js +169 -0
  181. package/dist/tabs/index.d.ts +5 -0
  182. package/dist/tabs/index.js +4 -0
  183. package/dist/tabs/index.parts.d.ts +4 -0
  184. package/dist/tabs/index.parts.js +8 -0
  185. package/dist/tabs/store.d.ts +131 -0
  186. package/dist/tabs/store.js +248 -0
  187. package/dist/tabs/tabs.d.ts +217 -0
  188. package/dist/tabs/tabs.js +458 -0
  189. package/dist/thread/geometry.d.ts +23 -0
  190. package/dist/thread/geometry.js +48 -0
  191. package/dist/thread/index.d.ts +4 -0
  192. package/dist/thread/index.js +3 -0
  193. package/dist/thread/index.parts.d.ts +1 -0
  194. package/dist/thread/index.parts.js +5 -0
  195. package/dist/thread/stores.d.ts +21 -0
  196. package/dist/thread/stores.js +63 -0
  197. package/dist/thread/thread.d.ts +57 -0
  198. package/dist/thread/thread.js +663 -0
  199. package/dist/types.d.ts +58 -0
  200. package/dist/types.js +17 -0
  201. package/package.json +120 -4
@@ -0,0 +1,177 @@
1
+ import type { InferInput, InferOutput, StandardJSONSchema, StandardSchema } from "../internal/standard-schema.js";
2
+ export type JsonObject = Record<string, unknown>;
3
+ export declare const isObject: (value: unknown) => value is Record<string, unknown>;
4
+ /**
5
+ * A component's schema: it validates the props, and converts to the JSON
6
+ * Schema the model is shown. zod 4.2+ and ArkType 2.1.28+ do both; Valibot
7
+ * through `toStandardJsonSchema`.
8
+ */
9
+ export type ComponentSchema = StandardSchema & StandardJSONSchema;
10
+ type BindKey<Schema extends ComponentSchema> = unknown extends InferOutput<Schema> ? string : keyof InferOutput<Schema> & string;
11
+ /** One component the model may use. */
12
+ export type ComponentDefinition<Schema extends ComponentSchema = ComponentSchema> = {
13
+ /** When to use it, written for the model. */
14
+ description: string;
15
+ /** Validates its props, and converts to the JSON Schema the model is shown. */
16
+ props: Schema;
17
+ /** Whether it holds other components. */
18
+ container?: boolean;
19
+ /** Props the model may point at data (`{ "$data": ref }`) instead of writing out. */
20
+ bind?: readonly BindKey<Schema>[];
21
+ /** How it reads as Markdown. `children` is its children's Markdown. */
22
+ markdown?(props: InferOutput<Schema>, children: string): string;
23
+ };
24
+ /** The components the model may use, by type. */
25
+ export type Catalog<Schemas extends Record<string, ComponentSchema> = Record<string, ComponentSchema>> = {
26
+ components: {
27
+ [Type in keyof Schemas]: ComponentDefinition<Schemas[Type]>;
28
+ };
29
+ /** Caps on one call: shown to the model in the tool's schema, and checked. */
30
+ limits?: Partial<Limits>;
31
+ /** What a ref looks like, in the model's terms. */
32
+ refDescription?: string;
33
+ };
34
+ type NoOtherKeys<Components> = {
35
+ [Type in keyof Components]: {
36
+ [Key in Exclude<keyof Components[Type], keyof ComponentDefinition>]: never;
37
+ };
38
+ };
39
+ /**
40
+ * Types a catalog from each component's schema. The catalog stays plain data,
41
+ * typed exactly as written, so the props each component binds are known too.
42
+ */
43
+ export declare const defineCatalog: <Schemas extends Record<string, ComponentSchema>, const Written extends {
44
+ components: Record<string, unknown>;
45
+ }>(catalog: Written & Catalog<Schemas> & {
46
+ components: NoOtherKeys<Written["components"]>;
47
+ }) => Written;
48
+ /** Any catalog: the bound for the helpers' type parameters, so every typed catalog fits. */
49
+ export type AnyCatalog = {
50
+ components: Record<string, {
51
+ description: string;
52
+ props: ComponentSchema;
53
+ container?: boolean;
54
+ bind?: readonly string[];
55
+ markdown?(props: never, children: string): string;
56
+ }>;
57
+ limits?: Partial<Limits>;
58
+ refDescription?: string;
59
+ };
60
+ /** One component of any catalog, as the helpers read it. */
61
+ export type AnyComponent = AnyCatalog["components"][string];
62
+ /**
63
+ * The component a type names, if it's one of the catalog's own. A name the
64
+ * catalog only inherits, such as `"constructor"`, is not a component.
65
+ */
66
+ export declare const componentOf: (catalog: AnyCatalog, type: unknown) => AnyComponent | undefined;
67
+ type ComponentType<C extends AnyCatalog> = keyof C["components"] & string;
68
+ type PropsOf<C extends AnyCatalog, Type extends ComponentType<C>> = InferOutput<C["components"][Type]["props"]>;
69
+ /** The props a component binds, from its `bind` as written. */
70
+ type BoundKey<C extends AnyCatalog, Type extends ComponentType<C>> = C["components"][Type] extends {
71
+ bind?: infer Keys;
72
+ } ? Keys extends readonly (infer Key)[] ? Key : never : never;
73
+ /** A component's props in a checked tree: a prop it binds may still hold its binding. */
74
+ type CheckedProps<C extends AnyCatalog, Type extends ComponentType<C>> = unknown extends PropsOf<C, Type> ? unknown : {
75
+ [Key in keyof PropsOf<C, Type>]: Key extends BoundKey<C, Type> ? PropsOf<C, Type>[Key] | Binding : PropsOf<C, Type>[Key];
76
+ };
77
+ /** One element of a checked tree. A prop its component binds may still hold its `Binding`. */
78
+ export type TreeElement<C extends AnyCatalog = AnyCatalog> = {
79
+ [Type in ComponentType<C>]: {
80
+ type: Type;
81
+ props: CheckedProps<C, Type>;
82
+ children?: string[];
83
+ };
84
+ }[ComponentType<C>];
85
+ /** One element of a resolved tree: every prop holds its data. */
86
+ export type ResolvedTreeElement<C extends AnyCatalog = AnyCatalog> = {
87
+ [Type in ComponentType<C>]: {
88
+ type: Type;
89
+ props: PropsOf<C, Type>;
90
+ children?: string[];
91
+ };
92
+ }[ComponentType<C>];
93
+ interface TreeOf<Element> {
94
+ root: string;
95
+ elements: Record<string, Element>;
96
+ }
97
+ /** A checked call: the root's id and every element by id. Plain JSON, safe to store. */
98
+ export type Tree<C extends AnyCatalog = AnyCatalog> = TreeOf<TreeElement<C>>;
99
+ /** A checked call with its bindings resolved, as `bindings.resolve` returns it. */
100
+ export type ResolvedTree<C extends AnyCatalog = AnyCatalog> = TreeOf<ResolvedTreeElement<C>>;
101
+ type BindingInput = {
102
+ $data: string;
103
+ columns?: string[] | null;
104
+ column?: string | null;
105
+ };
106
+ /** A component's props as its schema takes them in. */
107
+ type InputPropsOf<C extends AnyCatalog, Type extends ComponentType<C>> = InferInput<C["components"][Type]["props"]>;
108
+ /** A component's props as the model writes them, per the tool's schema. */
109
+ type InputProps<C extends AnyCatalog, Type extends ComponentType<C>> = unknown extends InputPropsOf<C, Type> ? unknown : {
110
+ [Key in keyof InputPropsOf<C, Type>]: InputPropsOf<C, Type>[Key] | (Key extends BoundKey<C, Type> ? BindingInput : never) | (undefined extends InputPropsOf<C, Type>[Key] ? null : never);
111
+ };
112
+ /** Whether a component holds children, from its `container` as written. */
113
+ type IsContainer<C extends AnyCatalog, Type extends ComponentType<C>> = C["components"][Type] extends {
114
+ container: true;
115
+ } ? true : false;
116
+ /**
117
+ * One component on its own, as the model writes it when the tool's schema
118
+ * comes from `tree.schema(catalog, { single: true })`.
119
+ */
120
+ export type ComponentInput<C extends AnyCatalog = AnyCatalog> = {
121
+ [Type in ComponentType<C>]: {
122
+ type: Type;
123
+ props: InputProps<C, Type>;
124
+ };
125
+ }[ComponentType<C>];
126
+ /** A call as the model writes it, per `tree.schema(catalog)`, which types a tool's input with it. */
127
+ export type TreeInput<C extends AnyCatalog = AnyCatalog> = {
128
+ root: string;
129
+ elements: {
130
+ [Type in ComponentType<C>]: {
131
+ id: string;
132
+ type: Type;
133
+ props: InputProps<C, Type>;
134
+ } & (IsContainer<C, Type> extends true ? {
135
+ children: string[];
136
+ } : unknown);
137
+ }[ComponentType<C>][];
138
+ };
139
+ /** One node, ready to draw. Its props are typed once its status is `ready`. */
140
+ export type TreeNode<C extends AnyCatalog = AnyCatalog> = {
141
+ [Type in ComponentType<C>]: {
142
+ id: string;
143
+ type: Type;
144
+ status: "ready";
145
+ props: PropsOf<C, Type>;
146
+ children: TreeNode<C>[];
147
+ } | {
148
+ id: string;
149
+ type: Type;
150
+ status: "pending";
151
+ props: unknown;
152
+ children: TreeNode<C>[];
153
+ };
154
+ }[ComponentType<C>];
155
+ /** Caps on one call. The node and children caps are also in the tool's schema. */
156
+ export type Limits = {
157
+ nodes: number;
158
+ depth: number;
159
+ children: number;
160
+ };
161
+ export declare const DEFAULT_LIMITS: Limits;
162
+ /** A catalog's limits, each one it leaves out at its default. */
163
+ export declare const limitsOf: (catalog: AnyCatalog) => Limits;
164
+ /** Data by reference: a tool result's ref, and the columns to pick from its rows. */
165
+ export type Binding = {
166
+ $data: string;
167
+ columns?: string[];
168
+ column?: string;
169
+ };
170
+ /** A binding found in a tree, and where it sits. */
171
+ export type FoundBinding = Binding & {
172
+ id: string;
173
+ prop: string;
174
+ };
175
+ export declare const DEFAULT_REF_DESCRIPTION = "Where the data comes from: its ref, exactly as given.";
176
+ export declare const isBinding: (value: unknown) => value is Binding;
177
+ export {};
@@ -0,0 +1,20 @@
1
+ // The catalog and the shapes the generative helpers read and return: what the
2
+ // model may use, the tree it writes, and the small lookups over both.
3
+ export const isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4
+ /**
5
+ * Types a catalog from each component's schema. The catalog stays plain data,
6
+ * typed exactly as written, so the props each component binds are known too.
7
+ */
8
+ export const defineCatalog = (catalog) => catalog;
9
+ /**
10
+ * The component a type names, if it's one of the catalog's own. A name the
11
+ * catalog only inherits, such as `"constructor"`, is not a component.
12
+ */
13
+ export const componentOf = (catalog, type) => typeof type === "string" && Object.hasOwn(catalog.components, type)
14
+ ? catalog.components[type]
15
+ : undefined;
16
+ export const DEFAULT_LIMITS = { nodes: 40, depth: 6, children: 24 };
17
+ /** A catalog's limits, each one it leaves out at its default. */
18
+ export const limitsOf = (catalog) => ({ ...DEFAULT_LIMITS, ...catalog.limits });
19
+ export const DEFAULT_REF_DESCRIPTION = "Where the data comes from: its ref, exactly as given.";
20
+ export const isBinding = (value) => isObject(value) && typeof value.$data === "string";
@@ -0,0 +1,26 @@
1
+ export { type AnyCatalog, type Binding, type Catalog, type ComponentDefinition, type ComponentSchema, DEFAULT_LIMITS, DEFAULT_REF_DESCRIPTION, defineCatalog, type FoundBinding, isBinding, type Limits, type ResolvedTree, type ResolvedTreeElement, type Tree, type TreeElement, type TreeNode, } from "./catalog.js";
2
+ export type { TreeSchemaOptions } from "./json-schema.js";
3
+ export type { ReadTreeOptions, ResolvedTreeResult, TreeIssue, TreeIssueCode, TreeRead, TreeResult, } from "./tree.js";
4
+ export { type UseTreeOptions, useTree } from "./use-tree.js";
5
+ /** What the model writes: its schema, a whole call checked, a partial one read, and issues worded for the model. */
6
+ export declare const tree: {
7
+ schema: <C extends import("./catalog.js").AnyCatalog, const Options extends import("./json-schema.js").TreeSchemaOptions = import("./json-schema.js").TreeSchemaOptions>(catalog: C, options?: Options) => import("./json-schema.js").TreeSchema<Options extends {
8
+ single: true;
9
+ } ? import("./catalog.js").ComponentInput<C> : import("./catalog.js").TreeInput<C>>;
10
+ validate: <C extends import("./catalog.js").AnyCatalog>(input: unknown, catalog: C) => Promise<import("./tree.js").TreeResult<C>>;
11
+ read: <C extends import("./catalog.js").AnyCatalog>(input: unknown, catalog: C, options?: import("./tree.js").ReadTreeOptions) => import("./tree.js").TreeRead<C>;
12
+ formatIssues: (issues: readonly import("./tree.js").TreeIssue[], max?: number) => string;
13
+ };
14
+ /** Data by reference: the bindings in a tree, and the tree with their data in place. */
15
+ export declare const bindings: {
16
+ find: <C extends import("./catalog.js").AnyCatalog>(tree: import("./catalog.js").Tree<C>) => import("./catalog.js").FoundBinding[];
17
+ resolve: <C extends import("./catalog.js").AnyCatalog>(tree: import("./catalog.js").Tree<C>, catalog: C, resolve: (binding: import("./catalog.js").FoundBinding) => unknown | Promise<unknown>) => Promise<import("./tree.js").ResolvedTreeResult<C>>;
18
+ };
19
+ /** A tree as Markdown, and the helpers that keep text the model wrote literal in it. */
20
+ export declare const markdown: {
21
+ tree: <C extends import("./catalog.js").AnyCatalog>(tree: import("./catalog.js").Tree<C>, catalog: C) => string;
22
+ text: (text: string) => string;
23
+ paragraph: (text: string) => string;
24
+ heading: (level: number, text: string) => string;
25
+ table: (header: readonly string[], rows: readonly (readonly unknown[])[]) => string;
26
+ };
@@ -0,0 +1,20 @@
1
+ // Public surface of @intentface/ui/generative. Experimental: it may change or
2
+ // be removed before 1.0. No directive, so the helpers stay importable on a
3
+ // server; the hook arrives there as a client reference.
4
+ import { treeSchema } from "./json-schema.js";
5
+ import { markdownHeading, markdownParagraph, markdownTable, markdownText, toMarkdown, } from "./markdown.js";
6
+ import { findBindings, formatIssues, readTree, resolveBindings, validateTree } from "./tree.js";
7
+ export { DEFAULT_LIMITS, DEFAULT_REF_DESCRIPTION, defineCatalog, isBinding, } from "./catalog.js";
8
+ export { useTree } from "./use-tree.js";
9
+ /** What the model writes: its schema, a whole call checked, a partial one read, and issues worded for the model. */
10
+ export const tree = { schema: treeSchema, validate: validateTree, read: readTree, formatIssues };
11
+ /** Data by reference: the bindings in a tree, and the tree with their data in place. */
12
+ export const bindings = { find: findBindings, resolve: resolveBindings };
13
+ /** A tree as Markdown, and the helpers that keep text the model wrote literal in it. */
14
+ export const markdown = {
15
+ tree: toMarkdown,
16
+ text: markdownText,
17
+ paragraph: markdownParagraph,
18
+ heading: markdownHeading,
19
+ table: markdownTable,
20
+ };
@@ -0,0 +1,45 @@
1
+ import type { StandardSchema } from "../internal/standard-schema.js";
2
+ import { type AnyCatalog, type AnyComponent, type ComponentInput, type JsonObject, type TreeInput } from "./catalog.js";
3
+ export type TreeSchemaOptions = {
4
+ /** The model writes one component as `{ type, props }` instead of a tree. */
5
+ single?: boolean;
6
+ };
7
+ /** The JSON Schema of a tool's input: always an object. */
8
+ type ObjectSchema = {
9
+ type: "object";
10
+ properties: JsonObject;
11
+ required: string[];
12
+ additionalProperties: false;
13
+ };
14
+ /**
15
+ * The tool's input schema: plain JSON Schema, which any model SDK takes as is,
16
+ * carrying a typed Standard Schema the AI SDK infers the tool's input from.
17
+ */
18
+ export type TreeSchema<Input> = ObjectSchema & {
19
+ readonly "~standard": StandardSchema<Input>["~standard"] & {
20
+ readonly jsonSchema: {
21
+ readonly input: (options: {
22
+ readonly target: string;
23
+ }) => ObjectSchema;
24
+ readonly output: (options: {
25
+ readonly target: string;
26
+ }) => ObjectSchema;
27
+ };
28
+ };
29
+ };
30
+ /** What the model writes under a schema built with these options. */
31
+ type InputOf<C extends AnyCatalog, Options extends TreeSchemaOptions> = Options extends {
32
+ single: true;
33
+ } ? ComponentInput<C> : TreeInput<C>;
34
+ /**
35
+ * The tool's input schema, typed as what the model writes, so an AI SDK tool
36
+ * infers its input. It passes the call through as written: `tree.validate`
37
+ * checks it, so the issues reach the model as the tool's result. Pass it as is:
38
+ * a spread copy loses the Standard Schema.
39
+ */
40
+ export declare const treeSchema: <C extends AnyCatalog, const Options extends TreeSchemaOptions = TreeSchemaOptions>(catalog: C, options?: Options) => TreeSchema<InputOf<C, Options>>;
41
+ /** A component's props as JSON Schema, or `null` when its schema can't convert. */
42
+ export declare const jsonSchemaOf: (definition: AnyComponent) => JsonObject | null;
43
+ /** A strict schema's nulls read back as absent, where the component's own schema has no null. */
44
+ export declare const dropNulls: (value: unknown, schema: unknown) => unknown;
45
+ export {};
@@ -0,0 +1,216 @@
1
+ // The tool's input schema: each component's own JSON Schema, made strict for
2
+ // structured-output modes, and the nulls that strictness adds read back out.
3
+ import { DEFAULT_REF_DESCRIPTION, isBinding, isObject, limitsOf, } from "./catalog.js";
4
+ /**
5
+ * The tool's input schema, typed as what the model writes, so an AI SDK tool
6
+ * infers its input. It passes the call through as written: `tree.validate`
7
+ * checks it, so the issues reach the model as the tool's result. Pass it as is:
8
+ * a spread copy loses the Standard Schema.
9
+ */
10
+ export const treeSchema = (catalog, options) => {
11
+ // Built now, so a component schema that can't convert throws here.
12
+ const schema = toJSONSchema(catalog, options);
13
+ const jsonSchema = ({ target }) => {
14
+ if (target !== "draft-07")
15
+ throw new Error(`tree.schema converts to draft-07, not ${target}.`);
16
+ return schema;
17
+ };
18
+ const standard = {
19
+ version: 1,
20
+ vendor: "intentface",
21
+ validate: (value) => ({ value: value }),
22
+ jsonSchema: { input: jsonSchema, output: jsonSchema },
23
+ };
24
+ // Not enumerable, so an SDK that sends the schema as JSON leaves it out; the AI SDK still finds it.
25
+ return Object.defineProperty(schema, "~standard", { value: standard });
26
+ };
27
+ /**
28
+ * The schema itself, built from each component's own. Strict, for
29
+ * structured-output modes: every object closed, every property required, and
30
+ * optional props nullable. `tree.validate` reads the nulls back as absent.
31
+ */
32
+ const toJSONSchema = (catalog, options = {}) => {
33
+ const limits = limitsOf(catalog);
34
+ const refDescription = catalog.refDescription ?? DEFAULT_REF_DESCRIPTION;
35
+ const components = Object.entries(catalog.components);
36
+ const types = components.map(([type]) => type);
37
+ const propsOf = (type, definition) => strict(withBindings(requireJsonSchema(type, definition), definition, refDescription));
38
+ if (options.single) {
39
+ return {
40
+ type: "object",
41
+ properties: {
42
+ type: { type: "string", enum: types, description: "Which component to show." },
43
+ props: {
44
+ anyOf: components.map(([type, definition]) => ({
45
+ ...propsOf(type, definition),
46
+ description: `Props for ${type}: ${definition.description}`,
47
+ })),
48
+ },
49
+ },
50
+ required: ["type", "props"],
51
+ additionalProperties: false,
52
+ };
53
+ }
54
+ const element = ([type, definition]) => {
55
+ const children = {
56
+ type: "array",
57
+ items: { type: "string" },
58
+ maxItems: limits.children,
59
+ description: "The ids of the elements inside, in order.",
60
+ };
61
+ return {
62
+ type: "object",
63
+ description: definition.description,
64
+ properties: {
65
+ id: { type: "string", description: "Unique within the call." },
66
+ type: { type: "string", enum: [type] },
67
+ props: propsOf(type, definition),
68
+ ...(definition.container ? { children } : {}),
69
+ },
70
+ required: ["id", "type", "props", ...(definition.container ? ["children"] : [])],
71
+ additionalProperties: false,
72
+ };
73
+ };
74
+ return {
75
+ type: "object",
76
+ properties: {
77
+ root: { type: "string", description: "The id of the element at the top." },
78
+ elements: {
79
+ type: "array",
80
+ maxItems: limits.nodes,
81
+ description: "Every element, each with its own id. Containers list their children by id.",
82
+ items: { anyOf: components.map(element) },
83
+ },
84
+ },
85
+ required: ["root", "elements"],
86
+ additionalProperties: false,
87
+ };
88
+ };
89
+ const conversions = new WeakMap();
90
+ /** A schema as JSON Schema, converted once; the conversion's error when it can't. */
91
+ const convert = (schema) => {
92
+ let converted = conversions.get(schema);
93
+ if (!converted) {
94
+ try {
95
+ converted = schema["~standard"].jsonSchema.input({ target: "draft-07" });
96
+ }
97
+ catch (error) {
98
+ converted = error instanceof Error ? error : new Error(String(error));
99
+ }
100
+ conversions.set(schema, converted);
101
+ }
102
+ return converted;
103
+ };
104
+ /** A component's props as JSON Schema, or `null` when its schema can't convert. */
105
+ export const jsonSchemaOf = (definition) => {
106
+ const converted = convert(definition.props);
107
+ return converted instanceof Error ? null : converted;
108
+ };
109
+ /** The JSON Schema the model is shown. A conversion's own error comes through. */
110
+ const requireJsonSchema = (type, definition) => {
111
+ // Typed as required, but a JavaScript caller can still pass an older validator.
112
+ if (!definition.props["~standard"].jsonSchema) {
113
+ throw new Error(`"${type}" needs a schema that converts to JSON Schema: zod 4.2+, ArkType 2.1.28+, or Valibot through toStandardJsonSchema.`);
114
+ }
115
+ const schema = convert(definition.props);
116
+ if (schema instanceof Error)
117
+ throw schema;
118
+ if (JSON.stringify(schema).includes('"$ref"')) {
119
+ throw new Error(`"${type}" uses $ref in its JSON Schema, which isn't supported yet.`);
120
+ }
121
+ return schema;
122
+ };
123
+ const bindingSchema = (refDescription) => ({
124
+ type: "object",
125
+ description: "Data by reference instead of written out: a tool result's ref, and what to pick.",
126
+ properties: {
127
+ $data: { type: "string", description: refDescription },
128
+ columns: {
129
+ type: "array",
130
+ items: { type: "string" },
131
+ description: "Columns to pick from each row, in order, for a list of rows.",
132
+ },
133
+ column: { type: "string", description: "One column to pick from each row." },
134
+ },
135
+ required: ["$data"],
136
+ additionalProperties: false,
137
+ });
138
+ const withBindings = (schema, definition, refDescription) => {
139
+ if (!definition.bind?.length || !isObject(schema.properties))
140
+ return schema;
141
+ const properties = { ...schema.properties };
142
+ for (const key of definition.bind) {
143
+ if (key in properties) {
144
+ properties[key] = { anyOf: [properties[key], bindingSchema(refDescription)] };
145
+ }
146
+ }
147
+ return { ...schema, properties };
148
+ };
149
+ const SCHEMA_LISTS = new Set(["anyOf", "oneOf", "allOf", "prefixItems"]);
150
+ const SCHEMA_SLOTS = new Set(["items", "not", "additionalProperties"]);
151
+ const strict = (schema) => {
152
+ if (!isObject(schema))
153
+ return schema;
154
+ const next = {};
155
+ for (const [key, value] of Object.entries(schema)) {
156
+ switch (true) {
157
+ case key === "$schema":
158
+ break;
159
+ case key === "properties" && isObject(value):
160
+ next[key] = Object.fromEntries(Object.entries(value).map(([name, property]) => [name, strict(property)]));
161
+ break;
162
+ case SCHEMA_LISTS.has(key) && Array.isArray(value):
163
+ next[key] = value.map(strict);
164
+ break;
165
+ case SCHEMA_SLOTS.has(key) && isObject(value):
166
+ next[key] = strict(value);
167
+ break;
168
+ default:
169
+ next[key] = value;
170
+ }
171
+ }
172
+ if (isObject(next.properties)) {
173
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
174
+ const properties = Object.fromEntries(Object.entries(next.properties).map(([name, property]) => [
175
+ name,
176
+ required.has(name) ? property : nullable(property),
177
+ ]));
178
+ next.properties = properties;
179
+ next.required = Object.keys(properties);
180
+ next.additionalProperties = false;
181
+ }
182
+ return next;
183
+ };
184
+ const nullable = (schema) =>
185
+ // An enum or a const still pins the value, so only the anyOf form lets null through.
186
+ isObject(schema) && typeof schema.type === "string" && !("enum" in schema) && !("const" in schema)
187
+ ? { ...schema, type: [schema.type, "null"] }
188
+ : { anyOf: [schema, { type: "null" }] };
189
+ const allowsNull = (schema) => isObject(schema) &&
190
+ (schema.type === "null" ||
191
+ (Array.isArray(schema.type) && schema.type.includes("null")) ||
192
+ schema.const === null ||
193
+ (Array.isArray(schema.enum) && schema.enum.includes(null)) ||
194
+ [schema.anyOf, schema.oneOf].some((branches) => Array.isArray(branches) && branches.some(allowsNull)));
195
+ /** A strict schema's nulls read back as absent, where the component's own schema has no null. */
196
+ export const dropNulls = (value, schema) => {
197
+ if (!isObject(schema))
198
+ return value;
199
+ if (Array.isArray(value))
200
+ return value.map((item) => dropNulls(item, schema.items));
201
+ if (!isObject(value) || !isObject(schema.properties))
202
+ return value;
203
+ const properties = schema.properties;
204
+ const required = new Set(Array.isArray(schema.required) ? schema.required : []);
205
+ return Object.fromEntries(Object.entries(value).flatMap(([key, item]) => item === null && !required.has(key) && !allowsNull(properties[key])
206
+ ? []
207
+ : [
208
+ [
209
+ key,
210
+ // A binding's optional parts come back null in strict mode; none of them allow it.
211
+ isBinding(item)
212
+ ? Object.fromEntries(Object.entries(item).filter(([, part]) => part !== null))
213
+ : dropNulls(item, properties[key]),
214
+ ],
215
+ ]));
216
+ };
@@ -0,0 +1,21 @@
1
+ import { type AnyCatalog, type Tree } from "./catalog.js";
2
+ /**
3
+ * One line of literal text, for a label, a cell or a heading. A marker that
4
+ * would open a block is escaped, so it stays text on a line of its own too.
5
+ */
6
+ export declare const markdownText: (text: string) => string;
7
+ /**
8
+ * Literal text over several lines, such as a paragraph. A line that would open
9
+ * a block has its marker escaped, and indentation is dropped.
10
+ */
11
+ export declare const markdownParagraph: (text: string) => string;
12
+ /** A heading of literal text. A trailing `#` stays text. */
13
+ export declare const markdownHeading: (level: number, text: string) => string;
14
+ /** A GitHub-flavoured table. Every cell is literal text, so a pipe can't split a column. */
15
+ export declare const markdownTable: (header: readonly string[], rows: readonly (readonly unknown[])[]) => string;
16
+ /**
17
+ * A tree as Markdown, through each component's `markdown`. A container
18
+ * without one reads as its children. An element still holding a binding is
19
+ * left out: resolve the tree first.
20
+ */
21
+ export declare const toMarkdown: <C extends AnyCatalog>(tree: Tree<C>, catalog: C) => string;
@@ -0,0 +1,76 @@
1
+ // A tree as Markdown, and the escaping that keeps model-written text literal.
2
+ import { componentOf, isBinding, isObject } from "./catalog.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Markdown
5
+ // ---------------------------------------------------------------------------
6
+ //
7
+ // Text from the model or a source must read as written: it may not format,
8
+ // link, or break the structure around it. Links come only from the consumer.
9
+ // What opens emphasis, code, a link or image, HTML, strikethrough or a table
10
+ // cell; and `@`, which GFM turns into a mailto link.
11
+ const INLINE = /[\\`*_[\]<>|~@]/g;
12
+ // An entity reference (`&amp;`) would be decoded, so its ampersand is escaped.
13
+ const ENTITY = /&(?=#?[a-zA-Z0-9]+;)/g;
14
+ // GFM links bare addresses too; escaping the colon or the dot breaks the pattern.
15
+ const SCHEME = /(https?|mailto|xmpp):/gi;
16
+ const WWW = /\b(www)\./gi;
17
+ const escapeCharacters = (text) => text
18
+ .replace(INLINE, "\\$&")
19
+ .replace(ENTITY, "\\&")
20
+ .replace(SCHEME, "$1\\:")
21
+ .replace(WWW, "$1\\.");
22
+ // A lone `\r` ends a line in Markdown, the same as `\n`.
23
+ const LINE_BREAK = /[\r\n]/;
24
+ // Each run of whitespace is matched once, whole, so this stays linear on long runs.
25
+ const oneLine = (text) => text.replace(/\s+/g, (run) => (LINE_BREAK.test(run) ? " " : run));
26
+ // A marker that would open a block at a line's start: a heading, a list item,
27
+ // a setext underline or a numbered item.
28
+ const escapeBlockStart = (line) => line.replace(/^(\s*)([#+=-])/, "$1\\$2").replace(/^(\s*)(\d{1,9})([.)])/, "$1$2\\$3");
29
+ /**
30
+ * One line of literal text, for a label, a cell or a heading. A marker that
31
+ * would open a block is escaped, so it stays text on a line of its own too.
32
+ */
33
+ export const markdownText = (text) => escapeBlockStart(escapeCharacters(oneLine(text)));
34
+ /**
35
+ * Literal text over several lines, such as a paragraph. A line that would open
36
+ * a block has its marker escaped, and indentation is dropped.
37
+ */
38
+ export const markdownParagraph = (text) => text
39
+ .split(/\r\n?|\n/)
40
+ .map((line) => escapeBlockStart(escapeCharacters(line.trim())))
41
+ .join("\n");
42
+ /** A heading of literal text. A trailing `#` stays text. */
43
+ export const markdownHeading = (level, text) => `${"#".repeat(level)} ${markdownText(text).replace(/(^|\s)(#+)$/, "$1\\$2")}`;
44
+ /** A GitHub-flavoured table. Every cell is literal text, so a pipe can't split a column. */
45
+ export const markdownTable = (header, rows) => {
46
+ const line = (cells) => `| ${header.map((_, index) => markdownText(String(cells[index] ?? ""))).join(" | ")} |`;
47
+ return [line(header), `| ${header.map(() => "---").join(" | ")} |`, ...rows.map(line)].join("\n");
48
+ };
49
+ const hasBinding = (props) => isObject(props) && Object.values(props).some(isBinding);
50
+ /**
51
+ * A tree as Markdown, through each component's `markdown`. A container
52
+ * without one reads as its children. An element still holding a binding is
53
+ * left out: resolve the tree first.
54
+ */
55
+ export const toMarkdown = (tree, catalog) => {
56
+ // Each element writes once, so a cycle or a shared child in a stored tree stops at the first.
57
+ const written = new Set();
58
+ const write = (id) => {
59
+ const element = tree.elements[id];
60
+ if (!element || written.has(id) || hasBinding(element.props))
61
+ return "";
62
+ written.add(id);
63
+ const children = (element.children ?? [])
64
+ .map((child) => write(child))
65
+ .filter((block) => block.trim() !== "")
66
+ .join("\n\n");
67
+ const definition = componentOf(catalog, element.type);
68
+ // Typed per component in the catalog; the element's props are that component's.
69
+ if (definition?.markdown)
70
+ return definition.markdown(element.props, children);
71
+ if (definition?.container)
72
+ return children;
73
+ throw new Error(`"${element.type}" has no markdown.`);
74
+ };
75
+ return write(tree.root);
76
+ };
@@ -0,0 +1,56 @@
1
+ import { type AnyCatalog, type FoundBinding, type ResolvedTree, type Tree, type TreeNode } from "./catalog.js";
2
+ export type TreeIssueCode = "invalid_input" | "missing_id" | "duplicate_id" | "duplicate_child" | "missing_root" | "root_not_found" | "unknown_type" | "unexpected_children" | "dangling_child" | "shared_child" | "cycle" | "too_deep" | "too_many_nodes" | "too_many_children" | "invalid_props" | "invalid_binding" | "unresolved_binding";
3
+ /** One problem with a call, in words the model can act on. */
4
+ export type TreeIssue = {
5
+ code: TreeIssueCode;
6
+ message: string;
7
+ path: (string | number)[];
8
+ };
9
+ type Result<Value> = {
10
+ value: Value;
11
+ issues?: undefined;
12
+ } | {
13
+ value?: undefined;
14
+ issues: TreeIssue[];
15
+ };
16
+ /** A checked call, or what's wrong with it. */
17
+ export type TreeResult<C extends AnyCatalog> = Result<Tree<C>>;
18
+ /** A tree with its data in place, or what couldn't be resolved. */
19
+ export type ResolvedTreeResult<C extends AnyCatalog> = Result<ResolvedTree<C>>;
20
+ /** Issues as text for the model, one per line: where, then what's wrong. */
21
+ export declare const formatIssues: (issues: readonly TreeIssue[], max?: number) => string;
22
+ /** Every binding in a tree, for the host to resolve. */
23
+ export declare const findBindings: <C extends AnyCatalog>(tree: Tree<C>) => FoundBinding[];
24
+ /**
25
+ * The tree with every binding replaced by its data, each element validated
26
+ * again with the data in place. `resolve` returns what a ref names, such as a
27
+ * tool result's rows, and may fetch it; the binding's columns are picked from
28
+ * it. `undefined` means not found.
29
+ */
30
+ export declare const resolveBindings: <C extends AnyCatalog>(tree: Tree<C>, catalog: C, resolve: (binding: FoundBinding) => unknown | Promise<unknown>) => Promise<ResolvedTreeResult<C>>;
31
+ /**
32
+ * A whole call checked against the catalog: its shape read as meant, its
33
+ * structure and limits checked, and each element's props validated. Issues
34
+ * name the field, so `tree.formatIssues` can send them straight back to the model.
35
+ */
36
+ export declare const validateTree: <C extends AnyCatalog>(input: unknown, catalog: C) => Promise<TreeResult<C>>;
37
+ export type ReadTreeOptions = {
38
+ /**
39
+ * Returns what a ref names from data already at hand, such as a tool
40
+ * result's rows among the message's parts; the binding's columns are picked
41
+ * from it. It answers within a render, so `undefined`, or a promise, keeps
42
+ * the node pending.
43
+ */
44
+ resolve?: (binding: FoundBinding) => unknown;
45
+ };
46
+ /** The root node, once there is one to draw. */
47
+ export type TreeRead<C extends AnyCatalog> = {
48
+ root?: TreeNode<C>;
49
+ };
50
+ /**
51
+ * Partial or whole input as nodes to draw, without throwing. A node whose type
52
+ * isn't known yet is skipped; one whose props don't validate yet, or whose
53
+ * data isn't resolved, is pending.
54
+ */
55
+ export declare const readTree: <C extends AnyCatalog>(input: unknown, catalog: C, options?: ReadTreeOptions) => TreeRead<C>;
56
+ export {};