@humain/ui 2.1.62 → 2.1.65

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 (160) hide show
  1. package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
  2. package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
  3. package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
  4. package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
  5. package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
  6. package/dist/index.js +52 -52
  7. package/dist/index151.js +1 -1
  8. package/dist/index174.js +10 -333
  9. package/dist/index174.js.map +1 -1
  10. package/dist/index175.js +310 -137
  11. package/dist/index175.js.map +1 -1
  12. package/dist/index176.js +148 -174
  13. package/dist/index176.js.map +1 -1
  14. package/dist/index177.js +186 -78
  15. package/dist/index177.js.map +1 -1
  16. package/dist/index178.js +74 -124
  17. package/dist/index178.js.map +1 -1
  18. package/dist/index179.js +133 -1
  19. package/dist/index179.js.map +1 -0
  20. package/dist/index180.js +2 -201
  21. package/dist/index181.js +201 -0
  22. package/dist/{index180.js.map → index181.js.map} +1 -1
  23. package/dist/index183.js +130 -166
  24. package/dist/index183.js.map +1 -1
  25. package/dist/index184.js +195 -983
  26. package/dist/index184.js.map +1 -1
  27. package/dist/index185.js +1069 -369
  28. package/dist/index185.js.map +1 -1
  29. package/dist/index186.js +395 -197
  30. package/dist/index186.js.map +1 -1
  31. package/dist/index187.js +198 -243
  32. package/dist/index187.js.map +1 -1
  33. package/dist/index188.js +263 -3
  34. package/dist/index188.js.map +1 -1
  35. package/dist/index189.js +3 -209
  36. package/dist/index189.js.map +1 -1
  37. package/dist/index190.js +190 -777
  38. package/dist/index190.js.map +1 -1
  39. package/dist/index191.js +771 -252
  40. package/dist/index191.js.map +1 -1
  41. package/dist/index192.js +250 -65
  42. package/dist/index192.js.map +1 -1
  43. package/dist/index193.js +72 -523
  44. package/dist/index193.js.map +1 -1
  45. package/dist/index194.js +537 -144
  46. package/dist/index194.js.map +1 -1
  47. package/dist/index195.js +139 -720
  48. package/dist/index195.js.map +1 -1
  49. package/dist/index196.js +707 -167
  50. package/dist/index196.js.map +1 -1
  51. package/dist/index197.js +175 -151
  52. package/dist/index197.js.map +1 -1
  53. package/dist/index198.js +152 -487
  54. package/dist/index198.js.map +1 -1
  55. package/dist/index199.js +472 -225
  56. package/dist/index199.js.map +1 -1
  57. package/dist/index200.js +236 -260
  58. package/dist/index200.js.map +1 -1
  59. package/dist/index201.js +265 -215
  60. package/dist/index201.js.map +1 -1
  61. package/dist/index202.js +207 -307
  62. package/dist/index202.js.map +1 -1
  63. package/dist/index203.js +302 -135
  64. package/dist/index203.js.map +1 -1
  65. package/dist/index204.js +140 -271
  66. package/dist/index204.js.map +1 -1
  67. package/dist/index205.js +263 -253
  68. package/dist/index205.js.map +1 -1
  69. package/dist/index206.js +244 -137
  70. package/dist/index206.js.map +1 -1
  71. package/dist/index207.js +100 -238
  72. package/dist/index207.js.map +1 -1
  73. package/dist/index208.js +278 -74
  74. package/dist/index208.js.map +1 -1
  75. package/dist/index209.js +56 -97
  76. package/dist/index209.js.map +1 -1
  77. package/dist/index210.js +142 -47
  78. package/dist/index210.js.map +1 -1
  79. package/dist/index211.js +38 -84
  80. package/dist/index211.js.map +1 -1
  81. package/dist/index212.js +72 -252
  82. package/dist/index212.js.map +1 -1
  83. package/dist/index213.js +274 -26
  84. package/dist/index213.js.map +1 -1
  85. package/dist/index214.js +29 -94
  86. package/dist/index214.js.map +1 -1
  87. package/dist/index215.js +98 -25
  88. package/dist/index215.js.map +1 -1
  89. package/dist/index216.js +20 -565
  90. package/dist/index216.js.map +1 -1
  91. package/dist/index217.js +564 -17
  92. package/dist/index217.js.map +1 -1
  93. package/dist/index218.js +20 -23
  94. package/dist/index218.js.map +1 -1
  95. package/dist/index219.js +20 -95
  96. package/dist/index219.js.map +1 -1
  97. package/dist/index220.js +92 -88
  98. package/dist/index220.js.map +1 -1
  99. package/dist/index221.js +97 -29
  100. package/dist/index221.js.map +1 -1
  101. package/dist/index222.js +24 -470
  102. package/dist/index222.js.map +1 -1
  103. package/dist/index223.js +446 -196
  104. package/dist/index223.js.map +1 -1
  105. package/dist/index224.js +199 -729
  106. package/dist/index224.js.map +1 -1
  107. package/dist/index225.js +750 -61
  108. package/dist/index225.js.map +1 -1
  109. package/dist/index226.js +58 -181
  110. package/dist/index226.js.map +1 -1
  111. package/dist/index227.js +175 -259
  112. package/dist/index227.js.map +1 -1
  113. package/dist/index228.js +246 -172
  114. package/dist/index228.js.map +1 -1
  115. package/dist/index229.js +195 -32
  116. package/dist/index229.js.map +1 -1
  117. package/dist/index230.js +12 -40
  118. package/dist/index230.js.map +1 -1
  119. package/dist/index231.js +23 -26
  120. package/dist/index231.js.map +1 -1
  121. package/dist/index232.js +45 -22
  122. package/dist/index232.js.map +1 -1
  123. package/dist/index233.js +27 -48
  124. package/dist/index233.js.map +1 -1
  125. package/dist/index234.js +52 -26
  126. package/dist/index234.js.map +1 -1
  127. package/dist/index235.js +40 -225
  128. package/dist/index235.js.map +1 -1
  129. package/dist/index236.js +217 -39
  130. package/dist/index236.js.map +1 -1
  131. package/dist/index237.js +50 -0
  132. package/dist/index237.js.map +1 -0
  133. package/dist/styles.css +1 -1
  134. package/dist/wc/AIToolCall.js +218 -0
  135. package/dist/wc/AIToolCall.js.map +1 -0
  136. package/dist/wc/hf-ai-tool-call.js +34 -219
  137. package/dist/wc/hf-ai-tool-call.js.map +1 -1
  138. package/dist/wc/hf-ai-tool-run.js +673 -576
  139. package/dist/wc/hf-ai-tool-run.js.map +1 -1
  140. package/dist/wc/workflow-step-renderer.js +94 -86
  141. package/dist/wc/workflow-step-renderer.js.map +1 -1
  142. package/dist/wc-react/AIToolCall.js +218 -0
  143. package/dist/wc-react/AIToolCall.js.map +1 -0
  144. package/dist/wc-react/hf-ai-tool-call.js +32 -217
  145. package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
  146. package/dist/wc-react/hf-ai-tool-run.js +698 -601
  147. package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
  148. package/dist/wc-react/workflow-step-renderer.js +76 -68
  149. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  150. package/package.json +1 -1
  151. package/skills/humain-ui/SKILL.md +1 -1
  152. package/skills/humain-ui-wc/SKILL.md +1 -1
  153. package/skills/humain-ui-wc.skill +0 -0
  154. package/skills/humain-ui.skill +0 -0
  155. package/dist/index182.js +0 -143
  156. package/dist/index182.js.map +0 -1
  157. package/dist/wc/wrench.js +0 -10
  158. package/dist/wc/wrench.js.map +0 -1
  159. package/dist/wc-react/wrench.js +0 -10
  160. package/dist/wc-react/wrench.js.map +0 -1
