@pellux/goodvibes-sdk 0.28.21 → 0.28.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/contracts/artifacts/operator-contract.json +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.js +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +1 -1
- package/dist/_internal/platform/knowledge/home-graph/ask-page-refresh.d.ts.map +1 -1
- package/dist/_internal/platform/knowledge/home-graph/ask-page-refresh.js +140 -1
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Synced from packages/contracts/src/generated/foundation-metadata.ts
|
|
2
2
|
export const FOUNDATION_METADATA = {
|
|
3
3
|
"productId": "goodvibes",
|
|
4
|
-
"productVersion": "0.28.
|
|
4
|
+
"productVersion": "0.28.22",
|
|
5
5
|
"operatorMethodCount": 265,
|
|
6
6
|
"operatorEventCount": 30,
|
|
7
7
|
"peerEndpointCount": 6
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask-page-refresh.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/ask-page-refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ask-page-refresh.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/home-graph/ask-page-refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,wBAAsB,iCAAiC,CAAC,KAAK,EAAE;IAC7D,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;IAChC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC,GAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAmCvE"}
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isUsefulHomeGraphPageFact } from '../semantic/fact-quality.js';
|
|
2
|
+
import { buildHomeGraphMetadata, isGeneratedPageSource, readRecord } from './helpers.js';
|
|
2
3
|
import { refreshHomeGraphDevicePassport } from './generated-pages.js';
|
|
3
4
|
export async function refreshDevicePagesForHomeGraphAsk(input) {
|
|
4
5
|
if ((input.answer.answer.facts?.length ?? 0) === 0 && input.answer.answer.sources.length === 0)
|
|
5
6
|
return { requested: false, refreshed: 0 };
|
|
6
7
|
const devices = input.answer.answer.linkedObjects.filter((node) => node.kind === 'ha_device').slice(0, 2);
|
|
8
|
+
try {
|
|
9
|
+
await persistAnswerFactSubjectLinks({
|
|
10
|
+
store: input.store,
|
|
11
|
+
spaceId: input.spaceId,
|
|
12
|
+
installationId: input.installationId,
|
|
13
|
+
devices,
|
|
14
|
+
facts: input.answer.answer.facts ?? [],
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Ask should still return even if page enrichment bookkeeping fails.
|
|
19
|
+
}
|
|
7
20
|
let refreshed = 0;
|
|
8
21
|
for (const device of devices) {
|
|
9
22
|
const deviceId = readHomeAssistantObjectId(device) ?? device.id;
|
|
@@ -27,8 +40,134 @@ export async function refreshDevicePagesForHomeGraphAsk(input) {
|
|
|
27
40
|
}
|
|
28
41
|
return { requested: devices.length > 0, refreshed };
|
|
29
42
|
}
|
|
43
|
+
async function persistAnswerFactSubjectLinks(input) {
|
|
44
|
+
if (input.devices.length === 0 || input.facts.length === 0)
|
|
45
|
+
return;
|
|
46
|
+
const devicesById = new Map(input.devices.map((device) => [device.id, device]));
|
|
47
|
+
for (const fact of input.facts) {
|
|
48
|
+
if (!isUsefulHomeGraphPageFact(fact) || !fact.sourceId)
|
|
49
|
+
continue;
|
|
50
|
+
const source = input.store.getSource(fact.sourceId);
|
|
51
|
+
if (!source || source.status === 'stale' || isGeneratedPageSource(source))
|
|
52
|
+
continue;
|
|
53
|
+
const targets = answerFactTargetDevices(fact, devicesById);
|
|
54
|
+
if (targets.length === 0)
|
|
55
|
+
continue;
|
|
56
|
+
const existing = input.store.getNode(fact.id) ?? fact;
|
|
57
|
+
const sourceId = existing.sourceId ?? fact.sourceId;
|
|
58
|
+
const subjectIds = uniqueStrings([
|
|
59
|
+
...readStringArray(existing.metadata.subjectIds),
|
|
60
|
+
...readStringArray(existing.metadata.linkedObjectIds),
|
|
61
|
+
...targets.map((device) => device.id),
|
|
62
|
+
]).filter((id) => devicesById.has(id));
|
|
63
|
+
const targetHints = uniqueTargetHints([
|
|
64
|
+
...targets.map((device) => ({
|
|
65
|
+
id: device.id,
|
|
66
|
+
kind: device.kind,
|
|
67
|
+
title: device.title,
|
|
68
|
+
...(device.summary ? { summary: device.summary } : {}),
|
|
69
|
+
})),
|
|
70
|
+
...readTargetHints(existing.metadata.targetHints),
|
|
71
|
+
]).filter((hint) => devicesById.has(readString(hint.id) ?? ''));
|
|
72
|
+
const updatedFact = await input.store.upsertNode({
|
|
73
|
+
id: existing.id,
|
|
74
|
+
kind: existing.kind,
|
|
75
|
+
slug: existing.slug,
|
|
76
|
+
title: existing.title,
|
|
77
|
+
...(existing.summary ? { summary: existing.summary } : {}),
|
|
78
|
+
aliases: existing.aliases,
|
|
79
|
+
status: existing.status,
|
|
80
|
+
confidence: existing.confidence,
|
|
81
|
+
...(sourceId ? { sourceId } : {}),
|
|
82
|
+
metadata: buildHomeGraphMetadata(input.spaceId, input.installationId, {
|
|
83
|
+
...existing.metadata,
|
|
84
|
+
semanticKind: 'fact',
|
|
85
|
+
subject: targets[0]?.title,
|
|
86
|
+
subjectIds,
|
|
87
|
+
linkedObjectIds: subjectIds,
|
|
88
|
+
targetHints,
|
|
89
|
+
sourceId,
|
|
90
|
+
linkedBy: 'homegraph-ask-page-refresh',
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
await input.store.upsertEdge({
|
|
94
|
+
fromKind: 'source',
|
|
95
|
+
fromId: source.id,
|
|
96
|
+
toKind: 'node',
|
|
97
|
+
toId: updatedFact.id,
|
|
98
|
+
relation: 'supports_fact',
|
|
99
|
+
weight: 0.82,
|
|
100
|
+
metadata: buildHomeGraphMetadata(input.spaceId, input.installationId, {
|
|
101
|
+
linkedBy: 'homegraph-ask-page-refresh',
|
|
102
|
+
}),
|
|
103
|
+
});
|
|
104
|
+
for (const device of targets) {
|
|
105
|
+
await input.store.upsertEdge({
|
|
106
|
+
fromKind: 'node',
|
|
107
|
+
fromId: updatedFact.id,
|
|
108
|
+
toKind: 'node',
|
|
109
|
+
toId: device.id,
|
|
110
|
+
relation: 'describes',
|
|
111
|
+
weight: 0.8,
|
|
112
|
+
metadata: buildHomeGraphMetadata(input.spaceId, input.installationId, {
|
|
113
|
+
linkedBy: 'homegraph-ask-page-refresh',
|
|
114
|
+
sourceId: source.id,
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function answerFactTargetDevices(fact, devicesById) {
|
|
121
|
+
const ids = uniqueStrings([
|
|
122
|
+
...readStringArray(fact.linkedObjectIds),
|
|
123
|
+
...readStringArray(fact.subjectIds),
|
|
124
|
+
...readStringArray(fact.metadata.linkedObjectIds),
|
|
125
|
+
...readStringArray(fact.metadata.subjectIds),
|
|
126
|
+
]);
|
|
127
|
+
const explicit = ids.map((id) => devicesById.get(id)).filter((device) => Boolean(device));
|
|
128
|
+
if (explicit.length > 0)
|
|
129
|
+
return explicit;
|
|
130
|
+
return devicesById.size === 1 ? [...devicesById.values()] : [];
|
|
131
|
+
}
|
|
30
132
|
function readHomeAssistantObjectId(node) {
|
|
31
133
|
const homeAssistant = readRecord(node.metadata.homeAssistant);
|
|
32
134
|
const value = homeAssistant.objectId ?? homeAssistant.deviceId;
|
|
33
135
|
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
34
136
|
}
|
|
137
|
+
function readString(value) {
|
|
138
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
139
|
+
}
|
|
140
|
+
function readStringArray(value) {
|
|
141
|
+
if (!Array.isArray(value))
|
|
142
|
+
return [];
|
|
143
|
+
return value.map((entry) => readString(entry)).filter((entry) => Boolean(entry));
|
|
144
|
+
}
|
|
145
|
+
function readTargetHints(value) {
|
|
146
|
+
if (!Array.isArray(value))
|
|
147
|
+
return [];
|
|
148
|
+
return value.filter((entry) => Boolean(entry && typeof entry === 'object' && !Array.isArray(entry)));
|
|
149
|
+
}
|
|
150
|
+
function uniqueStrings(values) {
|
|
151
|
+
const seen = new Set();
|
|
152
|
+
const result = [];
|
|
153
|
+
for (const value of values) {
|
|
154
|
+
const trimmed = typeof value === 'string' ? value.trim() : '';
|
|
155
|
+
if (!trimmed || seen.has(trimmed))
|
|
156
|
+
continue;
|
|
157
|
+
seen.add(trimmed);
|
|
158
|
+
result.push(trimmed);
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
function uniqueTargetHints(values) {
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
const result = [];
|
|
165
|
+
for (const value of values) {
|
|
166
|
+
const id = readString(value.id);
|
|
167
|
+
if (!id || seen.has(id))
|
|
168
|
+
continue;
|
|
169
|
+
seen.add(id);
|
|
170
|
+
result.push(value);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
let version = '0.28.
|
|
3
|
+
let version = '0.28.22';
|
|
4
4
|
try {
|
|
5
5
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
|
|
6
6
|
version = pkg.version ?? version;
|