@adia-ai/a2ui-retrieval 0.6.4 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/domain-router.js +362 -117
  3. package/embedding/chunk-embedding-retriever.js +47 -79
  4. package/embedding/embedding-provider.js +35 -71
  5. package/embedding/index.js +2 -10
  6. package/feedback/dialog-recorder.js +61 -145
  7. package/feedback/feedback-analyzer.js +46 -102
  8. package/feedback/feedback-store.js +91 -107
  9. package/feedback/feedback.js +36 -117
  10. package/feedback/gap-registry.js +40 -82
  11. package/feedback/index.js +14 -12
  12. package/index.d.ts +4 -0
  13. package/index.js +53 -16
  14. package/intent/clarity.js +61 -129
  15. package/intent/decomposer.js +51 -143
  16. package/intent/index.js +18 -14
  17. package/intent/intent-alignment.js +79 -150
  18. package/intent/intent-categorizer.js +34 -62
  19. package/intent/intent-gate.js +43 -102
  20. package/intent/prompt-analyzer.js +68 -126
  21. package/package.json +4 -2
  22. package/wiring-catalog.js +95 -146
  23. package/embedding/chunk-embedding-retriever.ts +0 -156
  24. package/embedding/embedding-provider.ts +0 -111
  25. package/embedding/index.ts +0 -10
  26. package/feedback/dialog-recorder.ts +0 -172
  27. package/feedback/feedback-analyzer.ts +0 -250
  28. package/feedback/feedback-store.ts +0 -229
  29. package/feedback/feedback.ts +0 -201
  30. package/feedback/gap-registry.ts +0 -137
  31. package/feedback/index.ts +0 -14
  32. package/intent/clarity.ts +0 -224
  33. package/intent/decomposer.ts +0 -229
  34. package/intent/index.ts +0 -20
  35. package/intent/intent-alignment.ts +0 -267
  36. package/intent/intent-categorizer.ts +0 -104
  37. package/intent/intent-gate.ts +0 -151
  38. package/intent/prompt-analyzer.ts +0 -231
package/intent/clarity.js CHANGED
@@ -1,196 +1,125 @@
1
- /**
2
- * Clarity Assessment Evaluates whether a user intent is clear enough
3
- * to generate quality UI, or needs clarifying questions first.
4
- *
5
- * Scores intents across 5 dimensions:
6
- * domain — Is the domain clear? (forms, data, layout, etc.)
7
- * scope — Is the scope defined? (how many items, what sections?)
8
- * content — Is the content specified? (labels, values, data?)
9
- * layout — Is the layout preference stated? (grid, stack, sidebar?)
10
- * action — Are actions/interactions mentioned? (buttons, forms, links?)
11
- *
12
- * Returns a clarity score (0-1) and targeted questions for what's missing.
13
- */
14
-
15
- import { classifyIntent } from '../domain-router.js';
16
- import { searchAll as searchCompositions } from '../../compose/strategies/zettel/composition-library.js';
17
-
18
- // ── Dimension detectors ──────────────────────────────────────────────────
19
-
20
- /** Scope indicators: quantity, enumeration, specificity */
1
+ import { classifyIntent } from "../domain-router.js";
2
+ import { searchAll as searchCompositions } from "../../compose/strategies/zettel/composition-library.js";
21
3
  const SCOPE_SIGNALS = [
22
- /\b\d+\b/, // contains a number
23
- /\b(three|two|four|five|six)\b/i, // spelled-out numbers
24
- /\b(with|containing|including|showing|displaying)\b/i, // enumerates content
25
- /\b(and|plus|also)\b/i, // multiple items
26
- /\b(columns?|rows?|items?|cards?|sections?|fields?|buttons?|tabs?|steps?)\b/i, // structural counts
4
+ /\b\d+\b/,
5
+ // contains a number
6
+ /\b(three|two|four|five|six)\b/i,
7
+ // spelled-out numbers
8
+ /\b(with|containing|including|showing|displaying)\b/i,
9
+ // enumerates content
10
+ /\b(and|plus|also)\b/i,
11
+ // multiple items
12
+ /\b(columns?|rows?|items?|cards?|sections?|fields?|buttons?|tabs?|steps?)\b/i
13
+ // structural counts
27
14
  ];
