@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.
Files changed (100) hide show
  1. package/dist/_internal/contracts/artifacts/operator-contract.json +845 -4
  2. package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
  3. package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
  4. package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
  5. package/dist/_internal/contracts/generated/operator-contract.js +845 -4
  6. package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
  7. package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
  8. package/dist/_internal/contracts/generated/operator-method-ids.js +2 -0
  9. package/dist/_internal/daemon/context.d.ts +1 -0
  10. package/dist/_internal/daemon/context.d.ts.map +1 -1
  11. package/dist/_internal/daemon/knowledge-route-types.d.ts +1 -0
  12. package/dist/_internal/daemon/knowledge-route-types.d.ts.map +1 -1
  13. package/dist/_internal/daemon/knowledge-routes.d.ts +1 -1
  14. package/dist/_internal/daemon/knowledge-routes.d.ts.map +1 -1
  15. package/dist/_internal/daemon/knowledge-routes.js +18 -0
  16. package/dist/_internal/daemon/operator.d.ts +1 -1
  17. package/dist/_internal/daemon/operator.d.ts.map +1 -1
  18. package/dist/_internal/daemon/operator.js +2 -0
  19. package/dist/_internal/platform/control-plane/method-catalog-homegraph.d.ts.map +1 -1
  20. package/dist/_internal/platform/control-plane/method-catalog-homegraph.js +10 -1
  21. package/dist/_internal/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
  22. package/dist/_internal/platform/control-plane/method-catalog-knowledge.js +20 -1
  23. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts +2 -0
  24. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts.map +1 -1
  25. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.js +23 -0
  26. package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
  27. package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
  28. package/dist/_internal/platform/control-plane/routes/operator.js +2 -0
  29. package/dist/_internal/platform/daemon/http/home-graph-routes.d.ts.map +1 -1
  30. package/dist/_internal/platform/daemon/http/home-graph-routes.js +7 -0
  31. package/dist/_internal/platform/daemon/http/router-route-contexts.d.ts.map +1 -1
  32. package/dist/_internal/platform/daemon/http/router-route-contexts.js +1 -0
  33. package/dist/_internal/platform/knowledge/extractors.d.ts.map +1 -1
  34. package/dist/_internal/platform/knowledge/extractors.js +1 -116
  35. package/dist/_internal/platform/knowledge/home-graph/ask.d.ts +13 -0
  36. package/dist/_internal/platform/knowledge/home-graph/ask.d.ts.map +1 -0
  37. package/dist/_internal/platform/knowledge/home-graph/ask.js +65 -0
  38. package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts +27 -0
  39. package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts.map +1 -0
  40. package/dist/_internal/platform/knowledge/home-graph/auto-link.js +236 -0
  41. package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts +1 -0
  42. package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts.map +1 -1
  43. package/dist/_internal/platform/knowledge/home-graph/generated-pages.js +24 -8
  44. package/dist/_internal/platform/knowledge/home-graph/index.d.ts +1 -1
  45. package/dist/_internal/platform/knowledge/home-graph/index.d.ts.map +1 -1
  46. package/dist/_internal/platform/knowledge/home-graph/pages.d.ts +11 -0
  47. package/dist/_internal/platform/knowledge/home-graph/pages.d.ts.map +1 -0
  48. package/dist/_internal/platform/knowledge/home-graph/pages.js +44 -0
  49. package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts +4 -1
  50. package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts.map +1 -1
  51. package/dist/_internal/platform/knowledge/home-graph/rendering.js +215 -4
  52. package/dist/_internal/platform/knowledge/home-graph/service.d.ts +12 -2
  53. package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
  54. package/dist/_internal/platform/knowledge/home-graph/service.js +78 -21
  55. package/dist/_internal/platform/knowledge/home-graph/types.d.ts +31 -1
  56. package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
  57. package/dist/_internal/platform/knowledge/home-graph/types.js +2 -0
  58. package/dist/_internal/platform/knowledge/index.d.ts +3 -1
  59. package/dist/_internal/platform/knowledge/index.d.ts.map +1 -1
  60. package/dist/_internal/platform/knowledge/index.js +1 -0
  61. package/dist/_internal/platform/knowledge/ingest-compile.d.ts.map +1 -1
  62. package/dist/_internal/platform/knowledge/ingest-compile.js +5 -0
  63. package/dist/_internal/platform/knowledge/ingest-context.d.ts +1 -0
  64. package/dist/_internal/platform/knowledge/ingest-context.d.ts.map +1 -1
  65. package/dist/_internal/platform/knowledge/map.js +15 -1
  66. package/dist/_internal/platform/knowledge/pdf-extractor.d.ts +3 -0
  67. package/dist/_internal/platform/knowledge/pdf-extractor.d.ts.map +1 -0
  68. package/dist/_internal/platform/knowledge/pdf-extractor.js +346 -0
  69. package/dist/_internal/platform/knowledge/scheduling.d.ts.map +1 -1
  70. package/dist/_internal/platform/knowledge/scheduling.js +1 -0
  71. package/dist/_internal/platform/knowledge/semantic/answer.d.ts +9 -0
  72. package/dist/_internal/platform/knowledge/semantic/answer.d.ts.map +1 -0
  73. package/dist/_internal/platform/knowledge/semantic/answer.js +407 -0
  74. package/dist/_internal/platform/knowledge/semantic/enrichment.d.ts +23 -0
  75. package/dist/_internal/platform/knowledge/semantic/enrichment.d.ts.map +1 -0
  76. package/dist/_internal/platform/knowledge/semantic/enrichment.js +491 -0
  77. package/dist/_internal/platform/knowledge/semantic/index.d.ts +5 -0
  78. package/dist/_internal/platform/knowledge/semantic/index.d.ts.map +1 -0
  79. package/dist/_internal/platform/knowledge/semantic/index.js +2 -0
  80. package/dist/_internal/platform/knowledge/semantic/llm.d.ts +4 -0
  81. package/dist/_internal/platform/knowledge/semantic/llm.d.ts.map +1 -0
  82. package/dist/_internal/platform/knowledge/semantic/llm.js +34 -0
  83. package/dist/_internal/platform/knowledge/semantic/service.d.ts +37 -0
  84. package/dist/_internal/platform/knowledge/semantic/service.d.ts.map +1 -0
  85. package/dist/_internal/platform/knowledge/semantic/service.js +55 -0
  86. package/dist/_internal/platform/knowledge/semantic/types.d.ts +107 -0
  87. package/dist/_internal/platform/knowledge/semantic/types.d.ts.map +1 -0
  88. package/dist/_internal/platform/knowledge/semantic/types.js +1 -0
  89. package/dist/_internal/platform/knowledge/semantic/utils.d.ts +39 -0
  90. package/dist/_internal/platform/knowledge/semantic/utils.d.ts.map +1 -0
  91. package/dist/_internal/platform/knowledge/semantic/utils.js +189 -0
  92. package/dist/_internal/platform/knowledge/service.d.ts +12 -0
  93. package/dist/_internal/platform/knowledge/service.d.ts.map +1 -1
  94. package/dist/_internal/platform/knowledge/service.js +14 -0
  95. package/dist/_internal/platform/knowledge/types.d.ts +2 -2
  96. package/dist/_internal/platform/knowledge/types.d.ts.map +1 -1
  97. package/dist/_internal/platform/runtime/services.d.ts.map +1 -1
  98. package/dist/_internal/platform/runtime/services.js +8 -2
  99. package/dist/_internal/platform/version.js +1 -1
  100. 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;AAIrB,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;CAClD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCnF;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,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,MAAM,CAoBT;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
