@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.
- package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
- package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
- package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
- package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
- package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
- package/dist/index.js +52 -52
- package/dist/index151.js +1 -1
- package/dist/index174.js +10 -333
- package/dist/index174.js.map +1 -1
- package/dist/index175.js +310 -137
- package/dist/index175.js.map +1 -1
- package/dist/index176.js +148 -174
- package/dist/index176.js.map +1 -1
- package/dist/index177.js +186 -78
- package/dist/index177.js.map +1 -1
- package/dist/index178.js +74 -124
- package/dist/index178.js.map +1 -1
- package/dist/index179.js +133 -1
- package/dist/index179.js.map +1 -0
- package/dist/index180.js +2 -201
- package/dist/index181.js +201 -0
- package/dist/{index180.js.map → index181.js.map} +1 -1
- package/dist/index183.js +130 -166
- package/dist/index183.js.map +1 -1
- package/dist/index184.js +195 -983
- package/dist/index184.js.map +1 -1
- package/dist/index185.js +1069 -369
- package/dist/index185.js.map +1 -1
- package/dist/index186.js +395 -197
- package/dist/index186.js.map +1 -1
- package/dist/index187.js +198 -243
- package/dist/index187.js.map +1 -1
- package/dist/index188.js +263 -3
- package/dist/index188.js.map +1 -1
- package/dist/index189.js +3 -209
- package/dist/index189.js.map +1 -1
- package/dist/index190.js +190 -777
- package/dist/index190.js.map +1 -1
- package/dist/index191.js +771 -252
- package/dist/index191.js.map +1 -1
- package/dist/index192.js +250 -65
- package/dist/index192.js.map +1 -1
- package/dist/index193.js +72 -523
- package/dist/index193.js.map +1 -1
- package/dist/index194.js +537 -144
- package/dist/index194.js.map +1 -1
- package/dist/index195.js +139 -720
- package/dist/index195.js.map +1 -1
- package/dist/index196.js +707 -167
- package/dist/index196.js.map +1 -1
- package/dist/index197.js +175 -151
- package/dist/index197.js.map +1 -1
- package/dist/index198.js +152 -487
- package/dist/index198.js.map +1 -1
- package/dist/index199.js +472 -225
- package/dist/index199.js.map +1 -1
- package/dist/index200.js +236 -260
- package/dist/index200.js.map +1 -1
- package/dist/index201.js +265 -215
- package/dist/index201.js.map +1 -1
- package/dist/index202.js +207 -307
- package/dist/index202.js.map +1 -1
- package/dist/index203.js +302 -135
- package/dist/index203.js.map +1 -1
- package/dist/index204.js +140 -271
- package/dist/index204.js.map +1 -1
- package/dist/index205.js +263 -253
- package/dist/index205.js.map +1 -1
- package/dist/index206.js +244 -137
- package/dist/index206.js.map +1 -1
- package/dist/index207.js +100 -238
- package/dist/index207.js.map +1 -1
- package/dist/index208.js +278 -74
- package/dist/index208.js.map +1 -1
- package/dist/index209.js +56 -97
- package/dist/index209.js.map +1 -1
- package/dist/index210.js +142 -47
- package/dist/index210.js.map +1 -1
- package/dist/index211.js +38 -84
- package/dist/index211.js.map +1 -1
- package/dist/index212.js +72 -252
- package/dist/index212.js.map +1 -1
- package/dist/index213.js +274 -26
- package/dist/index213.js.map +1 -1
- package/dist/index214.js +29 -94
- package/dist/index214.js.map +1 -1
- package/dist/index215.js +98 -25
- package/dist/index215.js.map +1 -1
- package/dist/index216.js +20 -565
- package/dist/index216.js.map +1 -1
- package/dist/index217.js +564 -17
- package/dist/index217.js.map +1 -1
- package/dist/index218.js +20 -23
- package/dist/index218.js.map +1 -1
- package/dist/index219.js +20 -95
- package/dist/index219.js.map +1 -1
- package/dist/index220.js +92 -88
- package/dist/index220.js.map +1 -1
- package/dist/index221.js +97 -29
- package/dist/index221.js.map +1 -1
- package/dist/index222.js +24 -470
- package/dist/index222.js.map +1 -1
- package/dist/index223.js +446 -196
- package/dist/index223.js.map +1 -1
- package/dist/index224.js +199 -729
- package/dist/index224.js.map +1 -1
- package/dist/index225.js +750 -61
- package/dist/index225.js.map +1 -1
- package/dist/index226.js +58 -181
- package/dist/index226.js.map +1 -1
- package/dist/index227.js +175 -259
- package/dist/index227.js.map +1 -1
- package/dist/index228.js +246 -172
- package/dist/index228.js.map +1 -1
- package/dist/index229.js +195 -32
- package/dist/index229.js.map +1 -1
- package/dist/index230.js +12 -40
- package/dist/index230.js.map +1 -1
- package/dist/index231.js +23 -26
- package/dist/index231.js.map +1 -1
- package/dist/index232.js +45 -22
- package/dist/index232.js.map +1 -1
- package/dist/index233.js +27 -48
- package/dist/index233.js.map +1 -1
- package/dist/index234.js +52 -26
- package/dist/index234.js.map +1 -1
- package/dist/index235.js +40 -225
- package/dist/index235.js.map +1 -1
- package/dist/index236.js +217 -39
- package/dist/index236.js.map +1 -1
- package/dist/index237.js +50 -0
- package/dist/index237.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/wc/AIToolCall.js +218 -0
- package/dist/wc/AIToolCall.js.map +1 -0
- package/dist/wc/hf-ai-tool-call.js +34 -219
- package/dist/wc/hf-ai-tool-call.js.map +1 -1
- package/dist/wc/hf-ai-tool-run.js +673 -576
- package/dist/wc/hf-ai-tool-run.js.map +1 -1
- package/dist/wc/workflow-step-renderer.js +94 -86
- package/dist/wc/workflow-step-renderer.js.map +1 -1
- package/dist/wc-react/AIToolCall.js +218 -0
- package/dist/wc-react/AIToolCall.js.map +1 -0
- package/dist/wc-react/hf-ai-tool-call.js +32 -217
- package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
- package/dist/wc-react/hf-ai-tool-run.js +698 -601
- package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
- package/dist/wc-react/workflow-step-renderer.js +76 -68
- package/dist/wc-react/workflow-step-renderer.js.map +1 -1
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
- package/dist/index182.js +0 -143
- package/dist/index182.js.map +0 -1
- package/dist/wc/wrench.js +0 -10
- package/dist/wc/wrench.js.map +0 -1
- package/dist/wc-react/wrench.js +0 -10
- package/dist/wc-react/wrench.js.map +0 -1
package/dist/index236.js
CHANGED
|
@@ -1,50 +1,228 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
*
|
|
6
|
-
|
|
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
|
|
9
|
-
* @
|
|
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
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* </AIInteractionProvider>
|
|
27
|
-
* );
|
|
28
|
-
* }
|
|
211
|
+
* // Markdown format
|
|
212
|
+
* formatInteractionForLLM(event, { format: 'markdown' })
|
|
213
|
+
* // => "**Selection (preferences):** `fast`, `quality`"
|
|
29
214
|
* ```
|
|
30
215
|
*/
|
|
31
|
-
function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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 {
|
|
226
|
+
export { formatInteractionForLLM };
|
|
49
227
|
|
|
50
228
|
//# sourceMappingURL=index236.js.map
|
package/dist/index236.js.map
CHANGED
|
@@ -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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"}
|
package/dist/index237.js
ADDED
|
@@ -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"}
|