@duckcodeailabs/dql-agent 1.7.0 → 1.7.2

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.
@@ -224,7 +224,12 @@ export async function buildLocalContextPack(projectRoot, request) {
224
224
  buildFollowUpSearchQuery(request.question, followUp),
225
225
  ...questionPlan.searchQueries,
226
226
  ]);
227
- const scopeObjects = (rows) => filterMetadataObjectsByDomainContext(rows, request.domainContext);
227
+ const areaObjects = filterMetadataObjectsByDomainContext(catalog.listObjects({ objectTypes: ['model_area'], limit: 500 }), request.domainContext);
228
+ const focusedArea = resolveFocusedModelArea(request.domainContext, request.question, areaObjects);
229
+ const effectiveDomainContext = focusedArea && request.domainContext
230
+ ? { ...request.domainContext, modelAreaId: focusedArea.id }
231
+ : request.domainContext;
232
+ const scopeObjects = (rows) => filterMetadataObjectsByDomainContext(rows, effectiveDomainContext);
228
233
  // Skill guidance is injected only through selectContextPackSkills below.
229
234
  // Leaving it in generic FTS results would bypass status/domain/area/exclusion
230
235
  // eligibility simply because a word in its body matched the question.
@@ -240,10 +245,11 @@ export async function buildLocalContextPack(projectRoot, request) {
240
245
  const exact = exactCandidate && retrievalObjects([exactCandidate]).length > 0 ? exactCandidate : null;
241
246
  const ranked = rankMetadataObjects({
242
247
  rows: retrievalObjects(mergeObjects(exact
243
- ? [exact, ...followUpSourceObjects, ...followUpObjects, ...searchRows, ...schemaShapeObjects, ...runtimeObjects, ...runtimeValueObjects, ...selectedObjects, ...priorSeedObjects]
244
- : [...followUpSourceObjects, ...followUpObjects, ...searchRows, ...schemaShapeObjects, ...runtimeObjects, ...runtimeValueObjects, ...selectedObjects, ...priorSeedObjects])),
248
+ ? [exact, ...(focusedArea ? [focusedArea.object] : []), ...followUpSourceObjects, ...followUpObjects, ...searchRows, ...schemaShapeObjects, ...runtimeObjects, ...runtimeValueObjects, ...selectedObjects, ...priorSeedObjects]
249
+ : [...(focusedArea ? [focusedArea.object] : []), ...followUpSourceObjects, ...followUpObjects, ...searchRows, ...schemaShapeObjects, ...runtimeObjects, ...runtimeValueObjects, ...selectedObjects, ...priorSeedObjects])),
245
250
  question: searchQueries.join(' '),
246
251
  questionPlan,
252
+ modelAreaId: focusedArea?.id,
247
253
  limit: request.limit ?? 80,
248
254
  });
249
255
  // Advisory 'contextual' carry: the prior turn's block competes on rank (it is
@@ -260,6 +266,7 @@ export async function buildLocalContextPack(projectRoot, request) {
260
266
  rows: retrievalObjects(mergeObjects([...followUpSourceObjects, ...followUpObjects, ...selected, ...graphObjects, ...schemaShapeObjects, ...runtimeObjects, ...runtimeValueObjects, ...selectedObjects])),
261
267
  question: searchQueries.join(' '),
262
268
  questionPlan,
269
+ modelAreaId: focusedArea?.id,
263
270
  limit: request.limit ?? 120,
264
271
  }).selected;
265
272
  const sqlParentObjects = sqlParentObjectsForSelectedColumns(rankedObjects, mergeObjects([...graphObjects, ...runtimeObjects]), questionPlan);
@@ -273,7 +280,7 @@ export async function buildLocalContextPack(projectRoot, request) {
273
280
  // Skills are selected from the catalog snapshot with the same hard domain,
274
281
  // area, status, and exclusion gates as the loader. They are not left to FTS
275
282
  // chance or re-read from disk after the snapshot has been fingerprinted.
276
- const selectedSkills = selectContextPackSkills(catalog.listObjects({ objectTypes: ['skill'], limit: 500 }), request.question, request.domainContext);
283
+ const selectedSkills = selectContextPackSkills(catalog.listObjects({ objectTypes: ['skill'], limit: 500 }), request.question, effectiveDomainContext);
277
284
  const selectedSkillObjects = selectedSkills.map((item) => item.object);
278
285
  const objects = fullCatalogObjects
279
286
  ? mergeObjects([...rankedObjects, ...sqlParentObjects, ...fullCatalogObjects, ...selectedSkillObjects])
@@ -309,6 +316,7 @@ export async function buildLocalContextPack(projectRoot, request) {
309
316
  rows: retrievalObjects(mergeObjects([...searchRows, ...schemaShapeObjects, ...objects])),
310
317
  question: searchQueries.join(' '),
311
318
  questionPlan,
319
+ modelAreaId: focusedArea?.id,
312
320
  limit: request.limit ?? 120,
313
321
  });