+ {"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 { edgeIsActive, isGeneratedPageSource } from './helpers.js';
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
- '## Profile',
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
- ? ['## Missing Fields', '', ...input.missingFields.map((field) => `- ${field}`), ''].join('\n')
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 { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapInput, HomeGraphMapResult, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReindexResult, HomeGraphReviewInput, HomeGraphSpaceInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult } from './types.js';
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
- constructor(store: KnowledgeStore, artifactStore: ArtifactStore);
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":"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"}
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 { collectLinkedObjects, inferHomeGraphSourceType, readHomeGraphState, renderAskAnswer, renderHomeGraphState, safeHomeGraphFilename, } from './state.js';
6
+ import { inferHomeGraphSourceType, readHomeGraphState, renderHomeGraphState, safeHomeGraphFilename, } from './state.js';
7
+ import { answerHomeGraphQuery } from './ask.js';
7
8
  import { renderHomeGraphMap } from './rendering.js';
8
- import { generateAutomaticHomeGraphPages, generateHomeGraphPacket, generateHomeGraphRoomPage, refreshHomeGraphDevicePassport, } from './generated-pages.js';
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
- constructor(store, artifactStore) {
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
- const sources = results.flatMap((result) => result.source ? [result.source] : []);
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
- return reindexHomeGraphSources({
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
- : undefined;
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;