@pellux/goodvibes-sdk 0.26.7 → 0.26.9

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 (65) hide show
  1. package/dist/_internal/contracts/artifacts/operator-contract.json +400 -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 +400 -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/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 +27 -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 +3 -0
  19. package/dist/_internal/platform/control-plane/method-catalog-knowledge.d.ts.map +1 -1
  20. package/dist/_internal/platform/control-plane/method-catalog-knowledge.js +18 -2
  21. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts +1 -0
  22. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.d.ts.map +1 -1
  23. package/dist/_internal/platform/control-plane/operator-contract-schemas-knowledge.js +8 -0
  24. package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
  25. package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
  26. package/dist/_internal/platform/control-plane/routes/operator.js +3 -0
  27. package/dist/_internal/platform/daemon/http/router-route-contexts.d.ts.map +1 -1
  28. package/dist/_internal/platform/daemon/http/router-route-contexts.js +1 -0
  29. package/dist/_internal/platform/knowledge/home-graph/documentation.d.ts +5 -0
  30. package/dist/_internal/platform/knowledge/home-graph/documentation.d.ts.map +1 -0
  31. package/dist/_internal/platform/knowledge/home-graph/documentation.js +80 -0
  32. package/dist/_internal/platform/knowledge/home-graph/quality.d.ts +5 -0
  33. package/dist/_internal/platform/knowledge/home-graph/quality.d.ts.map +1 -0
  34. package/dist/_internal/platform/knowledge/home-graph/quality.js +278 -0
  35. package/dist/_internal/platform/knowledge/home-graph/review.d.ts +14 -0
  36. package/dist/_internal/platform/knowledge/home-graph/review.d.ts.map +1 -0
  37. package/dist/_internal/platform/knowledge/home-graph/review.js +183 -0
  38. package/dist/_internal/platform/knowledge/home-graph/search.d.ts +1 -1
  39. package/dist/_internal/platform/knowledge/home-graph/search.d.ts.map +1 -1
  40. package/dist/_internal/platform/knowledge/home-graph/search.js +310 -25
  41. package/dist/_internal/platform/knowledge/home-graph/service.d.ts +2 -7
  42. package/dist/_internal/platform/knowledge/home-graph/service.d.ts.map +1 -1
  43. package/dist/_internal/platform/knowledge/home-graph/service.js +11 -83
  44. package/dist/_internal/platform/knowledge/home-graph/state.d.ts +2 -0
  45. package/dist/_internal/platform/knowledge/home-graph/state.d.ts.map +1 -1
  46. package/dist/_internal/platform/knowledge/home-graph/state.js +1 -1
  47. package/dist/_internal/platform/knowledge/home-graph/types.d.ts +2 -1
  48. package/dist/_internal/platform/knowledge/home-graph/types.d.ts.map +1 -1
  49. package/dist/_internal/platform/knowledge/home-graph/types.js +17 -1
  50. package/dist/_internal/platform/knowledge/knowledge-api.d.ts +2 -0
  51. package/dist/_internal/platform/knowledge/knowledge-api.d.ts.map +1 -1
  52. package/dist/_internal/platform/knowledge/knowledge-api.js +1 -0
  53. package/dist/_internal/platform/knowledge/review.d.ts +19 -0
  54. package/dist/_internal/platform/knowledge/review.d.ts.map +1 -0
  55. package/dist/_internal/platform/knowledge/review.js +117 -0
  56. package/dist/_internal/platform/knowledge/service.d.ts +2 -0
  57. package/dist/_internal/platform/knowledge/service.d.ts.map +1 -1
  58. package/dist/_internal/platform/knowledge/service.js +4 -0
  59. package/dist/_internal/platform/knowledge/store-schema.d.ts +2 -1
  60. package/dist/_internal/platform/knowledge/store-schema.d.ts.map +1 -1
  61. package/dist/_internal/platform/knowledge/store-schema.js +9 -0
  62. package/dist/_internal/platform/knowledge/store.d.ts.map +1 -1
  63. package/dist/_internal/platform/knowledge/store.js +14 -10
  64. package/dist/_internal/platform/version.js +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,183 @@
