@pellux/goodvibes-sdk 0.27.1 → 0.27.3

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 (62) hide show
  1. package/dist/_internal/contracts/artifacts/operator-contract.json +870 -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 +870 -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 +1 -0
  9. package/dist/_internal/daemon/knowledge-routes.d.ts.map +1 -1
  10. package/dist/_internal/daemon/knowledge-routes.js +27 -0
  11. package/dist/_internal/platform/control-plane/method-catalog-homegraph.d.ts.map +1 -1
  12. package/dist/_internal/platform/control-plane/method-catalog-homegraph.js +41 -2
  13. package/dist/_internal/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
  14. package/dist/_internal/platform/control-plane/method-catalog-knowledge.js +15 -1
  15. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts +1 -0
  16. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts.map +1 -1
  17. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.js +28 -0
  18. package/dist/_internal/platform/daemon/http/home-graph-routes.d.ts.map +1 -1
  19. package/dist/_internal/platform/daemon/http/home-graph-routes.js +50 -0
  20. package/dist/_internal/platform/knowledge/extractors.d.ts.map +1 -1
  21. package/dist/_internal/platform/knowledge/extractors.js +1 -116
  22. package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts +27 -0
  23. package/dist/_internal/platform/knowledge/home-graph/auto-link.d.ts.map +1 -0
  24. package/dist/_internal/platform/knowledge/home-graph/auto-link.js +236 -0
  25. package/dist/_internal/platform/knowledge/home-graph/extraction-quality.d.ts +2 -0
  26. package/dist/_internal/platform/knowledge/home-graph/extraction-quality.d.ts.map +1 -0
  27. package/dist/_internal/platform/knowledge/home-graph/extraction-quality.js +52 -0
  28. package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts +1 -0
  29. package/dist/_internal/platform/knowledge/home-graph/generated-pages.d.ts.map +1 -1
  30. package/dist/_internal/platform/knowledge/home-graph/generated-pages.js +14 -8
  31. package/dist/_internal/platform/knowledge/home-graph/index.d.ts +1 -1
  32. package/dist/_internal/platform/knowledge/home-graph/index.d.ts.map +1 -1
  33. package/dist/_internal/platform/knowledge/home-graph/pages.d.ts +11 -0
  34. package/dist/_internal/platform/knowledge/home-graph/pages.d.ts.map +1 -0
  35. package/dist/_internal/platform/knowledge/home-graph/pages.js +44 -0
  36. package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts +5 -6
  37. package/dist/_internal/platform/knowledge/home-graph/rendering.d.ts.map +1 -1
  38. package/dist/_internal/platform/knowledge/home-graph/rendering.js +284 -5
  39. package/dist/_internal/platform/knowledge/home-graph/search.d.ts.map +1 -1
  40. package/dist/_internal/platform/knowledge/home-graph/search.js +4 -6
  41. package/dist/_internal/platform/knowledge/home-graph/service.d.ts +6 -1
  42. package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
  43. package/dist/_internal/platform/knowledge/home-graph/service.js +60 -6
  44. package/dist/_internal/platform/knowledge/home-graph/types.d.ts +47 -1
  45. package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
  46. package/dist/_internal/platform/knowledge/index.d.ts +2 -2
  47. package/dist/_internal/platform/knowledge/index.d.ts.map +1 -1
  48. package/dist/_internal/platform/knowledge/map-filters.d.ts +24 -0
  49. package/dist/_internal/platform/knowledge/map-filters.d.ts.map +1 -0
  50. package/dist/_internal/platform/knowledge/map-filters.js +199 -0
  51. package/dist/_internal/platform/knowledge/map.d.ts +16 -1
  52. package/dist/_internal/platform/knowledge/map.d.ts.map +1 -1
  53. package/dist/_internal/platform/knowledge/map.js +19 -8
  54. package/dist/_internal/platform/knowledge/pdf-extractor.d.ts +3 -0
  55. package/dist/_internal/platform/knowledge/pdf-extractor.d.ts.map +1 -0
  56. package/dist/_internal/platform/knowledge/pdf-extractor.js +346 -0
  57. package/dist/_internal/platform/knowledge/service.d.ts +2 -6
  58. package/dist/_internal/platform/knowledge/service.d.ts.map +1 -1
  59. package/dist/_internal/platform/knowledge/types.d.ts +39 -1
  60. package/dist/_internal/platform/knowledge/types.d.ts.map +1 -1
  61. package/dist/_internal/platform/version.js +1 -1
  62. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  import { renderKnowledgeMap } from '../map.js';
