@adia-ai/a2ui-compose 0.2.1 → 0.2.2

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
@@ -14,6 +14,30 @@ _Nothing yet._
14
14
 
15
15
  ---
16
16
 
17
+ ## [0.2.2] - 2026-05-02
18
+
19
+ **Lockstep cut + reasoning-panel emission fixes.** All 8 published `@adia-ai/*` packages bump 0.2.1 → 0.2.2 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
20
+
21
+ ### Changed
22
+
23
+ - `version`: `0.2.1` → `0.2.2`.
24
+ - `dependencies["@adia-ai/a2ui-corpus"]`: `^0.2.0` (covers `0.2.2`).
25
+ - `dependencies["@adia-ai/a2ui-utils"]`: `^0.2.0` (covers `0.2.2`).
26
+ - `dependencies["@adia-ai/a2ui-validator"]`: `^0.2.0` (covers `0.2.2`).
27
+ - `dependencies["@adia-ai/a2ui-retrieval"]`: `^0.2.0` (covers `0.2.2`).
28
+ - `core/generator.js` and `strategies/` are the surfaces that gained the new behavior below; no other compose directories touched.
29
+
30
+ ### Fixed — Reasoning-panel emissions surface confidence + retrieval candidates (2026-05-02)
31
+
32
+ `generator.js` was emitting `status` events whose labels looked truthful but hid the data needed to judge their reliability. Two fixes that surface the missing data as `outcomes`:
33
+
34
+ - **Interpret stage** now includes the domain confidence percentage and the matched signals. Previously `Domain: data` read identical at 3% confidence vs 95% — same label. Now: `Domain: data (3% confidence)` plus `Matched signals: pricing` as outcomes. Per memory `feedback_panel_label_reliability.md`.
35
+ - **Analyze stage** runs a fast keyword `searchBlocks(intent)` and emits the top-5 candidates with scores + domains. Previously the stage reported `context.patterns.length` from `getContext(intent, 2)` — but the context-assembler only populates `result.patterns` at tier ≥ 3, so the count was structurally guaranteed to be 0. The label read "nothing relevant" when it actually meant "we didn't even look here." The fix runs a real retrieval at the analyze stage instead of relying on the wrong-tier context.
36
+
37
+ Companion fix in `@adia-ai/a2ui-retrieval` Unreleased (web-research.js EXPLICIT/IMPLICIT pattern split). Both surfaces feed the same reasoning-panel deception class — five distinct bugs caught + fixed in commit `9986c71e`.
38
+
39
+ ---
40
+
17
41
  ## [0.2.1] - 2026-05-02
18
42
 
19
43
  **Lockstep cut + scope-drift gate at composer time + skeleton harvest + Tier-1 block filter + high-resolution session ticket trace.** All 8 published `@adia-ai/*` packages bump 0.2.0 → 0.2.1 per [`docs/specs/package-architecture.md` § 15](../../../docs/specs/package-architecture.md#15-versioning-policy). Patch cut — no breaking changes.
package/core/generator.js CHANGED
@@ -244,9 +244,23 @@ export async function* generateUIStream({ intent, executionId, llmAdapter, model
244
244
  executionId = engine.start({ intent, mode: 'stream', previousExecId });
245
245
 
246
246
  // ── Stage 1: Interpret ──
247
+ // Include confidence + matched signals in the status message so a reader can
248
+ // distinguish a strong domain match from a 3% tie-breaker. The bare label
249
+ // "Domain: data" is indistinguishable between "build a data dashboard" (high
250
+ // confidence, many signals) and "tier pricing page" (0.03 confidence, one
251
+ // weak signal) — same text, very different reliability.
247
252
  const domain = lookupDomain(intent);
248
253
  engine.submitStage(executionId, 'interpret', { domain, intent, confidence: domain.confidence });
249
- yield { type: 'status', stage: 'interpret', message: `Domain: ${domain.domain}` };
254
+ const conf = domain.confidence != null ? Math.round(domain.confidence * 100) : null;
255
+ const signals = Array.isArray(domain.matchedSignals) && domain.matchedSignals.length
256
+ ? domain.matchedSignals.slice(0, 4)
257
+ : null;
258
+ yield {
259
+ type: 'status',
260
+ stage: 'interpret',
261
+ message: `Domain: ${domain.domain}${conf != null ? ` (${conf}% confidence)` : ''}`,
262
+ outcomes: signals ? [`Matched signals: ${signals.join(', ')}`] : [],
263
+ };
250
264
 
251
265
  // ── Clarity gate: yield clarify event if intent is vague ──
252
266
  // Only for fresh intents (not multi-turn iterations which have prior context)
@@ -267,12 +281,34 @@ export async function* generateUIStream({ intent, executionId, llmAdapter, model
267
281
  }
268
282
 
269
283
  // ── Stage 2: Analyze ──
284
+ // Surface the actual top-N retrieval candidates with scores. Two reasons the
285
+ // previous `${...patterns.length} patterns` line was misleading:
286
+ // (a) `getContext(intent, 2)` runs at tier=2, but the context-assembler
287
+ // only populates `result.patterns` at tier≥3 — so `context.patterns`
288
+ // was STRUCTURALLY empty. "0 patterns" wasn't a retrieval result; it
289
+ // was a tier mismatch. Fixed by running a fast keyword search here.
290
+ // (b) The synthesizer composes from below-threshold patterns too; "0
291
+ // patterns" reading as "nothing relevant" actively misleads the user.
270
292
  const context = await getContext(intent, 2);
293
+ const topPatternsRaw = searchBlocks(intent).slice(0, 5);
294
+ const candidateLines = topPatternsRaw.length
295
+ ? topPatternsRaw.map(p => {
296
+ const score = p.score != null ? ` · ${Number(p.score).toFixed(2)}` : '';
297
+ const domainTag = p.domain ? ` (${p.domain})` : '';
298
+ return ` • ${p.name}${domainTag}${score}`;
299
+ })
300
+ : [' (no keyword match — synthesizer will compose from components)'];
271
301
  engine.submitStage(executionId, 'analyze', {
272
- context, componentCount: context.components.length, patternCount: context.patterns.length,
302
+ context, componentCount: context.components.length, patternCount: topPatternsRaw.length,
303
+ topPatterns: topPatternsRaw.map(p => ({ name: p.name, score: p.score, domain: p.domain })),
273
304
  confidence: context.components.length > 0 ? 0.85 : 0.5,
274
305
  });
275
- yield { type: 'status', stage: 'analyze', message: `${context.components.length} components, ${context.patterns.length} patterns` };
306
+ yield {
307
+ type: 'status',
308
+ stage: 'analyze',
309
+ message: `${context.components.length} components inspected · ${topPatternsRaw.length} pattern candidate${topPatternsRaw.length === 1 ? '' : 's'}`,
310
+ outcomes: ['Top retrievals:', ...candidateLines],
311
+ };
276
312
 
277
313
  // ── Research: web search enrichment (optional) ──
278
314
  let researchContext = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adia-ai/a2ui-compose",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "AdiaUI A2UI compose engine — framework-agnostic. Takes natural-language intents + a catalog and produces A2UI protocol messages. Pairs with `@adia-ai/a2ui-retrieval` (intent classification, catalog lookup) and `@adia-ai/a2ui-validator` (schema + semantic checks).",
5
5
  "type": "module",
6
6
  "exports": {