314
322
  const conflicts = buildCandidateConflicts(reranked.ranked);
@@ -363,6 +371,8 @@ export async function buildLocalContextPack(projectRoot, request) {
363
371
  hintConflicts: hintResult.conflicts,
364
372
  retrievalDiagnostics: {
365
373
  strategy: usedFullCatalog ? 'full_catalog' : 'sqlite_fts',
374
+ focusedModelAreaId: focusedArea?.id,
375
+ modelAreaSource: focusedArea?.source,
366
376
  selectedObjects: objects.length,
367
377
  selectedEvidence: reranked.ranked.slice(0, 20).map((item) => ({
368
378
  objectKey: item.row.objectKey,
@@ -1218,6 +1228,7 @@ function manifestDiagnosticToMetadataDiagnostic(diagnostic) {
1218
1228
  }
1219
1229
  function objectFromKGNode(node) {
1220
1230
  const payload = {
1231
+ ...(node.payload ?? {}),
1221
1232
  kgNodeId: node.nodeId,
1222
1233
  tags: node.tags ?? [],
1223
1234
  examples: node.examples ?? [],
@@ -4761,12 +4772,13 @@ function rankMetadataObjects(args) {
4761
4772
  const scored = mergeObjects(args.rows).map((row) => {
4762
4773
  const baseScore = scoreMetadataObject(row, terms);
4763
4774
  const planScore = args.questionPlan ? scoreMetadataObjectWithAnalysisPlan(row, args.questionPlan) : { score: 0, reasons: [] };
4764
- const score = Number((baseScore + planScore.score).toFixed(3));
4775
+ const areaScore = modelAreaAffinityScore(row, args.modelAreaId);
4776
+ const score = Number((baseScore + planScore.score + areaScore).toFixed(3));
4765
4777
  return {
4766
4778
  row,
4767
4779
  rank: 0,
4768
4780
  score,
4769
- reason: selectionReason(row, score, planScore.reasons),
4781
+ reason: selectionReason(row, score, areaScore > 0 ? [...planScore.reasons, 'focused Model Area match'] : planScore.reasons),
4770
4782
  priorityTier: priorityTier(row),
4771
4783
  };
4772
4784
  });
@@ -4793,6 +4805,17 @@ function rankMetadataObjects(args) {
4793
4805
  })),
4794
4806
  };
4795
4807
  }
4808
+ function modelAreaAffinityScore(row, modelAreaId) {
4809
+ if (!modelAreaId)
4810
+ return 0;
4811
+ const qualifiedId = stringValue(row.payload?.qualifiedId);
4812
+ const areaId = stringValue(row.payload?.areaId);
4813
+ if (row.objectType === 'model_area' && qualifiedId === modelAreaId)
4814
+ return 48;
4815
+ if (areaId === modelAreaId)
4816
+ return 30;
4817
+ return 0;
4818
+ }
4796
4819
  function selectRankedMetadataObjects(ranked, limit) {
4797
4820
  if (ranked.length <= limit)
4798
4821
  return ranked;
@@ -4903,6 +4926,32 @@ function reasonForObject(row) {
4903
4926
  return 'Published consumption context';
4904
4927
  return 'Relevant project metadata';
4905
4928
  }
4929
+ function resolveFocusedModelArea(context, question, areaObjects) {
4930
+ if (!context?.activeDomain)
4931
+ return undefined;
4932
+ const candidates = areaObjects.filter((object) => object.objectType === 'model_area' && object.domain === context.activeDomain);
4933
+ if (context.modelAreaId) {
4934
+ const object = candidates.find((candidate) => stringValue(candidate.payload?.qualifiedId) === context.modelAreaId);
4935
+ return object ? { id: context.modelAreaId, object, source: 'explicit' } : undefined;
4936
+ }
4937
+ const terms = tokenize(question);
4938
+ if (terms.length === 0)
4939
+ return undefined;
4940
+ const ranked = candidates.map((object) => {
4941
+ const searchable = [
4942
+ object.name,
4943
+ object.description ?? '',
4944
+ ...metadataStringArray(object.payload?.intentExamples),
4945
+ ].join(' ');
4946
+ return { object, score: scoreText(searchable, terms) };
4947
+ }).sort((a, b) => b.score - a.score || a.object.name.localeCompare(b.object.name));
4948
+ const first = ranked[0];
4949
+ const second = ranked[1];
4950
+ if (!first || first.score < 1 || (second && first.score === second.score))
4951
+ return undefined;
4952
+ const id = stringValue(first.object.payload?.qualifiedId);
4953
+ return id ? { id, object: first.object, source: 'inferred' } : undefined;
4954
+ }
4906
4955
  function filterMetadataObjectsByDomainContext(rows, context) {
4907
4956
  if (!context?.activeDomain)
4908
4957
  return rows;