@pellux/goodvibes-sdk 0.28.15 → 0.28.16

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.
@@ -3,7 +3,7 @@
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.28.15"
6
+ "version": "0.28.16"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -1,6 +1,6 @@
1
1
  export declare const FOUNDATION_METADATA: {
2
2
  readonly productId: "goodvibes";
3
- readonly productVersion: "0.28.15";
3
+ readonly productVersion: "0.28.16";
4
4
  readonly operatorMethodCount: 265;
5
5
  readonly operatorEventCount: 30;
6
6
  readonly peerEndpointCount: 6;
@@ -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.15",
4
+ "productVersion": "0.28.16",
5
5
  "operatorMethodCount": 265,
6
6
  "operatorEventCount": 30,
7
7
  "peerEndpointCount": 6
@@ -3,7 +3,7 @@ export const OPERATOR_CONTRACT = {
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.28.15"
6
+ "version": "0.28.16"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -18,6 +18,7 @@ async function repairKnowledgeGapsWithWeb(request, options) {
18
18
  const sourceLimit = Math.max(2, Math.min(5, request.maxSources ?? options.maxSources ?? options.maxIngest ?? 5));
19
19
  const searchLimit = Math.max(1, Math.min(5, options.maxSearches ?? queries.length));
20
20
  const existingCandidates = selectExistingRepairSources(request, options, sourceLimit);
21
+ const acceptedExisting = candidateCanonicalUris(existingCandidates);
21
22
  const searchResults = new Map();
22
23
  const providerIds = new Set();
23
24
  let lastError;
@@ -47,7 +48,7 @@ async function repairKnowledgeGapsWithWeb(request, options) {
47
48
  continue;
48
49
  searchResults.set(canonical, { ...result, searchQuery: query, searchProviderId: response.providerId });
49
50
  }
50
- const partial = mergeRepairCandidates(existingCandidates, selectGapRepairCandidates([...searchResults.values()], existing, options, request, sourceLimit), sourceLimit);
51
+ const partial = mergeRepairCandidates(existingCandidates, selectGapRepairCandidates([...searchResults.values()], acceptedExisting, options, request, sourceLimit), sourceLimit);
51
52
  if (hasEnoughRepairEvidence(partial, options))
52
53
  break;
53
54
  }
@@ -58,7 +59,7 @@ async function repairKnowledgeGapsWithWeb(request, options) {
58
59
  }
59
60
  }
60
61
  const allResults = [...searchResults.values()];
61
- const candidates = mergeRepairCandidates(existingCandidates, selectGapRepairCandidates(allResults, existing, options, request, sourceLimit), sourceLimit);
62
+ const candidates = mergeRepairCandidates(existingCandidates, selectGapRepairCandidates(allResults, acceptedExisting, options, request, sourceLimit), sourceLimit);
62
63
  if (!hasEnoughRepairEvidence(candidates, options)) {
63
64
  return {
64
65
  searched: true,
@@ -228,7 +229,7 @@ function selectExistingRepairSources(request, options, sourceLimit) {
228
229
  const minimumConfidence = Math.max(1, Math.min(100, options.minConfidence ?? 70));
229
230
  const byDomain = new Map();
230
231
  for (const source of request.sources) {
231
- if (source.status !== 'indexed' || isGeneratedOrSyntheticSource(source))
232
+ if ((source.status !== 'indexed' && source.status !== 'pending') || isGeneratedOrSyntheticSource(source))
232
233
  continue;
233
234
  const url = source.sourceUri ?? source.canonicalUri;
234
235
  if (!url)
@@ -251,7 +252,10 @@ function selectExistingRepairSources(request, options, sourceLimit) {
251
252
  ...(snippet ? { snippet } : {}),
252
253
  };
253
254
  const assessment = assessGapRepairSource(result, request.query, request);
254
- if (assessment.confidence < minimumConfidence && !isOfficialOrVendorSource(assessment.reasons))
255
+ const officialOrVendor = isOfficialOrVendorSource(assessment.reasons);
256
+ if (source.status !== 'indexed' && !officialOrVendor)
257
+ continue;
258
+ if (assessment.confidence < minimumConfidence && !officialOrVendor)
255
259
  continue;
256
260
  byDomain.set(domain, {
257
261
  ...result,
@@ -262,6 +266,9 @@ function selectExistingRepairSources(request, options, sourceLimit) {
262
266
  }
263
267
  return [...byDomain.values()].sort(compareRepairCandidates).slice(0, sourceLimit);
264
268
  }
269
+ function candidateCanonicalUris(candidates) {
270
+ return new Set(candidates.map((candidate) => canonicalizeUri(candidate.url)).filter((value) => Boolean(value)));
271
+ }
265
272
  function assessGapRepairSource(result, query, request) {
266
273
  const searchable = [result.title, result.snippet, result.url, result.domain].filter(Boolean).join(' ').toLowerCase();
267
274
  const reasons = [];
@@ -7,5 +7,5 @@ export interface SelfImprovePromotionContext {
7
7
  readonly knowledgeSpaceId?: string;
8
8
  }) => Promise<unknown>;
9
9
  }
10
- export declare function promoteRepairSources(context: SelfImprovePromotionContext, spaceId: string, gap: KnowledgeNodeRecord, sourceIds: readonly string[], task: KnowledgeRefinementTaskRecord, deadlineAt: number): Promise<void>;
10
+ export declare function promoteRepairSources(context: SelfImprovePromotionContext, spaceId: string, gap: KnowledgeNodeRecord, sourceIds: readonly string[], task: KnowledgeRefinementTaskRecord, deadlineAt: number): Promise<number>;
11
11
  //# sourceMappingURL=self-improvement-promotion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self-improvement-promotion.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/self-improvement-promotion.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAEV,mBAAmB,EACnB,6BAA6B,EAE9B,MAAM,aAAa,CAAC;AAiBrB,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3I;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,EACpC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,mBAAmB,EACxB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,IAAI,EAAE,6BAA6B,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
1
+ {"version":3,"file":"self-improvement-promotion.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/self-improvement-promotion.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAEV,mBAAmB,EACnB,6BAA6B,EAE9B,MAAM,aAAa,CAAC;AAiBrB,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3I;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,EACpC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,mBAAmB,EACxB,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,IAAI,EAAE,6BAA6B,EACnC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAwBjB"}
@@ -17,10 +17,14 @@ export async function promoteRepairSources(context, spaceId, gap, sourceIds, tas
17
17
  }
18
18
  const promotedFactCount = await promoteRepairEvidenceFacts(context.store, spaceId, gap, sourceIds);
19
19
  await linkPromotedFactsToRepairSubjects(context.store, spaceId, gap, sourceIds);
20
+ const usableFactCount = promotedFactCount > 0
21
+ ? promotedFactCount
22
+ : countUsableRepairFacts(context.store, spaceId, sourceIds);
20
23
  await updateRefinementTask(context.store, context.store.getRefinementTask(task.id) ?? task, 'verified', 'Accepted repair sources were semantically enriched.', {
21
24
  promotedSourceIds: sourceIds,
22
- promotedFactCount,
25
+ promotedFactCount: usableFactCount,
23
26
  });
27
+ return usableFactCount;
24
28
  }
25
29
  async function promoteRepairEvidenceFacts(store, spaceId, gap, sourceIds) {
26
30
  const subjects = linkedRepairSubjects(store, spaceId, gap);
@@ -225,6 +229,15 @@ function sourceAuthority(source) {
225
229
  return 'vendor';
226
230
  return 'secondary';
227
231
  }
232
+ function countUsableRepairFacts(store, spaceId, sourceIds) {
233
+ const sources = new Set(sourceIds);
234
+ return store.listNodes(10_000)
235
+ .filter((node) => node.kind === 'fact' && node.status !== 'stale')
236
+ .filter((node) => getKnowledgeSpaceId(node) === spaceId)
237
+ .filter((node) => node.sourceId && sources.has(node.sourceId))
238
+ .filter((node) => ['feature', 'capability', 'specification', 'compatibility', 'configuration'].includes(readString(node.metadata.factKind) ?? ''))
239
+ .length;
240
+ }
228
241
  function uniqueById(items) {
229
242
  const seen = new Set();
230
243
  const result = [];
@@ -1 +1 @@
1
- {"version":3,"file":"self-improvement.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/self-improvement.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,KAAK,EACV,4BAA4B,EAC5B,iCAAiC,EACjC,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAapB,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAC;IAC3D,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3I;AAUD,wBAAsB,mCAAmC,CACvD,OAAO,EAAE,kBAAkB,EAC3B,KAAK,GAAE,iCAAsC,GAC5C,OAAO,CAAC,kCAAkC,CAAC,CA2N7C"}
1
+ {"version":3,"file":"self-improvement.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/self-improvement.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,KAAK,EACV,4BAA4B,EAC5B,iCAAiC,EACjC,kCAAkC,EACnC,MAAM,YAAY,CAAC;AAapB,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAC;IAC3D,QAAQ,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3I;AAUD,wBAAsB,mCAAmC,CACvD,OAAO,EAAE,kBAAkB,EAC3B,KAAK,GAAE,iCAAsC,GAC5C,OAAO,CAAC,kCAAkC,CAAC,CA8N7C"}
@@ -145,7 +145,7 @@ export async function runKnowledgeSemanticSelfImprovement(context, input = {}) {
145
145
  ingestedSources += result?.ingestedSourceIds.length ?? 0;
146
146
  ingestedSourceIds.push(...(result?.ingestedSourceIds ?? []));
147
147
  const acceptedSourceIds = uniqueStrings([...(result?.acceptedSourceIds ?? []), ...(result?.ingestedSourceIds ?? [])]);
148
- const evidenceSufficient = result?.evidenceSufficient !== false && acceptedSourceIds.length > 0;
148
+ let promotedFactCount = 0;
149
149
  task = await updateRefinementTask(context.store, task, 'evaluating', result?.reason ?? 'Source discovery completed.', {
150
150
  query: result?.query ?? gap.title,
151
151
  sourceAssessments: result?.sourceAssessments ?? [],
@@ -158,8 +158,9 @@ export async function runKnowledgeSemanticSelfImprovement(context, input = {}) {
158
158
  }
159
159
  linkedRepairs += await linkRepairSources(context.store, spaceId, gap, acceptedSourceIds, result?.query ?? gap.title);
160
160
  if (acceptedSourceIds.length > 0) {
161
- await promoteRepairSources(context, spaceId, gap, acceptedSourceIds, task, startedAt + maxRunMs);
161
+ promotedFactCount = await promoteRepairSources(context, spaceId, gap, acceptedSourceIds, task, startedAt + maxRunMs);
162
162
  }
163
+ const evidenceSufficient = result?.evidenceSufficient !== false && acceptedSourceIds.length > 0 && promotedFactCount > 0;
163
164
  await markGapRepairAttempt(context.store, gap, spaceId, {
164
165
  status: evidenceSufficient ? 'repaired' : acceptedSourceIds.length ? 'deferred' : 'searched_no_sources',
165
166
  reason: result?.reason,
@@ -170,12 +171,14 @@ export async function runKnowledgeSemanticSelfImprovement(context, input = {}) {
170
171
  await updateRefinementTask(context.store, task, 'closed', 'Repair sources were accepted and linked to the gap.', {
171
172
  acceptedSourceIds,
172
173
  ingestedSourceIds: result?.ingestedSourceIds ?? [],
174
+ promotedFactCount,
173
175
  });
174
176
  }
175
177
  else if (acceptedSourceIds.length) {
176
178
  blockedGaps += 1;
177
179
  await updateRefinementTask(context.store, task, 'blocked', result?.reason ?? 'Accepted source evidence was linked, but the gap still needs corroboration.', {
178
180
  acceptedSourceIds,
181
+ promotedFactCount,
179
182
  retryable: true,
180
183
  nextRepairAttemptAt: Date.now() + RETRY_DELAY_MS,
181
184
  });
@@ -413,8 +416,8 @@ function classifyGap(context, force) {
413
416
  return { action: 'skip', reason: 'Gap already has linked repair sources.', status: 'repaired' };
414
417
  if (!force && nextAttemptAt && nextAttemptAt > Date.now())
415
418
  return { action: 'skip', reason: 'Gap repair retry window has not elapsed.', status: 'retry_wait', markAttempt: true };
416
- if (hasRepairEdge(context))
417
- return { action: 'skip', reason: 'Gap already has a repair source.', status: 'already_repaired' };
419
+ if (!force && hasRepairEdge(context) && hasRepairFactEvidence(context))
420
+ return { action: 'skip', reason: 'Gap already has promoted repair facts.', status: 'already_repaired' };
418
421
  if (isNotApplicableGap(context))
419
422
  return { action: 'suppress', reason: 'The gap is not applicable to the linked subject.' };
420
423
  if (!hasConcreteSubject(context)) {
@@ -428,6 +431,10 @@ function classifyGap(context, force) {
428
431
  function hasRepairEdge(context) {
429
432
  return context.repairSourceIds.length > 0;
430
433
  }
434
+ function hasRepairFactEvidence(context) {
435
+ const repairSourceIds = new Set(context.repairSourceIds);
436
+ return context.facts.some((fact) => fact.sourceId && repairSourceIds.has(fact.sourceId) && readString(fact.metadata.extractor) === 'repair-promotion');
437
+ }
431
438
  function isNotApplicableGap(context) {
432
439
  const text = `${context.gap.title} ${context.gap.summary ?? ''}`.toLowerCase();
433
440
  if (text.includes('battery')) {
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/knowledge/semantic/service.ts"],"names":[],"mappings":"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"}
@@ -101,11 +101,26 @@ export class KnowledgeSemanticService {
101
101
  }
102
102
  async answer(input) {
103
103
  await this.store.init();
104
- const answer = await answerKnowledgeQuery({ store: this.store, llm: this.options.llm }, input);
104
+ let answer = await answerKnowledgeQuery({ store: this.store, llm: this.options.llm }, input);
105
105
  if (input.autoRepairGaps === false)
106
106
  return answer;
107
107
  if (this.options.gapRepairer && answer.answer.gaps.length > 0) {
108
108
  const repairSpaceId = answerRepairSpaceId(answer);
109
+ const foregroundBudgetMs = foregroundAnswerRepairBudget(input, answer);
110
+ const foregroundTaskIds = [];
111
+ if (foregroundBudgetMs > 0) {
112
+ const repaired = await this.repairAnswerGaps({
113
+ answer,
114
+ maxRunMs: foregroundBudgetMs,
115
+ limit: Math.min(5, answer.answer.gaps.length),
116
+ });
117
+ foregroundTaskIds.push(...repaired.taskIds);
118
+ if (repaired.closedGaps > 0 || repaired.linkedRepairs > 0) {
119
+ answer = withRefinementTaskIds(await answerKnowledgeQuery({ store: this.store, llm: this.options.llm }, input), foregroundTaskIds);
120
+ if (answer.answer.gaps.length === 0 || answerHasUsableEvidence(answer))
121
+ return answer;
122
+ }
123
+ }
109
124
  const refinement = await this.selfImprove({
110
125
  knowledgeSpaceId: repairSpaceId,
111
126
  gapIds: answer.answer.gaps.map((gap) => gap.id),
@@ -115,17 +130,12 @@ export class KnowledgeSemanticService {
115
130
  });
116
131
  this.runAnswerRefinementInBackground(repairSpaceId, answer.answer.gaps.map((gap) => gap.id));
117
132
  const taskIds = uniqueStrings([
133
+ ...foregroundTaskIds,
118
134
  ...refinement.taskIds,
119
135
  ...this.taskIdsForGaps(repairSpaceId, answer.answer.gaps.map((gap) => gap.id)),
120
136
  ]);
121
137
  if (taskIds.length > 0) {
122
- return {
123
- ...answer,
124
- answer: {
125
- ...answer.answer,
126
- refinementTaskIds: taskIds,
127
- },
128
- };
138
+ return withRefinementTaskIds(answer, taskIds);
129
139
  }
130
140
  }
131
141
  return answer;
@@ -239,12 +249,45 @@ function answerRepairSpaceId(answer) {
239
249
  }
240
250
  return answer.spaceId;
241
251
  }
252
+ function foregroundAnswerRepairBudget(input, answer) {
253
+ if (!answerNeedsForegroundRepair(input, answer))
254
+ return 0;
255
+ const requested = typeof input.timeoutMs === 'number' && Number.isFinite(input.timeoutMs)
256
+ ? input.timeoutMs
257
+ : 45_000;
258
+ if (requested < 15_000)
259
+ return 0;
260
+ return Math.max(5_000, Math.min(35_000, requested - 5_000));
261
+ }
262
+ function answerNeedsForegroundRepair(input, answer) {
263
+ const repairSpaceId = answerRepairSpaceId(answer);
264
+ const homeAssistantScoped = repairSpaceId === 'homeassistant' || repairSpaceId.startsWith('homeassistant:');
265
+ if (!input.strictCandidates && !homeAssistantScoped)
266
+ return false;
267
+ return answer.answer.facts.length === 0 || answer.answer.sources.length === 0 || answer.answer.confidence < 50;
268
+ }
269
+ function answerHasUsableEvidence(answer) {
270
+ return answer.answer.facts.length > 0 && answer.answer.sources.length > 0 && answer.answer.confidence >= 50;
271
+ }
272
+ function withRefinementTaskIds(answer, taskIds) {
273
+ const ids = uniqueStrings([...(answer.answer.refinementTaskIds ?? []), ...taskIds]);
274
+ if (ids.length === 0)
275
+ return answer;
276
+ return {
277
+ ...answer,
278
+ answer: {
279
+ ...answer.answer,
280
+ refinementTaskIds: ids,
281
+ },
282
+ };
283
+ }
242
284
  function activeSelfImproveResult(input) {
243
285
  const requestedLimit = Math.max(1, input.limit ?? 1);
244
286
  return {
245
287
  ...emptySelfImproveResult(),
246
288
  skippedGaps: 1,
247
289
  requestedLimit,
290
+ effectiveLimit: requestedLimit,
248
291
  truncated: true,
249
292
  budgetExhausted: true,
250
293
  };
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- let version = '0.28.15';
3
+ let version = '0.28.16';
4
4
  try {
5
5
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
6
6
  version = pkg.version ?? version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-sdk",
3
- "version": "0.28.15",
3
+ "version": "0.28.16",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/mgd34msu/goodvibes-sdk.git"