package/dist/index236.js CHANGED
@@ -1,50 +1,228 @@
1
- import { formatInteractionForLLM } from "./index235.js";
2
- import { useCallback, useMemo } from "react";
3
- //#region src/hooks/useInteractionHandler.ts
1
+ import { assertNever } from "./index2.js";
2
+ //#region src/lib/ai-interaction-format.ts
3
+ var UNEXPECTED_COMPONENT_TYPE_MESSAGE = "Unexpected AI interaction component type";
4
4
  /**
5
- * Hook that creates a memoized interaction handler that automatically
6
- * formats interaction events for LLM consumption.
5
+ * Normalize value to array
6
+ */
7
+ function normalizeToArray(value) {
8
+ if (Array.isArray(value)) return value.map(String);
9
+ if (value === null || value === void 0) return [];
10
+ return [String(value)];
11
+ }
12
+ /**
13
+ * Apply label mappings to values
14
+ */
15
+ function applyLabels(values, labels) {
16
+ if (!labels) return values;
17
+ return values.map((v) => labels[v] || v);
18
+ }
19
+ /**
20
+ * Format timestamp for display
21
+ */
22
+ function formatTimestamp(timestamp) {
23
+ return new Date(timestamp).toISOString();
24
+ }
25
+ function formatSelectNatural(event, options) {
26
+ const values = normalizeToArray(event.value);
27
+ if (values.length === 0) return "I cleared my selection";
28
+ return `I selected: ${applyLabels(values, options?.labels).join(", ")}`;
29
+ }
30
+ function formatFormNatural(event) {
31
+ const data = event.value;
32
+ if (!data || Object.keys(data).length === 0) return `I submitted the ${event.componentId} form with no data`;
33
+ const fields = Object.entries(data).map(([key, value]) => `\u2022 ${key}: ${value}`).join("\n");
34
+ return `I submitted the ${event.componentId} form:\n${fields}`;
35
+ }
36
+ function formatTableNatural(event) {
37
+ const rows = event.value?.selectedRows || [];
38
+ if (rows.length === 0) return `I cleared row selection from ${event.componentId}`;
39
+ return `I selected rows ${rows.join(", ")} from ${event.componentId}`;
40
+ }
41
+ function formatChartNatural(event) {
42
+ const data = event.value;
43
+ if (!data?.label) return `I clicked on ${event.componentId}`;
44
+ return `I clicked on ${data.label} (value: ${data.value}) in ${event.componentId}`;
45
+ }
46
+ function formatComponentNatural(event) {
47
+ if (event.action === "submit" || event.action === "start") return `I answered ${event.componentId}: ${JSON.stringify(event.value)}`;
48
+ return `I ${event.action} ${event.componentId}: ${JSON.stringify(event.value)}`;
49
+ }
50
+ function formatNatural(event, options) {
51
+ let result;
52
+ switch (event.componentType) {
53
+ case "select":
54
+ result = formatSelectNatural(event, options);
55
+ break;
56
+ case "form":
57
+ result = formatFormNatural(event);
58
+ break;
59
+ case "table":
60
+ result = formatTableNatural(event);
61
+ break;
62
+ case "chart":
63
+ result = formatChartNatural(event);
64
+ break;
65
+ case "component":
66
+ result = formatComponentNatural(event);
67
+ break;
68
+ default: return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);
69
+ }
70
+ if (options?.includeTimestamp) result = `[${formatTimestamp(event.timestamp)}] ${result}`;
71
+ return result;
72
+ }
73
+ function formatSelectStructured(event, options) {
74
+ const result = {
75
+ type: "user_interaction",
76
+ component: "select",
77
+ id: event.componentId,
78
+ action: event.action,
79
+ selection: normalizeToArray(event.value)
80
+ };
81
+ if (options?.includeTimestamp) result.timestamp = event.timestamp;
82
+ return result;
83
+ }
84
+ function formatFormStructured(event, options) {
85
+ const result = {
86
+ type: "user_interaction",
87
+ component: "form",
88
+ id: event.componentId,
89
+ action: event.action,
90
+ data: event.value || {}
91
+ };
92
+ if (options?.includeTimestamp) result.timestamp = event.timestamp;
93
+ return result;
94
+ }
95
+ function formatTableStructured(event, options) {
96
+ const data = event.value;
97
+ const result = {
98
+ type: "user_interaction",
99
+ component: "table",
100
+ id: event.componentId,
101
+ action: event.action,
102
+ selectedRows: data?.selectedRows || []
103
+ };
104
+ if (options?.includeTimestamp) result.timestamp = event.timestamp;
105
+ return result;
106
+ }
107
+ function formatChartStructured(event, options) {
108
+ const data = event.value;
109
+ const result = {
110
+ type: "user_interaction",
111
+ component: "chart",
112
+ id: event.componentId,
113
+ action: event.action,
114
+ dataPoint: data
115
+ };
116
+ if (options?.includeTimestamp) result.timestamp = event.timestamp;
117
+ return result;
118
+ }
119
+ function formatComponentStructured(event, options) {
120
+ const result = {
121
+ type: "user_interaction",
122
+ component: "component",
123
+ id: event.componentId,
124
+ action: event.action,
125
+ value: event.value
126
+ };
127
+ if (options?.includeTimestamp) result.timestamp = event.timestamp;
128
+ return result;
129
+ }
130
+ function formatStructured(event, options) {
131
+ switch (event.componentType) {
132
+ case "select": return formatSelectStructured(event, options);
133
+ case "form": return formatFormStructured(event, options);
134
+ case "table": return formatTableStructured(event, options);
135
+ case "chart": return formatChartStructured(event, options);
136
+ case "component": return formatComponentStructured(event, options);
137
+ default: return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);
138
+ }
139
+ }
140
+ function formatSelectMarkdown(event, options) {
141
+ const values = normalizeToArray(event.value);
142
+ if (values.length === 0) return `**Selection (${event.componentId}):** _cleared_`;
143
+ const formatted = applyLabels(values, options?.labels).map((v) => `\`${v}\``).join(", ");
144
+ return `**Selection (${event.componentId}):** ${formatted}`;
145
+ }
146
+ function formatFormMarkdown(event) {
147
+ const data = event.value;
148
+ if (!data || Object.keys(data).length === 0) return `**Form Submission (${event.componentId}):** _empty_`;
149
+ const fields = Object.entries(data).map(([key, value]) => `- **${key}:** ${value}`).join("\n");
150
+ return `**Form Submission (${event.componentId}):**\n${fields}`;
151
+ }
152
+ function formatTableMarkdown(event) {
153
+ const rows = event.value?.selectedRows || [];
154
+ if (rows.length === 0) return `**Table Selection (${event.componentId}):** _none_`;
155
+ const formatted = rows.map((r) => `\`${r}\``).join(", ");
156
+ return `**Table Selection (${event.componentId}):** rows ${formatted}`;
157
+ }
158
+ function formatChartMarkdown(event) {
159
+ const data = event.value;
160
+ if (!data?.label) return `**Chart Click (${event.componentId}):** _no data_`;
161
+ return `**Chart Click (${event.componentId}):** ${data.label} (value: \`${data.value}\`)`;
162
+ }
163
+ function formatComponentMarkdown(event) {
164
+ return `**Component Interaction (${event.componentId}):** ${event.action} \`${JSON.stringify(event.value)}\``;
165
+ }
166
+ function formatMarkdown(event, options) {
167
+ let result;
168
+ switch (event.componentType) {
169
+ case "select":
170
+ result = formatSelectMarkdown(event, options);
171
+ break;
172
+ case "form":
173
+ result = formatFormMarkdown(event);
174
+ break;
175
+ case "table":
176
+ result = formatTableMarkdown(event);
177
+ break;
178
+ case "chart":
179
+ result = formatChartMarkdown(event);
180
+ break;
181
+ case "component":
182
+ result = formatComponentMarkdown(event);
183
+ break;
184
+ default: return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);
185
+ }
186
+ if (options?.includeTimestamp) result = `${result} _at ${formatTimestamp(event.timestamp)}_`;
187
+ return result;
188
+ }
189
+ /**
190
+ * Format an AI interaction event for sending to an LLM.
191
+ *
192
+ * Supports three format modes:
193
+ * - 'natural': Human-readable text (default)
194
+ * - 'structured': JSON object structure
195
+ * - 'markdown': Markdown formatted text
7
196
  *
8
- * @param options - Configuration options including the callback and format settings
9
- * @returns A stable callback function that handles interaction events
197
+ * @param event - The interaction event to format
198
+ * @param options - Formatting options
199
+ * @returns Formatted string or object depending on format mode
10
200
  *
11
201
  * @example
12
- * ```tsx
13
- * function MyComponent() {
14
- * const handleInteraction = useInteractionHandler({
15
- * onInteraction: (event, formatted) => {
16
- * console.log('Event:', event);
17
- * console.log('Formatted:', formatted);
18
- * // Send formatted message to LLM
19
- * },
20
- * format: 'natural', // or 'structured', 'markdown'
21
- * });
202
+ * ```ts
203
+ * // Natural format (default)
204
+ * formatInteractionForLLM(event)
205
+ * // => "I selected: Fast delivery, Premium quality"
206
+ *
207
+ * // Structured format
208
+ * formatInteractionForLLM(event, { format: 'structured' })
209
+ * // => { type: 'user_interaction', component: 'select', ... }
22
210
  *
23
- * return (
24
- * <AIInteractionProvider onInteraction={handleInteraction}>
25
- * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>
26
- * </AIInteractionProvider>
27
- * );
28
- * }
211
+ * // Markdown format
212
+ * formatInteractionForLLM(event, { format: 'markdown' })
213
+ * // => "**Selection (preferences):** `fast`, `quality`"
29
214
  * ```
30
215
  */