28
-
29
- /** Content specificity: labels, values, named data */
30
15
  const CONTENT_SIGNALS = [
31
16
  /\b(name|email|password|title|description|price|date|status|role|avatar)\b/i,
32
17
  /\b(revenue|users|growth|sales|orders|metrics|analytics)\b/i,
33
18
  /\b(todo|done|in progress|pending|active|completed)\b/i,
34
19
  /\b(bleed|margin|trim|crop|preview|artwork|brand|design system)\b/i,
35
20
  /\b(approved|approval|production|settings|configure|preference)\b/i,
36
- /["'][\w\s]+["']/, // quoted strings (specific labels)
37
- /\$[\d,.]+/, // dollar amounts
38
- /\d+%/, // percentages
21
+ /["'][\w\s]+["']/,
22
+ // quoted strings (specific labels)
23
+ /\$[\d,.]+/,
24
+ // dollar amounts
25
+ /\d+%/
26
+ // percentages
39
27
  ];
40
-
41
- /** Layout preferences */
42
28
  const LAYOUT_SIGNALS = [
43
29
  /\b(grid|row|column|sidebar|split|horizontal|vertical|stack|centered)\b/i,
44
30
  /\b(full.?width|responsive|mobile|compact|wide|narrow)\b/i,
45
- /\b(\d+.?col(umn)?s?)\b/i, // "3 columns", "2-col"
46
- /\b(left|right|top|bottom|center)\b/i,
31
+ /\b(\d+.?col(umn)?s?)\b/i,
32
+ // "3 columns", "2-col"
33
+ /\b(left|right|top|bottom|center)\b/i
47
34
  ];
48
-
49
- /** Action/interaction indicators */
50
35
  const ACTION_SIGNALS = [
51
36
  /\b(button|submit|cancel|save|delete|edit|close|open|toggle|click)\b/i,
52
37
  /\b(form|input|select|search|filter|sort|upload|download)\b/i,
53
38
  /\b(login|signup|register|checkout|confirm|approve|reject)\b/i,
54
39
  /\b(navigate|link|redirect|route)\b/i,
55
- /\b(drag|drop|resize|expand|collapse)\b/i,
40
+ /\b(drag|drop|resize|expand|collapse)\b/i
56
41
  ];
57
-
58
- /**
59
- * Assess clarity of a user intent for UI generation.
60
- *
61
- * @param {string} intent — Raw user input
62
- * @param {{ domain: string, confidence: number, matchedSignals: string[] }} [classification] — Pre-computed classification
63
- * @returns {{
64
- * clear: boolean,
65
- * score: number,
66
- * dimensions: { domain: number, scope: number, content: number, layout: number, action: number },
67
- * questions: { text: string, dimension: string, priority: number }[],
68
- * summary: string,
69
- * }}
70
- */
71
- export function assessClarity(intent, classification) {
72
- const text = (intent ?? '').trim();
42
+ function assessClarity(intent, classification) {
43
+ const text = (intent ?? "").trim();
73
44
  if (!text) {
74
45
  return {
75
46
  clear: false,
76
47
  score: 0,
77
48
  dimensions: { domain: 0, scope: 0, content: 0, layout: 0, action: 0 },
78
- questions: [{ text: 'What would you like me to build?', dimension: 'domain', priority: 1 }],
79
- summary: 'No intent provided',
49
+ questions: [{ text: "What would you like me to build?", dimension: "domain", priority: 1 }],
50
+ summary: "No intent provided"
80
51
  };
81
52
  }
82
-
83
53
  const cls = classification || classifyIntent(text);
84
54
  const compositionMatches = searchCompositions(text);
85
- const lower = text.toLowerCase();
86
55
  const wordCount = text.split(/\s+/).length;
87
-
88
- // ── Score each dimension ──
89
-
90
- // Domain: how confident is the domain classification?
91
56
  const domainScore = cls.confidence >= 0.3 ? 1 : cls.confidence >= 0.15 ? 0.6 : cls.matchedSignals.length > 0 ? 0.3 : 0;
92
-
93
- // Scope: is the scope specific?
94
- const scopeHits = SCOPE_SIGNALS.filter(r => r.test(text)).length;
57
+ const scopeHits = SCOPE_SIGNALS.filter((r) => r.test(text)).length;
95
58
  const scopeScore = Math.min(1, scopeHits / 2);
96
-
97
- // Content: are concrete labels/values mentioned?
98
- const contentHits = CONTENT_SIGNALS.filter(r => r.test(text)).length;
59
+ const contentHits = CONTENT_SIGNALS.filter((r) => r.test(text)).length;
99
60
  const contentScore = Math.min(1, contentHits / 2);
100
-
101
- // Layout: is a layout preference stated?
102
- const layoutHits = LAYOUT_SIGNALS.filter(r => r.test(text)).length;
61
+ const layoutHits = LAYOUT_SIGNALS.filter((r) => r.test(text)).length;
103
62
  const layoutScore = Math.min(1, layoutHits);
104
-
105
- // Action: are interactions mentioned?
106
- const actionHits = ACTION_SIGNALS.filter(r => r.test(text)).length;
63
+ const actionHits = ACTION_SIGNALS.filter((r) => r.test(text)).length;
107
64
  const actionScore = Math.min(1, actionHits / 2);
108
-
109
- // ── Overall score (weighted) ──
110
- const score = (
111
- domainScore * 0.25 +
112
- scopeScore * 0.25 +
113
- contentScore * 0.20 +
114
- layoutScore * 0.15 +
115
- actionScore * 0.15
116
- );
117
-
118
- // ── Bonus: composition match adds confidence ──
65
+ const score = domainScore * 0.25 + scopeScore * 0.25 + contentScore * 0.2 + layoutScore * 0.15 + actionScore * 0.15;
119
66
  const patternBonus = compositionMatches.length > 0 ? 0.15 : 0;
120
- // Bonus: long intents are usually more specific
121
67
  const lengthBonus = wordCount > 10 ? 0.1 : wordCount > 6 ? 0.05 : 0;
122
-
123
68
  const finalScore = Math.min(1, score + patternBonus + lengthBonus);
124
-
125
- // ── Generate targeted questions for weak dimensions ──
126
69
  const questions = [];
127
-
128
70
  if (domainScore < 0.3) {
129
71
  questions.push({
130
- text: 'What type of UI is this? (e.g., a form, dashboard, profile card, settings page)',
131
- dimension: 'domain',
132
- priority: 1,
72
+ text: "What type of UI is this? (e.g., a form, dashboard, profile card, settings page)",
73
+ dimension: "domain",
74
+ priority: 1
133
75
  });
134
76
  }
135
-
136
77
  if (scopeScore < 0.5) {
137
78
  const domainQuestions = {
138
- forms: 'What fields should the form include?',
139
- data: 'What data should be displayed? How many items or metrics?',
140
- layout: 'How many sections or cards should it have?',
141
- agent: 'What actions should the assistant support?',
142
- navigation: 'What pages or sections should be navigable?',
79
+ forms: "What fields should the form include?",
80
+ data: "What data should be displayed? How many items or metrics?",
81
+ layout: "How many sections or cards should it have?",
82
+ agent: "What actions should the assistant support?",
83
+ navigation: "What pages or sections should be navigable?"
143
84
  };
144
85
  questions.push({
145
- text: domainQuestions[cls.domain] || 'Can you be more specific about what it should contain?',
146
- dimension: 'scope',
147
- priority: 2,
86
+ text: domainQuestions[cls.domain] ?? "Can you be more specific about what it should contain?",
87
+ dimension: "scope",
88
+ priority: 2
148
89
  });
149
90
  }
150
-
151
91
  if (contentScore < 0.3 && scopeScore >= 0.3) {
152
92
  const contentQuestions = {
153
93
  forms: 'What labels should the fields have? (e.g., "Email", "Password", "Full Name")',
154
- data: 'What metrics or values should be shown? (e.g., revenue, users, growth rate)',
155
- layout: 'What content goes in each section?',
156
- agent: 'What kind of messages or responses should be shown?',
157
- navigation: 'What should the menu items or links be labeled?',
94
+ data: "What metrics or values should be shown? (e.g., revenue, users, growth rate)",
95
+ layout: "What content goes in each section?",
96
+ agent: "What kind of messages or responses should be shown?",
97
+ navigation: "What should the menu items or links be labeled?"
158
98
  };
159
99
  questions.push({
160
- text: contentQuestions[cls.domain] || 'What specific content should be displayed?',
161
- dimension: 'content',
162
- priority: 3,
100
+ text: contentQuestions[cls.domain] ?? "What specific content should be displayed?",
101
+ dimension: "content",
102
+ priority: 3
163
103
  });
164
104
  }
165
-
166
105
  if (layoutScore < 0.3 && scopeScore >= 0.5) {
167
106
  questions.push({
168
- text: 'Any layout preference? (e.g., grid of cards, single column, sidebar + content)',
169
- dimension: 'layout',
170
- priority: 4,
107
+ text: "Any layout preference? (e.g., grid of cards, single column, sidebar + content)",
108
+ dimension: "layout",
109
+ priority: 4
171
110
  });
172
111
  }
173
-
174
112
  if (actionScore < 0.3 && domainScore >= 0.3) {
175
113
  questions.push({
176
- text: 'What actions should users be able to take? (e.g., submit, edit, delete, filter)',
177
- dimension: 'action',
178
- priority: 5,
114
+ text: "What actions should users be able to take? (e.g., submit, edit, delete, filter)",
115
+ dimension: "action",
116
+ priority: 5
179
117
  });
180
118
  }
181
-
182
- // Sort by priority, limit to 3
183
119
  questions.sort((a, b) => a.priority - b.priority);
184
120
  const topQuestions = questions.slice(0, 3);
185
-
186
- // ── Determine if clear enough to proceed ──
187
- // Clear only if dimensional score meets threshold
188
121
  const clear = finalScore >= 0.4;
189
-
190
- const summary = clear
191
- ? `Intent is ${finalScore >= 0.7 ? 'clear' : 'adequate'} (${Math.round(finalScore * 100)}%)`
192
- : `Intent needs clarification (${Math.round(finalScore * 100)}% — below 40% threshold)`;
193
-
122
+ const summary = clear ? `Intent is ${finalScore >= 0.7 ? "clear" : "adequate"} (${Math.round(finalScore * 100)}%)` : `Intent needs clarification (${Math.round(finalScore * 100)}% \u2014 below 40% threshold)`;
194
123
  return {
195
124
  clear,
196
125
  score: Math.round(finalScore * 100) / 100,
@@ -199,9 +128,12 @@ export function assessClarity(intent, classification) {
199
128
  scope: Math.round(scopeScore * 100) / 100,
200
129
  content: Math.round(contentScore * 100) / 100,
201
130
  layout: Math.round(layoutScore * 100) / 100,
202
- action: Math.round(actionScore * 100) / 100,
131
+ action: Math.round(actionScore * 100) / 100
203
132
  },
204
133
  questions: topQuestions,
205
- summary,
134
+ summary
206
135
  };
207
136
  }
137
+ export {
138
+ assessClarity
139
+ };
@@ -1,216 +1,124 @@
1
- /**
2
- * Intent Decomposer — breaks complex intents into independent subtasks.
3
- *
4
- * When an intent describes multiple sections, areas, or features,
5
- * the decomposer splits it into atomic generation units that can be
6
- * generated independently and composed into a layout.
7
- *
8
- * Example:
9
- * "settings page with profile, notifications, security, and billing"
10
- * → 4 subtasks + a composition plan (Tabs layout)
11
- *
12
- * The decomposition is the single most important capability per the
13
- * Software Factory Manifesto: "Get decomposition right and generation
14
- * is almost trivial."
15
- */
16
-
17
- import { classifyIntent } from '../domain-router.js';
18
-
19
- // ── Section Detection ────────────────────────────────────────────────────
20
-
21
- /** Connectors that separate sections in an intent */
1
+ import { classifyIntent } from "../domain-router.js";
22
2
  const SECTION_SPLITTERS = /\band\b|\bwith\b|\bplus\b|\balso\b|,\s*(?:and\s+)?/gi;
23
-
24
- /** Words that signal enumerated sections */
25
3
  const SECTION_SIGNALS = [
26
4
  /\b(\d+)\s+(sections?|areas?|parts?|panels?|columns?|cards?|tabs?|pages?|views?)\b/i,
27
5
  /\bsections?:\s/i,
28
6
  /\bincluding\b/i,
29
- /\beach\s+(with|having|containing)\b/i,
7
+ /\beach\s+(with|having|containing)\b/i
30
8
  ];
31
-
32
- /** Layout containers that imply multi-section structure */
33
9
  const LAYOUT_KEYWORDS = {
34
- tabs: { component: 'Tabs', child: 'Tab' },
35
- sections: { component: 'Column', child: 'Card' },
36
- columns: { component: 'Grid', child: 'Column' },
37
- cards: { component: 'Grid', child: 'Card' },
38
- panels: { component: 'Accordion', child: 'Panel' },
39
- pages: { component: 'Tabs', child: 'Tab' },
40
- areas: { component: 'Grid', child: 'Card' },
41
- steps: { component: 'Steps', child: 'Step' },
10
+ tabs: { component: "Tabs", child: "Tab" },
11
+ sections: { component: "Column", child: "Card" },
12
+ columns: { component: "Grid", child: "Column" },
13
+ cards: { component: "Grid", child: "Card" },
14
+ panels: { component: "Accordion", child: "Panel" },
15
+ pages: { component: "Tabs", child: "Tab" },
16
+ areas: { component: "Grid", child: "Card" },
17
+ steps: { component: "Steps", child: "Step" }
42
18
  };
43
-
44
- /**
45
- * Analyze an intent for decomposition potential.
46
- *
47
- * @param {string} intent
48
- * @returns {{ shouldDecompose: boolean, subtasks: { intent: string, label: string }[], layout: { component: string, child: string } | null, original: string }}
49
- */
50
- export function decomposeIntent(intent) {
51
- const trimmed = (intent || '').trim();
19
+ function decomposeIntent(intent) {
20
+ const trimmed = (intent || "").trim();
52
21
  if (!trimmed) return { shouldDecompose: false, subtasks: [], layout: null, original: trimmed };
53
-
54
- // ── Detect explicit section count ──
55
22
  for (const pattern of SECTION_SIGNALS) {
56
23
  if (pattern.test(trimmed)) {
57
- const sections = extractSections(trimmed);
58
- if (sections.length >= 2) {
59
- const layout = detectLayout(trimmed, sections.length);
24
+ const sections2 = extractSections(trimmed);
25
+ if (sections2.length >= 2) {
26
+ const layout = detectLayout(trimmed, sections2.length);
60
27
  return {
61
28
  shouldDecompose: true,
62
- subtasks: sections,
29
+ subtasks: sections2,
63
30
  layout,
64
- original: trimmed,
31
+ original: trimmed
65
32
  };
66
33
  }
67
34
  }
68
35
  }
69
-
70
- // ── Detect enumerated items ──
71
36
  const sections = extractSections(trimmed);
72
37
  if (sections.length >= 2) {
73
- // 2+ distinct sections → decompose
74
38
  const layout = detectLayout(trimmed, sections.length);
75
39
  return {
76
40
  shouldDecompose: true,
77
41
  subtasks: sections,
78
42
  layout,
79
- original: trimmed,
43
+ original: trimmed
80
44
  };
81
45
  }
82
-
83
- // ── Short or simple intent → don't decompose ──
84
46
  return { shouldDecompose: false, subtasks: [], layout: null, original: trimmed };
85
47
  }
86
-
87
- /**
88
- * Extract individual section descriptions from an intent.
89
- *
90
- * @param {string} intent
91
- * @returns {{ intent: string, label: string }[]}
92
- */
93
48
  function extractSections(intent) {
94
- // Find the "with X, Y, Z, and W" pattern
95
49
  const withMatch = intent.match(/\bwith\s+(.+)$/i);
96
- const payload = withMatch ? withMatch[1] : intent;
97
-
98
- // Split on connectors
99
- const parts = payload.split(SECTION_SPLITTERS)
100
- .map(s => s.trim())
101
- .filter(s => s.length > 2);
102
-
50
+ const payload = withMatch ? withMatch[1] ?? intent : intent;
51
+ const parts = payload.split(SECTION_SPLITTERS).map((s) => s.trim()).filter((s) => s.length > 2);
103
52
  if (parts.length < 2) return [];
104
-
105
- // Extract the base context (everything before "with")
106
- const baseContext = withMatch ? intent.slice(0, withMatch.index).trim() : '';
53
+ const baseContext = withMatch ? intent.slice(0, withMatch.index).trim() : "";
107
54
  const domain = classifyIntent(intent).domain;
108
-
109
- return parts.map(part => {
110
- // Build a self-contained subtask intent
111
- const label = part.replace(/\b(section|area|panel|tab|page)\b/gi, '').trim();
112
- const subtaskIntent = baseContext
113
- ? `${label} section for a ${baseContext}`
114
- : `${label}`;
115
-
55
+ void domain;
56
+ return parts.map((part) => {
57
+ const label = part.replace(/\b(section|area|panel|tab|page)\b/gi, "").trim();
58
+ const subtaskIntent = baseContext ? `${label} section for a ${baseContext}` : `${label}`;
116
59
  return { intent: subtaskIntent, label: capitalizeFirst(label) };
117
60
  });
118
61
  }
119
-
120
- /**
121
- * Detect the best layout container for the decomposed sections.
122
- *
123
- * @param {string} intent
124
- * @param {number} sectionCount
125
- * @returns {{ component: string, child: string }}
126
- */
127
62
  function detectLayout(intent, sectionCount) {
128
63
  const lower = intent.toLowerCase();
129
-
130
- // Explicit layout keywords in the intent
131
64
  for (const [keyword, layout] of Object.entries(LAYOUT_KEYWORDS)) {
132
65
  if (lower.includes(keyword)) return layout;
133
66
  }
134
-
135
- // Heuristic: settings/profile pages Tabs
136
- if (lower.includes('settings') || lower.includes('preferences') || lower.includes('account')) {
137
- return { component: 'Tabs', child: 'Tab' };
67
+ if (lower.includes("settings") || lower.includes("preferences") || lower.includes("account")) {
68
+ return { component: "Tabs", child: "Tab" };
138
69
  }
139
-
140
- // Heuristic: dashboard with metrics → Grid of Cards
141
- if (lower.includes('dashboard') || lower.includes('overview') || lower.includes('stat')) {
142
- return { component: 'Grid', child: 'Card' };
70
+ if (lower.includes("dashboard") || lower.includes("overview") || lower.includes("stat")) {
71
+ return { component: "Grid", child: "Card" };
143
72
  }
144
-
145
- // Default: small count → Tabs, large count → Grid
146
- if (sectionCount <= 4) return { component: 'Tabs', child: 'Tab' };
147
- return { component: 'Grid', child: 'Card' };
73
+ if (sectionCount <= 4) return { component: "Tabs", child: "Tab" };
74
+ return { component: "Grid", child: "Card" };
148
75
  }
149
-
150
- /**
151
- * Compose independently generated subtask results into a layout.
152
- *
153
- * @param {{ component: string, child: string }} layout
154
- * @param {{ label: string, messages: object[] }[]} subtaskResults
155
- * @returns {object[]} — A2UI messages for the composed layout
156
- */
157
- export function composeSubtasks(layout, subtaskResults) {
76
+ function composeSubtasks(layout, subtaskResults) {
158
77
  const rootChildren = [];
159
78
  const allComponents = [];
160
79
  let idCounter = 0;
161
-
162
80
  for (const { label, messages } of subtaskResults) {
163
81
  const prefix = `s${++idCounter}`;
164
- const subtaskComponents = messages?.[0]?.components || [];
165
-
166
- // Re-prefix all component IDs to avoid collisions
167
- const idMap = new Map();
168
- const remapped = subtaskComponents.map(c => {
169
- const newId = c.id === 'root' ? prefix : `${prefix}-${c.id}`;
82
+ const subtaskComponents = messages?.[0]?.components ?? [];
83
+ const idMap = /* @__PURE__ */ new Map();
84
+ const remapped = subtaskComponents.map((c) => {
85
+ const newId = c.id === "root" ? prefix : `${prefix}-${c.id}`;
170
86
  idMap.set(c.id, newId);
171
87
  return { ...c, id: newId };
172
88
  });
173
-
174
- // Fix child references
175
89
  for (const c of remapped) {
176
90
  if (c.children) {
177
- c.children = c.children.map(id => idMap.get(id) || id);
91
+ c.children = c.children.map((id) => idMap.get(id) ?? id);
178
92
  }
179
93
  }
180
-
181
- // Create the layout wrapper for this subtask
182
- if (layout.child === 'Tab') {
183
- // Tabs: wrap in a Tab with a label
94
+ if (layout.child === "Tab") {
184
95
  const tabId = `${prefix}-tab`;
185
- allComponents.push({ id: tabId, component: 'Tab', text: label, children: [prefix] });
96
+ allComponents.push({ id: tabId, component: "Tab", text: label, children: [prefix] });
186
97
  rootChildren.push(tabId);
187
98
  } else {
188
- // Grid/Column: subtask root becomes a direct child
189
99
  rootChildren.push(prefix);
190
100
  }
191
-
192
101
  allComponents.push(...remapped);
193
102
  }
194
-
195
- // Build the root layout
196
103
  const root = {
197
- id: 'root',
104
+ id: "root",
198
105
  component: layout.component,
199
- children: rootChildren,
106
+ children: rootChildren
200
107
  };
201
-
202
- if (layout.component === 'Grid') {
203
- root.columns = String(Math.min(subtaskResults.length, 4));
204
- root.gap = 'md';
108
+ if (layout.component === "Grid") {
109
+ root["columns"] = String(Math.min(subtaskResults.length, 4));
110
+ root["gap"] = "md";
205
111
  }
206
-
207
112
  return [{
208
- type: 'updateComponents',
209
- surfaceId: 'default',
210
- components: [root, ...allComponents],
113
+ type: "updateComponents",
114
+ surfaceId: "default",
115
+ components: [root, ...allComponents]
211
116
  }];
212
117
  }
213
-
214
118
  function capitalizeFirst(str) {
215
119
  return str.charAt(0).toUpperCase() + str.slice(1);
216
120
  }
121
+ export {
122
+ composeSubtasks,
123
+ decomposeIntent
124
+ };
package/intent/index.js CHANGED
@@ -1,14 +1,18 @@
1
- /**
2
- * @adia-ai/a2ui-retrieval/intent intent classification + decomposition surface.
3
- *
4
- * Re-exports the intent-shaped retrieval primitives. Importers can reach
5
- * individual files directly (e.g. `@adia-ai/a2ui-retrieval/intent/clarity`)
6
- * or pull the bundle via this barrel.
7
- */
8
-
9
- export { extractExpectations, verifyAlignment, checkIntentAlignment } from './intent-alignment.js';
10
- export { categorizeIntent } from './intent-categorizer.js';
11
- export { isConversational } from './intent-gate.js';
12
- export { analyzePrompt } from './prompt-analyzer.js';
13
- export { decomposeIntent, composeSubtasks } from './decomposer.js';
14
- export { assessClarity } from './clarity.js';
1
+ import { extractExpectations, verifyAlignment, checkIntentAlignment } from "./intent-alignment.js";
2
+ import { categorizeIntent } from "./intent-categorizer.js";
3
+ import { isConversational } from "./intent-gate.js";
4
+ import { analyzePrompt, formatAnalysisForPrompt } from "./prompt-analyzer.js";
5
+ import { decomposeIntent, composeSubtasks } from "./decomposer.js";
6
+ import { assessClarity } from "./clarity.js";
7
+ export {
8
+ analyzePrompt,
9
+ assessClarity,
10
+ categorizeIntent,
11
+ checkIntentAlignment,
12
+ composeSubtasks,
13
+ decomposeIntent,
14
+ extractExpectations,
15
+ formatAnalysisForPrompt,
16
+ isConversational,
17
+ verifyAlignment
18
+ };