@pellux/goodvibes-sdk 0.27.0 → 0.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/contracts/artifacts/operator-contract.json +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.js +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +1 -1
- package/dist/_internal/platform/daemon/http/home-graph-routes.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/home-graph-routes.js +39 -22
- package/dist/_internal/platform/knowledge/home-graph/search.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/search.js +56 -12
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Synced from packages/contracts/src/generated/foundation-metadata.ts
|
|
2
2
|
export const FOUNDATION_METADATA = {
|
|
3
3
|
"productId": "goodvibes",
|
|
4
|
-
"productVersion": "0.27.
|
|
4
|
+
"productVersion": "0.27.1",
|
|
5
5
|
"operatorMethodCount": 254,
|
|
6
6
|
"operatorEventCount": 30,
|
|
7
7
|
"peerEndpointCount": 6
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"home-graph-routes.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/daemon/http/home-graph-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,oCAAoC,CAAC;AAc5C,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACzE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;IACxF,QAAQ,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,IAAI,CAAC;CAC1D;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,qBAAqB;IAErD,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"home-graph-routes.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/daemon/http/home-graph-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,oCAAoC,CAAC;AAc5C,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;IAChD,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC;IACzE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;IACxF,QAAQ,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,GAAG,IAAI,CAAC;CAC1D;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,qBAAqB;IAErD,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;YAwGtC,KAAK;YAML,QAAQ;YAMR,gBAAgB;CAK/B"}
|
|
@@ -6,13 +6,14 @@ export class HomeGraphRoutes {
|
|
|
6
6
|
}
|
|
7
7
|
async handle(req) {
|
|
8
8
|
const url = new URL(req.url);
|
|
9
|
-
|
|
9
|
+
const pathname = normalizeHomeGraphPath(url.pathname);
|
|
10
|
+
if (!pathname.startsWith('/api/homeassistant/home-graph'))
|
|
10
11
|
return null;
|
|
11
12
|
try {
|
|
12
|
-
if (
|
|
13
|
+
if (pathname === '/api/homeassistant/home-graph/status' && req.method === 'GET') {
|
|
13
14
|
return Response.json(await this.context.homeGraphService.status(readSpaceFromUrl(url)));
|
|
14
15
|
}
|
|
15
|
-
if (
|
|
16
|
+
if (pathname === '/api/homeassistant/home-graph/issues' && req.method === 'GET') {
|
|
16
17
|
return Response.json(await this.context.homeGraphService.listIssues({
|
|
17
18
|
...readSpaceFromUrl(url),
|
|
18
19
|
status: url.searchParams.get('status') ?? undefined,
|
|
@@ -21,23 +22,25 @@ export class HomeGraphRoutes {
|
|
|
21
22
|
limit: readLimit(url, 100),
|
|
22
23
|
}));
|
|
23
24
|
}
|
|
24
|
-
if (
|
|
25
|
+
if (pathname === '/api/homeassistant/home-graph/sources' && req.method === 'GET') {
|
|
25
26
|
return Response.json(await this.context.homeGraphService.listSources({
|
|
26
27
|
...readSpaceFromUrl(url),
|
|
27
28
|
limit: readLimit(url, 100),
|
|
28
29
|
}));
|
|
29
30
|
}
|
|
30
|
-
if (
|
|
31
|
+
if (pathname === '/api/homeassistant/home-graph/browse' && req.method === 'GET') {
|
|
31
32
|
return Response.json(await this.context.homeGraphService.browse({
|
|
32
33
|
...readSpaceFromUrl(url),
|
|
33
34
|
limit: readLimit(url, 250),
|
|
34
35
|
}));
|
|
35
36
|
}
|
|
36
|
-
if (
|
|
37
|
+
if (pathname === '/api/homeassistant/home-graph/map' && (req.method === 'GET' || req.method === 'POST')) {
|
|
38
|
+
const body = req.method === 'POST' ? await this.readOptionalBody(req) : {};
|
|
37
39
|
const result = await this.context.homeGraphService.map({
|
|
38
40
|
...readSpaceFromUrl(url),
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
...body,
|
|
42
|
+
limit: readNumber(body.limit) ?? readLimit(url, 500),
|
|
43
|
+
includeSources: readBooleanValue(body.includeSources) ?? readBoolean(url, 'includeSources', true),
|
|
41
44
|
});
|
|
42
45
|
if (url.searchParams.get('format') === 'svg') {
|
|
43
46
|
return new Response(result.svg, {
|
|
@@ -48,25 +51,25 @@ export class HomeGraphRoutes {
|
|
|
48
51
|
}
|
|
49
52
|
return Response.json(result);
|
|
50
53
|
}
|
|
51
|
-
if (
|
|
54
|
+
if (pathname === '/api/homeassistant/home-graph/export' && req.method === 'POST') {
|
|
52
55
|
return Response.json(await this.context.homeGraphService.exportSpace(await this.readOptionalBody(req)));
|
|
53
56
|
}
|
|
54
|
-
if (
|
|
57
|
+
if (pathname === '/api/homeassistant/home-graph/ask' && req.method === 'POST') {
|
|
55
58
|
return Response.json(await this.context.homeGraphService.ask(await this.readBody(req)));
|
|
56
59
|
}
|
|
57
|
-
if (
|
|
60
|
+
if (pathname === '/api/homeassistant/home-graph/reindex' && req.method === 'POST') {
|
|
58
61
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.reindex(await this.readOptionalBody(req))));
|
|
59
62
|
}
|
|
60
|
-
if (
|
|
63
|
+
if (pathname === '/api/homeassistant/home-graph/sync' && req.method === 'POST') {
|
|
61
64
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.syncSnapshot(await this.readBody(req))));
|
|
62
65
|
}
|
|
63
|
-
if (
|
|
66
|
+
if (pathname === '/api/homeassistant/home-graph/ingest/url' && req.method === 'POST') {
|
|
64
67
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.ingestUrl(await this.readBody(req))));
|
|
65
68
|
}
|
|
66
|
-
if (
|
|
69
|
+
if (pathname === '/api/homeassistant/home-graph/ingest/note' && req.method === 'POST') {
|
|
67
70
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.ingestNote(await this.readBody(req))));
|
|
68
71
|
}
|
|
69
|
-
if (
|
|
72
|
+
if (pathname === '/api/homeassistant/home-graph/ingest/artifact' && req.method === 'POST') {
|
|
70
73
|
return await this.admin(req, async () => {
|
|
71
74
|
if (isArtifactUploadRequest(req)) {
|
|
72
75
|
const uploaded = await createArtifactFromUploadRequest(this.context.artifactStore, req);
|
|
@@ -80,25 +83,25 @@ export class HomeGraphRoutes {
|
|
|
80
83
|
return Response.json(await this.context.homeGraphService.ingestArtifact(await this.readBody(req)));
|
|
81
84
|
});
|
|
82
85
|
}
|
|
83
|
-
if (
|
|
86
|
+
if (pathname === '/api/homeassistant/home-graph/link' && req.method === 'POST') {
|
|
84
87
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.linkKnowledge(await this.readBody(req))));
|
|
85
88
|
}
|
|
86
|
-
if (
|
|
89
|
+
if (pathname === '/api/homeassistant/home-graph/unlink' && req.method === 'POST') {
|
|
87
90
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.unlinkKnowledge(await this.readBody(req))));
|
|
88
91
|
}
|
|
89
|
-
if (
|
|
92
|
+
if (pathname === '/api/homeassistant/home-graph/device-passport' && req.method === 'POST') {
|
|
90
93
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.refreshDevicePassport(await this.readBody(req))));
|
|
91
94
|
}
|
|
92
|
-
if (
|
|
95
|
+
if (pathname === '/api/homeassistant/home-graph/room-page' && req.method === 'POST') {
|
|
93
96
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.generateRoomPage(await this.readBody(req))));
|
|
94
97
|
}
|
|
95
|
-
if (
|
|
98
|
+
if (pathname === '/api/homeassistant/home-graph/packet' && req.method === 'POST') {
|
|
96
99
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.generatePacket(await this.readBody(req))));
|
|
97
100
|
}
|
|
98
|
-
if (
|
|
101
|
+
if (pathname === '/api/homeassistant/home-graph/facts/review' && req.method === 'POST') {
|
|
99
102
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.reviewFact(await this.readBody(req))));
|
|
100
103
|
}
|
|
101
|
-
if (
|
|
104
|
+
if (pathname === '/api/homeassistant/home-graph/import' && req.method === 'POST') {
|
|
102
105
|
return await this.admin(req, async () => Response.json(await this.context.homeGraphService.importSpace(await this.readBody(req))));
|
|
103
106
|
}
|
|
104
107
|
return Response.json({ error: 'Unknown Home Graph route' }, { status: 404 });
|
|
@@ -126,6 +129,9 @@ export class HomeGraphRoutes {
|
|
|
126
129
|
return body ?? {};
|
|
127
130
|
}
|
|
128
131
|
}
|
|
132
|
+
function normalizeHomeGraphPath(pathname) {
|
|
133
|
+
return pathname.length > 1 ? pathname.replace(/\/+$/g, '') : pathname;
|
|
134
|
+
}
|
|
129
135
|
function readSpaceFromUrl(url) {
|
|
130
136
|
return {
|
|
131
137
|
...(url.searchParams.get('installationId') ? { installationId: url.searchParams.get('installationId') } : {}),
|
|
@@ -142,3 +148,14 @@ function readBoolean(url, key, fallback) {
|
|
|
142
148
|
return fallback;
|
|
143
149
|
return !['0', 'false', 'no', 'off'].includes(value.trim().toLowerCase());
|
|
144
150
|
}
|
|
151
|
+
function readNumber(value) {
|
|
152
|
+
const parsed = typeof value === 'number' ? value : typeof value === 'string' ? Number(value) : NaN;
|
|
153
|
+
return Number.isFinite(parsed) ? Math.max(1, Math.trunc(parsed)) : undefined;
|
|
154
|
+
}
|
|
155
|
+
function readBooleanValue(value) {
|
|
156
|
+
if (typeof value === 'boolean')
|
|
157
|
+
return value;
|
|
158
|
+
if (typeof value !== 'string')
|
|
159
|
+
return undefined;
|
|
160
|
+
return !['0', 'false', 'no', 'off'].includes(value.trim().toLowerCase());
|
|
161
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAqGxD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;CAC/E;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAuBrG;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,yBAAyB,GAAG,IAAI,GAAG,SAAS,EACxF,KAAK,EAAE,MAAM,GACZ,qBAAqB,EAAE,CAmFzB;AAED,wBAAgB,yCAAyC,CACvD,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,KAAK,EAAE,SAAS,mBAAmB,EAAE,EACrC,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,yBAAyB,GAAG,IAAI,GAAG,SAAS,EACxF,KAAK,EAAE,MAAM,GACZ,qBAAqB,EAAE,CAoCzB;AAuMD,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,yBAAyB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAWhH"}
|
|
@@ -49,15 +49,22 @@ const SHORT_MEANINGFUL_TOKENS = new Set(['ac', 'av', 'dc', 'ha', 'ip', 'ir', 'lg
|
|
|
49
49
|
const GENERIC_ANCHOR_TOKENS = new Set([
|
|
50
50
|
'area',
|
|
51
51
|
'assistant',
|
|
52
|
+
'automation',
|
|
53
|
+
'calendar',
|
|
52
54
|
'device',
|
|
53
55
|
'entity',
|
|
54
56
|
'graph',
|
|
55
57
|
'home',
|
|
58
|
+
'library',
|
|
56
59
|
'living',
|
|
57
60
|
'media',
|
|
58
61
|
'media_player',
|
|
59
62
|
'room',
|
|
63
|
+
'sensor',
|
|
64
|
+
'shows',
|
|
60
65
|
'smart',
|
|
66
|
+
'storage',
|
|
67
|
+
'switch',
|
|
61
68
|
]);
|
|
62
69
|
const QUERY_EXPANSIONS = {
|
|
63
70
|
capability: ['capabilities', 'feature', 'features', 'function', 'functions', 'mode', 'modes', 'spec', 'specs', 'support', 'supports'],
|
|
@@ -111,10 +118,12 @@ export function scoreHomeGraphResults(query, sources, nodes, edges, extractionBy
|
|
|
111
118
|
return [];
|
|
112
119
|
const expandedTokens = expandTokens(tokens);
|
|
113
120
|
const anchors = selectAnchorNodes(tokens, nodes);
|
|
114
|
-
const
|
|
115
|
-
const
|
|
121
|
+
const sourceAnchors = selectSourceAnchors(tokens, anchors.map((anchor) => anchor.node));
|
|
122
|
+
const anchorIds = new Set(sourceAnchors.map((node) => node.id));
|
|
123
|
+
const anchorIdentityTokens = collectAnchorIdentityTokens(sourceAnchors);
|
|
116
124
|
const sourceLinks = buildSourceLinkIndex(edges);
|
|
117
|
-
const useAnchorScope =
|
|
125
|
+
const useAnchorScope = sourceAnchors.length > 0 && sourceAnchors.length <= ANCHOR_SCOPE_LIMIT;
|
|
126
|
+
const objectScopedQuery = sourceAnchors.length > 0;
|
|
118
127
|
const sourceEvidenceQuery = queryNeedsSourceEvidence(expandedTokens);
|
|
119
128
|
const integrationQuery = queryMentionsIntegration(tokens);
|
|
120
129
|
const sourceResults = sources.map((source) => {
|
|
@@ -127,7 +136,7 @@ export function scoreHomeGraphResults(query, sources, nodes, edges, extractionBy
|
|
|
127
136
|
}
|
|
128
137
|
const linkedNodeIds = sourceLinks.get(source.id) ?? new Set();
|
|
129
138
|
const linkedToAnchor = useAnchorScope && intersects(linkedNodeIds, anchorIds);
|
|
130
|
-
const anchorIdentityScore =
|
|
139
|
+
const anchorIdentityScore = objectScopedQuery
|
|
131
140
|
? sourceAnchorIdentityScore(anchorIdentityTokens, source, extraction)
|
|
132
141
|
: 0;
|
|
133
142
|
const identityScore = scoreFields(tokens, [
|
|
@@ -184,7 +193,7 @@ export function scoreHomeGraphResults(query, sources, nodes, edges, extractionBy
|
|
|
184
193
|
results = anchoredSourceResults.sort(compareHomeGraphResults);
|
|
185
194
|
}
|
|
186
195
|
if (sourceEvidenceQuery) {
|
|
187
|
-
results = pruneWeakSourceEvidence(results, tokens, sourceLinks, anchorIds, anchorIdentityTokens, extractionBySourceId);
|
|
196
|
+
results = pruneWeakSourceEvidence(results, tokens, sourceLinks, anchorIds, anchorIdentityTokens, objectScopedQuery, extractionBySourceId);
|
|
188
197
|
}
|
|
189
198
|
const strongResults = pruneWeakTokenCoverage(results, tokens);
|
|
190
199
|
return strongResults.slice(0, Math.max(1, limit));
|
|
@@ -194,16 +203,17 @@ export function selectHomeGraphExtractionRepairCandidates(query, sources, nodes,
|
|
|
194
203
|
if (tokens.length === 0)
|
|
195
204
|
return [];
|
|
196
205
|
const anchors = selectAnchorNodes(tokens, nodes);
|
|
197
|
-
const
|
|
198
|
-
const
|
|
206
|
+
const sourceAnchors = selectSourceAnchors(tokens, anchors.map((anchor) => anchor.node));
|
|
207
|
+
const anchorIds = new Set(sourceAnchors.map((anchor) => anchor.id));
|
|
208
|
+
const anchorIdentityTokens = collectAnchorIdentityTokens(sourceAnchors);
|
|
199
209
|
const sourceLinks = buildSourceLinkIndex(edges);
|
|
200
210
|
return sources
|
|
201
211
|
.map((source) => {
|
|
202
212
|
if (!source.artifactId || !homeGraphExtractionNeedsRepair(extractionBySourceId(source.id)))
|
|
203
213
|
return { source, score: 0 };
|
|
204
214
|
const linkedNodeIds = sourceLinks.get(source.id) ?? new Set();
|
|
205
|
-
const linkedToAnchor =
|
|
206
|
-
const anchorIdentityScore =
|
|
215
|
+
const linkedToAnchor = sourceAnchors.length > 0 && intersects(linkedNodeIds, anchorIds);
|
|
216
|
+
const anchorIdentityScore = sourceAnchors.length > 0
|
|
207
217
|
? sourceAnchorIdentityScore(anchorIdentityTokens, source, extractionBySourceId(source.id))
|
|
208
218
|
: 0;
|
|
209
219
|
const identityScore = scoreFields(tokens, [
|
|
@@ -309,15 +319,49 @@ function sourceAnchorIdentityScore(anchorTokens, source, extraction) {
|
|
|
309
319
|
function selectAnchorNodes(tokens, nodes) {
|
|
310
320
|
return nodes.map((node) => {
|
|
311
321
|
const baseScore = scoreFields(tokens, nodeIdentityFields(node));
|
|
322
|
+
const intentBoost = sourceAnchorIntentBoost(tokens, node);
|
|
312
323
|
return {
|
|
313
324
|
node,
|
|
314
|
-
score: baseScore > 0 ? baseScore + nodeKindBoost(node.kind) : 0,
|
|
325
|
+
score: baseScore > 0 ? baseScore + nodeKindBoost(node.kind) + intentBoost : 0,
|
|
315
326
|
};
|
|
316
327
|
})
|
|
317
328
|
.filter((entry) => entry.score >= 10)
|
|
318
329
|
.sort((a, b) => b.score - a.score || a.node.id.localeCompare(b.node.id))
|
|
319
330
|
.slice(0, 12);
|
|
320
331
|
}
|
|
332
|
+
function selectSourceAnchors(tokens, nodes) {
|
|
333
|
+
const preferred = nodes.filter((node) => sourceAnchorIntentBoost(tokens, node) >= 0);
|
|
334
|
+
if (preferred.length > 0)
|
|
335
|
+
return preferred.slice(0, 8);
|
|
336
|
+
return nodes.slice(0, ANCHOR_SCOPE_LIMIT);
|
|
337
|
+
}
|
|
338
|
+
function sourceAnchorIntentBoost(tokens, node) {
|
|
339
|
+
const metadata = readRecord(node.metadata);
|
|
340
|
+
const homeAssistant = readRecord(metadata.homeAssistant);
|
|
341
|
+
const domain = typeof metadata.domain === 'string' ? metadata.domain.toLowerCase() : '';
|
|
342
|
+
const platform = typeof metadata.platform === 'string' ? metadata.platform.toLowerCase() : '';
|
|
343
|
+
const objectKind = typeof homeAssistant.objectKind === 'string' ? homeAssistant.objectKind.toLowerCase() : '';
|
|
344
|
+
const text = nodeIdentityFields(node).join(' ').toLowerCase();
|
|
345
|
+
const tvQuery = tokens.some((token) => token === 'tv' || token === 'television' || token === 'media_player');
|
|
346
|
+
if (tvQuery) {
|
|
347
|
+
if (node.kind === 'ha_device' && /\b(tv|television|webos|bravia)\b/.test(text))
|
|
348
|
+
return 80;
|
|
349
|
+
if (node.kind === 'ha_entity' && (domain === 'media_player' || platform === 'webostv'))
|
|
350
|
+
return 70;
|
|
351
|
+
if (node.kind === 'ha_integration' && (platform === 'webostv' || text.includes('webos')))
|
|
352
|
+
return 40;
|
|
353
|
+
if (domain === 'calendar' || domain === 'sensor' || domain === 'automation' || domain === 'switch'
|
|
354
|
+
|| objectKind === 'automation' || node.kind === 'ha_automation')
|
|
355
|
+
return -80;
|
|
356
|
+
}
|
|
357
|
+
if (node.kind === 'ha_device')
|
|
358
|
+
return 30;
|
|
359
|
+
if (node.kind === 'ha_entity')
|
|
360
|
+
return 10;
|
|
361
|
+
if (node.kind === 'ha_integration' && queryMentionsIntegration(tokens))
|
|
362
|
+
return 8;
|
|
363
|
+
return node.kind === 'ha_integration' ? -10 : 0;
|
|
364
|
+
}
|
|
321
365
|
function buildSourceLinkIndex(edges) {
|
|
322
366
|
const links = new Map();
|
|
323
367
|
for (const edge of edges) {
|
|
@@ -419,7 +463,7 @@ function isHomeAssistantIntegrationSource(source) {
|
|
|
419
463
|
|| tags.includes('documentation')
|
|
420
464
|
|| sourceKind === 'documentation-candidate';
|
|
421
465
|
}
|
|
422
|
-
function pruneWeakSourceEvidence(results, tokens, sourceLinks, anchorIds, anchorIdentityTokens, extractionBySourceId) {
|
|
466
|
+
function pruneWeakSourceEvidence(results, tokens, sourceLinks, anchorIds, anchorIdentityTokens, objectScopedQuery, extractionBySourceId) {
|
|
423
467
|
const sourceResults = results.filter((result) => result.source);
|
|
424
468
|
if (sourceResults.length === 0)
|
|
425
469
|
return [...results];
|
|
@@ -434,7 +478,7 @@ function pruneWeakSourceEvidence(results, tokens, sourceLinks, anchorIds, anchor
|
|
|
434
478
|
const coverage = tokenCoverage(tokens, resultText(result));
|
|
435
479
|
return linkedToAnchor
|
|
436
480
|
|| (matchesAnchorIdentity && coverage >= 1)
|
|
437
|
-
|| coverage >= Math.min(2, tokens.length);
|
|
481
|
+
|| (!objectScopedQuery && coverage >= Math.min(2, tokens.length));
|
|
438
482
|
});
|
|
439
483
|
return strongSourceResults;
|
|
440
484
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
let version = '0.27.
|
|
3
|
+
let version = '0.27.1';
|
|
4
4
|
try {
|
|
5
5
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
|
|
6
6
|
version = pkg.version ?? version;
|