31
- function useInteractionHandler(options) {
32
- const { onInteraction, format, includeTimestamp, labels } = options;
33
- const formatOptions = useMemo(() => ({
34
- format,
35
- includeTimestamp,
36
- labels
37
- }), [
38
- format,
39
- includeTimestamp,
40
- labels
41
- ]);
42
- return useCallback((event) => {
43
- const formatted = formatInteractionForLLM(event, formatOptions);
44
- onInteraction(event, formatted);
45
- }, [onInteraction, formatOptions]);
216
+ function formatInteractionForLLM(event, options) {
217
+ const format = options?.format || "natural";
218
+ switch (format) {
219
+ case "structured": return formatStructured(event, options);
220
+ case "markdown": return formatMarkdown(event, options);
221
+ case "natural": return formatNatural(event, options);
222
+ default: return assertNever(format, "Unexpected AI interaction format");
223
+ }
46
224
  }
47
225
  //#endregion
48
- export { useInteractionHandler };
226
+ export { formatInteractionForLLM };
49
227
 
50
228
  //# sourceMappingURL=index236.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index236.js","names":[],"sources":["../src/hooks/useInteractionHandler.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport type { AIInteractionEvent } from '@/components/organisms/ai/_shared/interaction-context';\nimport {\n type FormatMode,\n type FormatOptions,\n formatInteractionForLLM,\n} from '@/lib/ai-interaction-format';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for the useInteractionHandler hook\n */\nexport interface UseInteractionHandlerOptions extends FormatOptions {\n /**\n * Callback invoked when an interaction occurs.\n * Receives both the raw event and the formatted message.\n */\n onInteraction: (\n event: AIInteractionEvent,\n formattedMessage: string | object,\n ) => void;\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\n/**\n * Hook that creates a memoized interaction handler that automatically\n * formats interaction events for LLM consumption.\n *\n * @param options - Configuration options including the callback and format settings\n * @returns A stable callback function that handles interaction events\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const handleInteraction = useInteractionHandler({\n * onInteraction: (event, formatted) => {\n * console.log('Event:', event);\n * console.log('Formatted:', formatted);\n * // Send formatted message to LLM\n * },\n * format: 'natural', // or 'structured', 'markdown'\n * });\n *\n * return (\n * <AIInteractionProvider onInteraction={handleInteraction}>\n * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>\n * </AIInteractionProvider>\n * );\n * }\n * ```\n */\nexport function useInteractionHandler(\n options: UseInteractionHandlerOptions,\n): (event: AIInteractionEvent) => void {\n const { onInteraction, format, includeTimestamp, labels } = options;\n\n // Memoize format options to ensure stable reference\n const formatOptions = useMemo<FormatOptions>(\n () => ({\n format,\n includeTimestamp,\n labels,\n }),\n [format, includeTimestamp, labels],\n );\n\n return useCallback(\n (event: AIInteractionEvent) => {\n const formatted = formatInteractionForLLM(event, formatOptions);\n onInteraction(event, formatted);\n },\n [onInteraction, formatOptions],\n );\n}\n\nexport type { FormatMode, FormatOptions };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,SAAgB,sBACd,SACqC;CACrC,MAAM,EAAE,eAAe,QAAQ,kBAAkB,WAAW;CAG5D,MAAM,gBAAgB,eACb;EACL;EACA;EACA;CACF,IACA;EAAC;EAAQ;EAAkB;CAAM,CACnC;CAEA,OAAO,aACJ,UAA8B;EAC7B,MAAM,YAAY,wBAAwB,OAAO,aAAa;EAC9D,cAAc,OAAO,SAAS;CAChC,GACA,CAAC,eAAe,aAAa,CAC/B;AACF"}
1
+ {"version":3,"file":"index236.js","names":[],"sources":["../src/lib/ai-interaction-format.ts"],"sourcesContent":["import type { AIInteractionEvent } from '@/components/organisms/ai/_shared/interaction-context';\nimport { assertNever } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Format modes for LLM interaction formatting\n */\nexport type FormatMode = 'natural' | 'structured' | 'markdown';\n\n/**\n * Options for formatting interaction events\n */\nexport interface FormatOptions {\n /** Output format mode. Defaults to 'natural' */\n format?: FormatMode;\n /** Whether to include timestamp in the output */\n includeTimestamp?: boolean;\n /** Label mappings for values (e.g., { 'fast': 'Fast delivery' }) */\n labels?: Record<string, string>;\n}\n\ntype ChartInteractionValue = { label?: string; value?: number } | null;\n\nconst UNEXPECTED_COMPONENT_TYPE_MESSAGE =\n 'Unexpected AI interaction component type';\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Normalize value to array\n */\nfunction normalizeToArray(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.map(String);\n }\n if (value === null || value === undefined) {\n return [];\n }\n return [String(value)];\n}\n\n/**\n * Apply label mappings to values\n */\nfunction applyLabels(\n values: string[],\n labels?: Record<string, string>,\n): string[] {\n if (!labels) return values;\n return values.map((v) => labels[v] || v);\n}\n\n/**\n * Format timestamp for display\n */\nfunction formatTimestamp(timestamp: number): string {\n return new Date(timestamp).toISOString();\n}\n\n// =============================================================================\n// Natural Format\n// =============================================================================\n\nfunction formatSelectNatural(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): string {\n const values = normalizeToArray(event.value);\n\n if (values.length === 0) {\n return 'I cleared my selection';\n }\n\n const labeledValues = applyLabels(values, options?.labels);\n return `I selected: ${labeledValues.join(', ')}`;\n}\n\nfunction formatFormNatural(event: AIInteractionEvent): string {\n const data = event.value as Record<string, unknown> | null;\n\n if (!data || Object.keys(data).length === 0) {\n return `I submitted the ${event.componentId} form with no data`;\n }\n\n const fields = Object.entries(data)\n .map(([key, value]) => `\\u2022 ${key}: ${value}`)\n .join('\\n');\n\n return `I submitted the ${event.componentId} form:\\n${fields}`;\n}\n\nfunction formatTableNatural(event: AIInteractionEvent): string {\n const data = event.value as { selectedRows?: string[] } | null;\n const rows = data?.selectedRows || [];\n\n if (rows.length === 0) {\n return `I cleared row selection from ${event.componentId}`;\n }\n\n return `I selected rows ${rows.join(', ')} from ${event.componentId}`;\n}\n\nfunction formatChartNatural(event: AIInteractionEvent): string {\n const data = event.value as ChartInteractionValue;\n\n if (!data?.label) {\n return `I clicked on ${event.componentId}`;\n }\n\n return `I clicked on ${data.label} (value: ${data.value}) in ${event.componentId}`;\n}\n\nfunction formatComponentNatural(event: AIInteractionEvent): string {\n if (event.action === 'submit' || event.action === 'start') {\n return `I answered ${event.componentId}: ${JSON.stringify(event.value)}`;\n }\n\n return `I ${event.action} ${event.componentId}: ${JSON.stringify(event.value)}`;\n}\n\nfunction formatNatural(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): string {\n let result: string;\n\n switch (event.componentType) {\n case 'select':\n result = formatSelectNatural(event, options);\n break;\n case 'form':\n result = formatFormNatural(event);\n break;\n case 'table':\n result = formatTableNatural(event);\n break;\n case 'chart':\n result = formatChartNatural(event);\n break;\n case 'component':\n result = formatComponentNatural(event);\n break;\n default:\n return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);\n }\n\n if (options?.includeTimestamp) {\n result = `[${formatTimestamp(event.timestamp)}] ${result}`;\n }\n\n return result;\n}\n\n// =============================================================================\n// Structured Format\n// =============================================================================\n\ninterface StructuredSelectResult {\n type: 'user_interaction';\n component: 'select';\n id: string;\n action: string;\n selection: string[];\n timestamp?: number;\n}\n\ninterface StructuredFormResult {\n type: 'user_interaction';\n component: 'form';\n id: string;\n action: string;\n data: Record<string, unknown>;\n timestamp?: number;\n}\n\ninterface StructuredTableResult {\n type: 'user_interaction';\n component: 'table';\n id: string;\n action: string;\n selectedRows: string[];\n timestamp?: number;\n}\n\ninterface StructuredChartResult {\n type: 'user_interaction';\n component: 'chart';\n id: string;\n action: string;\n dataPoint: ChartInteractionValue;\n timestamp?: number;\n}\n\ninterface StructuredComponentResult {\n type: 'user_interaction';\n component: 'component';\n id: string;\n action: string;\n value: unknown;\n timestamp?: number;\n}\n\ntype StructuredResult =\n | StructuredSelectResult\n | StructuredFormResult\n | StructuredTableResult\n | StructuredChartResult\n | StructuredComponentResult;\n\nfunction formatSelectStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredSelectResult {\n const result: StructuredSelectResult = {\n type: 'user_interaction',\n component: 'select',\n id: event.componentId,\n action: event.action,\n selection: normalizeToArray(event.value),\n };\n\n if (options?.includeTimestamp) {\n result.timestamp = event.timestamp;\n }\n\n return result;\n}\n\nfunction formatFormStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredFormResult {\n const result: StructuredFormResult = {\n type: 'user_interaction',\n component: 'form',\n id: event.componentId,\n action: event.action,\n data: (event.value as Record<string, unknown>) || {},\n };\n\n if (options?.includeTimestamp) {\n result.timestamp = event.timestamp;\n }\n\n return result;\n}\n\nfunction formatTableStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredTableResult {\n const data = event.value as { selectedRows?: string[] } | null;\n\n const result: StructuredTableResult = {\n type: 'user_interaction',\n component: 'table',\n id: event.componentId,\n action: event.action,\n selectedRows: data?.selectedRows || [],\n };\n\n if (options?.includeTimestamp) {\n result.timestamp = event.timestamp;\n }\n\n return result;\n}\n\nfunction formatChartStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredChartResult {\n const data = event.value as ChartInteractionValue;\n\n const result: StructuredChartResult = {\n type: 'user_interaction',\n component: 'chart',\n id: event.componentId,\n action: event.action,\n dataPoint: data,\n };\n\n if (options?.includeTimestamp) {\n result.timestamp = event.timestamp;\n }\n\n return result;\n}\n\nfunction formatComponentStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredComponentResult {\n const result: StructuredComponentResult = {\n type: 'user_interaction',\n component: 'component',\n id: event.componentId,\n action: event.action,\n value: event.value,\n };\n\n if (options?.includeTimestamp) {\n result.timestamp = event.timestamp;\n }\n\n return result;\n}\n\nfunction formatStructured(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): StructuredResult {\n switch (event.componentType) {\n case 'select':\n return formatSelectStructured(event, options);\n case 'form':\n return formatFormStructured(event, options);\n case 'table':\n return formatTableStructured(event, options);\n case 'chart':\n return formatChartStructured(event, options);\n case 'component':\n return formatComponentStructured(event, options);\n default:\n return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);\n }\n}\n\n// =============================================================================\n// Markdown Format\n// =============================================================================\n\nfunction formatSelectMarkdown(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): string {\n const values = normalizeToArray(event.value);\n\n if (values.length === 0) {\n return `**Selection (${event.componentId}):** _cleared_`;\n }\n\n const labeledValues = applyLabels(values, options?.labels);\n const formatted = labeledValues.map((v) => `\\`${v}\\``).join(', ');\n\n return `**Selection (${event.componentId}):** ${formatted}`;\n}\n\nfunction formatFormMarkdown(event: AIInteractionEvent): string {\n const data = event.value as Record<string, unknown> | null;\n\n if (!data || Object.keys(data).length === 0) {\n return `**Form Submission (${event.componentId}):** _empty_`;\n }\n\n const fields = Object.entries(data)\n .map(([key, value]) => `- **${key}:** ${value}`)\n .join('\\n');\n\n return `**Form Submission (${event.componentId}):**\\n${fields}`;\n}\n\nfunction formatTableMarkdown(event: AIInteractionEvent): string {\n const data = event.value as { selectedRows?: string[] } | null;\n const rows = data?.selectedRows || [];\n\n if (rows.length === 0) {\n return `**Table Selection (${event.componentId}):** _none_`;\n }\n\n const formatted = rows.map((r) => `\\`${r}\\``).join(', ');\n return `**Table Selection (${event.componentId}):** rows ${formatted}`;\n}\n\nfunction formatChartMarkdown(event: AIInteractionEvent): string {\n const data = event.value as ChartInteractionValue;\n\n if (!data?.label) {\n return `**Chart Click (${event.componentId}):** _no data_`;\n }\n\n return `**Chart Click (${event.componentId}):** ${data.label} (value: \\`${data.value}\\`)`;\n}\n\nfunction formatComponentMarkdown(event: AIInteractionEvent): string {\n return `**Component Interaction (${event.componentId}):** ${event.action} \\`${JSON.stringify(event.value)}\\``;\n}\n\nfunction formatMarkdown(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): string {\n let result: string;\n\n switch (event.componentType) {\n case 'select':\n result = formatSelectMarkdown(event, options);\n break;\n case 'form':\n result = formatFormMarkdown(event);\n break;\n case 'table':\n result = formatTableMarkdown(event);\n break;\n case 'chart':\n result = formatChartMarkdown(event);\n break;\n case 'component':\n result = formatComponentMarkdown(event);\n break;\n default:\n return assertNever(event, UNEXPECTED_COMPONENT_TYPE_MESSAGE);\n }\n\n if (options?.includeTimestamp) {\n result = `${result} _at ${formatTimestamp(event.timestamp)}_`;\n }\n\n return result;\n}\n\n// =============================================================================\n// Main Export\n// =============================================================================\n\n/**\n * Format an AI interaction event for sending to an LLM.\n *\n * Supports three format modes:\n * - 'natural': Human-readable text (default)\n * - 'structured': JSON object structure\n * - 'markdown': Markdown formatted text\n *\n * @param event - The interaction event to format\n * @param options - Formatting options\n * @returns Formatted string or object depending on format mode\n *\n * @example\n * ```ts\n * // Natural format (default)\n * formatInteractionForLLM(event)\n * // => \"I selected: Fast delivery, Premium quality\"\n *\n * // Structured format\n * formatInteractionForLLM(event, { format: 'structured' })\n * // => { type: 'user_interaction', component: 'select', ... }\n *\n * // Markdown format\n * formatInteractionForLLM(event, { format: 'markdown' })\n * // => \"**Selection (preferences):** `fast`, `quality`\"\n * ```\n */\nexport function formatInteractionForLLM(\n event: AIInteractionEvent,\n options?: FormatOptions,\n): string | object {\n const format = options?.format || 'natural';\n\n switch (format) {\n case 'structured':\n return formatStructured(event, options);\n case 'markdown':\n return formatMarkdown(event, options);\n case 'natural':\n return formatNatural(event, options);\n default:\n return assertNever(format, 'Unexpected AI interaction format');\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { formatInteractionForLLM } from "./index236.js";
2
+ import { useCallback, useMemo } from "react";
3
+ //#region src/hooks/useInteractionHandler.ts
4
+ /**
5
+ * Hook that creates a memoized interaction handler that automatically
6
+ * formats interaction events for LLM consumption.
7
+ *
8
+ * @param options - Configuration options including the callback and format settings
9
+ * @returns A stable callback function that handles interaction events
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function MyComponent() {
14
+ * const handleInteraction = useInteractionHandler({
15
+ * onInteraction: (event, formatted) => {
16
+ * console.log('Event:', event);
17
+ * console.log('Formatted:', formatted);
18
+ * // Send formatted message to LLM
19
+ * },
20
+ * format: 'natural', // or 'structured', 'markdown'
21
+ * });
22
+ *
23
+ * return (
24
+ * <AIInteractionProvider onInteraction={handleInteraction}>
25
+ * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>
26
+ * </AIInteractionProvider>
27
+ * );
28
+ * }
29
+ * ```
30
+ */
31
+ function useInteractionHandler(options) {
32
+ const { onInteraction, format, includeTimestamp, labels } = options;
33
+ const formatOptions = useMemo(() => ({
34
+ format,
35
+ includeTimestamp,
36
+ labels
37
+ }), [
38
+ format,
39
+ includeTimestamp,
40
+ labels
41
+ ]);
42
+ return useCallback((event) => {
43
+ const formatted = formatInteractionForLLM(event, formatOptions);
44
+ onInteraction(event, formatted);
45
+ }, [onInteraction, formatOptions]);
46
+ }
47
+ //#endregion
48
+ export { useInteractionHandler };
49
+
50
+ //# sourceMappingURL=index237.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index237.js","names":[],"sources":["../src/hooks/useInteractionHandler.ts"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport type { AIInteractionEvent } from '@/components/organisms/ai/_shared/interaction-context';\nimport {\n type FormatMode,\n type FormatOptions,\n formatInteractionForLLM,\n} from '@/lib/ai-interaction-format';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for the useInteractionHandler hook\n */\nexport interface UseInteractionHandlerOptions extends FormatOptions {\n /**\n * Callback invoked when an interaction occurs.\n * Receives both the raw event and the formatted message.\n */\n onInteraction: (\n event: AIInteractionEvent,\n formattedMessage: string | object,\n ) => void;\n}\n\n// =============================================================================\n// Hook\n// =============================================================================\n\n/**\n * Hook that creates a memoized interaction handler that automatically\n * formats interaction events for LLM consumption.\n *\n * @param options - Configuration options including the callback and format settings\n * @returns A stable callback function that handles interaction events\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const handleInteraction = useInteractionHandler({\n * onInteraction: (event, formatted) => {\n * console.log('Event:', event);\n * console.log('Formatted:', formatted);\n * // Send formatted message to LLM\n * },\n * format: 'natural', // or 'structured', 'markdown'\n * });\n *\n * return (\n * <AIInteractionProvider onInteraction={handleInteraction}>\n * <MarkdownRenderer>{markdownContent}</MarkdownRenderer>\n * </AIInteractionProvider>\n * );\n * }\n * ```\n */\nexport function useInteractionHandler(\n options: UseInteractionHandlerOptions,\n): (event: AIInteractionEvent) => void {\n const { onInteraction, format, includeTimestamp, labels } = options;\n\n // Memoize format options to ensure stable reference\n const formatOptions = useMemo<FormatOptions>(\n () => ({\n format,\n includeTimestamp,\n labels,\n }),\n [format, includeTimestamp, labels],\n );\n\n return useCallback(\n (event: AIInteractionEvent) => {\n const formatted = formatInteractionForLLM(event, formatOptions);\n onInteraction(event, formatted);\n },\n [onInteraction, formatOptions],\n );\n}\n\nexport type { FormatMode, FormatOptions };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,SAAgB,sBACd,SACqC;CACrC,MAAM,EAAE,eAAe,QAAQ,kBAAkB,WAAW;CAG5D,MAAM,gBAAgB,eACb;EACL;EACA;EACA;CACF,IACA;EAAC;EAAQ;EAAkB;CAAM,CACnC;CAEA,OAAO,aACJ,UAA8B;EAC7B,MAAM,YAAY,wBAAwB,OAAO,aAAa;EAC9D,cAAc,OAAO,SAAS;CAChC,GACA,CAAC,eAAe,aAAa,CAC/B;AACF"}