1
+ import { belongsToSpace, buildHomeGraphMetadata, readRecord } from './helpers.js';
2
+ export async function reviewHomeGraphFact(store, spaceId, installationId, input) {
3
+ const reviewedAt = Date.now();
4
+ if (input.issueId) {
5
+ const issue = store.getIssue(input.issueId);
6
+ if (!issue || !belongsToSpace(issue, spaceId))
7
+ throw new Error(`Unknown Home Graph issue: ${input.issueId}`);
8
+ const subjectNode = issue.nodeId ? store.getNode(issue.nodeId) : null;
9
+ const appliedFacts = await applyHomeGraphReviewFacts(store, spaceId, issue, subjectNode, input);
10
+ const suppression = buildSuppression(input, issue, reviewedAt);
11
+ const updatedIssue = await store.upsertIssue({
12
+ id: issue.id,
13
+ severity: issue.severity,
14
+ code: issue.code,
15
+ message: issue.message,
16
+ status: issueStatusForAction(input.action, issue.status),
17
+ sourceId: issue.sourceId,
18
+ nodeId: issue.nodeId,
19
+ metadata: buildHomeGraphMetadata(spaceId, installationId, {
20
+ review: reviewMetadata(input, reviewedAt),
21
+ ...(suppression ? { suppression } : {}),
22
+ }),
23
+ });
24
+ const node = appliedFacts?.node ?? subjectNode ?? undefined;
25
+ return {
26
+ ok: true,
27
+ spaceId,
28
+ issue: updatedIssue,
29
+ ...(node ? { node } : {}),
30
+ ...(suppression ? { suppression } : {}),
31
+ ...(appliedFacts?.facts ? { appliedFacts: appliedFacts.facts } : {}),
32
+ };
33
+ }
34
+ if (input.nodeId) {
35
+ const node = store.getNode(input.nodeId);
36
+ if (!node || !belongsToSpace(node, spaceId))
37
+ throw new Error(`Unknown Home Graph node: ${input.nodeId}`);
38
+ const facts = normalizeReviewFacts(input);
39
+ const updated = await store.upsertNode({
40
+ id: node.id,
41
+ kind: node.kind,
42
+ slug: node.slug,
43
+ title: node.title,
44
+ summary: node.summary,
45
+ aliases: node.aliases,
46
+ status: input.action === 'forget' ? 'stale' : node.status,
47
+ confidence: input.action === 'accept' ? 100 : node.confidence,
48
+ sourceId: node.sourceId,
49
+ metadata: buildHomeGraphMetadata(spaceId, installationId, {
50
+ ...facts,
51
+ review: reviewMetadata(input, reviewedAt),
52
+ }),
53
+ });
54
+ return { ok: true, spaceId, node: updated, ...(Object.keys(facts).length > 0 ? { appliedFacts: facts } : {}) };
55
+ }
56
+ if (input.sourceId) {
57
+ const source = store.getSource(input.sourceId);
58
+ if (!source || !belongsToSpace(source, spaceId))
59
+ throw new Error(`Unknown Home Graph source: ${input.sourceId}`);
60
+ const updated = await store.upsertSource({
61
+ id: source.id,
62
+ connectorId: source.connectorId,
63
+ sourceType: source.sourceType,
64
+ title: source.title,
65
+ sourceUri: source.sourceUri,
66
+ canonicalUri: source.canonicalUri,
67
+ summary: source.summary,
68
+ description: source.description,
69
+ tags: source.tags,
70
+ folderPath: source.folderPath,
71
+ status: input.action === 'forget' ? 'stale' : source.status,
72
+ artifactId: source.artifactId,
73
+ contentHash: source.contentHash,
74
+ lastCrawledAt: source.lastCrawledAt,
75
+ crawlError: source.crawlError,
76
+ sessionId: source.sessionId,
77
+ metadata: buildHomeGraphMetadata(spaceId, installationId, {
78
+ review: reviewMetadata(input, reviewedAt),
79
+ }),
80
+ });
81
+ return { ok: true, spaceId, source: updated };
82
+ }
83
+ throw new Error('reviewFact requires issueId, nodeId, or sourceId.');
84
+ }
85
+ async function applyHomeGraphReviewFacts(store, spaceId, issue, node, input) {
86
+ if (!node || !belongsToSpace(node, spaceId))
87
+ return undefined;
88
+ const facts = deriveIssueFacts(issue, input);
89
+ if (Object.keys(facts).length === 0)
90
+ return undefined;
91
+ const updated = await store.upsertNode({
92
+ id: node.id,
93
+ kind: node.kind,
94
+ slug: node.slug,
95
+ title: node.title,
96
+ summary: node.summary,
97
+ aliases: node.aliases,
98
+ status: node.status,
99
+ confidence: Math.max(node.confidence, input.action === 'accept' ? 100 : node.confidence),
100
+ sourceId: node.sourceId,
101
+ metadata: facts,
102
+ });
103
+ return { node: updated, facts };
104
+ }
105
+ function deriveIssueFacts(issue, input) {
106
+ const facts = normalizeReviewFacts(input);
107
+ if (issue.code === 'homegraph.device.unknown_battery') {
108
+ const category = readCategory(input);
109
+ const batteryType = readString(facts.batteryType);
110
+ if (batteryType && batteryType !== 'none' && typeof facts.batteryPowered !== 'boolean') {
111
+ return { ...facts, batteryPowered: true };
112
+ }
113
+ if (facts.batteryPowered === false && !batteryType) {
114
+ return { ...facts, batteryType: 'none' };
115
+ }
116
+ if (Object.keys(facts).length > 0)
117
+ return facts;
118
+ if (input.action === 'reject' || input.action === 'resolve' || category === 'not_applicable') {
119
+ return { batteryPowered: false, batteryType: 'none' };
120
+ }
121
+ }
122
+ if (issue.code === 'homegraph.device.missing_manual') {
123
+ const category = readCategory(input);
124
+ if (Object.keys(facts).length > 0)
125
+ return facts;
126
+ if (input.action === 'reject' || input.action === 'resolve' || category === 'not_applicable') {
127
+ return { manualRequired: false };
128
+ }
129
+ }
130
+ return facts;
131
+ }
132
+ function normalizeReviewFacts(input) {
133
+ const value = readRecord(input.value);
134
+ const fact = readRecord(value.fact);
135
+ const source = Object.keys(fact).length > 0 ? fact : value;
136
+ const allowed = {};
137
+ for (const key of [
138
+ 'batteryPowered',
139
+ 'batteryType',
140
+ 'manualRequired',
141
+ 'manufacturer',
142
+ 'model',
143
+ 'serial',
144
+ 'firmware',
145
+ 'installDate',
146
+ 'purchaseDate',
147
+ 'warrantyExpiration',
148
+ ]) {
149
+ if (key in source)
150
+ allowed[key] = source[key];
151
+ }
152
+ return allowed;
153
+ }
154
+ function reviewMetadata(input, reviewedAt) {
155
+ return {
156
+ action: input.action,
157
+ reviewer: input.reviewer ?? 'homeassistant',
158
+ reviewedAt,
159
+ ...(input.value ? { value: input.value } : {}),
160
+ };
161
+ }
162
+ function buildSuppression(input, issue, reviewedAt) {
163
+ if (!['accept', 'reject', 'resolve'].includes(input.action))
164
+ return undefined;
165
+ return {
166
+ suppressed: true,
167
+ action: input.action,
168
+ reviewedAt,
169
+ reviewer: input.reviewer ?? 'homeassistant',
170
+ issueId: issue.id,
171
+ code: issue.code,
172
+ subjectId: issue.metadata.subjectId ?? issue.nodeId ?? issue.sourceId ?? issue.id,
173
+ };
174
+ }
175
+ function issueStatusForAction(action, current) {
176
+ return action === 'reject' || action === 'resolve' || action === 'accept' ? 'resolved' : current;
177
+ }
178
+ function readCategory(input) {
179
+ return readString(readRecord(input.value).category)?.toLowerCase().replace(/[-\s]+/g, '_');
180
+ }
181
+ function readString(value) {
182
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
183
+ }
@@ -9,5 +9,5 @@ export interface HomeGraphSearchState {
9
9
  readonly extractionBySourceId: ReadonlyMap<string, KnowledgeExtractionRecord>;
10
10
  }
