@pellux/goodvibes-sdk 0.27.2 → 0.27.4
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 +845 -4
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
- package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
- package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +845 -4
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.js +2 -0
- package/dist/_internal/daemon/context.d.ts +1 -0
- package/dist/_internal/daemon/context.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-route-types.d.ts +1 -0
- package/dist/_internal/daemon/knowledge-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-routes.d.ts +1 -1
- package/dist/_internal/daemon/knowledge-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/knowledge-routes.js +18 -0
- package/dist/_internal/daemon/operator.d.ts +1 -1
- package/dist/_internal/daemon/operator.d.ts.map +1 -1
- package/dist/_internal/daemon/operator.js +2 -0
- package/dist/_internal/platform/control-plane/method-catalog-homegraph.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/method-catalog-homegraph.js +10 -1
- package/dist/_internal/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/method-catalog-knowledge.js +20 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts +2 -0
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.js +23 -0
- package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.js +2 -0
- package/dist/_internal/platform/daemon/http/home-graph-routes.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/home-graph-routes.js +7 -0
- package/dist/_internal/platform/daemon/http/router-route-contexts.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/router-route-contexts.js +1 -0
- package/dist/_internal/platform/knowledge/extractors.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/extractors.js +1 -116
- package/dist/_internal/platform/knowledge/home-graph/ask.d.ts +13 -0
- package/dist/_internal/platform/knowledge/home-graph/ask.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/home-graph/ask.js +65 -0
- package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts +27 -0
- package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/home-graph/auto-link.js +236 -0
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts +1 -0
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/generated-pages.js +24 -8
- package/dist/_internal/platform/knowledge/home-graph/index.d.ts +1 -1
- package/dist/_internal/platform/knowledge/home-graph/index.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts +11 -0
- package/dist/_internal/platform/knowledge/home-graph/pages.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/home-graph/pages.js +44 -0
- package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts +4 -1
- package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/rendering.js +215 -4
- package/dist/_internal/platform/knowledge/home-graph/service.d.ts +12 -2
- package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/service.js +78 -21
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts +31 -1
- package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/types.js +2 -0
- package/dist/_internal/platform/knowledge/index.d.ts +3 -1
- package/dist/_internal/platform/knowledge/index.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/index.js +1 -0
- package/dist/_internal/platform/knowledge/ingest-compile.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/ingest-compile.js +5 -0
- package/dist/_internal/platform/knowledge/ingest-context.d.ts +1 -0
- package/dist/_internal/platform/knowledge/ingest-context.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/map.js +15 -1
- package/dist/_internal/platform/knowledge/pdf-extractor.d.ts +3 -0
- package/dist/_internal/platform/knowledge/pdf-extractor.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/pdf-extractor.js +346 -0
- package/dist/_internal/platform/knowledge/scheduling.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/scheduling.js +1 -0
- package/dist/_internal/platform/knowledge/semantic/answer.d.ts +9 -0
- package/dist/_internal/platform/knowledge/semantic/answer.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/answer.js +407 -0
- package/dist/_internal/platform/knowledge/semantic/enrichment.d.ts +23 -0
- package/dist/_internal/platform/knowledge/semantic/enrichment.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/enrichment.js +491 -0
- package/dist/_internal/platform/knowledge/semantic/index.d.ts +5 -0
- package/dist/_internal/platform/knowledge/semantic/index.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/index.js +2 -0
- package/dist/_internal/platform/knowledge/semantic/llm.d.ts +4 -0
- package/dist/_internal/platform/knowledge/semantic/llm.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/llm.js +34 -0
- package/dist/_internal/platform/knowledge/semantic/service.d.ts +37 -0
- package/dist/_internal/platform/knowledge/semantic/service.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/service.js +55 -0
- package/dist/_internal/platform/knowledge/semantic/types.d.ts +107 -0
- package/dist/_internal/platform/knowledge/semantic/types.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/types.js +1 -0
- package/dist/_internal/platform/knowledge/semantic/utils.d.ts +39 -0
- package/dist/_internal/platform/knowledge/semantic/utils.d.ts.map +1 -0
- package/dist/_internal/platform/knowledge/semantic/utils.js +189 -0
- package/dist/_internal/platform/knowledge/service.d.ts +12 -0
- package/dist/_internal/platform/knowledge/service.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/service.js +14 -0
- package/dist/_internal/platform/knowledge/types.d.ts +2 -2
- package/dist/_internal/platform/knowledge/types.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/services.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/services.js +8 -2
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { KnowledgeEdgeRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
1
|
+
import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
2
2
|
import type { HomeGraphMapInput, HomeGraphMapResult } from './types.js';
|
|
3
3
|
export interface HomeGraphRenderState {
|
|
4
4
|
readonly spaceId: string;
|
|
@@ -7,6 +7,7 @@ export interface HomeGraphRenderState {
|
|
|
7
7
|
readonly nodes: readonly KnowledgeNodeRecord[];
|
|
8
8
|
readonly edges: readonly KnowledgeEdgeRecord[];
|
|
9
9
|
readonly issues: readonly KnowledgeIssueRecord[];
|
|
10
|
+
readonly extractions?: readonly KnowledgeExtractionRecord[];
|
|
10
11
|
}
|
|
11
12
|
export declare function renderRoomPage(state: HomeGraphRenderState, areaId?: string): string;
|
|
12
13
|
export declare function renderDevicePassportPage(input: {
|
|
@@ -14,8 +15,10 @@ export declare function renderDevicePassportPage(input: {
|
|
|
14
15
|
readonly device: KnowledgeNodeRecord;
|
|
15
16
|
readonly entities: readonly KnowledgeNodeRecord[];
|
|
16
17
|
readonly sources: readonly KnowledgeSourceRecord[];
|
|
18
|
+
readonly extractions?: readonly KnowledgeExtractionRecord[];
|
|
17
19
|
readonly issues: readonly KnowledgeIssueRecord[];
|
|
18
20
|
readonly missingFields: readonly string[];
|
|
21
|
+
readonly semanticFacts?: readonly KnowledgeNodeRecord[];
|
|
19
22
|
}): string;
|
|
20
23
|
export declare function renderPacketPage(state: HomeGraphRenderState, options?: {
|
|
21
24
|
readonly packetKind?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAEpB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rendering.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,EAEpB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAA6B,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEnG,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,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,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;CAC7D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAmDnF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACzD,GAAG,MAAM,CA+BT;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC,GAAG,MAAM,CAkBd;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,GAAE,iBAAsB,GAAG,kBAAkB,CAcnH"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { renderKnowledgeMap } from '../map.js';
|
|
2
2
|
import { countFacet, normalizeStringArray, readString } from '../map-filters.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isUnusableHomeGraphExtractionText } from './extraction-quality.js';
|
|
4
|
+
import { edgeIsActive, isGeneratedPageSource, readRecord, uniqueStrings } from './helpers.js';
|
|
4
5
|
export function renderRoomPage(state, areaId) {
|
|
5
6
|
const area = areaId
|
|
6
7
|
? findNodeByHaId(state.nodes, 'ha_area', areaId) ?? findNodeByHaId(state.nodes, 'ha_room', areaId)
|
|
@@ -23,38 +24,61 @@ export function renderRoomPage(state, areaId) {
|
|
|
23
24
|
...scripts.map((node) => node.id),
|
|
24
25
|
]);
|
|
25
26
|
const sources = relatedSources(state.sources, state.edges, relatedNodeIds);
|
|
27
|
+
const semanticFacts = semanticFactsLinkedToSources(sources, state.nodes, state.edges);
|
|
26
28
|
return [
|
|
27
29
|
`# ${title}`,
|
|
28
30
|
'',
|
|
29
31
|
`Knowledge space: \`${state.spaceId}\``,
|
|
30
32
|
'',
|
|
33
|
+
renderRoomOverview(title, devices, entities, automations, scenes, scripts),
|
|
31
34
|
renderNodeList('Devices', devices),
|
|
32
35
|
renderNodeList('Entities', entities),
|
|
33
36
|
renderNodeList('Automations', automations),
|
|
34
37
|
renderNodeList('Scenes', scenes),
|
|
35
38
|
renderNodeList('Scripts', scripts),
|
|
39
|
+
renderSourceEvidence('Source-Backed Knowledge', sources, state.extractions ?? [], {
|
|
40
|
+
tokens: uniqueStrings([
|
|
41
|
+
title,
|
|
42
|
+
...devices.map((node) => node.title),
|
|
43
|
+
...entities.map((node) => node.title),
|
|
44
|
+
].flatMap(tokenizeEvidence)),
|
|
45
|
+
maxSources: 12,
|
|
46
|
+
maxSnippetsPerSource: 2,
|
|
47
|
+
}),
|
|
48
|
+
renderSemanticFacts('Extracted Facts', semanticFacts),
|
|
36
49
|
renderSourceList('Linked Sources', sources),
|
|
37
50
|
renderIssueList('Open Issues', state.issues.filter((issue) => issue.status === 'open')),
|
|
38
51
|
].filter(Boolean).join('\n');
|
|
39
52
|
}
|
|
40
53
|
export function renderDevicePassportPage(input) {
|
|
54
|
+
const deviceTokens = deviceEvidenceTokens(input.device, input.entities);
|
|
41
55
|
return [
|
|
42
56
|
`# ${input.device.title}`,
|
|
43
57
|
'',
|
|
44
58
|
`Knowledge space: \`${input.spaceId}\``,
|
|
45
59
|
'',
|
|
46
|
-
'##
|
|
60
|
+
'## Overview',
|
|
61
|
+
'',
|
|
62
|
+
renderDeviceOverview(input.device, input.entities, input.sources),
|
|
63
|
+
'',
|
|
64
|
+
'## Home Assistant Profile',
|
|
47
65
|
'',
|
|
48
66
|
renderMetadataField('Manufacturer', input.device.metadata.manufacturer),
|
|
49
67
|
renderMetadataField('Model', input.device.metadata.model),
|
|
50
68
|
renderMetadataField('Area', readHa(input.device, 'areaId')),
|
|
51
69
|
renderMetadataField('Device id', readHa(input.device, 'deviceId')),
|
|
52
70
|
'',
|
|
53
|
-
renderNodeList('Entities', input.entities),
|
|
71
|
+
renderNodeList('Entities Exposed To Home Assistant', input.entities),
|
|
72
|
+
renderSemanticFacts('Extracted Device Facts', input.semanticFacts ?? []),
|
|
73
|
+
renderSourceEvidence('Source-Backed Features And Notes', input.sources, input.extractions ?? [], {
|
|
74
|
+
tokens: deviceTokens,
|
|
75
|
+
maxSources: 8,
|
|
76
|
+
maxSnippetsPerSource: 4,
|
|
77
|
+
}),
|
|
54
78
|
renderSourceList('Sources', input.sources),
|
|
55
79
|
renderIssueList('Issues', input.issues),
|
|
56
80
|
input.missingFields.length > 0
|
|
57
|
-
? ['##
|
|
81
|
+
? ['## Open Questions', '', ...input.missingFields.map((field) => `- ${field}`), ''].join('\n')
|
|
58
82
|
: '',
|
|
59
83
|
].filter(Boolean).join('\n');
|
|
60
84
|
}
|
|
@@ -215,6 +239,142 @@ function renderNodeList(title, nodes) {
|
|
|
215
239
|
'',
|
|
216
240
|
].join('\n');
|
|
217
241
|
}
|
|
242
|
+
function renderRoomOverview(title, devices, entities, automations, scenes, scripts) {
|
|
243
|
+
return [
|
|
244
|
+
'## Overview',
|
|
245
|
+
'',
|
|
246
|
+
`${title} currently has ${devices.length} device(s), ${entities.length} entity record(s), ${automations.length} automation(s), ${scenes.length} scene(s), and ${scripts.length} script(s) in the Home Graph.`,
|
|
247
|
+
'',
|
|
248
|
+
].join('\n');
|
|
249
|
+
}
|
|
250
|
+
function renderDeviceOverview(device, entities, sources) {
|
|
251
|
+
const identity = uniqueStrings([
|
|
252
|
+
readMetadataString(device, 'manufacturer'),
|
|
253
|
+
readMetadataString(device, 'model'),
|
|
254
|
+
readHa(device, 'areaId') ? `area ${readHa(device, 'areaId')}` : undefined,
|
|
255
|
+
]);
|
|
256
|
+
const details = identity.length > 0 ? ` ${identity.join(' - ')}.` : '.';
|
|
257
|
+
return `${device.title}${details} The Home Graph links this device to ${entities.length} Home Assistant entity record(s) and ${sources.length} source(s).`;
|
|
258
|
+
}
|
|
259
|
+
function renderSourceEvidence(title, sources, extractions, options) {
|
|
260
|
+
const extractionBySourceId = new Map(extractions.map((extraction) => [extraction.sourceId, extraction]));
|
|
261
|
+
const entries = sources
|
|
262
|
+
.map((source) => ({
|
|
263
|
+
source,
|
|
264
|
+
snippets: sourceEvidenceSnippets(source, extractionBySourceId.get(source.id), options.tokens, options.maxSnippetsPerSource),
|
|
265
|
+
}))
|
|
266
|
+
.filter((entry) => entry.snippets.length > 0)
|
|
267
|
+
.slice(0, options.maxSources);
|
|
268
|
+
if (entries.length === 0) {
|
|
269
|
+
return [
|
|
270
|
+
`## ${title}`,
|
|
271
|
+
'',
|
|
272
|
+
'No linked source-backed details have been extracted yet.',
|
|
273
|
+
'',
|
|
274
|
+
].join('\n');
|
|
275
|
+
}
|
|
276
|
+
return [
|
|
277
|
+
`## ${title}`,
|
|
278
|
+
'',
|
|
279
|
+
...entries.flatMap((entry) => [
|
|
280
|
+
`### ${entry.source.title ?? entry.source.sourceUri ?? entry.source.id}`,
|
|
281
|
+
'',
|
|
282
|
+
...entry.snippets.map((snippet) => `- ${snippet}`),
|
|
283
|
+
'',
|
|
284
|
+
]),
|
|
285
|
+
].join('\n');
|
|
286
|
+
}
|
|
287
|
+
function sourceEvidenceSnippets(source, extraction, tokens, limit) {
|
|
288
|
+
const structure = readRecord(extraction?.structure);
|
|
289
|
+
const searchText = typeof structure.searchText === 'string' ? structure.searchText : undefined;
|
|
290
|
+
const candidates = uniqueStrings([
|
|
291
|
+
extraction?.summary,
|
|
292
|
+
extraction?.excerpt,
|
|
293
|
+
...(extraction?.sections ?? []),
|
|
294
|
+
...evidenceWindows(searchText, tokens),
|
|
295
|
+
...featureSentences(searchText),
|
|
296
|
+
source.summary,
|
|
297
|
+
source.description,
|
|
298
|
+
]).filter((entry) => !isUnusableHomeGraphExtractionText(entry)).slice(0, 80);
|
|
299
|
+
const scored = candidates
|
|
300
|
+
.map((text) => ({ text: clampEvidence(text), score: evidenceScore(text, tokens) }))
|
|
301
|
+
.filter((entry) => entry.text.length > 0)
|
|
302
|
+
.sort((left, right) => right.score - left.score || left.text.length - right.text.length);
|
|
303
|
+
return uniqueStrings(scored.map((entry) => entry.text)).slice(0, limit);
|
|
304
|
+
}
|
|
305
|
+
function evidenceWindows(value, tokens) {
|
|
306
|
+
const text = normalizeWhitespace(value ?? '');
|
|
307
|
+
if (!text)
|
|
308
|
+
return [];
|
|
309
|
+
const lower = text.toLowerCase();
|
|
310
|
+
const windows = [];
|
|
311
|
+
for (const token of tokens) {
|
|
312
|
+
if (token.length < 3)
|
|
313
|
+
continue;
|
|
314
|
+
const index = lower.indexOf(token.toLowerCase());
|
|
315
|
+
if (index < 0)
|
|
316
|
+
continue;
|
|
317
|
+
const start = Math.max(0, index - 180);
|
|
318
|
+
const end = Math.min(text.length, index + 420);
|
|
319
|
+
windows.push(`${start > 0 ? '...' : ''}${text.slice(start, end).trim()}${end < text.length ? '...' : ''}`);
|
|
320
|
+
}
|
|
321
|
+
return windows;
|
|
322
|
+
}
|
|
323
|
+
function featureSentences(value) {
|
|
324
|
+
const text = normalizeWhitespace(value ?? '');
|
|
325
|
+
if (!text)
|
|
326
|
+
return [];
|
|
327
|
+
const keywords = /\b(feature|features|support|supports|capability|capabilities|specification|specifications|mode|modes|hdmi|hdr|dolby|battery|reset|warranty|firmware|voice|remote)\b/i;
|
|
328
|
+
return (text.match(/[^.!?\n]+[.!?]?/g) ?? [])
|
|
329
|
+
.map((entry) => entry.trim())
|
|
330
|
+
.filter((entry) => keywords.test(entry))
|
|
331
|
+
.slice(0, 24);
|
|
332
|
+
}
|
|
333
|
+
function evidenceScore(value, tokens) {
|
|
334
|
+
const lower = value.toLowerCase();
|
|
335
|
+
let score = 0;
|
|
336
|
+
for (const token of tokens) {
|
|
337
|
+
if (token.length >= 3 && lower.includes(token.toLowerCase()))
|
|
338
|
+
score += 10;
|
|
339
|
+
}
|
|
340
|
+
if (/\b(feature|features|support|supports|mode|hdmi|hdr|dolby|voice|remote)\b/i.test(value))
|
|
341
|
+
score += 25;
|
|
342
|
+
return score;
|
|
343
|
+
}
|
|
344
|
+
function deviceEvidenceTokens(device, entities) {
|
|
345
|
+
return uniqueStrings([
|
|
346
|
+
device.title,
|
|
347
|
+
...device.aliases,
|
|
348
|
+
readMetadataString(device, 'manufacturer'),
|
|
349
|
+
readMetadataString(device, 'model'),
|
|
350
|
+
readHa(device, 'deviceId'),
|
|
351
|
+
...entities.flatMap((entity) => [
|
|
352
|
+
entity.title,
|
|
353
|
+
readHa(entity, 'entityId'),
|
|
354
|
+
readMetadataString(entity, 'domain'),
|
|
355
|
+
readMetadataString(entity, 'platform'),
|
|
356
|
+
]),
|
|
357
|
+
].flatMap(tokenizeEvidence));
|
|
358
|
+
}
|
|
359
|
+
function tokenizeEvidence(value) {
|
|
360
|
+
if (!value)
|
|
361
|
+
return [];
|
|
362
|
+
return value.toLowerCase()
|
|
363
|
+
.split(/[^a-z0-9_.:-]+/)
|
|
364
|
+
.map((entry) => entry.trim())
|
|
365
|
+
.filter((entry) => entry.length >= 2 && !['the', 'and', 'home', 'assistant', 'device'].includes(entry));
|
|
366
|
+
}
|
|
367
|
+
function clampEvidence(value) {
|
|
368
|
+
const normalized = normalizeWhitespace(value);
|
|
369
|
+
return normalized.length <= 420 ? normalized : `${normalized.slice(0, 419).trim()}...`;
|
|
370
|
+
}
|
|
371
|
+
function normalizeWhitespace(value) {
|
|
372
|
+
return value.replace(/\s+/g, ' ').trim();
|
|
373
|
+
}
|
|
374
|
+
function readMetadataString(node, key) {
|
|
375
|
+
const value = node.metadata[key];
|
|
376
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
377
|
+
}
|
|
218
378
|
function renderSourceList(title, sources) {
|
|
219
379
|
if (sources.length === 0)
|
|
220
380
|
return '';
|
|
@@ -228,6 +388,57 @@ function renderSourceList(title, sources) {
|
|
|
228
388
|
'',
|
|
229
389
|
].join('\n');
|
|
230
390
|
}
|
|
391
|
+
function renderSemanticFacts(title, facts) {
|
|
392
|
+
const entries = facts
|
|
393
|
+
.filter((node) => node.metadata.semanticKind === 'fact')
|
|
394
|
+
.sort((left, right) => semanticFactSortKey(left).localeCompare(semanticFactSortKey(right)) || left.title.localeCompare(right.title))
|
|
395
|
+
.slice(0, 80);
|
|
396
|
+
if (entries.length === 0)
|
|
397
|
+
return '';
|
|
398
|
+
const groups = new Map();
|
|
399
|
+
for (const fact of entries) {
|
|
400
|
+
const kind = readString(fact.metadata.factKind) ?? 'fact';
|
|
401
|
+
groups.set(kind, [...(groups.get(kind) ?? []), fact]);
|
|
402
|
+
}
|
|
403
|
+
return [
|
|
404
|
+
`## ${title}`,
|
|
405
|
+
'',
|
|
406
|
+
...[...groups.entries()].flatMap(([kind, group]) => [
|
|
407
|
+
`### ${titleCase(kind)}`,
|
|
408
|
+
'',
|
|
409
|
+
...group.slice(0, 24).map((fact) => {
|
|
410
|
+
const value = readString(fact.metadata.value);
|
|
411
|
+
const evidence = readString(fact.metadata.evidence);
|
|
412
|
+
const detail = fact.summary ?? evidence;
|
|
413
|
+
return `- ${fact.title}${value ? `: ${value}` : ''}${detail ? ` - ${detail}` : ''}`;
|
|
414
|
+
}),
|
|
415
|
+
'',
|
|
416
|
+
]),
|
|
417
|
+
].join('\n');
|
|
418
|
+
}
|
|
419
|
+
function semanticFactsLinkedToSources(sources, nodes, edges) {
|
|
420
|
+
const sourceIds = new Set(sources.map((source) => source.id));
|
|
421
|
+
const factIds = new Set(edges.filter((edge) => (edgeIsActive(edge)
|
|
422
|
+
&& edge.fromKind === 'source'
|
|
423
|
+
&& sourceIds.has(edge.fromId)
|
|
424
|
+
&& edge.toKind === 'node'
|
|
425
|
+
&& edge.relation === 'supports_fact')).map((edge) => edge.toId));
|
|
426
|
+
return nodes.filter((node) => factIds.has(node.id));
|
|
427
|
+
}
|
|
428
|
+
function semanticFactSortKey(node) {
|
|
429
|
+
const order = {
|
|
430
|
+
feature: '01',
|
|
431
|
+
capability: '02',
|
|
432
|
+
specification: '03',
|
|
433
|
+
configuration: '04',
|
|
434
|
+
compatibility: '05',
|
|
435
|
+
procedure: '06',
|
|
436
|
+
maintenance: '07',
|
|
437
|
+
troubleshooting: '08',
|
|
438
|
+
warning: '09',
|
|
439
|
+
};
|
|
440
|
+
return order[readString(node.metadata.factKind) ?? ''] ?? '99';
|
|
441
|
+
}
|
|
231
442
|
function renderIssueList(title, issues) {
|
|
232
443
|
if (issues.length === 0)
|
|
233
444
|
return '';
|
|
@@ -2,11 +2,15 @@ import type { ArtifactStore } from '../../artifacts/index.js';
|
|
|
2
2
|
import type { KnowledgeStore } from '../store.js';
|
|
3
3
|
import type { KnowledgeEdgeRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
|
|
4
4
|
import { type HomeGraphReviewResult } from './review.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { KnowledgeSemanticService } from '../semantic/index.js';
|
|
6
|
+
import type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapInput, HomeGraphMapResult, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphPageListResult, HomeGraphReindexResult, HomeGraphReviewInput, HomeGraphSpaceInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult } from './types.js';
|
|
6
7
|
export declare class HomeGraphService {
|
|
7
8
|
private readonly store;
|
|
8
9
|
private readonly artifactStore;
|
|
9
|
-
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(store: KnowledgeStore, artifactStore: ArtifactStore, options?: {
|
|
12
|
+
readonly semanticService?: KnowledgeSemanticService;
|
|
13
|
+
});
|
|
10
14
|
status(input?: {
|
|
11
15
|
readonly installationId?: string;
|
|
12
16
|
readonly knowledgeSpaceId?: string;
|
|
@@ -41,6 +45,10 @@ export declare class HomeGraphService {
|
|
|
41
45
|
readonly spaceId: string;
|
|
42
46
|
readonly sources: readonly KnowledgeSourceRecord[];
|
|
43
47
|
}>;
|
|
48
|
+
listPages(input?: HomeGraphSpaceInput & {
|
|
49
|
+
readonly limit?: number;
|
|
50
|
+
readonly includeMarkdown?: boolean;
|
|
51
|
+
}): Promise<HomeGraphPageListResult>;
|
|
44
52
|
browse(input?: HomeGraphSpaceInput & {
|
|
45
53
|
readonly limit?: number;
|
|
46
54
|
}): Promise<{
|
|
@@ -68,11 +76,13 @@ export declare class HomeGraphService {
|
|
|
68
76
|
}>;
|
|
69
77
|
private ingestCreatedArtifact;
|
|
70
78
|
private extractArtifact;
|
|
79
|
+
private autoLinkExistingSources;
|
|
71
80
|
private upsertHomeNode;
|
|
72
81
|
private upsertSnapshotObjects;
|
|
73
82
|
private linkSnapshotObjectRelations;
|
|
74
83
|
private tryLinkNode;
|
|
75
84
|
private refreshQualityIssues;
|
|
85
|
+
private enrichSpaceSources;
|
|
76
86
|
private resolveLinkSource;
|
|
77
87
|
private ensureTarget;
|
|
78
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EACV,mBAAmB,EAEnB,oBAAoB,EACpB,mBAAmB,EAEnB,qBAAqB,EAEtB,MAAM,aAAa,CAAC;AAmBrB,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,10 +3,13 @@ import { HOME_GRAPH_CONNECTOR_ID, belongsToSpace, buildHomeGraphMetadata, buildH
|
|
|
3
3
|
import { upsertIntegrationDocumentationCandidates } from './documentation.js';
|
|
4
4
|
import { refreshHomeGraphQualityIssues } from './quality.js';
|
|
5
5
|
import { reviewHomeGraphFact } from './review.js';
|
|
6
|
-
import {
|
|
6
|
+
import { inferHomeGraphSourceType, readHomeGraphState, renderHomeGraphState, safeHomeGraphFilename, } from './state.js';
|
|
7
|
+
import { answerHomeGraphQuery } from './ask.js';
|
|
7
8
|
import { renderHomeGraphMap } from './rendering.js';
|
|
8
|
-
import {
|
|
9
|
+
import { autoLinkHomeGraphSource, autoLinkHomeGraphSources, } from './auto-link.js';
|
|
10
|
+
import { generateAutomaticHomeGraphPages, generateHomeGraphPacket, generateHomeGraphRoomPage, refreshAutomaticHomeGraphPages, refreshHomeGraphDevicePassport, } from './generated-pages.js';
|
|
9
11
|
import { reindexHomeGraphSources } from './reindex.js';
|
|
12
|
+
import { listHomeGraphPages } from './pages.js';
|
|
10
13
|
import { isUnusableHomeGraphExtractionText } from './extraction-quality.js';
|
|
11
14
|
import { readHomeGraphSearchState, scoreHomeGraphResults, selectHomeGraphExtractionRepairCandidates, } from './search.js';
|
|
12
15
|
import { resolveReadableHomeGraphSpace } from './space-selection.js';
|
|
@@ -14,9 +17,11 @@ import { HOME_GRAPH_CAPABILITIES } from './types.js';
|
|
|
14
17
|
export class HomeGraphService {
|
|
15
18
|
store;
|
|
16
19
|
artifactStore;
|
|
17
|
-
|
|
20
|
+
options;
|
|
21
|
+
constructor(store, artifactStore, options = {}) {
|
|
18
22
|
this.store = store;
|
|
19
23
|
this.artifactStore = artifactStore;
|
|
24
|
+
this.options = options;
|
|
20
25
|
}
|
|
21
26
|
async status(input = {}) {
|
|
22
27
|
await this.store.init();
|
|
@@ -62,6 +67,7 @@ export class HomeGraphService {
|
|
|
62
67
|
const beforeNodeIds = new Set(readHomeGraphState(this.store, spaceId).nodes.map((node) => node.id));
|
|
63
68
|
const beforeEdgeIds = new Set(readHomeGraphState(this.store, spaceId).edges.map((edge) => edge.id));
|
|
64
69
|
const groups = await this.upsertSnapshotObjects(spaceId, installationId, input, home.id, source.id);
|
|
70
|
+
await this.autoLinkExistingSources(spaceId, installationId);
|
|
65
71
|
const issues = await this.refreshQualityIssues(spaceId, installationId);
|
|
66
72
|
const generated = await generateAutomaticHomeGraphPages({
|
|
67
73
|
store: this.store,
|
|
@@ -207,34 +213,34 @@ export class HomeGraphService {
|
|
|
207
213
|
state = readHomeGraphSearchState(this.store, spaceId);
|
|
208
214
|
}
|
|
209
215
|
const results = scoreHomeGraphResults(input.query, state.sources, state.nodes, state.edges, (sourceId) => state.extractionBySourceId.get(sourceId), input.limit ?? 8);
|
|
210
|
-
|
|
211
|
-
const linkedObjects = collectLinkedObjects(results, state);
|
|
212
|
-
const confidence = Math.min(100, Math.max(10, results[0]?.score ?? 10));
|
|
213
|
-
return {
|
|
214
|
-
ok: true,
|
|
215
|
-
spaceId,
|
|
216
|
-
query: input.query,
|
|
217
|
-
answer: {
|
|
218
|
-
text: renderAskAnswer(input.query, results, input.mode ?? 'standard'),
|
|
219
|
-
mode: input.mode ?? 'standard',
|
|
220
|
-
confidence,
|
|
221
|
-
sources: input.includeSources === false ? [] : sources,
|
|
222
|
-
linkedObjects: input.includeLinkedObjects === false ? [] : linkedObjects,
|
|
223
|
-
},
|
|
224
|
-
results,
|
|
225
|
-
};
|
|
216
|
+
return answerHomeGraphQuery({ store: this.store, semanticService: this.options.semanticService, spaceId, query: input, state, results });
|
|
226
217
|
}
|
|
227
218
|
async reindex(input = {}) {
|
|
228
219
|
await this.store.init();
|
|
229
220
|
const { spaceId, installationId } = resolveReadableHomeGraphSpace(this.store, input);
|
|
230
221
|
const state = readHomeGraphSearchState(this.store, spaceId);
|
|
231
|
-
|
|
222
|
+
const reindex = await reindexHomeGraphSources({
|
|
232
223
|
spaceId,
|
|
233
224
|
sources: state.sources,
|
|
234
225
|
extractionBySourceId: state.extractionBySourceId,
|
|
235
226
|
artifactStore: this.artifactStore,
|
|
236
227
|
extract: (source, artifact) => this.extractArtifact(source, artifact, spaceId, installationId),
|
|
237
228
|
});
|
|
229
|
+
const linked = await this.autoLinkExistingSources(spaceId, installationId);
|
|
230
|
+
const semantic = await this.options.semanticService?.reindex({
|
|
231
|
+
knowledgeSpaceId: spaceId,
|
|
232
|
+
sourceIds: state.sources.map((source) => source.id),
|
|
233
|
+
force: false,
|
|
234
|
+
});
|
|
235
|
+
const generated = reindex.reparsed > 0 || linked.length > 0
|
|
236
|
+
? await refreshAutomaticHomeGraphPages({ store: this.store, artifactStore: this.artifactStore, spaceId, installationId })
|
|
237
|
+
: undefined;
|
|
238
|
+
return {
|
|
239
|
+
...reindex,
|
|
240
|
+
...(linked.length > 0 ? { linked } : {}),
|
|
241
|
+
...(semantic ? { semantic } : {}),
|
|
242
|
+
...(generated ? { generated } : {}),
|
|
243
|
+
};
|
|
238
244
|
}
|
|
239
245
|
async repairWeakExtractionsForAsk(spaceId, installationId, query, state) {
|
|
240
246
|
const candidates = selectHomeGraphExtractionRepairCandidates(query, state.sources, state.nodes, state.edges, (sourceId) => state.extractionBySourceId.get(sourceId), 8);
|
|
@@ -247,6 +253,16 @@ export class HomeGraphService {
|
|
|
247
253
|
if (!artifact)
|
|
248
254
|
continue;
|
|
249
255
|
const extraction = await this.extractArtifact(source, artifact, spaceId, installationId);
|
|
256
|
+
if (extraction) {
|
|
257
|
+
await autoLinkHomeGraphSource({
|
|
258
|
+
store: this.store,
|
|
259
|
+
spaceId,
|
|
260
|
+
installationId,
|
|
261
|
+
source,
|
|
262
|
+
extraction,
|
|
263
|
+
state: readHomeGraphState(this.store, spaceId),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
250
266
|
if (extraction && extractionHasSearchableText(extraction))
|
|
251
267
|
repaired += 1;
|
|
252
268
|
}
|
|
@@ -255,6 +271,7 @@ export class HomeGraphService {
|
|
|
255
271
|
async refreshDevicePassport(input) {
|
|
256
272
|
await this.store.init();
|
|
257
273
|
const { spaceId, installationId } = resolveHomeGraphSpace(input);
|
|
274
|
+
await this.enrichSpaceSources(spaceId);
|
|
258
275
|
return refreshHomeGraphDevicePassport({
|
|
259
276
|
store: this.store,
|
|
260
277
|
artifactStore: this.artifactStore,
|
|
@@ -266,6 +283,7 @@ export class HomeGraphService {
|
|
|
266
283
|
async generateRoomPage(input) {
|
|
267
284
|
await this.store.init();
|
|
268
285
|
const { spaceId, installationId } = resolveHomeGraphSpace(input);
|
|
286
|
+
await this.enrichSpaceSources(spaceId);
|
|
269
287
|
return generateHomeGraphRoomPage({
|
|
270
288
|
store: this.store,
|
|
271
289
|
artifactStore: this.artifactStore,
|
|
@@ -277,6 +295,7 @@ export class HomeGraphService {
|
|
|
277
295
|
async generatePacket(input) {
|
|
278
296
|
await this.store.init();
|
|
279
297
|
const { spaceId, installationId } = resolveHomeGraphSpace(input);
|
|
298
|
+
await this.enrichSpaceSources(spaceId);
|
|
280
299
|
return generateHomeGraphPacket({
|
|
281
300
|
store: this.store,
|
|
282
301
|
artifactStore: this.artifactStore,
|
|
@@ -306,6 +325,18 @@ export class HomeGraphService {
|
|
|
306
325
|
const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
|
|
307
326
|
return { ok: true, spaceId, sources: readHomeGraphState(this.store, spaceId).sources.slice(0, Math.max(1, input.limit ?? 100)) };
|
|
308
327
|
}
|
|
328
|
+
async listPages(input = {}) {
|
|
329
|
+
await this.store.init();
|
|
330
|
+
const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
|
|
331
|
+
const state = readHomeGraphState(this.store, spaceId);
|
|
332
|
+
return listHomeGraphPages({
|
|
333
|
+
artifactStore: this.artifactStore,
|
|
334
|
+
spaceId,
|
|
335
|
+
sources: state.sources,
|
|
336
|
+
limit: Math.max(1, input.limit ?? 100),
|
|
337
|
+
includeMarkdown: input.includeMarkdown !== false,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
309
340
|
async browse(input = {}) {
|
|
310
341
|
await this.store.init();
|
|
311
342
|
const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
|
|
@@ -395,7 +426,15 @@ export class HomeGraphService {
|
|
|
395
426
|
const extraction = await this.extractArtifact(source, input.artifact, input.spaceId, input.installationId);
|
|
396
427
|
const linked = input.target
|
|
397
428
|
? (await this.linkKnowledge({ knowledgeSpaceId: input.spaceId, sourceId: source.id, target: input.target })).edge
|
|
398
|
-
:
|
|
429
|
+
: (await autoLinkHomeGraphSource({
|
|
430
|
+
store: this.store,
|
|
431
|
+
spaceId: input.spaceId,
|
|
432
|
+
installationId: input.installationId,
|
|
433
|
+
source,
|
|
434
|
+
...(extraction ? { extraction } : {}),
|
|
435
|
+
state: readHomeGraphState(this.store, input.spaceId),
|
|
436
|
+
}))?.edge;
|
|
437
|
+
void this.options.semanticService?.enrichSource(source.id, { knowledgeSpaceId: input.spaceId }).catch(() => { });
|
|
399
438
|
return {
|
|
400
439
|
ok: true,
|
|
401
440
|
spaceId: input.spaceId,
|
|
@@ -433,6 +472,18 @@ export class HomeGraphService {
|
|
|
433
472
|
return undefined;
|
|
434
473
|
}
|
|
435
474
|
}
|
|
475
|
+
async autoLinkExistingSources(spaceId, installationId) {
|
|
476
|
+
const state = readHomeGraphState(this.store, spaceId);
|
|
477
|
+
const extractionBySourceId = new Map(state.extractions.map((extraction) => [extraction.sourceId, extraction]));
|
|
478
|
+
return autoLinkHomeGraphSources({
|
|
479
|
+
store: this.store,
|
|
480
|
+
spaceId,
|
|
481
|
+
installationId,
|
|
482
|
+
sources: state.sources,
|
|
483
|
+
extractionBySourceId,
|
|
484
|
+
state,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
436
487
|
async upsertHomeNode(spaceId, installationId, input) {
|
|
437
488
|
return this.store.upsertNode({
|
|
438
489
|
id: homeGraphNodeId(spaceId, 'ha_home', input.homeId ?? installationId),
|
|
@@ -517,6 +568,12 @@ export class HomeGraphService {
|
|
|
517
568
|
async refreshQualityIssues(spaceId, installationId) {
|
|
518
569
|
return refreshHomeGraphQualityIssues(this.store, spaceId, installationId);
|
|
519
570
|
}
|
|
571
|
+
async enrichSpaceSources(spaceId) {
|
|
572
|
+
if (!this.options.semanticService)
|
|
573
|
+
return;
|
|
574
|
+
const sources = readHomeGraphSearchState(this.store, spaceId).sources;
|
|
575
|
+
await this.options.semanticService.enrichSources(sources, { knowledgeSpaceId: spaceId });
|
|
576
|
+
}
|
|
520
577
|
resolveLinkSource(spaceId, input) {
|
|
521
578
|
if (input.sourceId) {
|
|
522
579
|
const source = this.store.getSource(input.sourceId);
|
|
@@ -3,7 +3,7 @@ export declare const HOME_GRAPH_NODE_KINDS: readonly ["ha_home", "ha_entity", "h
|
|
|
3
3
|
export type HomeGraphNodeKind = typeof HOME_GRAPH_NODE_KINDS[number];
|
|
4
4
|
export declare const HOME_GRAPH_RELATIONS: readonly ["controls", "located_in", "belongs_to_device", "has_manual", "has_receipt", "has_warranty", "has_issue", "fixed_by", "uses_battery", "connected_via", "part_of_network", "mentioned_by", "source_for"];
|
|
5
5
|
export type HomeGraphRelation = typeof HOME_GRAPH_RELATIONS[number];
|
|
6
|
-
export declare const HOME_GRAPH_CAPABILITIES: readonly ["knowledge-space-isolation", "snapshot-sync", "source-backed-ingest", "knowledge-linking", "ask-home-graph", "device-passports", "room-pages", "automatic-page-generation", "visual-knowledge-map", "packets", "source-inventory", "review-queue", "durable-review-decisions", "quality-rule-heuristics", "documentation-candidates", "export-import", "namespace-aware-graph-browse"];
|
|
6
|
+
export declare const HOME_GRAPH_CAPABILITIES: readonly ["knowledge-space-isolation", "snapshot-sync", "source-backed-ingest", "semantic-enrichment", "llm-answer-synthesis", "knowledge-linking", "ask-home-graph", "device-passports", "room-pages", "automatic-page-generation", "visual-knowledge-map", "packets", "source-inventory", "review-queue", "durable-review-decisions", "quality-rule-heuristics", "documentation-candidates", "export-import", "namespace-aware-graph-browse"];
|
|
7
7
|
export type HomeGraphObjectKind = 'home' | 'entity' | 'device' | 'area' | 'automation' | 'script' | 'scene' | 'label' | 'integration' | 'room' | 'device_passport' | 'maintenance_item' | 'troubleshooting_case' | 'purchase' | 'network_node';
|
|
8
8
|
export interface HomeGraphSpaceInput {
|
|
9
9
|
readonly installationId?: string;
|
|
@@ -163,6 +163,9 @@ export interface HomeGraphAskResult {
|
|
|
163
163
|
readonly confidence: number;
|
|
164
164
|
readonly sources: readonly KnowledgeSourceRecord[];
|
|
165
165
|
readonly linkedObjects: readonly KnowledgeNodeRecord[];
|
|
166
|
+
readonly facts?: readonly KnowledgeNodeRecord[];
|
|
167
|
+
readonly gaps?: readonly KnowledgeNodeRecord[];
|
|
168
|
+
readonly synthesized?: boolean;
|
|
166
169
|
};
|
|
167
170
|
readonly results: readonly HomeGraphSearchResult[];
|
|
168
171
|
}
|
|
@@ -216,6 +219,24 @@ export interface HomeGraphReindexResult {
|
|
|
216
219
|
readonly sourceId: string;
|
|
217
220
|
readonly error: string;
|
|
218
221
|
}[];
|
|
222
|
+
readonly linked?: readonly {
|
|
223
|
+
readonly edge: KnowledgeEdgeRecord;
|
|
224
|
+
readonly node: KnowledgeNodeRecord;
|
|
225
|
+
readonly relation: string;
|
|
226
|
+
readonly score: number;
|
|
227
|
+
readonly reasons: readonly string[];
|
|
228
|
+
}[];
|
|
229
|
+
readonly generated?: HomeGraphGeneratedPagesSummary;
|
|
230
|
+
readonly semantic?: {
|
|
231
|
+
readonly scanned: number;
|
|
232
|
+
readonly enriched: number;
|
|
233
|
+
readonly skipped: number;
|
|
234
|
+
readonly failed: number;
|
|
235
|
+
readonly errors: readonly {
|
|
236
|
+
readonly sourceId: string;
|
|
237
|
+
readonly error: string;
|
|
238
|
+
}[];
|
|
239
|
+
};
|
|
219
240
|
}
|
|
220
241
|
export interface HomeGraphSearchResult {
|
|
221
242
|
readonly kind: 'source' | 'node';
|
|
@@ -258,6 +279,15 @@ export interface HomeGraphDevicePassportResult extends HomeGraphProjectionResult
|
|
|
258
279
|
readonly passport: KnowledgeNodeRecord;
|
|
259
280
|
readonly missingFields: readonly string[];
|
|
260
281
|
}
|
|
282
|
+
export interface HomeGraphPageListResult {
|
|
283
|
+
readonly ok: true;
|
|
284
|
+
readonly spaceId: string;
|
|
285
|
+
readonly pages: readonly {
|
|
286
|
+
readonly source: KnowledgeSourceRecord;
|
|
287
|
+
readonly artifact?: HomeGraphProjectionResult['artifact'];
|
|
288
|
+
readonly markdown?: string;
|
|
289
|
+
}[];
|
|
290
|
+
}
|
|
261
291
|
export interface HomeGraphReviewInput extends HomeGraphSpaceInput {
|
|
262
292
|
readonly issueId?: string;
|
|
263
293
|
readonly nodeId?: string;
|