2
- import { edgeIsActive, isGeneratedPageSource } from './helpers.js';
2
+ import { countFacet, normalizeStringArray, readString } from '../map-filters.js';
3
+ import { isUnusableHomeGraphExtractionText } from './extraction-quality.js';
4
+ import { edgeIsActive, isGeneratedPageSource, readRecord, uniqueStrings } from './helpers.js';
3
5
  export function renderRoomPage(state, areaId) {
4
6
  const area = areaId
5
7
  ? findNodeByHaId(state.nodes, 'ha_area', areaId) ?? findNodeByHaId(state.nodes, 'ha_room', areaId)
@@ -27,33 +29,53 @@ export function renderRoomPage(state, areaId) {
27
29
  '',
28
30
  `Knowledge space: \`${state.spaceId}\``,
29
31
  '',
32
+ renderRoomOverview(title, devices, entities, automations, scenes, scripts),
30
33
  renderNodeList('Devices', devices),
31
34
  renderNodeList('Entities', entities),
32
35
  renderNodeList('Automations', automations),
33
36
  renderNodeList('Scenes', scenes),
34
37
  renderNodeList('Scripts', scripts),
38
+ renderSourceEvidence('Source-Backed Knowledge', sources, state.extractions ?? [], {
39
+ tokens: uniqueStrings([
40
+ title,
41
+ ...devices.map((node) => node.title),
42
+ ...entities.map((node) => node.title),
43
+ ].flatMap(tokenizeEvidence)),
44
+ maxSources: 12,
45
+ maxSnippetsPerSource: 2,
46
+ }),
35
47
  renderSourceList('Linked Sources', sources),
36
48
  renderIssueList('Open Issues', state.issues.filter((issue) => issue.status === 'open')),
37
49
  ].filter(Boolean).join('\n');
38
50
  }
39
51
  export function renderDevicePassportPage(input) {
52
+ const deviceTokens = deviceEvidenceTokens(input.device, input.entities);
40
53
  return [
41
54
  `# ${input.device.title}`,
42
55
  '',
43
56
  `Knowledge space: \`${input.spaceId}\``,
44
57
  '',
45
- '## Profile',
58
+ '## Overview',
59
+ '',
60
+ renderDeviceOverview(input.device, input.entities, input.sources),
61
+ '',
62
+ '## Home Assistant Profile',
46
63
  '',
47
64
  renderMetadataField('Manufacturer', input.device.metadata.manufacturer),
48
65
  renderMetadataField('Model', input.device.metadata.model),
49
66
  renderMetadataField('Area', readHa(input.device, 'areaId')),
50
67
  renderMetadataField('Device id', readHa(input.device, 'deviceId')),
51
68
  '',
52
- renderNodeList('Entities', input.entities),
69
+ renderNodeList('Entities Exposed To Home Assistant', input.entities),
70
+ renderSourceEvidence('Source-Backed Features And Notes', input.sources, input.extractions ?? [], {
71
+ tokens: deviceTokens,
72
+ maxSources: 8,
73
+ maxSnippetsPerSource: 4,
74
+ }),
53
75
  renderSourceList('Sources', input.sources),
54
76
  renderIssueList('Issues', input.issues),
55
77
  input.missingFields.length > 0
56
- ? ['## Missing Fields', '', ...input.missingFields.map((field) => `- ${field}`), ''].join('\n')
78
+ ? ['## Open Questions', '', ...input.missingFields.map((field) => `- ${field}`), ''].join('\n')
57
79
  : '',
58
80
  ].filter(Boolean).join('\n');
59
81
  }
@@ -77,11 +99,132 @@ export function renderPacketPage(state, options = {}) {
77
99
  ].filter(Boolean).join('\n');
78
100
  }
