@asteby/metacore-runtime-react 38.0.0 → 38.1.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 38.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 086e2b3: Paso asistido por IA en los wizards declarativos (`form_layout.sections[].assist`, kernel ≥ 0.141.0): `AssistInterview` renderiza dentro del paso una entrevista conversacional guiada por el proveedor del host (`/assist/:provider/sessions`): una pregunta a la vez con efecto de escritura, progreso en vivo (leyendo el sitio, buscando logo, detectando colores, IA…), tarjetas de vista previa (logo en claro/oscuro, paleta) y respuestas rápidas; al terminar rellena los campos `output` del formulario. Disponible en `DynamicRecordDialog` y `DynamicForm`.
8
+
3
9
  ## 38.0.0
4
10
 
5
11
  ### Minor Changes
@@ -0,0 +1,67 @@
1
+ import type { FormAssist } from './form-layout';
2
+ export interface AssistProgressStep {
3
+ label: string;
4
+ state: 'pending' | 'running' | 'done' | 'error';
5
+ detail?: string;
6
+ }
7
+ export interface AssistQuestion {
8
+ key: string;
9
+ prompt: string;
10
+ kind?: 'text' | 'choice' | 'confirm';
11
+ options?: {
12
+ value: string;
13
+ label: string;
14
+ }[];
15
+ placeholder?: string;
16
+ /** Prefilled suggestion the user can accept with Enter. */
17
+ suggestion?: string;
18
+ }
19
+ export interface AssistCard {
20
+ kind: string;
21
+ title?: string;
22
+ logo?: string;
23
+ logo_light?: string;
24
+ logo_dark?: string;
25
+ colors?: Record<string, string>;
26
+ lines?: {
27
+ label: string;
28
+ value: string;
29
+ }[];
30
+ }
31
+ export interface AssistTurn {
32
+ id: string;
33
+ type: 'message' | 'progress' | 'card' | 'question' | 'answer' | 'result';
34
+ text?: string;
35
+ steps?: AssistProgressStep[];
36
+ card?: AssistCard;
37
+ question?: AssistQuestion;
38
+ fields?: Record<string, any>;
39
+ }
40
+ export interface AssistSession {
41
+ id: string;
42
+ working: boolean;
43
+ done: boolean;
44
+ turns: AssistTurn[];
45
+ result?: Record<string, any>;
46
+ error?: string;
47
+ /** Optional: how many beats the provider expects (progress dots). */
48
+ beats?: number;
49
+ }
50
+ export interface AssistInterviewProps {
51
+ assist: FormAssist;
52
+ /** Live form values; the declared `input` fields are sent on start. */
53
+ values: Record<string, any>;
54
+ /** Called with the provider's result fields (limited to `output`). */
55
+ onApply: (fields: Record<string, any>) => void;
56
+ /** Start immediately (the step is the chat itself). Default true. */
57
+ autoStart?: boolean;
58
+ /** Small uppercase label above the headline (e.g. the step title). */
59
+ eyebrow?: string;
60
+ className?: string;
61
+ }
62
+ export declare function AssistInterview({ assist, values, onApply, autoStart, eyebrow, className }: AssistInterviewProps): import("react").JSX.Element;
63
+ /** Preview card: logo on dark and light, colour swatches, key/value lines. */
64
+ export declare function AssistCardView({ card }: {
65
+ card: AssistCard;
66
+ }): import("react").JSX.Element;
67
+ //# sourceMappingURL=assist-interview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assist-interview.d.ts","sourceRoot":"","sources":["../src/assist-interview.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;IACpC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC7C;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAA;IACxE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAC/B;AAED,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,UAAU,CAAA;IAClB,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3B,sEAAsE;IACtE,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAA;IAC9C,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACrB;AAwBD,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,SAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,oBAAoB,+BAyQtH;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,+BAwC5D"}
@@ -0,0 +1,214 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // AssistInterview — the conversational AI step of a declarative wizard
3
+ // (`form_layout.sections[].assist`, kernel v0.141.0).
4
+ //
5
+ // Link-onboarding style: ONE question at a time as a big typed headline,
6
+ // progress beats on top, a single answer input (or quick-reply chips) at the
7
+ // bottom, and the assistant's work (fetching a website, thinking…) shown as
8
+ // live status. No form inputs: the provider asks for whatever it needs, does
9
+ // the work, previews what it found and returns the fields the form takes.
10
+ // The panel is generic — it renders the turns the provider sends and knows
11
+ // nothing about brands. Protocol (host `/assist/:provider/…`):
12
+ //
13
+ // POST /assist/:provider/sessions { input } → Session
14
+ // GET /assist/:provider/sessions/:id → Session (poll while working)
15
+ // POST /assist/:provider/sessions/:id/reply { key, value } → Session
16
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
17
+ import { Button, Input } from '@asteby/metacore-ui/primitives';
18
+ import { ArrowRight, Check, CheckCircle2, Loader2, RotateCcw, Sparkles, XCircle } from 'lucide-react';
19
+ import { useApi } from './api-context';
20
+ const POLL_MS = 800;
21
+ const THINKING_HINTS = ['Un momento…', 'Sigo trabajando…', 'Casi listo…'];
22
+ function unwrap(res) {
23
+ const d = res?.data?.data ?? res?.data ?? res;
24
+ return d;
25
+ }
26
+ function useTypewriter(text) {
27
+ const [n, setN] = useState(0);
28
+ const reduce = typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
29
+ useEffect(() => {
30
+ setN(reduce ? text.length : 0);
31
+ }, [text, reduce]);
32
+ useEffect(() => {
33
+ if (n >= text.length)
34
+ return;
35
+ const t = setTimeout(() => setN(v => Math.min(text.length, v + 3)), 22);
36
+ return () => clearTimeout(t);
37
+ }, [n, text]);
38
+ return { shown: text.slice(0, n), typing: n < text.length };
39
+ }
40
+ export function AssistInterview({ assist, values, onApply, autoStart = true, eyebrow, className }) {
41
+ const api = useApi();
42
+ const [session, setSession] = useState(null);
43
+ const [starting, setStarting] = useState(false);
44
+ const [answer, setAnswer] = useState('');
45
+ const [applied, setApplied] = useState(false);
46
+ const [error, setError] = useState(null);
47
+ const [hintIdx, setHintIdx] = useState(0);
48
+ const inputRef = useRef(null);
49
+ // Answers given so far: if the host loses the session (restart, TTL) we
50
+ // start a new one and replay them, so the user never types twice.
51
+ const answersRef = useRef([]);
52
+ const base = `/assist/${encodeURIComponent(assist.provider)}/sessions`;
53
+ const inputPayload = useMemo(() => {
54
+ const out = {};
55
+ for (const k of assist.input ?? [])
56
+ out[k] = values?.[k];
57
+ return out;
58
+ }, [assist.input, values]);
59
+ const start = useCallback(async () => {
60
+ if (starting)
61
+ return;
62
+ setStarting(true);
63
+ setError(null);
64
+ setApplied(false);
65
+ answersRef.current = [];
66
+ try {
67
+ const res = await api.post(base, { input: inputPayload });
68
+ setSession(unwrap(res));
69
+ }
70
+ catch (e) {
71
+ setError(e?.response?.data?.message || e?.message || 'No se pudo iniciar el asistente');
72
+ }
73
+ finally {
74
+ setStarting(false);
75
+ }
76
+ }, [api, base, inputPayload, starting]);
77
+ const autoFired = useRef(false);
78
+ useEffect(() => {
79
+ if (!autoStart || autoFired.current || session)
80
+ return;
81
+ autoFired.current = true;
82
+ void start();
83
+ }, [autoStart, session, start]);
84
+ // Poll while the provider works.
85
+ useEffect(() => {
86
+ if (!session || !session.working || session.done)
87
+ return;
88
+ const t = setInterval(async () => {
89
+ try {
90
+ const res = await api.get(`${base}/${session.id}`);
91
+ setSession(unwrap(res));
92
+ }
93
+ catch (e) {
94
+ if (isGone(e)) {
95
+ try {
96
+ setSession(await recover());
97
+ }
98
+ catch {
99
+ /* next tick retries */
100
+ }
101
+ }
102
+ }
103
+ }, POLL_MS);
104
+ return () => clearInterval(t);
105
+ }, [api, base, session]);
106
+ // Rotate the thinking hint while working.
107
+ useEffect(() => {
108
+ if (!session?.working)
109
+ return;
110
+ setHintIdx(0);
111
+ const t = setInterval(() => setHintIdx(i => Math.min(i + 1, THINKING_HINTS.length - 1)), 2600);
112
+ return () => clearInterval(t);
113
+ }, [session?.working]);
114
+ // Apply the result once.
115
+ useEffect(() => {
116
+ if (!session?.done || !session.result || applied)
117
+ return;
118
+ const allowed = assist.output?.length ? new Set(assist.output) : null;
119
+ const out = {};
120
+ for (const [k, v] of Object.entries(session.result)) {
121
+ if (allowed && !allowed.has(k))
122
+ continue;
123
+ if (v === undefined || v === null || v === '')
124
+ continue;
125
+ out[k] = v;
126
+ }
127
+ onApply(out);
128
+ setApplied(true);
129
+ }, [session, applied, assist.output, onApply]);
130
+ const isGone = (e) => e?.response?.status === 404 || /sesi[oó]n no encontrada/i.test(String(e?.response?.data?.message || e?.message || ''));
131
+ // Recreate the session and replay every answer (host lost it).
132
+ const recover = useCallback(async () => {
133
+ const res = await api.post(base, { input: inputPayload });
134
+ let s = unwrap(res);
135
+ for (const a of answersRef.current) {
136
+ // wait until the provider is ready for the next answer
137
+ for (let i = 0; i < 120 && s.working && !s.done; i++) {
138
+ await new Promise(r => setTimeout(r, POLL_MS));
139
+ s = unwrap(await api.get(`${base}/${s.id}`));
140
+ }
141
+ if (s.done)
142
+ break;
143
+ s = unwrap(await api.post(`${base}/${s.id}/reply`, { key: a.key, value: a.value }));
144
+ }
145
+ return s;
146
+ }, [api, base, inputPayload]);
147
+ const reply = useCallback(async (key, value) => {
148
+ if (!session)
149
+ return;
150
+ setAnswer('');
151
+ setError(null);
152
+ setSession(s => (s ? { ...s, working: true } : s));
153
+ try {
154
+ const res = await api.post(`${base}/${session.id}/reply`, { key, value });
155
+ answersRef.current = [...answersRef.current, { key, value }];
156
+ setSession(unwrap(res));
157
+ }
158
+ catch (e) {
159
+ if (isGone(e)) {
160
+ try {
161
+ answersRef.current = [...answersRef.current, { key, value }];
162
+ setSession(await recover());
163
+ return;
164
+ }
165
+ catch (e2) {
166
+ setError(e2?.response?.data?.message || e2?.message || 'No se pudo retomar la conversación');
167
+ }
168
+ }
169
+ else {
170
+ setError(e?.response?.data?.message || e?.message || 'No se pudo enviar la respuesta');
171
+ }
172
+ setSession(s => (s ? { ...s, working: false } : s));
173
+ }
174
+ }, [api, base, session, recover]);
175
+ const turns = session?.turns ?? [];
176
+ const last = turns[turns.length - 1];
177
+ const pendingQuestion = !session?.working && !session?.done && last?.type === 'question' ? last.question : null;
178
+ const lastSpoken = [...turns].reverse().find(t => t.type === 'message' || t.type === 'question');
179
+ const headline = lastSpoken?.type === 'question' ? lastSpoken.question?.prompt ?? '' : lastSpoken?.text ?? '';
180
+ const { shown, typing } = useTypewriter(headline || (starting ? 'Un segundo…' : ''));
181
+ // The latest progress block stays visible as compact chips (done / error
182
+ // included) until the next block replaces it; the card that followed it
183
+ // shows whenever the assistant is waiting on the user or finished.
184
+ const activeProgress = [...turns].reverse().find(t => t.type === 'progress');
185
+ const lastCard = [...turns].reverse().find(t => t.type === 'card')?.card;
186
+ const answered = turns.filter(t => t.type === 'answer').length;
187
+ const beats = Math.max(session?.beats ?? 5, 2);
188
+ const progress = session?.done ? beats : Math.min(answered + 1, beats);
189
+ const running = activeProgress?.steps?.find(s => s.state === 'running');
190
+ useEffect(() => {
191
+ if (pendingQuestion && !typing)
192
+ inputRef.current?.focus();
193
+ }, [pendingQuestion, typing]);
194
+ const submitText = () => {
195
+ if (!pendingQuestion)
196
+ return;
197
+ const v = answer.trim() || pendingQuestion.suggestion || '';
198
+ if (v)
199
+ void reply(pendingQuestion.key, v);
200
+ };
201
+ return (_jsxs("div", { className: 'relative overflow-hidden rounded-2xl border bg-gradient-to-b from-primary/[0.06] via-background to-background px-5 py-6 sm:px-8 sm:py-8 ' + (className ?? ''), children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-primary", children: eyebrow || assist.label || 'Asistente' }), _jsx("div", { className: "flex items-center gap-1.5", "aria-label": "progreso", children: Array.from({ length: beats }).map((_, i) => (_jsx("span", { className: 'h-1.5 rounded-full transition-all duration-500 ' + (i < progress ? 'w-6 bg-primary' : 'w-3 bg-muted-foreground/25') }, i))) })] }), _jsxs("div", { className: "mt-5 flex items-start gap-3 sm:gap-4", children: [_jsx("span", { className: "mt-1 flex size-9 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-lg shadow-primary/25 sm:size-10", children: _jsx(Sparkles, { className: 'size-4 sm:size-5 ' + (session?.working || starting ? 'animate-pulse' : '') }) }), _jsxs("h3", { className: "min-h-[3.5rem] text-lg font-semibold leading-snug tracking-tight sm:min-h-[4rem] sm:text-2xl", children: [shown, typing && _jsx("span", { className: "ml-0.5 inline-block h-5 w-[2px] animate-pulse bg-primary align-middle" })] })] }), _jsxs("div", { className: "mt-3 min-h-6 pl-12 sm:pl-14", children: [(session?.working || starting) && !running && (_jsxs("span", { className: "inline-flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "size-3.5 animate-spin" }), THINKING_HINTS[hintIdx]] })), activeProgress && (_jsx("ul", { className: "mt-2 flex flex-wrap gap-x-4 gap-y-1", "aria-label": "pasos", children: (activeProgress.steps ?? []).map((s, i) => (_jsxs("li", { className: 'inline-flex items-center gap-1.5 text-xs ' + (s.state === 'pending' ? 'text-muted-foreground/70' : s.state === 'error' ? 'text-destructive' : 'text-foreground/80'), children: [s.state === 'done' ? _jsx(CheckCircle2, { className: "size-3.5 text-emerald-500" }) : s.state === 'running' ? _jsx(Loader2, { className: "size-3.5 animate-spin text-primary" }) : s.state === 'error' ? _jsx(XCircle, { className: "size-3.5" }) : _jsx("span", { className: "size-1.5 rounded-full bg-muted-foreground/40" }), s.label, s.state === 'running' && s.detail && _jsxs("span", { className: "text-muted-foreground", children: ["\u00B7 ", s.detail] })] }, i))) })), lastCard && !session?.working && _jsx(AssistCardView, { card: lastCard }), session?.done && (_jsxs("span", { className: "inline-flex items-center gap-2 text-sm font-medium text-emerald-600 dark:text-emerald-400", children: [_jsx(Check, { className: "size-4" }), applied ? 'Listo. Pulsa Siguiente para revisar lo que armé.' : 'Listo.'] })), (error || session?.error) && _jsx("p", { className: "text-sm text-destructive", children: error || session?.error })] }), pendingQuestion && (_jsxs("div", { className: "mt-5 pl-0 sm:pl-14", children: [pendingQuestion.kind === 'choice' || pendingQuestion.kind === 'confirm' ? (_jsx("div", { className: "flex flex-wrap gap-2", children: (pendingQuestion.options ?? [{ value: 'yes', label: 'Sí' }, { value: 'no', label: 'No' }]).map(o => (_jsx(Button, { type: "button", variant: "outline", className: "h-10 rounded-full px-4", onClick: () => void reply(pendingQuestion.key, o.value), children: o.label }, o.value))) })) : (_jsxs("div", { className: "relative", children: [_jsx(Input, { ref: inputRef, value: answer, onChange: e => setAnswer(e.target.value), onKeyDown: e => {
202
+ if (e.key === 'Enter') {
203
+ e.preventDefault();
204
+ submitText();
205
+ }
206
+ }, placeholder: pendingQuestion.suggestion || pendingQuestion.placeholder || 'Escribe tu respuesta…', className: "h-12 pr-12 text-base", autoFocus: true }), _jsx(Button, { type: "button", size: "icon", className: "absolute right-1.5 top-1.5 size-9", onClick: submitText, disabled: !answer.trim() && !pendingQuestion.suggestion, children: _jsx(ArrowRight, { className: "size-4" }) })] })), pendingQuestion.suggestion && pendingQuestion.kind !== 'choice' && (_jsx("p", { className: "pt-1.5 text-xs text-muted-foreground", children: "Enter acepta la sugerencia." }))] })), !session && !starting && (_jsx("div", { className: "mt-5 pl-0 sm:pl-14", children: _jsxs(Button, { type: "button", onClick: () => void start(), children: [_jsx(Sparkles, { className: "mr-2 size-4" }), assist.label || 'Empezar'] }) })), session?.done && (_jsx("div", { className: "mt-4 pl-0 sm:pl-14", children: _jsxs("button", { type: "button", onClick: () => { setSession(null); setApplied(false); autoFired.current = false; }, className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground", children: [_jsx(RotateCcw, { className: "size-3.5" }), " Empezar de nuevo"] }) }))] }));
207
+ }
208
+ /** Preview card: logo on dark and light, colour swatches, key/value lines. */
209
+ export function AssistCardView({ card }) {
210
+ const colors = Object.entries(card.colors ?? {});
211
+ const logoDark = card.logo_light || card.logo;
212
+ const logoLight = card.logo_dark || card.logo;
213
+ return (_jsxs("div", { className: "mt-3 rounded-xl border bg-background p-3", children: [card.title && _jsx("p", { className: "pb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: card.title }), (card.logo || card.logo_light || card.logo_dark) && (_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx("div", { className: "flex h-20 items-center justify-center rounded-lg bg-neutral-950 p-3", children: logoDark && _jsx("img", { src: logoDark, alt: "", className: "max-h-full max-w-full object-contain" }) }), _jsx("div", { className: "flex h-20 items-center justify-center rounded-lg border bg-white p-3", children: logoLight && _jsx("img", { src: logoLight, alt: "", className: "max-h-full max-w-full object-contain" }) })] })), colors.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 pt-3", children: colors.map(([k, v]) => (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full border px-2 py-1 text-xs", children: [_jsx("span", { className: "size-4 rounded-full border", style: { backgroundColor: v } }), _jsx("span", { className: "text-muted-foreground", children: k }), _jsx("span", { className: "font-mono", children: v })] }, k))) })), (card.lines ?? []).length > 0 && (_jsx("dl", { className: "grid gap-1 pt-3 text-sm", children: card.lines.map(l => (_jsxs("div", { className: "grid grid-cols-[6rem_1fr] gap-2", children: [_jsx("dt", { className: "text-muted-foreground", children: l.label }), _jsx("dd", { className: "min-w-0 break-words", children: l.value })] }, l.label))) }))] }));
214
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AA+C1C,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAoB3C,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnE,OAAO,EAAqC,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAK1F,YAAY,EAAE,WAAW,EAAE,CAAA;AAE3B,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;IACpH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;IACvB,YAAY,CAAC,EAAE,GAAG,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACjC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,SAAS,EAAE,CAAA;IACxB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,SAAS,EAAE,CAAA;IACzB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,0CAA0C;IAC1C,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AA0CD,MAAM,WAAW,wBAAwB;IACrC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAA;IACzB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;2DAEuD;IACvD,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IAClF;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACpG;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;IAC1C;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAK1D;AAaD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,CAgBtE;AAID,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,EAAE,GAAG,SAAS,CAExE;AAQD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAerE;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,cAAc,GAAG,IAAI,CAa5F;AA+GD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAUjE;AAaD,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,EAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,QAAQ,EAAE,CAOZ;AAUD,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB;AAiBD,wBAAgB,mBAAmB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,sBAAsB,EACtB,YAAY,EACZ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,cAAc,EACd,aAAa,EACb,WAA8B,EAC9B,QAAQ,EACR,QAAQ,EACR,QAAQ,GACX,EAAE,wBAAwB,+BAkkB1B;AAuED,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,+BAelF;AA+GD,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,KAAK,EAAE,QAAQ,EACf,MAAM,EACN,WAAW,EAAE,eAAe,EAC5B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,GACzB,EAAE;IACC,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,GAAG,CAAA;IACV,MAAM,EAAE,GAAG,CAAA;IACX,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB,+BA6SA;AAwLD,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IACnE,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB,+BA+NA"}
1
+ {"version":3,"file":"dynamic-record.d.ts","sourceRoot":"","sources":["../../src/dialogs/dynamic-record.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AA+C1C,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAqB3C,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEnE,OAAO,EAAqC,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAK1F,YAAY,EAAE,WAAW,EAAE,CAAA;AAE3B,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;IACpH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;IACvB,YAAY,CAAC,EAAE,GAAG,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACjC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,SAAS,EAAE,CAAA;IACxB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,SAAS,EAAE,CAAA;IACzB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,0CAA0C;IAC1C,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AA0CD,MAAM,WAAW,wBAAwB;IACrC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,QAAQ,EAAE,CAAA;IACzB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;2DAEuD;IACvD,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IAClF;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACpG;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAA;IAC1C;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACxB;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAK1D;AAaD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,CAgBtE;AAID,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,EAAE,GAAG,SAAS,CAExE;AAQD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAerE;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,cAAc,GAAG,IAAI,CAa5F;AA+GD,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAUjE;AAaD,wBAAgB,mBAAmB,CAC/B,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,EAChC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,QAAQ,EAAE,CAOZ;AAUD,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,MAAM,EAAE,QAAQ,EAAE,GAAG,SAAS,EAC9B,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB;AAiBD,wBAAgB,mBAAmB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,sBAAsB,EACtB,YAAY,EACZ,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,cAAc,EACd,aAAa,EACb,WAA8B,EAC9B,QAAQ,EACR,QAAQ,EACR,QAAQ,GACX,EAAE,wBAAwB,+BAwlB1B;AAuED,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,+BAelF;AA+GD,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,KAAK,EAAE,QAAQ,EACf,MAAM,EACN,WAAW,EAAE,eAAe,EAC5B,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,YAAY,GACzB,EAAE;IACC,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,GAAG,CAAA;IACV,MAAM,EAAE,GAAG,CAAA;IACX,mFAAmF;IACnF,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB,+BA6SA;AAwLD,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IACnE,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,GAAG,CAAA;IACV,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,8EAA8E;IAC9E,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB,+BA+NA"}
@@ -32,6 +32,7 @@ import { useOptionsResolver } from '../use-options-resolver';
32
32
  import { getFieldRef, getVisibleWhen, evaluateVisibleWhen } from '../dynamic-form-schema';
33
33
  import { groupFieldsBySection } from '../form-layout';
34
34
  import { FieldSection, WizardProgress } from '../form-layout-ui';
35
+ import { AssistInterview } from '../assist-interview';
35
36
  import { FieldCell } from '../field-grid';
36
37
  import { isNilUuid, normalizeNilUuid } from '../nil-uuid';
37
38
  import { normalizeRefFieldsForSubmit } from './normalize-submit';
@@ -718,7 +719,10 @@ export function DynamicRecordDialog({ open, onOpenChange, nestedInlineCreateSelf
718
719
  setStepIndex(Math.min(clampedStep + 1, groups.length - 1));
719
720
  };
720
721
  const goBackStep = () => setStepIndex(Math.max(clampedStep - 1, 0));
721
- return (_jsx(RecordDialogModelContext.Provider, { value: model, children: _jsx(Dialog, { open: open, onOpenChange: onOpenChange, nestedInlineCreateSelf: nestedInlineCreateSelf, children: _jsxs(DialogContent, { className: "sm:max-w-2xl max-h-[90dvh] flex flex-col p-0 gap-0 overflow-hidden", style: { maxHeight: '90dvh' }, children: [_jsxs(DialogHeader, { className: "p-6 pb-4 border-b shrink-0", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: config.description })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-6", children: loading ? (_jsx(LoadingSkeleton, {})) : modalMeta ? (_jsx(ModelContext.Provider, { value: model, children: _jsx(ImageUrlContext.Provider, { value: getImageUrl, children: _jsx(TimeZoneContext.Provider, { value: timeZone, children: _jsxs(CurrencyContext.Provider, { value: currency, children: [_jsxs("form", { id: formId, onSubmit: handleSubmit, className: "grid gap-y-4", children: [isSteps && (_jsx(WizardProgress, { groups: groups, stepIndex: clampedStep, onStepClick: i => setStepIndex(i) })), (isSteps ? [groups[clampedStep]] : groups).map(group => (_jsx(FieldSection, { group: group, children: _jsx("div", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: renderFields(group.fields) }) }, group.key))), record?.external_url && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2", children: _jsx("div", { className: "sm:col-span-2 min-w-0", children: _jsxs("a", { href: record.external_url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline mt-1", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Ver en ", record.external_provider ?? 'proveedor externo'] }) }) }))] }), !isCreate && record && relations.length > 0 && (_jsx("div", { className: "mt-6", children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, embedOnly: true, canCreate: mode === 'edit', canEdit: mode === 'edit', canDelete: mode === 'edit', onChange: handleChildChange }) }))] }) }) }) })) : null }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0 sm:justify-between", children: [isView && onOpenFullPage ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground", onClick: () => { onOpenChange(false); onOpenFullPage(); }, children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), "Ver p\u00E1gina completa"] })) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [isSteps && clampedStep > 0 ? (_jsx(Button, { variant: "outline", onClick: goBackStep, disabled: saving || deleting, children: "Anterior" })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: saving || deleting, children: config.cancelLabel })), isView && onDelete && (_jsxs(Button, { variant: "destructive", onClick: handleDelete, disabled: deleting || loading, children: [deleting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), deleting ? 'Eliminando...' : 'Eliminar'] })), isView && onEdit && (_jsx(Button, { onClick: onEdit, disabled: deleting || loading, children: "Editar" })), isEditable && isSteps && !isLastStep && (_jsx(Button, { type: "button", onClick: goNextStep, disabled: saving || loading, children: "Siguiente" })), isEditable && (!isSteps || isLastStep) && (_jsxs(Button, { type: "submit", form: formId, disabled: saving || loading, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? config.submittingLabel : config.submitLabel] }))] })] })] }) }) }));
722
+ return (_jsx(RecordDialogModelContext.Provider, { value: model, children: _jsx(Dialog, { open: open, onOpenChange: onOpenChange, nestedInlineCreateSelf: nestedInlineCreateSelf, children: _jsxs(DialogContent, { className: "sm:max-w-2xl max-h-[90dvh] flex flex-col p-0 gap-0 overflow-hidden", style: { maxHeight: '90dvh' }, children: [_jsxs(DialogHeader, { className: "p-6 pb-4 border-b shrink-0", children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: config.description })] }), _jsx("div", { className: "flex-1 overflow-y-auto p-6", children: loading ? (_jsx(LoadingSkeleton, {})) : modalMeta ? (_jsx(ModelContext.Provider, { value: model, children: _jsx(ImageUrlContext.Provider, { value: getImageUrl, children: _jsx(TimeZoneContext.Provider, { value: timeZone, children: _jsxs(CurrencyContext.Provider, { value: currency, children: [_jsxs("form", { id: formId, onSubmit: handleSubmit, className: "grid gap-y-4", children: [isSteps && (_jsx(WizardProgress, { groups: groups, stepIndex: clampedStep, onStepClick: i => setStepIndex(i) })), (isSteps ? [groups[clampedStep]] : groups).map(group =>
723
+ // An assisted step IS the interview: no form inputs, the
724
+ // provider asks what it needs and fills the fields.
725
+ isSteps && isEditable && group.assist ? (_jsx(AssistInterview, { assist: group.assist, values: formValues, eyebrow: group.title, autoStart: group.assist.trigger !== 'button', onApply: fields => setFormValues(prev => ({ ...prev, ...fields })) }, group.key)) : (_jsxs(FieldSection, { group: group, children: [_jsx("div", { className: "grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2", children: renderFields(group.fields) }), isEditable && group.assist && (_jsx(AssistInterview, { assist: group.assist, values: formValues, eyebrow: group.title, autoStart: group.assist.trigger === 'auto', onApply: fields => setFormValues(prev => ({ ...prev, ...fields })) }))] }, group.key))), record?.external_url && (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2", children: _jsx("div", { className: "sm:col-span-2 min-w-0", children: _jsxs("a", { href: record.external_url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1.5 text-sm text-primary hover:underline mt-1", children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Ver en ", record.external_provider ?? 'proveedor externo'] }) }) }))] }), !isCreate && record && relations.length > 0 && (_jsx("div", { className: "mt-6", children: _jsx(DynamicRelations, { record: record, relations: relations, lineSubtable: true, embedOnly: true, canCreate: mode === 'edit', canEdit: mode === 'edit', canDelete: mode === 'edit', onChange: handleChildChange }) }))] }) }) }) })) : null }), _jsxs(DialogFooter, { className: "p-4 border-t shrink-0 sm:justify-between", children: [isView && onOpenFullPage ? (_jsxs(Button, { variant: "ghost", size: "sm", className: "text-muted-foreground", onClick: () => { onOpenChange(false); onOpenFullPage(); }, children: [_jsx(ExternalLink, { className: "mr-1.5 h-3.5 w-3.5" }), "Ver p\u00E1gina completa"] })) : _jsx("span", {}), _jsxs("div", { className: "flex items-center gap-2", children: [isSteps && clampedStep > 0 ? (_jsx(Button, { variant: "outline", onClick: goBackStep, disabled: saving || deleting, children: "Anterior" })) : (_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: saving || deleting, children: config.cancelLabel })), isView && onDelete && (_jsxs(Button, { variant: "destructive", onClick: handleDelete, disabled: deleting || loading, children: [deleting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), deleting ? 'Eliminando...' : 'Eliminar'] })), isView && onEdit && (_jsx(Button, { onClick: onEdit, disabled: deleting || loading, children: "Editar" })), isEditable && isSteps && !isLastStep && (_jsx(Button, { type: "button", onClick: goNextStep, disabled: saving || loading, children: "Siguiente" })), isEditable && (!isSteps || isLastStep) && (_jsxs(Button, { type: "submit", form: formId, disabled: saving || loading, children: [saving && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), saving ? config.submittingLabel : config.submitLabel] }))] })] })] }) }) }));
722
726
  }
723
727
  function LoadingSkeleton() {
724
728
  return (_jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-4", children: Array.from({ length: 6 }).map((_, i) => (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Skeleton, { className: "h-3.5 w-24" }), _jsx(Skeleton, { className: "h-9 w-full" })] }, i))) }));
@@ -1 +1 @@
1
- {"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAcrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAOhB,MAAM,uBAAuB,CAAA;AAY9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEzF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,EAChB,UAAU,GACb,EAAE,gBAAgB,+BA8LlB"}
1
+ {"version":3,"file":"dynamic-form.d.ts","sourceRoot":"","sources":["../src/dynamic-form.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAerE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,EACH,cAAc,EACd,aAAa,EAOhB,MAAM,uBAAuB,CAAA;AAY9B,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEzF,MAAM,WAAW,gBAAgB;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CAC1B;AAED,wBAAgB,WAAW,CAAC,EACxB,MAAM,EACN,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,WAAuB,EACvB,WAAwB,EACxB,QAAgB,EAChB,UAAU,GACb,EAAE,gBAAgB,+BAwMlB"}
@@ -5,6 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  import { useEffect, useMemo, useState } from 'react';
6
6
  import { groupFieldsBySection } from './form-layout';
7
7
  import { FieldSection, WizardProgress } from './form-layout-ui';
8
+ import { AssistInterview } from './assist-interview';
8
9
  import { Input, Textarea, Label, Switch, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@asteby/metacore-ui/primitives';
9
10
  import { buildZodSchema, resolveWidget, isLineItemsField, evaluateBalance, applyOptionWhen, getDependsOn, getVisibleWhen, evaluateVisibleWhen, } from './dynamic-form-schema';
10
11
  import { ScanLine } from 'lucide-react';
@@ -132,7 +133,7 @@ export function DynamicForm({ fields, initialValues, onSubmit, onCancel, submitL
132
133
  setStepIndex((i) => Math.min(i + 1, groups.length - 1));
133
134
  };
134
135
  const goBack = () => setStepIndex((i) => Math.max(i - 1, 0));
135
- return (_jsxs("form", { onSubmit: handleSubmit, className: "grid gap-4", children: [_jsx(WizardProgress, { groups: groups, stepIndex: stepIndex, onStepClick: i => setStepIndex(i) }), renderGrid(step.fields), _jsxs("div", { className: "flex justify-between gap-2 pt-2", children: [stepIndex > 0 ? (_jsx(Button, { type: "button", variant: "outline", onClick: goBack, disabled: submitting || disabled, children: "Anterior" })) : onCancel ? (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: submitting || disabled, children: cancelLabel })) : (_jsx("span", {})), isLast ? (_jsx(Button, { type: "submit", disabled: submitting || disabled || balanceBlocked, children: submitLabel })) : (_jsx(Button, { type: "button", onClick: goNext, disabled: submitting || disabled, children: "Siguiente" }))] })] }));
136
+ return (_jsxs("form", { onSubmit: handleSubmit, className: "grid gap-4", children: [_jsx(WizardProgress, { groups: groups, stepIndex: stepIndex, onStepClick: i => setStepIndex(i) }), step.assist ? (_jsx(AssistInterview, { assist: step.assist, values: values, eyebrow: step.title, autoStart: step.assist.trigger !== 'button', onApply: fields => setValues(prev => ({ ...prev, ...fields })) })) : (renderGrid(step.fields)), _jsxs("div", { className: "flex justify-between gap-2 pt-2", children: [stepIndex > 0 ? (_jsx(Button, { type: "button", variant: "outline", onClick: goBack, disabled: submitting || disabled, children: "Anterior" })) : onCancel ? (_jsx(Button, { type: "button", variant: "outline", onClick: onCancel, disabled: submitting || disabled, children: cancelLabel })) : (_jsx("span", {})), isLast ? (_jsx(Button, { type: "submit", disabled: submitting || disabled || balanceBlocked, children: submitLabel })) : (_jsx(Button, { type: "button", onClick: goNext, disabled: submitting || disabled, children: "Siguiente" }))] })] }));
136
137
  }
137
138
  // ── Sections / flat mode ───────────────────────────────────────────────
138
139
  // Layout: scalar header fields flow through a responsive 2-column grid;
@@ -1 +1 @@
1
- {"version":3,"file":"form-layout-ui.d.ts","sourceRoot":"","sources":["../src/form-layout-ui.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,GACX,EAAE;IACC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC5B,+BA6CA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,SAAkB,EAClB,WAAW,GACd,EAAE;IACC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gFAAgF;IAChF,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC,+BAeA"}
1
+ {"version":3,"file":"form-layout-ui.d.ts","sourceRoot":"","sources":["../src/form-layout-ui.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,GACX,EAAE;IACC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC5B,+BA6CA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,SAAkB,EAClB,WAAW,GACd,EAAE;IACC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gFAAgF;IAChF,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC,+BAYA"}
@@ -37,5 +37,5 @@ export function FieldSection({ group, children, }) {
37
37
  export function WizardProgress({ groups, stepIndex, stepLabel = 'Paso', onStepClick, }) {
38
38
  const current = groups[stepIndex];
39
39
  const steps = groups.map((g, i) => ({ key: g.key, label: g.title ?? `${stepLabel} ${i + 1}` }));
40
- return (_jsxs("div", { className: "pt-1", children: [_jsx(ProcessStepper, { steps: steps, activeIndex: stepIndex, onStepClick: onStepClick }), _jsxs("p", { className: "pt-3 text-sm text-muted-foreground", children: [stepLabel, " ", stepIndex + 1, "/", groups.length, current?.title ? ` · ${current.title}` : ''] }), current?.description && (_jsx("p", { className: "pt-1 text-sm text-muted-foreground", children: current.description }))] }));
40
+ return (_jsxs("div", { className: "pt-1", children: [_jsx(ProcessStepper, { steps: steps, activeIndex: stepIndex, onStepClick: onStepClick }), _jsxs("p", { className: "pt-3 text-sm text-muted-foreground", children: [stepLabel, " ", stepIndex + 1, "/", groups.length, current?.title ? ` · ${current.title}` : ''] })] }));
41
41
  }
@@ -13,6 +13,22 @@ export interface FormSection {
13
13
  * Tolerates the camelCase alias, same as fields. */
14
14
  visible_when?: VisibleWhen;
15
15
  visibleWhen?: VisibleWhen;
16
+ /** AI-assisted step (kernel v0.141.0): the SDK renders an interview panel
17
+ * driven by the host's assist provider inside this section. */
18
+ assist?: FormAssist;
19
+ }
20
+ /** Declaration of an AI-assisted step (`form_layout.sections[].assist`). */
21
+ export interface FormAssist {
22
+ /** Host-registered provider key, e.g. `brand.website_dna`. */
23
+ provider: string;
24
+ label?: string;
25
+ description?: string;
26
+ /** Form fields sent to the provider when the session starts. */
27
+ input?: string[];
28
+ /** Form fields the provider may fill when it finishes. */
29
+ output?: string[];
30
+ /** `button` (default) or `auto` (start as soon as every input has a value). */
31
+ trigger?: 'button' | 'auto';
16
32
  }
17
33
  /** Model-level layout directive. `mode` defaults to `"sections"`. */
18
34
  export interface FormLayout {
@@ -30,6 +46,8 @@ export interface FieldGroup<F> {
30
46
  /** True for the synthetic group holding section-less / unknown-section fields. */
31
47
  isDefault: boolean;
32
48
  fields: F[];
49
+ /** AI-assisted step declaration, when the section has one. */
50
+ assist?: FormAssist;
33
51
  }
34
52
  /** The synthetic key of the orphan group (fields with no / unknown `section`). */
35
53
  export declare const DEFAULT_SECTION_KEY = "__default__";
@@ -1 +1 @@
1
- {"version":3,"file":"form-layout.d.ts","sourceRoot":"","sources":["../src/form-layout.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG1C;0DAC0D;AAC1D,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;wDAGoD;IACpD,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;CAC5B;AAED,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACvB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAC3B;AAED;oDACoD;AACpD,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kFAAkF;IAClF,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,CAAC,EAAE,CAAA;CACd;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,gBAAgB,CAAA;AAEhD,yEAAyE;AACzE,wBAAgB,eAAe,CAC3B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GACjE,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/D,MAAM,EAAE,CAAC,EAAE,EACX,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GACpC,UAAU,CAAC,CAAC,CAAC,EAAE,CAoDjB"}
1
+ {"version":3,"file":"form-layout.d.ts","sourceRoot":"","sources":["../src/form-layout.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG1C;0DAC0D;AAC1D,MAAM,WAAW,WAAW;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;wDAGoD;IACpD,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB;mEAC+D;IAC/D,MAAM,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACvB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;CAC9B;AAED,qEAAqE;AACrE,MAAM,WAAW,UAAU;IACvB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CAC3B;AAED;oDACoD;AACpD,MAAM,WAAW,UAAU,CAAC,CAAC;IACzB,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kFAAkF;IAClF,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,CAAC,EAAE,CAAA;IACX,8DAA8D;IAC9D,MAAM,CAAC,EAAE,UAAU,CAAA;CACtB;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,gBAAgB,CAAA;AAEhD,yEAAyE;AACzE,wBAAgB,eAAe,CAC3B,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GACjE,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/D,MAAM,EAAE,CAAC,EAAE,EACX,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GACpC,UAAU,CAAC,CAAC,CAAC,EAAE,CAqDjB"}
@@ -95,6 +95,7 @@ export function groupFieldsBySection(fields, layout, values) {
95
95
  collapsed: s.collapsed,
96
96
  isDefault: false,
97
97
  fields: secFields,
98
+ assist: s.assist,
98
99
  });
99
100
  }
100
101
  return groups;
package/dist/index.d.ts CHANGED
@@ -86,4 +86,6 @@ export { StatWidget, BarWidget, LineWidget, AreaWidget, PieWidget, DonutWidget,
86
86
  export { WidgetRenderer, WidgetSkeleton, SIZE_SPAN, SIZE_CLASS, type WidgetRendererProps, } from './widgets/widget-renderer';
87
87
  export { WidgetCard, DeltaChip, WidgetEmpty, WidgetError, type WidgetCardProps, } from './widgets/widget-card';
88
88
  export { formatWidgetValue, formatAxisTick, formatDelta, accentClasses, paletteColor, CHART_PALETTE, type AccentClasses, type WidgetFormatCtx, } from './widgets/widget-format';
89
+ export { AssistInterview, AssistCardView } from './assist-interview';
90
+ export type { AssistSession, AssistTurn, AssistQuestion, AssistCard, AssistProgressStep } from './assist-interview';
89
91
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -85,3 +85,4 @@ export { StatWidget, BarWidget, LineWidget, AreaWidget, PieWidget, DonutWidget,
85
85
  export { WidgetRenderer, WidgetSkeleton, SIZE_SPAN, SIZE_CLASS, } from './widgets/widget-renderer';
86
86
  export { WidgetCard, DeltaChip, WidgetEmpty, WidgetError, } from './widgets/widget-card';
87
87
  export { formatWidgetValue, formatAxisTick, formatDelta, accentClasses, paletteColor, CHART_PALETTE, } from './widgets/widget-format';
88
+ export { AssistInterview, AssistCardView } from './assist-interview';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "38.0.0",
3
+ "version": "38.1.0",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,411 @@
1
+ // AssistInterview — the conversational AI step of a declarative wizard
2
+ // (`form_layout.sections[].assist`, kernel v0.141.0).
3
+ //
4
+ // Link-onboarding style: ONE question at a time as a big typed headline,
5
+ // progress beats on top, a single answer input (or quick-reply chips) at the
6
+ // bottom, and the assistant's work (fetching a website, thinking…) shown as
7
+ // live status. No form inputs: the provider asks for whatever it needs, does
8
+ // the work, previews what it found and returns the fields the form takes.
9
+ // The panel is generic — it renders the turns the provider sends and knows
10
+ // nothing about brands. Protocol (host `/assist/:provider/…`):
11
+ //
12
+ // POST /assist/:provider/sessions { input } → Session
13
+ // GET /assist/:provider/sessions/:id → Session (poll while working)
14
+ // POST /assist/:provider/sessions/:id/reply { key, value } → Session
15
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
16
+ import { Button, Input } from '@asteby/metacore-ui/primitives'
17
+ import { ArrowRight, Check, CheckCircle2, Loader2, RotateCcw, Sparkles, XCircle } from 'lucide-react'
18
+ import { useApi } from './api-context'
19
+ import type { FormAssist } from './form-layout'
20
+
21
+ export interface AssistProgressStep {
22
+ label: string
23
+ state: 'pending' | 'running' | 'done' | 'error'
24
+ detail?: string
25
+ }
26
+
27
+ export interface AssistQuestion {
28
+ key: string
29
+ prompt: string
30
+ kind?: 'text' | 'choice' | 'confirm'
31
+ options?: { value: string; label: string }[]
32
+ placeholder?: string
33
+ /** Prefilled suggestion the user can accept with Enter. */
34
+ suggestion?: string
35
+ }
36
+
37
+ export interface AssistCard {
38
+ kind: string
39
+ title?: string
40
+ logo?: string
41
+ logo_light?: string
42
+ logo_dark?: string
43
+ colors?: Record<string, string>
44
+ lines?: { label: string; value: string }[]
45
+ }
46
+
47
+ export interface AssistTurn {
48
+ id: string
49
+ type: 'message' | 'progress' | 'card' | 'question' | 'answer' | 'result'
50
+ text?: string
51
+ steps?: AssistProgressStep[]
52
+ card?: AssistCard
53
+ question?: AssistQuestion
54
+ fields?: Record<string, any>
55
+ }
56
+
57
+ export interface AssistSession {
58
+ id: string
59
+ working: boolean
60
+ done: boolean
61
+ turns: AssistTurn[]
62
+ result?: Record<string, any>
63
+ error?: string
64
+ /** Optional: how many beats the provider expects (progress dots). */
65
+ beats?: number
66
+ }
67
+
68
+ export interface AssistInterviewProps {
69
+ assist: FormAssist
70
+ /** Live form values; the declared `input` fields are sent on start. */
71
+ values: Record<string, any>
72
+ /** Called with the provider's result fields (limited to `output`). */
73
+ onApply: (fields: Record<string, any>) => void
74
+ /** Start immediately (the step is the chat itself). Default true. */
75
+ autoStart?: boolean
76
+ /** Small uppercase label above the headline (e.g. the step title). */
77
+ eyebrow?: string
78
+ className?: string
79
+ }
80
+
81
+ const POLL_MS = 800
82
+ const THINKING_HINTS = ['Un momento…', 'Sigo trabajando…', 'Casi listo…']
83
+
84
+ function unwrap(res: any): AssistSession {
85
+ const d = res?.data?.data ?? res?.data ?? res
86
+ return d as AssistSession
87
+ }
88
+
89
+ function useTypewriter(text: string) {
90
+ const [n, setN] = useState(0)
91
+ const reduce = typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches
92
+ useEffect(() => {
93
+ setN(reduce ? text.length : 0)
94
+ }, [text, reduce])
95
+ useEffect(() => {
96
+ if (n >= text.length) return
97
+ const t = setTimeout(() => setN(v => Math.min(text.length, v + 3)), 22)
98
+ return () => clearTimeout(t)
99
+ }, [n, text])
100
+ return { shown: text.slice(0, n), typing: n < text.length }
101
+ }
102
+
103
+ export function AssistInterview({ assist, values, onApply, autoStart = true, eyebrow, className }: AssistInterviewProps) {
104
+ const api = useApi()
105
+ const [session, setSession] = useState<AssistSession | null>(null)
106
+ const [starting, setStarting] = useState(false)
107
+ const [answer, setAnswer] = useState('')
108
+ const [applied, setApplied] = useState(false)
109
+ const [error, setError] = useState<string | null>(null)
110
+ const [hintIdx, setHintIdx] = useState(0)
111
+ const inputRef = useRef<HTMLInputElement | null>(null)
112
+ // Answers given so far: if the host loses the session (restart, TTL) we
113
+ // start a new one and replay them, so the user never types twice.
114
+ const answersRef = useRef<{ key: string; value: any }[]>([])
115
+ const base = `/assist/${encodeURIComponent(assist.provider)}/sessions`
116
+
117
+ const inputPayload = useMemo(() => {
118
+ const out: Record<string, any> = {}
119
+ for (const k of assist.input ?? []) out[k] = values?.[k]
120
+ return out
121
+ }, [assist.input, values])
122
+
123
+ const start = useCallback(async () => {
124
+ if (starting) return
125
+ setStarting(true)
126
+ setError(null)
127
+ setApplied(false)
128
+ answersRef.current = []
129
+ try {
130
+ const res = await api.post(base, { input: inputPayload })
131
+ setSession(unwrap(res))
132
+ } catch (e: any) {
133
+ setError(e?.response?.data?.message || e?.message || 'No se pudo iniciar el asistente')
134
+ } finally {
135
+ setStarting(false)
136
+ }
137
+ }, [api, base, inputPayload, starting])
138
+
139
+ const autoFired = useRef(false)
140
+ useEffect(() => {
141
+ if (!autoStart || autoFired.current || session) return
142
+ autoFired.current = true
143
+ void start()
144
+ }, [autoStart, session, start])
145
+
146
+ // Poll while the provider works.
147
+ useEffect(() => {
148
+ if (!session || !session.working || session.done) return
149
+ const t = setInterval(async () => {
150
+ try {
151
+ const res = await api.get(`${base}/${session.id}`)
152
+ setSession(unwrap(res))
153
+ } catch (e: any) {
154
+ if (isGone(e)) {
155
+ try {
156
+ setSession(await recover())
157
+ } catch {
158
+ /* next tick retries */
159
+ }
160
+ }
161
+ }
162
+ }, POLL_MS)
163
+ return () => clearInterval(t)
164
+ }, [api, base, session])
165
+
166
+ // Rotate the thinking hint while working.
167
+ useEffect(() => {
168
+ if (!session?.working) return
169
+ setHintIdx(0)
170
+ const t = setInterval(() => setHintIdx(i => Math.min(i + 1, THINKING_HINTS.length - 1)), 2600)
171
+ return () => clearInterval(t)
172
+ }, [session?.working])
173
+
174
+ // Apply the result once.
175
+ useEffect(() => {
176
+ if (!session?.done || !session.result || applied) return
177
+ const allowed = assist.output?.length ? new Set(assist.output) : null
178
+ const out: Record<string, any> = {}
179
+ for (const [k, v] of Object.entries(session.result)) {
180
+ if (allowed && !allowed.has(k)) continue
181
+ if (v === undefined || v === null || v === '') continue
182
+ out[k] = v
183
+ }
184
+ onApply(out)
185
+ setApplied(true)
186
+ }, [session, applied, assist.output, onApply])
187
+
188
+ const isGone = (e: any) => e?.response?.status === 404 || /sesi[oó]n no encontrada/i.test(String(e?.response?.data?.message || e?.message || ''))
189
+
190
+ // Recreate the session and replay every answer (host lost it).
191
+ const recover = useCallback(async () => {
192
+ const res = await api.post(base, { input: inputPayload })
193
+ let s = unwrap(res)
194
+ for (const a of answersRef.current) {
195
+ // wait until the provider is ready for the next answer
196
+ for (let i = 0; i < 120 && s.working && !s.done; i++) {
197
+ await new Promise(r => setTimeout(r, POLL_MS))
198
+ s = unwrap(await api.get(`${base}/${s.id}`))
199
+ }
200
+ if (s.done) break
201
+ s = unwrap(await api.post(`${base}/${s.id}/reply`, { key: a.key, value: a.value }))
202
+ }
203
+ return s
204
+ }, [api, base, inputPayload])
205
+
206
+ const reply = useCallback(
207
+ async (key: string, value: any) => {
208
+ if (!session) return
209
+ setAnswer('')
210
+ setError(null)
211
+ setSession(s => (s ? { ...s, working: true } : s))
212
+ try {
213
+ const res = await api.post(`${base}/${session.id}/reply`, { key, value })
214
+ answersRef.current = [...answersRef.current, { key, value }]
215
+ setSession(unwrap(res))
216
+ } catch (e: any) {
217
+ if (isGone(e)) {
218
+ try {
219
+ answersRef.current = [...answersRef.current, { key, value }]
220
+ setSession(await recover())
221
+ return
222
+ } catch (e2: any) {
223
+ setError(e2?.response?.data?.message || e2?.message || 'No se pudo retomar la conversación')
224
+ }
225
+ } else {
226
+ setError(e?.response?.data?.message || e?.message || 'No se pudo enviar la respuesta')
227
+ }
228
+ setSession(s => (s ? { ...s, working: false } : s))
229
+ }
230
+ },
231
+ [api, base, session, recover],
232
+ )
233
+
234
+ const turns = session?.turns ?? []
235
+ const last = turns[turns.length - 1]
236
+ const pendingQuestion = !session?.working && !session?.done && last?.type === 'question' ? last.question : null
237
+ const lastSpoken = [...turns].reverse().find(t => t.type === 'message' || t.type === 'question')
238
+ const headline = lastSpoken?.type === 'question' ? lastSpoken.question?.prompt ?? '' : lastSpoken?.text ?? ''
239
+ const { shown, typing } = useTypewriter(headline || (starting ? 'Un segundo…' : ''))
240
+ // The latest progress block stays visible as compact chips (done / error
241
+ // included) until the next block replaces it; the card that followed it
242
+ // shows whenever the assistant is waiting on the user or finished.
243
+ const activeProgress = [...turns].reverse().find(t => t.type === 'progress')
244
+ const lastCard = [...turns].reverse().find(t => t.type === 'card')?.card
245
+ const answered = turns.filter(t => t.type === 'answer').length
246
+ const beats = Math.max(session?.beats ?? 5, 2)
247
+ const progress = session?.done ? beats : Math.min(answered + 1, beats)
248
+ const running = activeProgress?.steps?.find(s => s.state === 'running')
249
+
250
+ useEffect(() => {
251
+ if (pendingQuestion && !typing) inputRef.current?.focus()
252
+ }, [pendingQuestion, typing])
253
+
254
+ const submitText = () => {
255
+ if (!pendingQuestion) return
256
+ const v = answer.trim() || pendingQuestion.suggestion || ''
257
+ if (v) void reply(pendingQuestion.key, v)
258
+ }
259
+
260
+ return (
261
+ <div className={'relative overflow-hidden rounded-2xl border bg-gradient-to-b from-primary/[0.06] via-background to-background px-5 py-6 sm:px-8 sm:py-8 ' + (className ?? '')}>
262
+ {/* top: eyebrow + beats */}
263
+ <div className="flex items-center justify-between gap-4">
264
+ <p className="text-xs font-semibold uppercase tracking-wider text-primary">{eyebrow || assist.label || 'Asistente'}</p>
265
+ <div className="flex items-center gap-1.5" aria-label="progreso">
266
+ {Array.from({ length: beats }).map((_, i) => (
267
+ <span key={i} className={'h-1.5 rounded-full transition-all duration-500 ' + (i < progress ? 'w-6 bg-primary' : 'w-3 bg-muted-foreground/25')} />
268
+ ))}
269
+ </div>
270
+ </div>
271
+
272
+ {/* the question — one at a time, typed out */}
273
+ <div className="mt-5 flex items-start gap-3 sm:gap-4">
274
+ <span className="mt-1 flex size-9 shrink-0 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-lg shadow-primary/25 sm:size-10">
275
+ <Sparkles className={'size-4 sm:size-5 ' + (session?.working || starting ? 'animate-pulse' : '')} />
276
+ </span>
277
+ <h3 className="min-h-[3.5rem] text-lg font-semibold leading-snug tracking-tight sm:min-h-[4rem] sm:text-2xl">
278
+ {shown}
279
+ {typing && <span className="ml-0.5 inline-block h-5 w-[2px] animate-pulse bg-primary align-middle" />}
280
+ </h3>
281
+ </div>
282
+
283
+ {/* status line */}
284
+ <div className="mt-3 min-h-6 pl-12 sm:pl-14">
285
+ {(session?.working || starting) && !running && (
286
+ <span className="inline-flex items-center gap-2 text-sm text-muted-foreground">
287
+ <Loader2 className="size-3.5 animate-spin" />
288
+ {THINKING_HINTS[hintIdx]}
289
+ </span>
290
+ )}
291
+ {activeProgress && (
292
+ <ul className="mt-2 flex flex-wrap gap-x-4 gap-y-1" aria-label="pasos">
293
+ {(activeProgress.steps ?? []).map((s, i) => (
294
+ <li key={i} className={'inline-flex items-center gap-1.5 text-xs ' + (s.state === 'pending' ? 'text-muted-foreground/70' : s.state === 'error' ? 'text-destructive' : 'text-foreground/80')}>
295
+ {s.state === 'done' ? <CheckCircle2 className="size-3.5 text-emerald-500" /> : s.state === 'running' ? <Loader2 className="size-3.5 animate-spin text-primary" /> : s.state === 'error' ? <XCircle className="size-3.5" /> : <span className="size-1.5 rounded-full bg-muted-foreground/40" />}
296
+ {s.label}
297
+ {s.state === 'running' && s.detail && <span className="text-muted-foreground">· {s.detail}</span>}
298
+ </li>
299
+ ))}
300
+ </ul>
301
+ )}
302
+ {lastCard && !session?.working && <AssistCardView card={lastCard} />}
303
+ {session?.done && (
304
+ <span className="inline-flex items-center gap-2 text-sm font-medium text-emerald-600 dark:text-emerald-400">
305
+ <Check className="size-4" />
306
+ {applied ? 'Listo. Pulsa Siguiente para revisar lo que armé.' : 'Listo.'}
307
+ </span>
308
+ )}
309
+ {(error || session?.error) && <p className="text-sm text-destructive">{error || session?.error}</p>}
310
+ </div>
311
+
312
+ {/* the answer */}
313
+ {pendingQuestion && (
314
+ <div className="mt-5 pl-0 sm:pl-14">
315
+ {pendingQuestion.kind === 'choice' || pendingQuestion.kind === 'confirm' ? (
316
+ <div className="flex flex-wrap gap-2">
317
+ {(pendingQuestion.options ?? [{ value: 'yes', label: 'Sí' }, { value: 'no', label: 'No' }]).map(o => (
318
+ <Button key={o.value} type="button" variant="outline" className="h-10 rounded-full px-4" onClick={() => void reply(pendingQuestion.key, o.value)}>
319
+ {o.label}
320
+ </Button>
321
+ ))}
322
+ </div>
323
+ ) : (
324
+ <div className="relative">
325
+ <Input
326
+ ref={inputRef}
327
+ value={answer}
328
+ onChange={e => setAnswer(e.target.value)}
329
+ onKeyDown={e => {
330
+ if (e.key === 'Enter') {
331
+ e.preventDefault()
332
+ submitText()
333
+ }
334
+ }}
335
+ placeholder={pendingQuestion.suggestion || pendingQuestion.placeholder || 'Escribe tu respuesta…'}
336
+ className="h-12 pr-12 text-base"
337
+ autoFocus
338
+ />
339
+ <Button type="button" size="icon" className="absolute right-1.5 top-1.5 size-9" onClick={submitText} disabled={!answer.trim() && !pendingQuestion.suggestion}>
340
+ <ArrowRight className="size-4" />
341
+ </Button>
342
+ </div>
343
+ )}
344
+ {pendingQuestion.suggestion && pendingQuestion.kind !== 'choice' && (
345
+ <p className="pt-1.5 text-xs text-muted-foreground">Enter acepta la sugerencia.</p>
346
+ )}
347
+ </div>
348
+ )}
349
+
350
+ {/* idle / retry */}
351
+ {!session && !starting && (
352
+ <div className="mt-5 pl-0 sm:pl-14">
353
+ <Button type="button" onClick={() => void start()}>
354
+ <Sparkles className="mr-2 size-4" />
355
+ {assist.label || 'Empezar'}
356
+ </Button>
357
+ </div>
358
+ )}
359
+ {session?.done && (
360
+ <div className="mt-4 pl-0 sm:pl-14">
361
+ <button type="button" onClick={() => { setSession(null); setApplied(false); autoFired.current = false }} className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground">
362
+ <RotateCcw className="size-3.5" /> Empezar de nuevo
363
+ </button>
364
+ </div>
365
+ )}
366
+ </div>
367
+ )
368
+ }
369
+
370
+ /** Preview card: logo on dark and light, colour swatches, key/value lines. */
371
+ export function AssistCardView({ card }: { card: AssistCard }) {
372
+ const colors = Object.entries(card.colors ?? {})
373
+ const logoDark = card.logo_light || card.logo
374
+ const logoLight = card.logo_dark || card.logo
375
+ return (
376
+ <div className="mt-3 rounded-xl border bg-background p-3">
377
+ {card.title && <p className="pb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">{card.title}</p>}
378
+ {(card.logo || card.logo_light || card.logo_dark) && (
379
+ <div className="grid grid-cols-2 gap-2">
380
+ <div className="flex h-20 items-center justify-center rounded-lg bg-neutral-950 p-3">
381
+ {logoDark && <img src={logoDark} alt="" className="max-h-full max-w-full object-contain" />}
382
+ </div>
383
+ <div className="flex h-20 items-center justify-center rounded-lg border bg-white p-3">
384
+ {logoLight && <img src={logoLight} alt="" className="max-h-full max-w-full object-contain" />}
385
+ </div>
386
+ </div>
387
+ )}
388
+ {colors.length > 0 && (
389
+ <div className="flex flex-wrap gap-2 pt-3">
390
+ {colors.map(([k, v]) => (
391
+ <span key={k} className="inline-flex items-center gap-1.5 rounded-full border px-2 py-1 text-xs">
392
+ <span className="size-4 rounded-full border" style={{ backgroundColor: v }} />
393
+ <span className="text-muted-foreground">{k}</span>
394
+ <span className="font-mono">{v}</span>
395
+ </span>
396
+ ))}
397
+ </div>
398
+ )}
399
+ {(card.lines ?? []).length > 0 && (
400
+ <dl className="grid gap-1 pt-3 text-sm">
401
+ {card.lines!.map(l => (
402
+ <div key={l.label} className="grid grid-cols-[6rem_1fr] gap-2">
403
+ <dt className="text-muted-foreground">{l.label}</dt>
404
+ <dd className="min-w-0 break-words">{l.value}</dd>
405
+ </div>
406
+ ))}
407
+ </dl>
408
+ )}
409
+ </div>
410
+ )
411
+ }
@@ -63,6 +63,7 @@ import { getFieldRef, getVisibleWhen, evaluateVisibleWhen } from '../dynamic-for
63
63
  import type { VisibleWhen } from '../types'
64
64
  import { groupFieldsBySection, type FormLayout } from '../form-layout'
65
65
  import { FieldSection, WizardProgress } from '../form-layout-ui'
66
+ import { AssistInterview } from '../assist-interview'
66
67
  import { FieldCell } from '../field-grid'
67
68
  import { isNilUuid, normalizeNilUuid } from '../nil-uuid'
68
69
  import { normalizeRefFieldsForSubmit } from './normalize-submit'
@@ -1082,13 +1083,35 @@ export function DynamicRecordDialog({
1082
1083
  {isSteps && (
1083
1084
  <WizardProgress groups={groups} stepIndex={clampedStep} onStepClick={i => setStepIndex(i)} />
1084
1085
  )}
1085
- {(isSteps ? [groups[clampedStep]] : groups).map(group => (
1086
- <FieldSection key={group.key} group={group}>
1087
- <div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2">
1088
- {renderFields(group.fields)}
1089
- </div>
1090
- </FieldSection>
1091
- ))}
1086
+ {(isSteps ? [groups[clampedStep]] : groups).map(group =>
1087
+ // An assisted step IS the interview: no form inputs, the
1088
+ // provider asks what it needs and fills the fields.
1089
+ isSteps && isEditable && group.assist ? (
1090
+ <AssistInterview
1091
+ key={group.key}
1092
+ assist={group.assist}
1093
+ values={formValues}
1094
+ eyebrow={group.title}
1095
+ autoStart={group.assist.trigger !== 'button'}
1096
+ onApply={fields => setFormValues(prev => ({ ...prev, ...fields }))}
1097
+ />
1098
+ ) : (
1099
+ <FieldSection key={group.key} group={group}>
1100
+ <div className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2">
1101
+ {renderFields(group.fields)}
1102
+ </div>
1103
+ {isEditable && group.assist && (
1104
+ <AssistInterview
1105
+ assist={group.assist}
1106
+ values={formValues}
1107
+ eyebrow={group.title}
1108
+ autoStart={group.assist.trigger === 'auto'}
1109
+ onApply={fields => setFormValues(prev => ({ ...prev, ...fields }))}
1110
+ />
1111
+ )}
1112
+ </FieldSection>
1113
+ ),
1114
+ )}
1092
1115
 
1093
1116
  {record?.external_url && (
1094
1117
  <div className="grid grid-cols-1 sm:grid-cols-2">
@@ -4,6 +4,7 @@
4
4
  import { useEffect, useMemo, useState } from 'react'
5
5
  import { groupFieldsBySection, type FormLayout } from './form-layout'
6
6
  import { FieldSection, WizardProgress } from './form-layout-ui'
7
+ import { AssistInterview } from './assist-interview'
7
8
  import {
8
9
  Input,
9
10
  Textarea,
@@ -212,7 +213,17 @@ export function DynamicForm({
212
213
  return (
213
214
  <form onSubmit={handleSubmit} className="grid gap-4">
214
215
  <WizardProgress groups={groups} stepIndex={stepIndex} onStepClick={i => setStepIndex(i)} />
215
- {renderGrid(step.fields)}
216
+ {step.assist ? (
217
+ <AssistInterview
218
+ assist={step.assist}
219
+ values={values}
220
+ eyebrow={step.title}
221
+ autoStart={step.assist.trigger !== 'button'}
222
+ onApply={fields => setValues(prev => ({ ...prev, ...fields }))}
223
+ />
224
+ ) : (
225
+ renderGrid(step.fields)
226
+ )}
216
227
  <div className="flex justify-between gap-2 pt-2">
217
228
  {stepIndex > 0 ? (
218
229
  <Button type="button" variant="outline" onClick={goBack} disabled={submitting || disabled}>
@@ -103,9 +103,6 @@ export function WizardProgress({
103
103
  {stepLabel} {stepIndex + 1}/{groups.length}
104
104
  {current?.title ? ` · ${current.title}` : ''}
105
105
  </p>
106
- {current?.description && (
107
- <p className="pt-1 text-sm text-muted-foreground">{current.description}</p>
108
- )}
109
106
  </div>
110
107
  )
111
108
  }
@@ -31,6 +31,23 @@ export interface FormSection {
31
31
  * Tolerates the camelCase alias, same as fields. */
32
32
  visible_when?: VisibleWhen
33
33
  visibleWhen?: VisibleWhen
34
+ /** AI-assisted step (kernel v0.141.0): the SDK renders an interview panel
35
+ * driven by the host's assist provider inside this section. */
36
+ assist?: FormAssist
37
+ }
38
+
39
+ /** Declaration of an AI-assisted step (`form_layout.sections[].assist`). */
40
+ export interface FormAssist {
41
+ /** Host-registered provider key, e.g. `brand.website_dna`. */
42
+ provider: string
43
+ label?: string
44
+ description?: string
45
+ /** Form fields sent to the provider when the session starts. */
46
+ input?: string[]
47
+ /** Form fields the provider may fill when it finishes. */
48
+ output?: string[]
49
+ /** `button` (default) or `auto` (start as soon as every input has a value). */
50
+ trigger?: 'button' | 'auto'
34
51
  }
35
52
 
36
53
  /** Model-level layout directive. `mode` defaults to `"sections"`. */
@@ -50,6 +67,8 @@ export interface FieldGroup<F> {
50
67
  /** True for the synthetic group holding section-less / unknown-section fields. */
51
68
  isDefault: boolean
52
69
  fields: F[]
70
+ /** AI-assisted step declaration, when the section has one. */
71
+ assist?: FormAssist
53
72
  }
54
73
 
55
74
  /** The synthetic key of the orphan group (fields with no / unknown `section`). */
@@ -141,6 +160,7 @@ export function groupFieldsBySection<F extends { section?: string }>(
141
160
  collapsed: s.collapsed,
142
161
  isDefault: false,
143
162
  fields: secFields,
163
+ assist: s.assist,
144
164
  })
145
165
  }
146
166
  return groups
package/src/index.ts CHANGED
@@ -475,3 +475,5 @@ export {
475
475
  type AccentClasses,
476
476
  type WidgetFormatCtx,
477
477
  } from './widgets/widget-format'
478
+ export { AssistInterview, AssistCardView } from './assist-interview'
479
+ export type { AssistSession, AssistTurn, AssistQuestion, AssistCard, AssistProgressStep } from './assist-interview'