@adia-ai/a2ui-retrieval 0.0.1 → 0.2.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 +64 -0
- package/README.md +43 -12
- package/anti-patterns.js +1 -1
- package/authoring/index.js +13 -0
- package/{pattern-promotion.js → authoring/pattern-promotion.js} +1 -1
- package/{synthetic-data.js → authoring/synthetic-data.js} +6 -6
- package/catalog.js +1 -1
- package/concept-mapper.js +1 -1
- package/embedding/chunk-embedding-retriever.js +112 -0
- package/{embedding-retriever.js → embedding/embedding-retriever.js} +3 -2
- package/embedding/index.js +7 -0
- package/{dialog-recorder.js → feedback/dialog-recorder.js} +2 -2
- package/{feedback-analyzer.js → feedback/feedback-analyzer.js} +3 -2
- package/{feedback-store.js → feedback/feedback-store.js} +2 -1
- package/{gap-registry.js → feedback/gap-registry.js} +2 -1
- package/feedback/index.js +12 -0
- package/index.js +5 -5
- package/{clarity.js → intent/clarity.js} +2 -2
- package/{decomposer.js → intent/decomposer.js} +1 -1
- package/intent/index.js +14 -0
- package/{prompt-analyzer.js → intent/prompt-analyzer.js} +3 -2
- package/package.json +16 -4
- package/pattern-library.js +1 -1
- package/wiring-catalog.js +6 -6
- /package/{web-research.js → authoring/web-research.js} +0 -0
- /package/{embedding-provider.js → embedding/embedding-provider.js} +0 -0
- /package/{feedback.js → feedback/feedback.js} +0 -0
- /package/{intent-alignment.js → intent/intent-alignment.js} +0 -0
- /package/{intent-categorizer.js → intent/intent-categorizer.js} +0 -0
- /package/{intent-gate.js → intent/intent-gate.js} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,70 @@ _Nothing yet._
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [0.2.0] - 2026-05-02
|
|
13
|
+
|
|
14
|
+
**Lockstep cut + boundary reorganization.** All 8 published
|
|
15
|
+
`@adia-ai/*` packages now share one version, governed by
|
|
16
|
+
[`docs/specs/package-architecture.md` § 15 (Versioning Policy)](../../../docs/specs/package-architecture.md#15-versioning-policy).
|
|
17
|
+
This release also lands the boundary cleanup from T4 of the
|
|
18
|
+
[`docs/plans/packages-architecture-fixes-2026-05-02.md`](../../../docs/plans/packages-architecture-fixes-2026-05-02.md)
|
|
19
|
+
plan.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- `version`: `0.0.1` → `0.2.0`.
|
|
24
|
+
- `dependencies["@adia-ai/a2ui-utils"]`: `^0.0.2` → `^0.2.0`.
|
|
25
|
+
|
|
26
|
+
- **Subdir reorganization** — 26 .js files at the top level
|
|
27
|
+
reorganized into 4 named concerns. Lookup-shaped files stay at the
|
|
28
|
+
top level; the rest move into subdirs. Top-level external imports
|
|
29
|
+
(`@adia-ai/a2ui-retrieval`) continue to work unchanged via the
|
|
30
|
+
re-exporting top-level barrel.
|
|
31
|
+
|
|
32
|
+
| New path | Members |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `intent/` | `intent-alignment`, `intent-categorizer`, `intent-gate`, `prompt-analyzer`, `decomposer`, `clarity` |
|
|
35
|
+
| `embedding/` | `embedding-provider`, `embedding-retriever`, `chunk-embedding-retriever` |
|
|
36
|
+
| `feedback/` | `feedback`, `feedback-store`, `feedback-analyzer`, `dialog-recorder`, `gap-registry` |
|
|
37
|
+
| `authoring/` | `synthetic-data`, `web-research`, `pattern-promotion` |
|
|
38
|
+
| top level (kept) | `catalog`, `pattern-library`, `concept-mapper`, `domain-router`, `wiring-catalog`, `anti-patterns`, `context-assembler`, `component-entry`, `index` |
|
|
39
|
+
|
|
40
|
+
- New subpath exports: `./intent`, `./embedding`, `./feedback`,
|
|
41
|
+
`./authoring` each expose a barrel `index.js`. Wildcard subpaths
|
|
42
|
+
(`./intent/*`, `./embedding/*`, etc.) expose individual files for
|
|
43
|
+
fine-grained imports. The old wildcard `./*` is retained for
|
|
44
|
+
backward compatibility — direct imports of moved files still work
|
|
45
|
+
(e.g. `import { feedbackStore } from '@adia-ai/a2ui-retrieval/feedback/feedback-store'`)
|
|
46
|
+
but consumers should prefer the barrel form.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- 6 `__dirname`-based path computations (in `dialog-recorder`,
|
|
51
|
+
`feedback-store`, `feedback-analyzer`, `gap-registry`, the two
|
|
52
|
+
embedding retrievers, and `prompt-analyzer`) gained one more `..`
|
|
53
|
+
segment to climb out of the new subdir to the corpus directory.
|
|
54
|
+
Without this, the moved files would write to a non-existent path
|
|
55
|
+
(`packages/a2ui/a2ui/corpus/...`). Caught during the post-move
|
|
56
|
+
smoke run; same class as the
|
|
57
|
+
`feedback_git_mv_audit_imports` memory entry.
|
|
58
|
+
|
|
59
|
+
### Migration
|
|
60
|
+
|
|
61
|
+
```diff
|
|
62
|
+
- import { feedbackStore } from '@adia-ai/a2ui-retrieval'; // still works (top-level barrel)
|
|
63
|
+
- import { feedbackStore } from '@adia-ai/a2ui-retrieval/feedback-store'; // BREAKS — file moved
|
|
64
|
+
+ import { feedbackStore } from '@adia-ai/a2ui-retrieval/feedback'; // new barrel
|
|
65
|
+
+ import { feedbackStore } from '@adia-ai/a2ui-retrieval/feedback/feedback-store'; // explicit
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The top-level `index.js` still re-exports the previously-public surface
|
|
69
|
+
(`assessClarity`, `isConversational`, `decomposeIntent`,
|
|
70
|
+
`checkIntentAlignment`, etc.) — those imports do not need updating.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
12
76
|
## [0.0.1] - 2026-04-24
|
|
13
77
|
|
|
14
78
|
First public release. Extracted from
|
package/README.md
CHANGED
|
@@ -14,18 +14,49 @@ npm install @adia-ai/a2ui-retrieval
|
|
|
14
14
|
|
|
15
15
|
## What's here
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
17
|
+
The package groups its 26 source files into 4 sub-concerns plus a
|
|
18
|
+
top-level lookup surface. Importers can pull the top-level barrel
|
|
19
|
+
(`@adia-ai/a2ui-retrieval`) for the previously-public surface, the
|
|
20
|
+
per-subdir barrels (`@adia-ai/a2ui-retrieval/intent` etc.), or
|
|
21
|
+
individual files for fine-grained imports.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
a2ui-retrieval/
|
|
25
|
+
├── catalog.js top-level — catalog lookup (loaded from corpus)
|
|
26
|
+
├── pattern-library.js top-level — keyword + semantic pattern search
|
|
27
|
+
├── concept-mapper.js top-level — concept → catalog-entry mapping
|
|
28
|
+
├── domain-router.js top-level — intent → catalog-domain classifier
|
|
29
|
+
├── wiring-catalog.js top-level — controller / handler reference
|
|
30
|
+
├── anti-patterns.js top-level — known-bad pattern detector
|
|
31
|
+
├── context-assembler.js top-level — retrieval results → LLM context
|
|
32
|
+
├── component-entry.js top-level — catalog row serializer
|
|
33
|
+
├── index.js top-level — barrel
|
|
34
|
+
│
|
|
35
|
+
├── intent/ intent classification + decomposition
|
|
36
|
+
│ ├── intent-alignment.js
|
|
37
|
+
│ ├── intent-categorizer.js
|
|
38
|
+
│ ├── intent-gate.js UI-generating vs conversational
|
|
39
|
+
│ ├── prompt-analyzer.js
|
|
40
|
+
│ ├── decomposer.js compound intents → subtasks
|
|
41
|
+
│ └── clarity.js clarity scoring
|
|
42
|
+
│
|
|
43
|
+
├── embedding/ dense-vector retrieval
|
|
44
|
+
│ ├── embedding-provider.js adapter (Voyage / OpenAI / fallback)
|
|
45
|
+
│ ├── embedding-retriever.js top-N pattern retrieval
|
|
46
|
+
│ └── chunk-embedding-retriever.js chunk-level retrieval
|
|
47
|
+
│
|
|
48
|
+
├── feedback/ user-feedback ingestion loop
|
|
49
|
+
│ ├── feedback.js
|
|
50
|
+
│ ├── feedback-store.js JSONL store under .brain/feedback/
|
|
51
|
+
│ ├── feedback-analyzer.js
|
|
52
|
+
│ ├── dialog-recorder.js LLM round-trip capture (gated by env)
|
|
53
|
+
│ └── gap-registry.js tracked gaps in catalog coverage
|
|
54
|
+
│
|
|
55
|
+
└── authoring/ corpus-authoring helpers (upstream of retrieval)
|
|
56
|
+
├── synthetic-data.js
|
|
57
|
+
├── web-research.js
|
|
58
|
+
└── pattern-promotion.js
|
|
59
|
+
```
|
|
29
60
|
|
|
30
61
|
## Runtime
|
|
31
62
|
|
package/anti-patterns.js
CHANGED
|
@@ -76,7 +76,7 @@ const antiPatterns = [
|
|
|
76
76
|
'table-ui', 'chart-ui', 'embed-ui', 'stack-ui', 'block-ui', 'code-ui',
|
|
77
77
|
'textarea-ui', 'radio-ui', 'radio-ui', 'tag-ui', 'accordion-ui',
|
|
78
78
|
'modal-ui', 'alert-ui', 'tooltip-ui', 'menu-ui', 'breadcrumb-ui',
|
|
79
|
-
'nav-
|
|
79
|
+
'nav-ui', 'pagination-ui', 'avatar-group-ui', 'segmented-ui',
|
|
80
80
|
'segment-ui', 'command-ui', 'command-item-ui', 'command-group-ui',
|
|
81
81
|
'calendar-picker-ui', 'color-picker-ui', 'kbd-ui', 'toolbar-ui',
|
|
82
82
|
'otp-input-ui',
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adia-ai/a2ui-retrieval/authoring — corpus authoring helpers.
|
|
3
|
+
*
|
|
4
|
+
* Scripts and helpers that produce or extend retrieval inputs:
|
|
5
|
+
* synthetic-data generation, web research, pattern promotion. These are
|
|
6
|
+
* upstream of retrieval (they create what retrieval reads) — kept inside
|
|
7
|
+
* the retrieval package because they share the catalog + pattern-library
|
|
8
|
+
* surfaces, but logically a separate concern from lookup.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export * from './synthetic-data.js';
|
|
12
|
+
export * from './web-research.js';
|
|
13
|
+
export * from './pattern-promotion.js';
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* Spec: A003 section 6 — Synthetic Data Generation
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { getCatalog } from '
|
|
13
|
-
import { getAntiPatterns } from '
|
|
14
|
-
import { getAllPatterns } from '
|
|
15
|
-
import { serializeEntry } from '
|
|
12
|
+
import { getCatalog } from '../catalog.js';
|
|
13
|
+
import { getAntiPatterns } from '../anti-patterns.js';
|
|
14
|
+
import { getAllPatterns } from '../pattern-library.js';
|
|
15
|
+
import { serializeEntry } from '../component-entry.js';
|
|
16
16
|
|
|
17
17
|
// ── Coverage targets (spec section 6.2) ──
|
|
18
18
|
|
|
@@ -409,7 +409,7 @@ export class SyntheticDataGenerator {
|
|
|
409
409
|
|
|
410
410
|
// Map A2UI types to their AdiaUI tag names for anti-pattern checking
|
|
411
411
|
const tag = type.toLowerCase().replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
412
|
-
const tagName = tag.endsWith('-
|
|
412
|
+
const tagName = tag.endsWith('-ui') ? tag : `${tag}-ui`;
|
|
413
413
|
|
|
414
414
|
// Build a minimal HTML representation
|
|
415
415
|
const attrs = [];
|
|
@@ -425,7 +425,7 @@ export class SyntheticDataGenerator {
|
|
|
425
425
|
.filter(Boolean)
|
|
426
426
|
.map(c => {
|
|
427
427
|
const ct = c.component?.toLowerCase().replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() || '';
|
|
428
|
-
return ct.endsWith('-
|
|
428
|
+
return ct.endsWith('-ui') ? ct : ct;
|
|
429
429
|
});
|
|
430
430
|
lines.push(`<${tagName}${attrStr}>${childTypes.map(ct => `<${ct}>`).join('')}</${tagName}>`);
|
|
431
431
|
} else {
|
package/catalog.js
CHANGED
|
@@ -83,7 +83,7 @@ const categoryMap = {
|
|
|
83
83
|
'section': 'card-child', 'header': 'card-child', 'footer': 'card-child',
|
|
84
84
|
'stream-ui': 'agent', 'table-ui': 'agent', 'chart-ui': 'agent',
|
|
85
85
|
'embed-ui': 'agent', 'noodles-ui': 'agent',
|
|
86
|
-
'breadcrumb-ui': 'navigation', 'nav-
|
|
86
|
+
'breadcrumb-ui': 'navigation', 'nav-ui': 'navigation', 'pagination-ui': 'navigation',
|
|
87
87
|
'segmented-ui': 'navigation', 'segment-ui': 'navigation', 'router-ui': 'navigation',
|
|
88
88
|
'toggle-group-ui': 'navigation', 'toggle-option-ui': 'navigation',
|
|
89
89
|
};
|
package/concept-mapper.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { searchBlocks } from '../engine/reference.js';
|
|
23
|
-
import { scoreAll as embeddingScoreAll, available as embeddingAvailable } from './embedding-retriever.js';
|
|
23
|
+
import { scoreAll as embeddingScoreAll, available as embeddingAvailable } from './embedding/embedding-retriever.js';
|
|
24
24
|
|
|
25
25
|
/** Weights for the combined score. Tuned to keep lexical authoritative
|
|
26
26
|
* but let strong conceptual+structural+semantic signals override marginal
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chunk embedding retriever — loads the build-time chunk embedding index
|
|
3
|
+
* and scores a query against every chunk via cosine similarity.
|
|
4
|
+
*
|
|
5
|
+
* Sibling to `embedding-retriever.js` (pattern embeddings); same provider
|
|
6
|
+
* conventions, same graceful-degradation contract.
|
|
7
|
+
*
|
|
8
|
+
* Index: packages/a2ui/corpus/chunk-embeddings.json (built by
|
|
9
|
+
* scripts/build/embeddings-chunks.mjs). When missing or empty, the
|
|
10
|
+
* retriever is effectively a no-op — callers see an empty score map and
|
|
11
|
+
* should fall back to keyword-only ranking.
|
|
12
|
+
*
|
|
13
|
+
* Used by chunk-library.searchChunks() to blend semantic + keyword scores.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { detectProvider, cosine, voyage, openai } from './embedding-provider.js';
|
|
17
|
+
|
|
18
|
+
const IS_NODE = typeof process !== 'undefined' && !!process.versions?.node;
|
|
19
|
+
|
|
20
|
+
let _index = null;
|
|
21
|
+
let _indexByName = null; // Map<chunk-name, Float32Array>
|
|
22
|
+
let _loadPromise = null;
|
|
23
|
+
let _embedFn = null;
|
|
24
|
+
let _available = null;
|
|
25
|
+
|
|
26
|
+
async function _loadIndex() {
|
|
27
|
+
if (_index !== null) return _index;
|
|
28
|
+
if (_loadPromise) return _loadPromise;
|
|
29
|
+
_loadPromise = (async () => {
|
|
30
|
+
try {
|
|
31
|
+
if (IS_NODE) {
|
|
32
|
+
const fs = await import(/* @vite-ignore */ 'node:fs/promises');
|
|
33
|
+
const path = await import(/* @vite-ignore */ 'node:path');
|
|
34
|
+
const url = await import(/* @vite-ignore */ 'node:url');
|
|
35
|
+
// packages/a2ui/retrieval/embedding → up 2 → packages/a2ui → corpus/chunk-embeddings.json
|
|
36
|
+
const here = path.dirname(url.fileURLToPath(import.meta.url));
|
|
37
|
+
const p = path.resolve(here, '../../corpus/chunk-embeddings.json');
|
|
38
|
+
const raw = await fs.readFile(p, 'utf8');
|
|
39
|
+
_index = JSON.parse(raw);
|
|
40
|
+
} else {
|
|
41
|
+
const url = new URL('../../corpus/chunk-embeddings.json', import.meta.url);
|
|
42
|
+
const res = await fetch(url).catch(() => null);
|
|
43
|
+
_index = res?.ok ? await res.json().catch(() => null) : null;
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
_index = null;
|
|
47
|
+
}
|
|
48
|
+
if (_index?.chunks?.length) {
|
|
49
|
+
_indexByName = new Map();
|
|
50
|
+
for (const c of _index.chunks) {
|
|
51
|
+
if (c?.name && Array.isArray(c.vector)) {
|
|
52
|
+
_indexByName.set(c.name, Float32Array.from(c.vector));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return _index;
|
|
57
|
+
})();
|
|
58
|
+
return _loadPromise;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function _resolveEmbed(providerName, model) {
|
|
62
|
+
if (providerName === 'voyage') return voyage({ model });
|
|
63
|
+
if (providerName === 'openai') return openai({ model });
|
|
64
|
+
const auto = detectProvider();
|
|
65
|
+
return auto?.embed || null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function available() {
|
|
69
|
+
if (_available !== null) return _available;
|
|
70
|
+
const idx = await _loadIndex();
|
|
71
|
+
if (!idx || !idx.chunks?.length) {
|
|
72
|
+
_available = false;
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
_embedFn = _resolveEmbed(idx.provider, idx.model);
|
|
76
|
+
_available = !!_embedFn;
|
|
77
|
+
return _available;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Embed a query and return a Map<chunk-name → cosine-score>.
|
|
82
|
+
* Returns an empty Map when unavailable (no index or no API key).
|
|
83
|
+
*/
|
|
84
|
+
export async function scoreAll(query) {
|
|
85
|
+
if (!query || typeof query !== 'string') return new Map();
|
|
86
|
+
if (!(await available())) return new Map();
|
|
87
|
+
|
|
88
|
+
let qVec;
|
|
89
|
+
try {
|
|
90
|
+
const [v] = await _embedFn([query]);
|
|
91
|
+
qVec = v;
|
|
92
|
+
} catch (e) {
|
|
93
|
+
if (typeof console !== 'undefined') console.warn('[chunk-embedding-retriever]', e.message);
|
|
94
|
+
return new Map();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const out = new Map();
|
|
98
|
+
for (const [name, vec] of _indexByName) {
|
|
99
|
+
out.set(name, cosine(qVec, vec));
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function size() {
|
|
105
|
+
const idx = await _loadIndex();
|
|
106
|
+
return idx?.chunks?.length || 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function providerInfo() {
|
|
110
|
+
const idx = await _loadIndex();
|
|
111
|
+
return idx ? { provider: idx.provider, model: idx.model, dims: idx.dims } : null;
|
|
112
|
+
}
|
|
@@ -32,12 +32,13 @@ async function _loadIndex() {
|
|
|
32
32
|
const fs = await import(/* @vite-ignore */ 'node:fs/promises');
|
|
33
33
|
const path = await import(/* @vite-ignore */ 'node:path');
|
|
34
34
|
const url = await import(/* @vite-ignore */ 'node:url');
|
|
35
|
+
// packages/a2ui/retrieval/embedding → up 2 → packages/a2ui → corpus/pattern-embeddings.json
|
|
35
36
|
const here = path.dirname(url.fileURLToPath(import.meta.url));
|
|
36
|
-
const p = path.resolve(here, '
|
|
37
|
+
const p = path.resolve(here, '../../corpus/pattern-embeddings.json');
|
|
37
38
|
const raw = await fs.readFile(p, 'utf8');
|
|
38
39
|
_index = JSON.parse(raw);
|
|
39
40
|
} else {
|
|
40
|
-
const url = new URL('
|
|
41
|
+
const url = new URL('../../corpus/pattern-embeddings.json', import.meta.url);
|
|
41
42
|
const res = await fetch(url).catch(() => null);
|
|
42
43
|
_index = res?.ok ? await res.json().catch(() => null) : null;
|
|
43
44
|
}
|
|
@@ -36,9 +36,9 @@ async function _ensureModules() {
|
|
|
36
36
|
_fs = await import(/* @vite-ignore */ 'node:fs/promises');
|
|
37
37
|
_path = await import(/* @vite-ignore */ 'node:path');
|
|
38
38
|
_url = await import(/* @vite-ignore */ 'node:url');
|
|
39
|
-
// logs/ lives at the repo root: packages/a2ui/retrieval → up
|
|
39
|
+
// logs/ lives at the repo root: packages/a2ui/retrieval/feedback → up 4 → repo root
|
|
40
40
|
const __dirname = _path.dirname(_url.fileURLToPath(import.meta.url));
|
|
41
|
-
_logsRoot = _path.resolve(__dirname, '..', '..', '..', 'logs', 'dialogs');
|
|
41
|
+
_logsRoot = _path.resolve(__dirname, '..', '..', '..', '..', 'logs', 'dialogs');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// In-memory turn counter per session — keeps the on-disk turn ordering correct
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { feedbackStore } from './feedback-store.js';
|
|
16
|
-
import { categorizeIntent } from '
|
|
16
|
+
import { categorizeIntent } from '../intent/intent-categorizer.js';
|
|
17
17
|
|
|
18
18
|
let fs, path;
|
|
19
19
|
const IS_NODE = typeof process !== 'undefined' && process.versions?.node;
|
|
@@ -26,8 +26,9 @@ if (IS_NODE) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// packages/a2ui/retrieval/feedback → up 3 → packages/a2ui → corpus/feedback
|
|
29
30
|
const FEEDBACK_DIR = path
|
|
30
|
-
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'a2ui/corpus', 'feedback')
|
|
31
|
+
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', '..', 'a2ui/corpus', 'feedback')
|
|
31
32
|
: null;
|
|
32
33
|
|
|
33
34
|
export class FeedbackAnalyzer {
|
|
@@ -23,8 +23,9 @@ if (IS_NODE) {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
// packages/a2ui/retrieval/feedback → up 3 → packages/a2ui → corpus/feedback
|
|
26
27
|
const FEEDBACK_DIR = path
|
|
27
|
-
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'a2ui/corpus', 'feedback')
|
|
28
|
+
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', '..', 'a2ui/corpus', 'feedback')
|
|
28
29
|
: null;
|
|
29
30
|
|
|
30
31
|
function todayFile() {
|
|
@@ -24,8 +24,9 @@ if (IS_NODE) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// packages/a2ui/retrieval/feedback → up 3 → packages/a2ui → corpus/gaps/registry.json
|
|
27
28
|
const REGISTRY_PATH = path
|
|
28
|
-
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', 'a2ui/corpus', 'gaps', 'registry.json')
|
|
29
|
+
? path.join(path.dirname(new URL(import.meta.url).pathname), '..', '..', '..', 'a2ui/corpus', 'gaps', 'registry.json')
|
|
29
30
|
: null;
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adia-ai/a2ui-retrieval/feedback — feedback-loop surface.
|
|
3
|
+
*
|
|
4
|
+
* Pairs the feedback store, analyzer, dialog recorder, and gap registry
|
|
5
|
+
* — all the artifacts that compose the user-feedback ingestion loop.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { feedbackStore } from './feedback-store.js';
|
|
9
|
+
export { FeedbackAnalyzer } from './feedback-analyzer.js';
|
|
10
|
+
export * from './feedback.js';
|
|
11
|
+
export { recordTurn, isRecording } from './dialog-recorder.js';
|
|
12
|
+
export { loadGaps, addGap, updateGapStatus } from './gap-registry.js';
|
package/index.js
CHANGED
|
@@ -6,11 +6,11 @@ export { getCatalog, getComponent, getComponentsByCategory, getTraits, getTraits
|
|
|
6
6
|
export { serializeEntry } from './component-entry.js';
|
|
7
7
|
export { getAntiPatterns, checkAntiPattern, checkAllAntiPatterns } from './anti-patterns.js';
|
|
8
8
|
export { classifyIntent, getDomain, getAllDomains } from './domain-router.js';
|
|
9
|
-
export { isConversational } from './intent-gate.js';
|
|
10
|
-
export { assessClarity } from './clarity.js';
|
|
11
|
-
export { detectReferences, researchIntent } from './web-research.js';
|
|
9
|
+
export { isConversational } from './intent/intent-gate.js';
|
|
10
|
+
export { assessClarity } from './intent/clarity.js';
|
|
11
|
+
export { detectReferences, researchIntent } from './authoring/web-research.js';
|
|
12
12
|
export { assembleContext } from './context-assembler.js';
|
|
13
13
|
export { getPattern, searchPatterns, semanticSearchPatterns, getAllPatterns, registerPattern } from './pattern-library.js';
|
|
14
|
-
export { extractExpectations, verifyAlignment, checkIntentAlignment } from './intent-alignment.js';
|
|
15
|
-
export { decomposeIntent, composeSubtasks } from './decomposer.js';
|
|
14
|
+
export { extractExpectations, verifyAlignment, checkIntentAlignment } from './intent/intent-alignment.js';
|
|
15
|
+
export { decomposeIntent, composeSubtasks } from './intent/decomposer.js';
|
|
16
16
|
export { getWiringCatalog, getControllerInfo, getHandlerInfo } from './wiring-catalog.js';
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
* Returns a clarity score (0-1) and targeted questions for what's missing.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { classifyIntent } from '
|
|
16
|
-
import { searchPatterns } from '
|
|
15
|
+
import { classifyIntent } from '../domain-router.js';
|
|
16
|
+
import { searchPatterns } from '../pattern-library.js';
|
|
17
17
|
|
|
18
18
|
// ── Dimension detectors ──────────────────────────────────────────────────
|
|
19
19
|
|
package/intent/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
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';
|
|
@@ -45,11 +45,12 @@ async function getVocab() {
|
|
|
45
45
|
const fs = await import(/* @vite-ignore */ 'node:fs/promises');
|
|
46
46
|
const path = await import(/* @vite-ignore */ 'node:path');
|
|
47
47
|
const url = await import(/* @vite-ignore */ 'node:url');
|
|
48
|
+
// packages/a2ui/retrieval/intent → up 2 → packages/a2ui → corpus/patterns/_components.json
|
|
48
49
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
49
|
-
const raw = await fs.readFile(path.join(__dirname, '
|
|
50
|
+
const raw = await fs.readFile(path.join(__dirname, '../../corpus/patterns/_components.json'), 'utf8');
|
|
50
51
|
catalog = JSON.parse(raw);
|
|
51
52
|
} else {
|
|
52
|
-
const resp = await fetch(new URL('
|
|
53
|
+
const resp = await fetch(new URL('../../corpus/patterns/_components.json', import.meta.url));
|
|
53
54
|
if (resp.ok) catalog = await resp.json();
|
|
54
55
|
}
|
|
55
56
|
} catch { /* empty vocab — analyzer will still work, just unconstrained */ }
|
package/package.json
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/a2ui-retrieval",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AdiaUI A2UI retrieval layer — catalog lookup, intent classification, domain routing, pattern + anti-pattern matching, clarity + context assembly. Consumed by the compose engine and any A2UI-protocol tooling that needs to reason about user intent against the catalog.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
"
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./intent": "./intent/index.js",
|
|
10
|
+
"./intent/*": "./intent/*.js",
|
|
11
|
+
"./embedding": "./embedding/index.js",
|
|
12
|
+
"./embedding/*": "./embedding/*.js",
|
|
13
|
+
"./feedback": "./feedback/index.js",
|
|
14
|
+
"./feedback/*": "./feedback/*.js",
|
|
15
|
+
"./authoring": "./authoring/index.js",
|
|
16
|
+
"./authoring/*": "./authoring/*.js",
|
|
17
|
+
"./*": "./*.js"
|
|
10
18
|
},
|
|
11
19
|
"files": [
|
|
12
20
|
"*.js",
|
|
21
|
+
"intent/",
|
|
22
|
+
"embedding/",
|
|
23
|
+
"feedback/",
|
|
24
|
+
"authoring/",
|
|
13
25
|
"README.md",
|
|
14
26
|
"CHANGELOG.md"
|
|
15
27
|
],
|
|
@@ -24,6 +36,6 @@
|
|
|
24
36
|
"directory": "packages/a2ui/retrieval"
|
|
25
37
|
},
|
|
26
38
|
"dependencies": {
|
|
27
|
-
"@adia-ai/a2ui-utils": "^0.0
|
|
39
|
+
"@adia-ai/a2ui-utils": "^0.2.0"
|
|
28
40
|
}
|
|
29
41
|
}
|
package/pattern-library.js
CHANGED
|
@@ -535,7 +535,7 @@ export async function semanticSearchPatterns(query, options = {}) {
|
|
|
535
535
|
// where keyword collisions pick the wrong pattern. Graceful degradation:
|
|
536
536
|
// empty map → no effect, pipeline behaves exactly as pre-embedding.
|
|
537
537
|
try {
|
|
538
|
-
const { scoreAll, available } = await import('./embedding-retriever.js');
|
|
538
|
+
const { scoreAll, available } = await import('./embedding/embedding-retriever.js');
|
|
539
539
|
if (await available()) {
|
|
540
540
|
const semanticMap = await scoreAll(query);
|
|
541
541
|
if (semanticMap.size > 0) {
|
package/wiring-catalog.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* The schema has 5 docking points:
|
|
8
8
|
* DATA — sources, params (how the surface gets its data)
|
|
9
9
|
* STATE — controllers, model (how components manage behavior)
|
|
10
|
-
* ACTIONS —
|
|
10
|
+
* ACTIONS — UIEvent → handler chains (what happens on events)
|
|
11
11
|
* PROVIDES — context injection into subtrees
|
|
12
12
|
* LIFECYCLE — onMount, onUnmount, onModelChange hooks
|
|
13
13
|
*
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* A full app needs all five.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
// ──
|
|
20
|
+
// ── UIEvent ──────────────────────────────────────────────────
|
|
21
21
|
// A typed event object that the wiring system understands natively.
|
|
22
22
|
// Maps 1:1 to DOM events but with AdiaUI semantics and payload contracts.
|
|
23
23
|
//
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// { "event": "submit", "target": "form-col" }
|
|
27
27
|
// { "event": "mount" }
|
|
28
28
|
//
|
|
29
|
-
// "event" —
|
|
29
|
+
// "event" — UIEvent type name (see adiaEvents below)
|
|
30
30
|
// "target" — component id that emits. Omit for surface-level events.
|
|
31
31
|
// "debounce" — ms, coalesce rapid-fire (input, resize)
|
|
32
32
|
// "throttle" — ms, limit frequency (scroll, drag)
|
|
@@ -129,9 +129,9 @@ export function getWiringCatalog() {
|
|
|
129
129
|
{ name: 'notify', description: 'Show a toast/alert notification.', config: ['message', 'variant'] },
|
|
130
130
|
],
|
|
131
131
|
|
|
132
|
-
// ── ACTION SHAPE (
|
|
132
|
+
// ── ACTION SHAPE (UIEvent → handler) ──
|
|
133
133
|
actionShape: {
|
|
134
|
-
event: '
|
|
134
|
+
event: 'UIEvent object: { event, target?, debounce?, throttle?, condition? }',
|
|
135
135
|
handler: 'Handler name from the handlers list.',
|
|
136
136
|
config: 'Handler-specific configuration object.',
|
|
137
137
|
onSuccess: 'Follow-up actions array (each is { handler, config }).',
|
|
@@ -174,7 +174,7 @@ export function getWiringCatalog() {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
* Get
|
|
177
|
+
* Get UIEvent type info.
|
|
178
178
|
*/
|
|
179
179
|
export function getAdiaEvent(type) {
|
|
180
180
|
return adiaEvents.find(e => e.event === type) || null;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|