11
11
  export declare function readHomeGraphSearchState(store: KnowledgeStore, spaceId: string): HomeGraphSearchState;
12
- export declare function scoreHomeGraphResults(query: string, sources: readonly KnowledgeSourceRecord[], nodes: readonly KnowledgeNodeRecord[], extractionBySourceId: (sourceId: string) => KnowledgeExtractionRecord | null | undefined, limit: number): HomeGraphSearchResult[];
12
+ export declare function scoreHomeGraphResults(query: string, sources: readonly KnowledgeSourceRecord[], nodes: readonly KnowledgeNodeRecord[], edges: readonly KnowledgeEdgeRecord[], extractionBySourceId: (sourceId: string) => KnowledgeExtractionRecord | null | undefined, limit: number): HomeGraphSearchResult[];
13
13
  //# sourceMappingURL=search.d.ts.map
@@ -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;AAMxD,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,CAqBrG;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,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,CA+CzB"}
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;AA6DxD,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,CAqBrG;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,CA+DzB"}
@@ -2,6 +2,58 @@ import { belongsToSpace, edgeIsActive, readRecord } from './helpers.js';
2
2
  const MAX_FIELD_CHARS = 4_096;
3
3
  const MAX_SECTION_COUNT = 32;
4
4
  const MAX_SEARCH_TEXT_CHARS = 64 * 1024;
