@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
@@ -0,0 +1,236 @@
1
+ import { buildHomeGraphMetadata, edgeIsActive, isGeneratedPageSource, readRecord, uniqueStrings, } from './helpers.js';
2
+ const MIN_AUTO_LINK_SCORE = 90;
3
+ const MIN_SOURCE_TEXT_CHARS = 16;
4
+ const MAX_TEXT_FIELD_CHARS = 32_768;
5
+ const GENERIC_TOKENS = new Set(['device', 'home', 'assistant', 'smart', 'manual', 'owner', 'guide', 'user', 'the']);
6
+ export async function autoLinkHomeGraphSource(input) {
7
+ if (isGeneratedPageSource(input.source) || shouldSkipAutoLink(input.source))
8
+ return undefined;
9
+ if (hasActiveSourceLink(input.source.id, input.state.edges))
10
+ return undefined;
11
+ const candidates = scoreCandidates(input.source, input.extraction, input.state);
12
+ const best = candidates[0];
13
+ if (!best || best.score < MIN_AUTO_LINK_SCORE)
14
+ return undefined;
15
+ const next = candidates[1];
16
+ if (next && best.score - next.score < 20 && !best.reasons.some((reason) => reason.startsWith('exact-model:'))) {
17
+ return undefined;
18
+ }
19
+ const relation = inferRelation(input.source);
20
+ const edge = await input.store.upsertEdge({
21
+ fromKind: 'source',
22
+ fromId: input.source.id,
23
+ toKind: 'node',
24
+ toId: best.node.id,
25
+ relation,
26
+ weight: Math.min(5, Math.max(1, Math.round(best.score / 60))),
27
+ metadata: buildHomeGraphMetadata(input.spaceId, input.installationId, {
28
+ linkStatus: 'active',
29
+ linkMethod: 'homegraph-auto-link',
30
+ autoLinkedAt: Date.now(),
31
+ autoLinkScore: best.score,
32
+ autoLinkReasons: best.reasons,
33
+ }),
34
+ });
35
+ return { edge, node: best.node, relation, score: best.score, reasons: best.reasons };
36
+ }
37
+ export async function autoLinkHomeGraphSources(input) {
38
+ const linked = [];
39
+ for (const source of input.sources) {
40
+ const result = await autoLinkHomeGraphSource({
41
+ store: input.store,
42
+ spaceId: input.spaceId,
43
+ installationId: input.installationId,
44
+ source,
45
+ extraction: input.extractionBySourceId.get(source.id),
46
+ state: {
47
+ ...input.state,
48
+ edges: [...input.state.edges, ...linked.map((entry) => entry.edge)],
49
+ },
50
+ });
51
+ if (result)
52
+ linked.push(result);
53
+ }
54
+ return linked;
55
+ }
56
+ function scoreCandidates(source, extraction, state) {
57
+ const sourceText = sourceEvidenceText(source, extraction);
58
+ if (sourceText.length < MIN_SOURCE_TEXT_CHARS)
59
+ return [];
60
+ const lower = sourceText.toLowerCase();
61
+ const sourceTokens = new Set(tokenize(sourceText));
62
+ return state.nodes
63
+ .filter((node) => isAutoLinkCandidateNode(node))
64
+ .map((node) => {
65
+ const reasons = [];
66
+ let score = 0;
67
+ const identity = nodeIdentity(node, state);
68
+ for (const model of identity.models) {
69
+ if (model.length >= 4 && includesIdentity(lower, model)) {
70
+ score += model.length >= 8 ? 180 : 120;
71
+ reasons.push(`exact-model:${model}`);
72
+ }
73
+ }
74
+ for (const entityId of identity.entityIds) {
75
+ if (includesIdentity(lower, entityId)) {
76
+ score += 140;
77
+ reasons.push(`entity-id:${entityId}`);
78
+ }
79
+ }
80
+ for (const deviceId of identity.deviceIds) {
81
+ if (includesIdentity(lower, deviceId)) {
82
+ score += 120;
83
+ reasons.push(`device-id:${deviceId}`);
84
+ }
85
+ }
86
+ const titleTokens = tokenize(node.title).filter((token) => !isGenericToken(token));
87
+ const overlap = titleTokens.filter((token) => sourceTokens.has(token));
88
+ if (overlap.length > 0) {
89
+ score += overlap.reduce((sum, token) => sum + (token.length <= 3 ? 12 : 18), 0);
90
+ reasons.push(`title:${overlap.slice(0, 5).join(',')}`);
91
+ }
92
+ const manufacturerMatches = identity.manufacturers.filter((manufacturer) => includesIdentity(lower, manufacturer));
93
+ if (manufacturerMatches.length > 0) {
94
+ score += 28;
95
+ reasons.push(`manufacturer:${manufacturerMatches[0]}`);
96
+ }
97
+ const relatedEntityMatches = identity.relatedEntityTokens.filter((token) => sourceTokens.has(token));
98
+ if (relatedEntityMatches.length > 0) {
99
+ score += Math.min(50, relatedEntityMatches.length * 10);
100
+ reasons.push(`related-entity:${relatedEntityMatches.slice(0, 5).join(',')}`);
101
+ }
102
+ if (node.kind === 'ha_device' && isManualLikeSource(source))
103
+ score += 16;
104
+ if (node.kind === 'ha_integration' && isIntegrationDocumentationSource(source))
105
+ score += 40;
106
+ if (node.kind === 'ha_integration' && isManualLikeSource(source))
107
+ score -= 45;
108
+ return { node, score, reasons };
109
+ })
110
+ .filter((entry) => entry.score > 0)
111
+ .sort((left, right) => right.score - left.score || left.node.id.localeCompare(right.node.id));
112
+ }
113
+ function shouldSkipAutoLink(source) {
114
+ const kind = typeof source.metadata.homeGraphSourceKind === 'string' ? source.metadata.homeGraphSourceKind : '';
115
+ return kind === 'snapshot' || kind === 'generated-page';
116
+ }
117
+ function hasActiveSourceLink(sourceId, edges) {
118
+ return edges.some((edge) => edgeIsActive(edge) && ((edge.fromKind === 'source' && edge.fromId === sourceId && edge.toKind === 'node')
119
+ || (edge.fromKind === 'node' && edge.toKind === 'source' && edge.toId === sourceId)));
120
+ }
121
+ function isAutoLinkCandidateNode(node) {
122
+ return node.kind === 'ha_device'
123
+ || node.kind === 'ha_entity'
124
+ || node.kind === 'ha_integration'
125
+ || node.kind === 'ha_area'
126
+ || node.kind === 'ha_room';
127
+ }
128
+ function sourceEvidenceText(source, extraction) {
129
+ const structure = readRecord(extraction?.structure);
130
+ return uniqueStrings([
131
+ source.title,
132
+ source.summary,
133
+ source.description,
134
+ source.sourceUri,
135
+ source.canonicalUri,
136
+ source.tags.join(' '),
137
+ extraction?.title,
138
+ extraction?.summary,
139
+ extraction?.excerpt,
140
+ ...(extraction?.sections ?? []),
141
+ readString(structure.searchText),
142
+ ]).join('\n').slice(0, MAX_TEXT_FIELD_CHARS);
143
+ }
144
+ function nodeIdentity(node, state) {
145
+ const homeAssistant = readRecord(node.metadata.homeAssistant);
146
+ const relatedEntities = node.kind === 'ha_device'
147
+ ? relatedEntityNodes(node.id, state)
148
+ : [];
149
+ return {
150
+ models: uniqueStrings([
151
+ readString(node.metadata.model),
152
+ readString(node.metadata.modelId),
153
+ readString(node.metadata.model_id),
154
+ ]),
155
+ manufacturers: uniqueStrings([
156
+ readString(node.metadata.manufacturer),
157
+ readString(node.metadata.vendor),
158
+ ]),
159
+ entityIds: uniqueStrings([
160
+ readString(homeAssistant.entityId),
161
+ ...relatedEntities.map((entity) => readString(readRecord(entity.metadata.homeAssistant).entityId)),
162
+ ]),
163
+ deviceIds: uniqueStrings([
164
+ readString(homeAssistant.deviceId),
165
+ node.kind === 'ha_device' ? readString(homeAssistant.objectId) : undefined,
166
+ ]),
167
+ relatedEntityTokens: uniqueStrings(relatedEntities.flatMap((entity) => [
168
+ ...tokenize(entity.title),
169
+ ...tokenize(readString(readRecord(entity.metadata.homeAssistant).entityId) ?? ''),
170
+ readString(entity.metadata.domain),
171
+ readString(entity.metadata.platform),
172
+ ])),
173
+ };
174
+ }
175
+ function relatedEntityNodes(deviceNodeId, state) {
176
+ const entityIds = new Set(state.edges.filter((edge) => (edgeIsActive(edge)
177
+ && edge.fromKind === 'node'
178
+ && edge.toKind === 'node'
179
+ && edge.toId === deviceNodeId
180
+ && edge.relation === 'belongs_to_device')).map((edge) => edge.fromId));
181
+ return state.nodes.filter((node) => entityIds.has(node.id) && node.kind === 'ha_entity');
182
+ }
183
+ function inferRelation(source) {
184
+ const tags = source.tags.map((tag) => tag.toLowerCase());
185
+ const text = [source.sourceType, source.title, source.sourceUri, ...tags].join(' ').toLowerCase();
186
+ if (text.includes('receipt'))
187
+ return 'has_receipt';
188
+ if (text.includes('warranty'))
189
+ return 'has_warranty';
190
+ if (isManualLikeSource(source))
191
+ return 'has_manual';
192
+ return 'source_for';
193
+ }
194
+ function isManualLikeSource(source) {
195
+ const tags = source.tags.map((tag) => tag.toLowerCase());
196
+ const text = [source.sourceType, source.title, source.sourceUri, ...tags].join(' ').toLowerCase();
197
+ return source.sourceType === 'manual'
198
+ || tags.includes('manual')
199
+ || tags.includes('artifact')
200
+ || tags.includes('document')
201
+ || /\bmanual\b|\.pdf\b|owner.?s guide|user guide/.test(text);
202
+ }
203
+ function isIntegrationDocumentationSource(source) {
204
+ const tags = source.tags.map((tag) => tag.toLowerCase());
205
+ const kind = typeof source.metadata.homeGraphSourceKind === 'string'
206
+ ? source.metadata.homeGraphSourceKind.toLowerCase()
207
+ : '';
208
+ return tags.includes('integration') || tags.includes('documentation') || kind === 'documentation-candidate';
209
+ }
210
+ function tokenize(value) {
211
+ return uniqueStrings(value.toLowerCase().split(/[^a-z0-9_.:-]+/).filter((token) => token.length >= 2));
212
+ }
213
+ function isGenericToken(value) {
214
+ return GENERIC_TOKENS.has(value);
215
+ }
216
+ function includesIdentity(haystack, identity) {
217
+ const normalized = identity.trim().toLowerCase();
218
+ if (!normalized)
219
+ return false;
220
+ if (/^[a-z0-9_.:-]+$/.test(normalized)) {
221
+ return new RegExp(`(?:^|[^a-z0-9])${escapeRegExp(normalized)}(?:$|[^a-z0-9])`).test(haystack);
222
+ }
223
+ return haystack.includes(normalized);
224
+ }
225
+ function readString(value) {
226
+ if (typeof value === 'string') {
227
+ const trimmed = value.trim();
228
+ return trimmed.length > 0 ? trimmed : undefined;
229
+ }
230
+ if (typeof value === 'number' && Number.isFinite(value))
231
+ return String(value);
232
+ return undefined;
233
+ }
234
+ function escapeRegExp(value) {
235
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
236
+ }
@@ -0,0 +1,2 @@
1
+ export declare function isUnusableHomeGraphExtractionText(value: string | undefined): boolean;
2
+ //# sourceMappingURL=extraction-quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extraction-quality.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/extraction-quality.ts"],"names":[],"mappings":"AAAA,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAYpF"}
@@ -0,0 +1,52 @@
1
+ export function isUnusableHomeGraphExtractionText(value) {
2
+ const text = value?.trim() ?? '';
3
+ if (!text)
4
+ return true;
5
+ const normalized = text.toLowerCase();
6
+ if (normalized.includes('pdf extraction produced limited text')
7
+ || normalized.includes('no readable text streams')
8
+ || normalized.includes('no specialized extractor matched')
9
+ || normalized.includes('has no specialized in-core extractor')) {
10
+ return true;
11
+ }
12
+ if (looksLikeRawPdfPayload(text))
13
+ return true;
14
+ return looksBinaryLike(text);
15
+ }
16
+ function looksLikeRawPdfPayload(value) {
17
+ const lower = value.toLowerCase();
18
+ return lower.includes('%pdf')
19
+ || /\b\d+\s+\d+\s+obj\b/.test(lower)
20
+ || (lower.includes(' endobj') && lower.includes(' stream'))
21
+ || (lower.includes('/filter') && lower.includes('/flatedecode'));
22
+ }
23
+ function looksBinaryLike(value) {
24
+ const sample = value.slice(0, 4_096);
25
+ if (sample.length < 120)
26
+ return false;
27
+ let control = 0;
28
+ let extended = 0;
29
+ let letters = 0;
30
+ let whitespace = 0;
31
+ let punctuation = 0;
32
+ for (const char of sample) {
33
+ const code = char.charCodeAt(0);
34
+ if ((code < 32 && char !== '\n' && char !== '\r' && char !== '\t') || code === 65533)
35
+ control += 1;
36
+ if (code > 126)
37
+ extended += 1;
38
+ if (/[a-z0-9]/i.test(char))
39
+ letters += 1;
40
+ if (/\s/.test(char))
41
+ whitespace += 1;
42
+ if (/[^a-z0-9\s]/i.test(char))
43
+ punctuation += 1;
44
+ }
45
+ const length = sample.length;
46
+ const extendedRatio = extended / length;
47
+ const usefulRatio = (letters + whitespace) / length;
48
+ const punctuationRatio = punctuation / length;
49
+ return control > 0
50
+ || (extendedRatio > 0.18 && usefulRatio < 0.78)
51
+ || (punctuationRatio > 0.42 && whitespace / length < 0.08);
52
+ }
@@ -10,6 +10,7 @@ interface HomeGraphPageContext {
10
10
  export declare function generateAutomaticHomeGraphPages(context: HomeGraphPageContext & {
11
11
  readonly input: HomeGraphSnapshotInput;
12
12
  }): Promise<HomeGraphGeneratedPagesSummary>;
13
+ export declare function refreshAutomaticHomeGraphPages(context: HomeGraphPageContext): Promise<HomeGraphGeneratedPagesSummary>;
13
14
  export declare function refreshHomeGraphDevicePassport(context: HomeGraphPageContext & {
14
15
  readonly input: HomeGraphProjectionInput;
15
16
  }): Promise<HomeGraphDevicePassportResult & {
@@ -1 +1 @@
1
- {"version":3,"file":"generated-pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/generated-pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8BlD,OAAO,KAAK,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;CAAE,GACzE,OAAO,CAAC,8BAA8B,CAAC,CAoEzC;AAED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,6BAA6B,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CA0EhF;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAsC5E;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAyB5E"}
1
+ {"version":3,"file":"generated-pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/generated-pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AA8BlD,OAAO,KAAK,EACV,6BAA6B,EAC7B,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;CAAE,GACzE,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AAED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,8BAA8B,CAAC,CAEzC;AA2ED,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,6BAA6B,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CA0EhF;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAsC5E;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,oBAAoB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CAAE,GAC3E,OAAO,CAAC,yBAAyB,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAAE,CAAC,CAyB5E"}
@@ -3,13 +3,19 @@ import { HOME_GRAPH_CONNECTOR_ID, buildHomeGraphMetadata, edgeIsActive, homeGrap
3
3
  import { findHomeAssistantNode, missingDevicePassportFields, readHomeGraphState, renderHomeGraphState, safeHomeGraphFilename, sourcesLinkedToNode, } from './state.js';
4
4
  import { renderDevicePassportPage, renderPacketPage, renderRoomPage, } from './rendering.js';
5
5
  export async function generateAutomaticHomeGraphPages(context) {
6
- const options = context.input.pageAutomation ?? {};
6
+ return generateHomeGraphPagesForCurrentState(context, context.input.pageAutomation ?? {});
7
+ }
8
+ export async function refreshAutomaticHomeGraphPages(context) {
9
+ return generateHomeGraphPagesForCurrentState(context, {});
10
+ }
11
+ async function generateHomeGraphPagesForCurrentState(context, options) {
12
+ const effectiveOptions = options ?? {};
7
13
  const summary = createGeneratedPagesSummary();
8
- if (options.enabled === false)
14
+ if (effectiveOptions.enabled === false)
9
15
  return summary;
10
16
  const state = readHomeGraphState(context.store, context.spaceId);
11
- if (options.devicePassports !== false) {
12
- const devices = limitRecords(state.nodes.filter((node) => node.kind === 'ha_device' && node.status !== 'stale').sort(compareByTitle), options.maxDevicePassports);
17
+ if (effectiveOptions.devicePassports !== false) {
18
+ const devices = limitRecords(state.nodes.filter((node) => node.kind === 'ha_device' && node.status !== 'stale').sort(compareByTitle), effectiveOptions.maxDevicePassports);
13
19
  for (const device of devices) {
14
20
  const deviceId = readHomeAssistantObjectId(device, 'objectId', 'deviceId') ?? device.id;
15
21
  try {
@@ -36,10 +42,10 @@ export async function generateAutomaticHomeGraphPages(context) {
36
42
  }
37
43
  }
38
44
  }
39
- if (options.roomPages !== false) {
45
+ if (effectiveOptions.roomPages !== false) {
40
46
  const rooms = limitRecords(state.nodes
41
47
  .filter((node) => (node.kind === 'ha_area' || node.kind === 'ha_room') && node.status !== 'stale')
42
- .sort(compareByTitle), options.maxRoomPages);
48
+ .sort(compareByTitle), effectiveOptions.maxRoomPages);
43
49
  for (const room of rooms) {
44
50
  const areaId = readHomeAssistantObjectId(room, 'objectId', 'areaId') ?? room.id;
45
51
  try {
@@ -109,7 +115,7 @@ export async function refreshHomeGraphDevicePassport(context) {
109
115
  relation: 'source_for',
110
116
  metadata: buildHomeGraphMetadata(spaceId, installationId),
111
117
  });
112
- const markdown = renderDevicePassportPage({ spaceId, device, entities, sources, issues, missingFields });
118
+ const markdown = renderDevicePassportPage({ spaceId, device, entities, sources, extractions: state.extractions, issues, missingFields });
113
119
  const generated = await materializeGeneratedMarkdown({
114
120
  store,
115
121
  artifactStore,
@@ -147,7 +153,7 @@ export async function generateHomeGraphRoomPage(context) {
147
153
  const state = readHomeGraphState(store, spaceId);
148
154
  const areaId = input.areaId ?? input.roomId;
149
155
  const title = input.title ?? resolveRoomTitle(state.nodes, areaId) ?? 'Home Graph Room';
150
- const markdown = renderRoomPage({ ...state, title }, areaId);
156
+ const markdown = renderRoomPage({ ...state, title, extractions: state.extractions }, areaId);
151
157
  const filename = `${safeHomeGraphFilename(title)}.md`;
152
158
  const targetNode = areaId
153
159
  ? findHomeAssistantNode(state.nodes, 'ha_area', areaId) ?? findHomeAssistantNode(state.nodes, 'ha_room', areaId)
@@ -1,4 +1,4 @@
1
1
  export { HomeGraphService } from './service.js';
2
2
  export { HOME_GRAPH_NODE_KINDS, HOME_GRAPH_RELATIONS, } from './types.js';
3
- export type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphGeneratedPagesSummary, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphKnowledgeTarget, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapEdge, HomeGraphMapInput, HomeGraphMapNode, HomeGraphMapResult, HomeGraphNodeKind, HomeGraphObjectInput, HomeGraphObjectKind, HomeGraphPageAutomationOptions, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReindexResult, HomeGraphRelation, HomeGraphReviewInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult, } from './types.js';
3
+ export type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphGeneratedPagesSummary, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphKnowledgeTarget, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphMapEdge, HomeGraphMapHaFilterInput, HomeGraphMapInput, HomeGraphMapNode, HomeGraphMapResult, HomeGraphNodeKind, HomeGraphObjectInput, HomeGraphObjectKind, HomeGraphPageAutomationOptions, HomeGraphPageListResult, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReindexResult, HomeGraphRelation, HomeGraphReviewInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult, } from './types.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,6BAA6B,EAC7B,eAAe,EACf,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,6BAA6B,EAC7B,eAAe,EACf,8BAA8B,EAC9B,4BAA4B,EAC5B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,8BAA8B,EAC9B,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { ArtifactStore } from '../../artifacts/index.js';
2
+ import type { KnowledgeSourceRecord } from '../types.js';
3
+ import type { HomeGraphPageListResult } from './types.js';
4
+ export declare function listHomeGraphPages(input: {
5
+ readonly artifactStore: ArtifactStore;
6
+ readonly spaceId: string;
7
+ readonly sources: readonly KnowledgeSourceRecord[];
8
+ readonly limit: number;
9
+ readonly includeMarkdown: boolean;
10
+ }): Promise<HomeGraphPageListResult>;
11
+ //# sourceMappingURL=pages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/pages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA0BnC"}
@@ -0,0 +1,44 @@
1
+ import { isGeneratedPageSource } from './helpers.js';
2
+ export async function listHomeGraphPages(input) {
3
+ const pages = [];
4
+ const sources = input.sources
5
+ .filter(isGeneratedPageSource)
6
+ .sort(compareGeneratedPages)
7
+ .slice(0, input.limit);
8
+ for (const source of sources) {
9
+ const artifact = typeof source.artifactId === 'string' ? input.artifactStore.get(source.artifactId) : undefined;
10
+ const markdown = input.includeMarkdown && artifact
11
+ ? await readMarkdown(input.artifactStore, artifact.id)
12
+ : undefined;
13
+ pages.push({
14
+ source,
15
+ ...(artifact ? {
16
+ artifact: {
17
+ id: artifact.id,
18
+ mimeType: artifact.mimeType,
19
+ filename: artifact.filename,
20
+ createdAt: artifact.createdAt,
21
+ metadata: artifact.metadata,
22
+ },
23
+ } : {}),
24
+ ...(markdown ? { markdown } : {}),
25
+ });
26
+ }
27
+ return { ok: true, spaceId: input.spaceId, pages };
28
+ }
29
+ function compareGeneratedPages(left, right) {
30
+ const leftKind = typeof left.metadata.projectionKind === 'string' ? left.metadata.projectionKind : '';
31
+ const rightKind = typeof right.metadata.projectionKind === 'string' ? right.metadata.projectionKind : '';
32
+ return leftKind.localeCompare(rightKind)
33
+ || (left.title ?? left.id).localeCompare(right.title ?? right.id)
34
+ || left.id.localeCompare(right.id);
35
+ }
36
+ async function readMarkdown(artifactStore, artifactId) {
37
+ try {
38
+ const { buffer } = await artifactStore.readContent(artifactId);
39
+ return buffer.toString('utf-8');
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
@@ -1,5 +1,5 @@
1
- import type { KnowledgeEdgeRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
2
- import type { HomeGraphMapResult } from './types.js';
1
+ import type { KnowledgeEdgeRecord, KnowledgeExtractionRecord, KnowledgeIssueRecord, KnowledgeNodeRecord, KnowledgeSourceRecord } from '../types.js';
2
+ import type { HomeGraphMapInput, HomeGraphMapResult } from './types.js';
3
3
  export interface HomeGraphRenderState {
4
4
  readonly spaceId: string;
5
5
  readonly title: 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,6 +15,7 @@ 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[];
19
21
  }): string;
@@ -23,8 +25,5 @@ export declare function renderPacketPage(state: HomeGraphRenderState, options?:
23
25
  readonly includeFields?: readonly string[];
24
26
  readonly excludeFields?: readonly string[];
25
27
  }): string;
26
- export declare function renderHomeGraphMap(state: HomeGraphRenderState, options?: {
27
- readonly limit?: number;
28
- readonly includeSources?: boolean;
29
- }): HomeGraphMapResult;
28
+ export declare function renderHomeGraphMap(state: HomeGraphRenderState, options?: HomeGraphMapInput): HomeGraphMapResult;
30
29
  //# sourceMappingURL=rendering.d.ts.map
@@ -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,EACpB,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAGrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,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;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,kBAAkB,CAM1B"}
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,CAiDnF;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;CAC3C,GAAG,MAAM,CA8BT;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"}