79
101
  export function renderHomeGraphMap(state, options = {}) {
80
- return renderKnowledgeMap(state, {
102
+ const filtered = applyHomeGraphMapFilters(state, options.ha);
103
+ const result = renderKnowledgeMap(filtered, {
81
104
  ...options,
82
105
  title: state.title,
83
106
  spaceId: state.spaceId,
84
107
  });
108
+ return {
109
+ ...result,
110
+ facets: {
111
+ ...result.facets,
112
+ homeAssistant: buildHomeAssistantMapFacets(state),
113
+ },
114
+ };
115
+ }
116
+ function applyHomeGraphMapFilters(state, input) {
117
+ const filters = normalizeHomeGraphMapFilters(input);
118
+ if (!hasHomeGraphFilters(filters))
119
+ return state;
120
+ const nodes = state.nodes.filter((node) => matchesHomeGraphNode(node, state.edges, filters, state.nodes));
121
+ const nodeIds = new Set(nodes.map((node) => node.id));
122
+ const sourceIds = sourceIdsLinkedToNodes(state.edges, nodeIds);
123
+ const sources = state.sources.filter((source) => sourceIds.has(source.id) || matchesHomeGraphSource(source, filters));
124
+ const sourceSet = new Set(sources.map((source) => source.id));
125
+ const issues = state.issues.filter((issue) => ((issue.nodeId && nodeIds.has(issue.nodeId))
126
+ || (issue.sourceId && sourceSet.has(issue.sourceId))));
127
+ const visibleIds = new Set([...nodeIds, ...sourceSet, ...issues.map((issue) => issue.id)]);
128
+ const edges = state.edges.filter((edge) => visibleIds.has(edge.fromId) && visibleIds.has(edge.toId));
129
+ return { ...state, nodes, sources, issues, edges };
130
+ }
131
+ function buildHomeAssistantMapFacets(state) {
132
+ return {
133
+ objectKinds: countFacet(state.nodes.map((node) => readHomeAssistantRecord(node).objectKind ?? node.kind)),
134
+ entityIds: countFacet(state.nodes.map((node) => readHomeAssistantRecord(node).entityId)),
135
+ deviceIds: countFacet(state.nodes.map((node) => readHomeAssistantRecord(node).deviceId)),
136
+ areaIds: countFacet(state.nodes.map((node) => readHomeAssistantRecord(node).areaId)),
137
+ integrationIds: countFacet(state.nodes.map((node) => readHomeAssistantRecord(node).integrationId)),
138
+ integrationDomains: countFacet(state.nodes.map((node) => readIntegrationDomain(node))),
139
+ domains: countFacet(state.nodes.map((node) => readEntityDomain(node))),
140
+ deviceClasses: countFacet(state.nodes.map((node) => readDeviceClass(node))),
141
+ labels: countFacet(state.nodes.flatMap((node) => normalizeStringArray(node.metadata.labels))),
142
+ };
143
+ }
144
+ function normalizeHomeGraphMapFilters(input) {
145
+ return {
146
+ objectKinds: normalizeStringArray(input?.objectKinds),
147
+ entityIds: normalizeStringArray(input?.entityIds),
148
+ deviceIds: normalizeStringArray(input?.deviceIds),
149
+ areaIds: normalizeStringArray(input?.areaIds),
150
+ integrationIds: normalizeStringArray(input?.integrationIds),
151
+ integrationDomains: normalizeStringArray(input?.integrationDomains),
152
+ domains: normalizeStringArray(input?.domains),
153
+ deviceClasses: normalizeStringArray(input?.deviceClasses),
154
+ labels: normalizeStringArray(input?.labels),
155
+ };
156
+ }
157
+ function hasHomeGraphFilters(filters) {
158
+ return Object.values(filters).some((value) => value.length > 0);
159
+ }
160
+ function matchesHomeGraphNode(node, edges, filters, nodes) {
161
+ const ha = readHomeAssistantRecord(node);
162
+ return matchesFilter(filters.objectKinds, String(ha.objectKind ?? node.kind), node.kind)
163
+ && matchesFilter(filters.entityIds, readString(ha.entityId), readString(ha.objectId))
164
+ && matchesFilter(filters.deviceIds, readString(ha.deviceId), node.kind === 'ha_device' ? readString(ha.objectId) : undefined)
165
+ && matchesAreaFilter(filters.areaIds, node, edges, nodes)
166
+ && matchesFilter(filters.integrationIds, readString(ha.integrationId), node.kind === 'ha_integration' ? readString(ha.objectId) : undefined)
167
+ && matchesFilter(filters.integrationDomains, readIntegrationDomain(node))
168
+ && matchesFilter(filters.domains, readEntityDomain(node))
169
+ && matchesFilter(filters.deviceClasses, readDeviceClass(node))
170
+ && matchesAny(filters.labels, normalizeStringArray(node.metadata.labels));
171
+ }
172
+ function matchesHomeGraphSource(source, filters) {
173
+ return matchesAny(filters.labels, [...source.tags, ...normalizeStringArray(source.metadata.labels)]);
174
+ }
175
+ function matchesAreaFilter(areaIds, node, edges, nodes) {
176
+ if (areaIds.length === 0)
177
+ return true;
178
+ const ha = readHomeAssistantRecord(node);
179
+ if (matchesFilter(areaIds, readString(ha.areaId), node.kind === 'ha_area' || node.kind === 'ha_room' ? readString(ha.objectId) : undefined)) {
180
+ return true;
181
+ }
182
+ const targetAreaNodeIds = new Set(nodes
183
+ .filter((candidate) => (candidate.kind === 'ha_area' || candidate.kind === 'ha_room')
184
+ && matchesFilter(areaIds, readString(readHomeAssistantRecord(candidate).objectId), readString(readHomeAssistantRecord(candidate).areaId)))
185
+ .map((candidate) => candidate.id));
186
+ return edges.some((edge) => edgeIsActive(edge)
187
+ && edge.fromId === node.id
188
+ && edge.relation === 'located_in'
189
+ && targetAreaNodeIds.has(edge.toId));
190
+ }
191
+ function sourceIdsLinkedToNodes(edges, nodeIds) {
192
+ const sourceIds = new Set();
193
+ for (const edge of edges) {
194
+ if (edge.fromKind === 'source' && edge.toKind === 'node' && nodeIds.has(edge.toId))
195
+ sourceIds.add(edge.fromId);
196
+ if (edge.fromKind === 'node' && nodeIds.has(edge.fromId) && edge.toKind === 'source')
197
+ sourceIds.add(edge.toId);
198
+ }
199
+ return sourceIds;
200
+ }
201
+ function readHomeAssistantRecord(node) {
202
+ const value = node.metadata.homeAssistant;
203
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
204
+ }
205
+ function readIntegrationDomain(node) {
206
+ const ha = readHomeAssistantRecord(node);
207
+ return readString(ha.integrationId)
208
+ ?? readString(node.metadata.integrationDomain)
209
+ ?? readString(node.metadata.platform)
210
+ ?? readString(node.metadata.domain);
211
+ }
212
+ function readEntityDomain(node) {
213
+ const entityId = readString(readHomeAssistantRecord(node).entityId);
214
+ const fromEntity = entityId?.includes('.') ? entityId.split('.')[0] : undefined;
215
+ return fromEntity ?? readString(node.metadata.domain);
216
+ }
217
+ function readDeviceClass(node) {
218
+ const attributes = node.metadata.attributes && typeof node.metadata.attributes === 'object' && !Array.isArray(node.metadata.attributes)
219
+ ? node.metadata.attributes
220
+ : {};
221
+ return readString(node.metadata.deviceClass) ?? readString(node.metadata.device_class) ?? readString(attributes.device_class);
222
+ }
223
+ function matchesFilter(allowed, ...values) {
224
+ return allowed.length === 0 || values.some((value) => value !== undefined && allowed.includes(value));
225
+ }
226
+ function matchesAny(allowed, values) {
227
+ return allowed.length === 0 || values.some((value) => allowed.includes(value));
85
228
  }
86
229
  function renderNodeList(title, nodes) {
87
230
  if (nodes.length === 0)
@@ -93,6 +236,142 @@ function renderNodeList(title, nodes) {
93
236
  '',
94
237
  ].join('\n');
95
238
  }
239
+ function renderRoomOverview(title, devices, entities, automations, scenes, scripts) {
240
+ return [
241
+ '## Overview',
242
+ '',
243
+ `${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.`,
244
+ '',
245
+ ].join('\n');
246
+ }
247
+ function renderDeviceOverview(device, entities, sources) {
248
+ const identity = uniqueStrings([
249
+ readMetadataString(device, 'manufacturer'),
250
+ readMetadataString(device, 'model'),
251
+ readHa(device, 'areaId') ? `area ${readHa(device, 'areaId')}` : undefined,
252
+ ]);
253
+ const details = identity.length > 0 ? ` ${identity.join(' - ')}.` : '.';
254
+ return `${device.title}${details} The Home Graph links this device to ${entities.length} Home Assistant entity record(s) and ${sources.length} source(s).`;
255
+ }
256
+ function renderSourceEvidence(title, sources, extractions, options) {
257
+ const extractionBySourceId = new Map(extractions.map((extraction) => [extraction.sourceId, extraction]));
258
+ const entries = sources
259
+ .map((source) => ({
260
+ source,
261
+ snippets: sourceEvidenceSnippets(source, extractionBySourceId.get(source.id), options.tokens, options.maxSnippetsPerSource),
262
+ }))
263
+ .filter((entry) => entry.snippets.length > 0)
264
+ .slice(0, options.maxSources);
265
+ if (entries.length === 0) {
266
+ return [
267
+ `## ${title}`,
268
+ '',
269
+ 'No linked source-backed details have been extracted yet.',
270
+ '',
271
+ ].join('\n');
272
+ }
273
+ return [
274
+ `## ${title}`,
275
+ '',
276
+ ...entries.flatMap((entry) => [
277
+ `### ${entry.source.title ?? entry.source.sourceUri ?? entry.source.id}`,
278
+ '',
279
+ ...entry.snippets.map((snippet) => `- ${snippet}`),
280
+ '',
281
+ ]),
282
+ ].join('\n');
283
+ }
284
+ function sourceEvidenceSnippets(source, extraction, tokens, limit) {
285
+ const structure = readRecord(extraction?.structure);
286
+ const searchText = typeof structure.searchText === 'string' ? structure.searchText : undefined;
287
+ const candidates = uniqueStrings([
288
+ extraction?.summary,
289
+ extraction?.excerpt,
290
+ ...(extraction?.sections ?? []),
291
+ ...evidenceWindows(searchText, tokens),
292
+ ...featureSentences(searchText),
293
+ source.summary,
294
+ source.description,
295
+ ]).filter((entry) => !isUnusableHomeGraphExtractionText(entry)).slice(0, 80);
296
+ const scored = candidates
297
+ .map((text) => ({ text: clampEvidence(text), score: evidenceScore(text, tokens) }))
298
+ .filter((entry) => entry.text.length > 0)
299
+ .sort((left, right) => right.score - left.score || left.text.length - right.text.length);
300
+ return uniqueStrings(scored.map((entry) => entry.text)).slice(0, limit);
301
+ }
302
+ function evidenceWindows(value, tokens) {
303
+ const text = normalizeWhitespace(value ?? '');
304
+ if (!text)
305
+ return [];
306
+ const lower = text.toLowerCase();
307
+ const windows = [];
308
+ for (const token of tokens) {
309
+ if (token.length < 3)
310
+ continue;
311
+ const index = lower.indexOf(token.toLowerCase());
312
+ if (index < 0)
313
+ continue;
314
+ const start = Math.max(0, index - 180);
315
+ const end = Math.min(text.length, index + 420);
316
+ windows.push(`${start > 0 ? '...' : ''}${text.slice(start, end).trim()}${end < text.length ? '...' : ''}`);
317
+ }
318
+ return windows;
319
+ }
320
+ function featureSentences(value) {
321
+ const text = normalizeWhitespace(value ?? '');
322
+ if (!text)
323
+ return [];
324
+ const keywords = /\b(feature|features|support|supports|capability|capabilities|specification|specifications|mode|modes|hdmi|hdr|dolby|battery|reset|warranty|firmware|voice|remote)\b/i;
325
+ return (text.match(/[^.!?\n]+[.!?]?/g) ?? [])
326
+ .map((entry) => entry.trim())
327
+ .filter((entry) => keywords.test(entry))
328
+ .slice(0, 24);
329
+ }
330
+ function evidenceScore(value, tokens) {
331
+ const lower = value.toLowerCase();
332
+ let score = 0;
333
+ for (const token of tokens) {
334
+ if (token.length >= 3 && lower.includes(token.toLowerCase()))
335
+ score += 10;
336
+ }
337
+ if (/\b(feature|features|support|supports|mode|hdmi|hdr|dolby|voice|remote)\b/i.test(value))
338
+ score += 25;
339
+ return score;
340
+ }
341
+ function deviceEvidenceTokens(device, entities) {
342
+ return uniqueStrings([
343
+ device.title,
344
+ ...device.aliases,
345
+ readMetadataString(device, 'manufacturer'),
346
+ readMetadataString(device, 'model'),
347
+ readHa(device, 'deviceId'),
348
+ ...entities.flatMap((entity) => [
349
+ entity.title,
350
+ readHa(entity, 'entityId'),
351
+ readMetadataString(entity, 'domain'),
352
+ readMetadataString(entity, 'platform'),
353
+ ]),
354
+ ].flatMap(tokenizeEvidence));
355
+ }
356
+ function tokenizeEvidence(value) {
357
+ if (!value)
358
+ return [];
359
+ return value.toLowerCase()
360
+ .split(/[^a-z0-9_.:-]+/)
361
+ .map((entry) => entry.trim())
362
+ .filter((entry) => entry.length >= 2 && !['the', 'and', 'home', 'assistant', 'device'].includes(entry));
363
+ }
364
+ function clampEvidence(value) {
365
+ const normalized = normalizeWhitespace(value);
366
+ return normalized.length <= 420 ? normalized : `${normalized.slice(0, 419).trim()}...`;
367
+ }
368
+ function normalizeWhitespace(value) {
369
+ return value.replace(/\s+/g, ' ').trim();
370
+ }
371
+ function readMetadataString(node, key) {
372
+ const value = node.metadata[key];
373
+ return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
374
+ }
96
375
  function renderSourceList(title, sources) {
97
376
  if (sources.length === 0)
98
377
  return '';
@@ -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;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"}
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;AAGrB,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;AAwMD,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,yBAAyB,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAWhH"}
@@ -1,4 +1,5 @@
1
1
  import { belongsToSpace, edgeIsActive, isGeneratedPageSource, readRecord } from './helpers.js';
2
+ import { isUnusableHomeGraphExtractionText } from './extraction-quality.js';
2
3
  const MAX_FIELD_CHARS = 4_096;
3
4
  const MAX_SECTION_COUNT = 32;
4
5
  const MAX_SEARCH_TEXT_CHARS = 64 * 1024;
@@ -258,12 +259,13 @@ function readSearchText(extraction) {
258
259
  return undefined;
259
260
  const structure = readRecord(extraction.structure);
260
261
  const metadata = readRecord(extraction.metadata);
261
- return firstBoundedText([
262
+ const text = firstBoundedText([
262
263
  structure.searchText,
263
264
  structure.text,
264
265
  structure.content,
265
266
  metadata.searchText,
266
267
  ], MAX_SEARCH_TEXT_CHARS);
268
+ return isUnusableHomeGraphExtractionText(text) ? undefined : text;
267
269
  }
268
270
  function readNodeMetadataText(node) {
269
271
  const homeAssistant = readRecord(node.metadata.homeAssistant);
@@ -520,11 +522,7 @@ function usefulExtractionSummary(extraction) {
520
522
  return summary && !isLowInformationExtractionText(summary) ? summary : undefined;
521
523
  }
522
524
  function isLowInformationExtractionText(value) {
523
- const normalized = value.toLowerCase();
524
- return normalized.includes('pdf extraction produced limited text')
525
- || normalized.includes('no readable text streams')
526
- || normalized.includes('no specialized extractor matched')
527
- || normalized.includes('has no specialized in-core extractor');
525
+ return isUnusableHomeGraphExtractionText(value);
528
526
  }
529
527
  function sentenceChunks(value) {
530
528
  const text = cleanWhitespace(value ?? '');
@@ -2,7 +2,7 @@ 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 { 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
6
  export declare class HomeGraphService {
7
7
  private readonly store;
8
8
  private readonly artifactStore;
@@ -41,6 +41,10 @@ export declare class HomeGraphService {
41
41
  readonly spaceId: string;
42
42
  readonly sources: readonly KnowledgeSourceRecord[];
43
43
  }>;
44
+ listPages(input?: HomeGraphSpaceInput & {
45
+ readonly limit?: number;
46
+ readonly includeMarkdown?: boolean;
47
+ }): Promise<HomeGraphPageListResult>;
44
48
  browse(input?: HomeGraphSpaceInput & {
45
49
  readonly limit?: number;
46
50
  }): Promise<{
@@ -68,6 +72,7 @@ export declare class HomeGraphService {
68
72
  }>;
69
73
  private ingestCreatedArtifact;
70
74
  private extractArtifact;
75
+ private autoLinkExistingSources;
71
76
  private upsertHomeNode;
72
77
  private upsertSnapshotObjects;
73
78
  private linkSnapshotObjectRelations;
@@ -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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"}
@@ -5,8 +5,11 @@ import { refreshHomeGraphQualityIssues } from './quality.js';
5
5
  import { reviewHomeGraphFact } from './review.js';
6
6
  import { collectLinkedObjects, inferHomeGraphSourceType, readHomeGraphState, renderAskAnswer, renderHomeGraphState, safeHomeGraphFilename, } from './state.js';
7
7
  import { renderHomeGraphMap } from './rendering.js';
8
- import { generateAutomaticHomeGraphPages, generateHomeGraphPacket, generateHomeGraphRoomPage, refreshHomeGraphDevicePassport, } from './generated-pages.js';
8
+ import { autoLinkHomeGraphSource, autoLinkHomeGraphSources, } from './auto-link.js';
9
+ import { generateAutomaticHomeGraphPages, generateHomeGraphPacket, generateHomeGraphRoomPage, refreshAutomaticHomeGraphPages, refreshHomeGraphDevicePassport, } from './generated-pages.js';
9
10
  import { reindexHomeGraphSources } from './reindex.js';
11
+ import { listHomeGraphPages } from './pages.js';
12
+ import { isUnusableHomeGraphExtractionText } from './extraction-quality.js';
10
13
  import { readHomeGraphSearchState, scoreHomeGraphResults, selectHomeGraphExtractionRepairCandidates, } from './search.js';
11
14
  import { resolveReadableHomeGraphSpace } from './space-selection.js';
12
15
  import { HOME_GRAPH_CAPABILITIES } from './types.js';
@@ -61,6 +64,7 @@ export class HomeGraphService {
61
64
  const beforeNodeIds = new Set(readHomeGraphState(this.store, spaceId).nodes.map((node) => node.id));
62
65
  const beforeEdgeIds = new Set(readHomeGraphState(this.store, spaceId).edges.map((edge) => edge.id));
63
66
  const groups = await this.upsertSnapshotObjects(spaceId, installationId, input, home.id, source.id);
67
+ await this.autoLinkExistingSources(spaceId, installationId);
64
68
  const issues = await this.refreshQualityIssues(spaceId, installationId);
65
69
  const generated = await generateAutomaticHomeGraphPages({
66
70
  store: this.store,
@@ -227,13 +231,22 @@ export class HomeGraphService {
227
231
  await this.store.init();
228
232
  const { spaceId, installationId } = resolveReadableHomeGraphSpace(this.store, input);
229
233
  const state = readHomeGraphSearchState(this.store, spaceId);
230
- return reindexHomeGraphSources({
234
+ const reindex = await reindexHomeGraphSources({
231
235
  spaceId,
232
236
  sources: state.sources,
233
237
  extractionBySourceId: state.extractionBySourceId,
234
238
  artifactStore: this.artifactStore,
235
239
  extract: (source, artifact) => this.extractArtifact(source, artifact, spaceId, installationId),
236
240
  });
241
+ const linked = await this.autoLinkExistingSources(spaceId, installationId);
242
+ const generated = reindex.reparsed > 0 || linked.length > 0
243
+ ? await refreshAutomaticHomeGraphPages({ store: this.store, artifactStore: this.artifactStore, spaceId, installationId })
244
+ : undefined;
245
+ return {
246
+ ...reindex,
247
+ ...(linked.length > 0 ? { linked } : {}),
248
+ ...(generated ? { generated } : {}),
249
+ };
237
250
  }
238
251
  async repairWeakExtractionsForAsk(spaceId, installationId, query, state) {
239
252
  const candidates = selectHomeGraphExtractionRepairCandidates(query, state.sources, state.nodes, state.edges, (sourceId) => state.extractionBySourceId.get(sourceId), 8);
@@ -246,6 +259,16 @@ export class HomeGraphService {
246
259
  if (!artifact)
247
260
  continue;
248
261
  const extraction = await this.extractArtifact(source, artifact, spaceId, installationId);
262
+ if (extraction) {
263
+ await autoLinkHomeGraphSource({
264
+ store: this.store,
265
+ spaceId,
266
+ installationId,
267
+ source,
268
+ extraction,
269
+ state: readHomeGraphState(this.store, spaceId),
270
+ });
271
+ }
249
272
  if (extraction && extractionHasSearchableText(extraction))
250
273
  repaired += 1;
251
274
  }
@@ -305,6 +328,18 @@ export class HomeGraphService {
305
328
  const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
306
329
  return { ok: true, spaceId, sources: readHomeGraphState(this.store, spaceId).sources.slice(0, Math.max(1, input.limit ?? 100)) };
307
330
  }
331
+ async listPages(input = {}) {
332
+ await this.store.init();
333
+ const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
334
+ const state = readHomeGraphState(this.store, spaceId);
335
+ return listHomeGraphPages({
336
+ artifactStore: this.artifactStore,
337
+ spaceId,
338
+ sources: state.sources,
339
+ limit: Math.max(1, input.limit ?? 100),
340
+ includeMarkdown: input.includeMarkdown !== false,
341
+ });
342
+ }
308
343
  async browse(input = {}) {
309
344
  await this.store.init();
310
345
  const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
@@ -323,8 +358,8 @@ export class HomeGraphService {
323
358
  await this.store.init();
324
359
  const { spaceId } = resolveReadableHomeGraphSpace(this.store, input);
325
360
  return renderHomeGraphMap(renderHomeGraphState(this.store, spaceId, 'Home Graph Map'), {
326
- limit: input.limit,
327
- includeSources: input.includeSources,
361
+ ...input,
362
+ knowledgeSpaceId: spaceId,
328
363
  });
329
364
  }
330
365
  async exportSpace(input = {}) {
@@ -394,7 +429,14 @@ export class HomeGraphService {
394
429
  const extraction = await this.extractArtifact(source, input.artifact, input.spaceId, input.installationId);
395
430
  const linked = input.target
396
431
  ? (await this.linkKnowledge({ knowledgeSpaceId: input.spaceId, sourceId: source.id, target: input.target })).edge
397
- : undefined;
432
+ : (await autoLinkHomeGraphSource({
433
+ store: this.store,
434
+ spaceId: input.spaceId,
435
+ installationId: input.installationId,
436
+ source,
437
+ ...(extraction ? { extraction } : {}),
438
+ state: readHomeGraphState(this.store, input.spaceId),
439
+ }))?.edge;
398
440
  return {
399
441
  ok: true,
400
442
  spaceId: input.spaceId,
@@ -432,6 +474,18 @@ export class HomeGraphService {
432
474
  return undefined;
433
475
  }
434
476
  }
477
+ async autoLinkExistingSources(spaceId, installationId) {
478
+ const state = readHomeGraphState(this.store, spaceId);
479
+ const extractionBySourceId = new Map(state.extractions.map((extraction) => [extraction.sourceId, extraction]));
480
+ return autoLinkHomeGraphSources({
481
+ store: this.store,
482
+ spaceId,
483
+ installationId,
484
+ sources: state.sources,
485
+ extractionBySourceId,
486
+ state,
487
+ });
488
+ }
435
489
  async upsertHomeNode(spaceId, installationId, input) {
436
490
  return this.store.upsertNode({
437
491
  id: homeGraphNodeId(spaceId, 'ha_home', input.homeId ?? installationId),
@@ -565,5 +619,5 @@ export class HomeGraphService {
565
619
  }
566
620
  function extractionHasSearchableText(extraction) {
567
621
  const structure = readRecord(extraction.structure);
568
- return typeof structure.searchText === 'string' && structure.searchText.trim().length > 0;
622
+ return typeof structure.searchText === 'string' && !isUnusableHomeGraphExtractionText(structure.searchText);
569
623
  }
@@ -1,4 +1,4 @@
1
- import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeMapEdge, KnowledgeMapNode, KnowledgeMapResult, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
1
+ import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeMapFilterInput, KnowledgeMapEdge, KnowledgeMapNode, KnowledgeMapResult, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
2
2
  export declare const HOME_GRAPH_NODE_KINDS: readonly ["ha_home", "ha_entity", "ha_device", "ha_area", "ha_automation", "ha_script", "ha_scene", "ha_label", "ha_integration", "ha_room", "ha_device_passport", "ha_maintenance_item", "ha_troubleshooting_case", "ha_purchase", "ha_network_node"];
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"];
@@ -169,6 +169,35 @@ export interface HomeGraphAskResult {
169
169
  export interface HomeGraphMapInput extends HomeGraphSpaceInput {
170
170
  readonly limit?: number;
171
171
  readonly includeSources?: boolean;
172
+ readonly includeIssues?: boolean;
173
+ readonly includeGenerated?: boolean;
174
+ readonly filters?: KnowledgeMapFilterInput;
175
+ readonly query?: string;
176
+ readonly recordKinds?: readonly ('source' | 'node' | 'issue')[];
177
+ readonly ids?: readonly string[];
178
+ readonly linkedToIds?: readonly string[];
179
+ readonly nodeKinds?: readonly string[];
180
+ readonly sourceTypes?: readonly string[];
181
+ readonly sourceStatuses?: readonly string[];
182
+ readonly nodeStatuses?: readonly string[];
183
+ readonly issueCodes?: readonly string[];
184
+ readonly issueStatuses?: readonly string[];
185
+ readonly issueSeverities?: readonly string[];
186
+ readonly edgeRelations?: readonly string[];
187
+ readonly tags?: readonly string[];
188
+ readonly minConfidence?: number;
189
+ readonly ha?: HomeGraphMapHaFilterInput;
190
+ }
191
+ export interface HomeGraphMapHaFilterInput {
192
+ readonly objectKinds?: readonly string[];
193
+ readonly entityIds?: readonly string[];
194
+ readonly deviceIds?: readonly string[];
195
+ readonly areaIds?: readonly string[];
196
+ readonly integrationIds?: readonly string[];
197
+ readonly integrationDomains?: readonly string[];
198
+ readonly domains?: readonly string[];
199
+ readonly deviceClasses?: readonly string[];
200
+ readonly labels?: readonly string[];
172
201
  }
173
202
  export type HomeGraphMapNode = KnowledgeMapNode;
174
203
  export type HomeGraphMapEdge = KnowledgeMapEdge;
@@ -187,6 +216,14 @@ export interface HomeGraphReindexResult {
187
216
  readonly sourceId: string;
188
217
  readonly error: string;
189
218
  }[];
219
+ readonly linked?: readonly {
220
+ readonly edge: KnowledgeEdgeRecord;
221
+ readonly node: KnowledgeNodeRecord;
222
+ readonly relation: string;
223
+ readonly score: number;
224
+ readonly reasons: readonly string[];
225
+ }[];
226
+ readonly generated?: HomeGraphGeneratedPagesSummary;
190
227
  }
191
228
  export interface HomeGraphSearchResult {
192
229
  readonly kind: 'source' | 'node';
@@ -229,6 +266,15 @@ export interface HomeGraphDevicePassportResult extends HomeGraphProjectionResult
229
266
  readonly passport: KnowledgeNodeRecord;
230
267
  readonly missingFields: readonly string[];
231
268
  }
269
+ export interface HomeGraphPageListResult {
270
+ readonly ok: true;
271
+ readonly spaceId: string;
272
+ readonly pages: readonly {
273
+ readonly source: KnowledgeSourceRecord;
274
+ readonly artifact?: HomeGraphProjectionResult['artifact'];
275
+ readonly markdown?: string;
276
+ }[];
277
+ }
232
278
  export interface HomeGraphReviewInput extends HomeGraphSpaceInput {
233
279
  readonly issueId?: string;
234
280
  readonly nodeId?: string;