5
+ const MAX_ANSWER_EXCERPT_CHARS = 640;
6
+ const ANCHOR_SCOPE_LIMIT = 5;
7
+ const STOPWORDS = new Set([
8
+ 'a',
9
+ 'about',
10
+ 'all',
11
+ 'an',
12
+ 'and',
13
+ 'are',
14
+ 'as',
15
+ 'at',
16
+ 'available',
17
+ 'be',
18
+ 'can',
19
+ 'could',
20
+ 'do',
21
+ 'does',
22
+ 'for',
23
+ 'from',
24
+ 'has',
25
+ 'have',
26
+ 'how',
27
+ 'i',
28
+ 'in',
29
+ 'is',
30
+ 'it',
31
+ 'me',
32
+ 'my',
33
+ 'of',
34
+ 'on',
35
+ 'or',
36
+ 'our',
37
+ 'show',
38
+ 'tell',
39
+ 'that',
40
+ 'the',
41
+ 'this',
42
+ 'to',
43
+ 'use',
44
+ 'what',
45
+ 'which',
46
+ 'with',
47
+ ]);
48
+ const SHORT_MEANINGFUL_TOKENS = new Set(['ac', 'av', 'dc', 'ha', 'ip', 'ir', 'lg', 'pc', 'tv']);
49
+ const QUERY_EXPANSIONS = {
50
+ capability: ['capabilities', 'feature', 'features', 'function', 'functions', 'mode', 'modes', 'spec', 'specs', 'support', 'supports'],
51
+ capabilities: ['capability', 'feature', 'features', 'function', 'functions', 'mode', 'modes', 'spec', 'specs', 'support', 'supports'],
52
+ feature: ['features', 'capability', 'capabilities', 'function', 'functions', 'mode', 'modes', 'spec', 'specs', 'support', 'supports'],
53
+ features: ['feature', 'capability', 'capabilities', 'function', 'functions', 'mode', 'modes', 'spec', 'specs', 'support', 'supports'],
54
+ television: ['tv', 'media_player'],
55
+ tv: ['television', 'media_player'],
56
+ };
5
57
  export function readHomeGraphSearchState(store, spaceId) {
6
58
  const sources = store.listSources(10_000).filter((source) => belongsToSpace(source, spaceId));
7
59
  const nodes = store.listNodes(10_000).filter((node) => belongsToSpace(node, spaceId));
@@ -23,54 +75,81 @@ export function readHomeGraphSearchState(store, spaceId) {
23
75
  }
24
76
  return { spaceId, sources, nodes, edges, extractionBySourceId };
25
77
  }
26
- export function scoreHomeGraphResults(query, sources, nodes, extractionBySourceId, limit) {
27
- const tokens = tokenize(query);
78
+ export function scoreHomeGraphResults(query, sources, nodes, edges, extractionBySourceId, limit) {
79
+ const tokens = tokenizeQuery(query);
28
80
  if (tokens.length === 0)
29
81
  return [];
82
+ const expandedTokens = expandTokens(tokens);
83
+ const anchors = selectAnchorNodes(tokens, nodes);
84
+ const anchorIds = new Set(anchors.map((anchor) => anchor.node.id));
85
+ const sourceLinks = buildSourceLinkIndex(edges);
86
+ const useAnchorScope = anchors.length > 0 && anchors.length <= ANCHOR_SCOPE_LIMIT;
30
87
  const sourceResults = sources.map((source) => {
31
88
  const extraction = extractionBySourceId(source.id);
32
- const baseScore = scoreFields(tokens, [
89
+ if (isPendingDocumentationCandidate(source, extraction)) {
90
+ return sourceResult(source, extraction, 0);
91
+ }
92
+ const linkedNodeIds = sourceLinks.get(source.id) ?? new Set();
93
+ const linkedToAnchor = useAnchorScope && intersects(linkedNodeIds, anchorIds);
94
+ const identityScore = scoreFields(tokens, [
33
95
  source.title,
34
96
  source.summary,
35
97
  source.description,
36
98
  source.sourceUri,
37
99
  source.canonicalUri,
38
100
  source.tags.join(' '),
101
+ ]);
102
+ const contentScore = scoreFields(expandedTokens, [
39
103
  extraction?.title,
40
104
  extraction?.summary,
41
105
  extraction?.excerpt,
42
106
  readSearchText(extraction),
43
107
  ...limitedSections(extraction),
44
108
  ]);
45
- return {
46
- kind: 'source',
47
- id: source.id,
48
- score: baseScore > 0 ? baseScore + (extraction ? 8 : 0) : 0,
49
- title: source.title ?? source.sourceUri ?? source.id,
50
- summary: extraction?.summary ?? source.summary,
51
- source,
52
- };
109
+ const baseScore = identityScore + contentScore;
110
+ const linkBoost = linkedToAnchor ? 120 + relationBoost(source.id, anchorIds, edges) : 0;
111
+ const indexedBoost = source.status === 'indexed' ? 18 : source.status === 'stale' ? 6 : 0;
112
+ const extractionBoost = extraction ? 20 : 0;
113
+ const score = baseScore > 0 || linkBoost > 0
114
+ ? baseScore + linkBoost + indexedBoost + extractionBoost
115
+ : 0;
116
+ return sourceResult(source, extraction, score, selectRelevantExcerpt(expandedTokens, source, extraction));
53
117
  });
54
118
  const nodeResults = nodes.map((node) => {
55
- const baseScore = scoreFields(tokens, [
56
- node.title,
57
- node.summary,
58
- node.aliases.join(' '),
59
- readNodeMetadataText(node),
60
- ]);
119
+ const baseScore = scoreFields(tokens, nodeIdentityFields(node));
120
+ const anchorBoost = anchorIds.has(node.id) ? 40 + nodeKindBoost(node.kind) : 0;
61
121
  return {
62
122
  kind: 'node',
63
123
  id: node.id,
64
- score: baseScore > 0 ? baseScore + Math.round(node.confidence / 20) : 0,
124
+ score: baseScore > 0 ? baseScore + anchorBoost + Math.round(node.confidence / 20) : 0,
65
125
  title: node.title,
66
126
  summary: node.summary,
127
+ excerpt: node.summary,
67
128
  node,
68
129
  };
69
130
  });
70
- return [...sourceResults, ...nodeResults]
131
+ let results = [...sourceResults, ...nodeResults]
71
132
  .filter((entry) => entry.score > 0)
72
- .sort((a, b) => b.score - a.score || a.id.localeCompare(b.id))
73
- .slice(0, Math.max(1, limit));
133
+ .sort(compareHomeGraphResults);
134
+ const anchoredSourceResults = useAnchorScope
135
+ ? results.filter((result) => result.source && intersects(sourceLinks.get(result.source.id) ?? new Set(), anchorIds))
136
+ : [];
137
+ if (anchoredSourceResults.length > 0) {
138
+ results = anchoredSourceResults.sort(compareHomeGraphResults);
139
+ }
140
+ const strongResults = pruneWeakTokenCoverage(results, tokens);
141
+ return strongResults.slice(0, Math.max(1, limit));
142
+ }
143
+ function sourceResult(source, extraction, score, excerpt) {
144
+ return {
145
+ kind: 'source',
146
+ id: source.id,
147
+ score,
148
+ title: source.title ?? source.sourceUri ?? source.id,
149
+ summary: extraction?.summary ?? source.summary,
150
+ ...(excerpt ? { excerpt } : {}),
151
+ source,
152
+ };
74
153
  }
75
154
  function limitedSections(extraction) {
76
155
  if (!extraction)
@@ -103,6 +182,168 @@ function readNodeMetadataText(node) {
103
182
  ].filter((value) => typeof value === 'string' && value.trim().length > 0);
104
183
  return values.length > 0 ? values.join(' ') : undefined;
105
184
  }
185
+ function nodeIdentityFields(node) {
186
+ return [
187
+ node.title,
188
+ node.summary,
189
+ node.aliases.join(' '),
190
+ readNodeMetadataText(node),
191
+ ].filter((value) => typeof value === 'string' && value.trim().length > 0);
192
+ }
193
+ function selectAnchorNodes(tokens, nodes) {
194
+ return nodes.map((node) => {
195
+ const baseScore = scoreFields(tokens, nodeIdentityFields(node));
196
+ return {
197
+ node,
198
+ score: baseScore > 0 ? baseScore + nodeKindBoost(node.kind) : 0,
199
+ };
200
+ })
201
+ .filter((entry) => entry.score >= 10)
202
+ .sort((a, b) => b.score - a.score || a.node.id.localeCompare(b.node.id))
203
+ .slice(0, 12);
204
+ }
205
+ function buildSourceLinkIndex(edges) {
206
+ const links = new Map();
207
+ for (const edge of edges) {
208
+ if (edge.fromKind === 'source' && edge.toKind === 'node') {
209
+ addSourceLink(links, edge.fromId, edge.toId);
210
+ }
211
+ else if (edge.fromKind === 'node' && edge.toKind === 'source') {
212
+ addSourceLink(links, edge.toId, edge.fromId);
213
+ }
214
+ }
215
+ return links;
216
+ }
217
+ function addSourceLink(links, sourceId, nodeId) {
218
+ const current = links.get(sourceId) ?? new Set();
219
+ current.add(nodeId);
220
+ links.set(sourceId, current);
221
+ }
222
+ function relationBoost(sourceId, anchorIds, edges) {
223
+ let boost = 0;
224
+ for (const edge of edges) {
225
+ const connectsAnchor = (edge.fromKind === 'source' && edge.fromId === sourceId && edge.toKind === 'node' && anchorIds.has(edge.toId))
226
+ || (edge.fromKind === 'node' && anchorIds.has(edge.fromId) && edge.toKind === 'source' && edge.toId === sourceId);
227
+ if (!connectsAnchor)
228
+ continue;
229
+ if (edge.relation === 'has_manual')
230
+ boost = Math.max(boost, 45);
231
+ else if (edge.relation === 'source_for')
232
+ boost = Math.max(boost, 25);
233
+ else
234
+ boost = Math.max(boost, 15);
235
+ }
236
+ return boost;
237
+ }
238
+ function nodeKindBoost(kind) {
239
+ switch (kind) {
240
+ case 'ha_device':
241
+ case 'ha_entity':
242
+ return 20;
243
+ case 'ha_area':
244
+ case 'ha_room':
245
+ case 'ha_automation':
246
+ case 'ha_script':
247
+ case 'ha_scene':
248
+ return 12;
249
+ case 'ha_integration':
250
+ return 6;
251
+ default:
252
+ return 0;
253
+ }
254
+ }
255
+ function intersects(left, right) {
256
+ for (const value of left) {
257
+ if (right.has(value))
258
+ return true;
259
+ }
260
+ return false;
261
+ }
262
+ function isPendingDocumentationCandidate(source, extraction) {
263
+ return !extraction
264
+ && source.status !== 'indexed'
265
+ && source.metadata.homeGraphSourceKind === 'documentation-candidate';
266
+ }
267
+ function selectRelevantExcerpt(tokens, source, extraction) {
268
+ const chunks = candidateExcerptChunks(source, extraction);
269
+ let best;
270
+ for (const chunk of chunks) {
271
+ const text = cleanWhitespace(chunk);
272
+ if (!text)
273
+ continue;
274
+ const score = scoreFields(tokens, [text]);
275
+ if (!best || score > best.score || (score === best.score && text.length < best.text.length)) {
276
+ best = { score, text };
277
+ }
278
+ }
279
+ if (!best || best.score <= 0)
280
+ return firstBoundedText(chunks, MAX_ANSWER_EXCERPT_CHARS);
281
+ return clampAroundBestToken(best.text, tokens, MAX_ANSWER_EXCERPT_CHARS);
282
+ }
283
+ function candidateExcerptChunks(source, extraction) {
284
+ const searchText = readSearchText(extraction);
285
+ return [
286
+ extraction?.excerpt,
287
+ extraction?.summary,
288
+ ...limitedSections(extraction),
289
+ ...sentenceChunks(searchText),
290
+ source.description,
291
+ source.summary,
292
+ ].filter((value) => typeof value === 'string' && value.trim().length > 0);
293
+ }
294
+ function sentenceChunks(value) {
295
+ const text = cleanWhitespace(value ?? '');
296
+ if (!text)
297
+ return [];
298
+ const matches = text.match(/[^.!?\n]+[.!?]?/g) ?? [text];
299
+ return matches.map((entry) => entry.trim()).filter(Boolean).slice(0, 80);
300
+ }
301
+ function clampAroundBestToken(value, tokens, maxLength) {
302
+ const text = cleanWhitespace(value);
303
+ if (text.length <= maxLength)
304
+ return text;
305
+ const lower = text.toLowerCase();
306
+ const index = tokens
307
+ .map((token) => lower.indexOf(token.toLowerCase()))
308
+ .filter((entry) => entry >= 0)
309
+ .sort((a, b) => a - b)[0] ?? 0;
310
+ const start = Math.max(0, index - Math.floor(maxLength / 3));
311
+ const end = Math.min(text.length, start + maxLength);
312
+ const prefix = start > 0 ? '...' : '';
313
+ const suffix = end < text.length ? '...' : '';
314
+ return `${prefix}${text.slice(start, end).trim()}${suffix}`;
315
+ }
316
+ function cleanWhitespace(value) {
317
+ return value.replace(/\s+/g, ' ').trim();
318
+ }
319
+ function pruneWeakTokenCoverage(results, tokens) {
320
+ if (results.length <= 1 || tokens.length <= 1)
321
+ return [...results];
322
+ const topCoverage = tokenCoverage(tokens, resultText(results[0]));
323
+ if (topCoverage < 2)
324
+ return [...results];
325
+ return results.filter((result) => tokenCoverage(tokens, resultText(result)) >= Math.max(1, topCoverage - 1));
326
+ }
327
+ function tokenCoverage(tokens, text) {
328
+ const haystack = text.toLowerCase();
329
+ let count = 0;
330
+ for (const token of tokens) {
331
+ if (fieldIncludesToken(haystack, token))
332
+ count += 1;
333
+ }
334
+ return count;
335
+ }
336
+ function resultText(result) {
337
+ return [
338
+ result.title,
339
+ result.summary,
340
+ result.excerpt,
341
+ result.source?.description,
342
+ result.source?.sourceUri,
343
+ result.source?.canonicalUri,
344
+ result.source?.tags.join(' '),
345
+ ].filter((value) => typeof value === 'string').join(' ');
346
+ }
106
347
  function firstBoundedText(values, maxLength) {
107
348
  for (const value of values) {
108
349
  if (typeof value !== 'string')
@@ -117,8 +358,31 @@ function firstBoundedText(values, maxLength) {
117
358
  function clampText(value, maxLength) {
118
359
  return value.length <= maxLength ? value : value.slice(0, maxLength);
119
360
  }
120
- function tokenize(value) {
121
- return value.toLowerCase().split(/[^a-z0-9_.:-]+/).map((entry) => entry.trim()).filter(Boolean);
361
+ function tokenizeQuery(value) {
362
+ const tokens = value.toLowerCase()
363
+ .split(/[^a-z0-9_.:-]+/)
364
+ .map((entry) => entry.trim())
365
+ .filter((entry) => isMeaningfulToken(entry));
366
+ return [...new Set(tokens)];
367
+ }
368
+ function expandTokens(tokens) {
369
+ const expanded = new Set();
370
+ for (const token of tokens) {
371
+ expanded.add(token);
372
+ for (const synonym of QUERY_EXPANSIONS[token] ?? []) {
373
+ expanded.add(synonym);
374
+ }
375
+ }
376
+ return [...expanded];
377
+ }
378
+ function isMeaningfulToken(token) {
379
+ if (!token || STOPWORDS.has(token))
380
+ return false;
381
+ if (token.length === 1)
382
+ return false;
383
+ if (token.length <= 2 && !SHORT_MEANINGFUL_TOKENS.has(token))
384
+ return false;
385
+ return true;
122
386
  }
123
387
  function scoreFields(tokens, fields) {
124
388
  let score = 0;
@@ -128,9 +392,30 @@ function scoreFields(tokens, fields) {
128
392
  if (!haystack)
129
393
  continue;
130
394
  for (const token of tokens) {
131
- if (haystack.includes(token))
132
- score += 10;
395
+ if (fieldIncludesToken(haystack, token))
396
+ score += token.length <= 3 ? 14 : 10;
133
397
  }
134
398
  }
135
399
  return score;
136
400
  }
401
+ function fieldIncludesToken(haystack, token) {
402
+ if (token.length <= 3 || token.includes('_') || token.includes('-')) {
403
+ return new RegExp(`(?:^|[^a-z0-9])${escapeRegExp(token)}(?:$|[^a-z0-9])`).test(haystack);
404
+ }
405
+ return haystack.includes(token);
406
+ }
407
+ function escapeRegExp(value) {
408
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
409
+ }
410
+ function compareHomeGraphResults(left, right) {
411
+ return right.score - left.score
412
+ || resultKindPriority(right) - resultKindPriority(left)
413
+ || left.id.localeCompare(right.id);
414
+ }
415
+ function resultKindPriority(result) {
416
+ if (result.source)
417
+ return 2;
418
+ if (result.node)
419
+ return 1;
420
+ return 0;
421
+ }
@@ -1,6 +1,7 @@
1
1
  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
+ import { type HomeGraphReviewResult } from './review.js';
4
5
  import type { HomeGraphAskInput, HomeGraphAskResult, HomeGraphDevicePassportResult, HomeGraphExport, HomeGraphIngestArtifactInput, HomeGraphIngestNoteInput, HomeGraphIngestResult, HomeGraphIngestUrlInput, HomeGraphLinkInput, HomeGraphLinkResult, HomeGraphProjectionInput, HomeGraphProjectionResult, HomeGraphReviewInput, HomeGraphSpaceInput, HomeGraphSnapshotInput, HomeGraphStatus, HomeGraphSyncResult } from './types.js';
5
6
  export declare class HomeGraphService {
6
7
  private readonly store;
@@ -30,13 +31,7 @@ export declare class HomeGraphService {
30
31
  readonly spaceId: string;
31
32
  readonly issues: readonly KnowledgeIssueRecord[];
32
33
  }>;
33
- reviewFact(input: HomeGraphReviewInput): Promise<{
34
- readonly ok: true;
35
- readonly spaceId: string;
36
- readonly issue?: KnowledgeIssueRecord;
37
- readonly node?: KnowledgeNodeRecord;
38
- readonly source?: KnowledgeSourceRecord;
39
- }>;
34
+ reviewFact(input: HomeGraphReviewInput): Promise<HomeGraphReviewResult>;
40
35
  listSources(input?: HomeGraphSpaceInput & {
41
36
  readonly limit?: number;
42
37
  }): Promise<{
@@ -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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"}