@duckcodeailabs/dql-agent 1.12.2 → 1.12.4

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 (52) hide show
  1. package/dist/agent-run-engine.d.ts +9 -0
  2. package/dist/agent-run-engine.d.ts.map +1 -1
  3. package/dist/agent-run-engine.js +50 -3
  4. package/dist/agent-run-engine.js.map +1 -1
  5. package/dist/agent-run-gates.d.ts.map +1 -1
  6. package/dist/agent-run-gates.js +17 -2
  7. package/dist/agent-run-gates.js.map +1 -1
  8. package/dist/analytical-error.d.ts +95 -0
  9. package/dist/analytical-error.d.ts.map +1 -0
  10. package/dist/analytical-error.js +116 -0
  11. package/dist/analytical-error.js.map +1 -0
  12. package/dist/analytical-failure-repair.d.ts.map +1 -1
  13. package/dist/analytical-failure-repair.js +11 -0
  14. package/dist/analytical-failure-repair.js.map +1 -1
  15. package/dist/answer-loop.d.ts +23 -0
  16. package/dist/answer-loop.d.ts.map +1 -1
  17. package/dist/answer-loop.js +77 -6
  18. package/dist/answer-loop.js.map +1 -1
  19. package/dist/conversation/session-store.d.ts +14 -0
  20. package/dist/conversation/session-store.d.ts.map +1 -1
  21. package/dist/conversation/session-store.js +28 -7
  22. package/dist/conversation/session-store.js.map +1 -1
  23. package/dist/conversation/snapshot.d.ts +12 -0
  24. package/dist/conversation/snapshot.d.ts.map +1 -1
  25. package/dist/conversation/snapshot.js +68 -12
  26. package/dist/conversation/snapshot.js.map +1 -1
  27. package/dist/conversation/turn-trust.d.ts +64 -0
  28. package/dist/conversation/turn-trust.d.ts.map +1 -0
  29. package/dist/conversation/turn-trust.js +73 -0
  30. package/dist/conversation/turn-trust.js.map +1 -0
  31. package/dist/grounding/context-ledger.js +1 -1
  32. package/dist/grounding/context-ledger.js.map +1 -1
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/intent-controller.d.ts +3 -1
  38. package/dist/intent-controller.d.ts.map +1 -1
  39. package/dist/intent-controller.js +29 -0
  40. package/dist/intent-controller.js.map +1 -1
  41. package/dist/metadata/catalog.d.ts +20 -3
  42. package/dist/metadata/catalog.d.ts.map +1 -1
  43. package/dist/metadata/catalog.js +92 -13
  44. package/dist/metadata/catalog.js.map +1 -1
  45. package/dist/metadata/sql-grounding.d.ts +8 -0
  46. package/dist/metadata/sql-grounding.d.ts.map +1 -1
  47. package/dist/metadata/sql-grounding.js +30 -0
  48. package/dist/metadata/sql-grounding.js.map +1 -1
  49. package/dist/router.d.ts.map +1 -1
  50. package/dist/router.js +17 -1
  51. package/dist/router.js.map +1 -1
  52. package/package.json +4 -4
@@ -516,6 +516,7 @@ export async function buildLocalContextPack(projectRoot, request) {
516
516
  const runtimeCatalog = openMetadataCatalog(projectRoot);
517
517
  try {
518
518
  const mode = request.mode ?? 'question';
519
+ const includeDraftBlocks = allowsDraftBlockRetrieval(request);
519
520
  const followUp = normalizeFollowUpContext(request.followUp);
520
521
  const questionPlan = buildAnalysisQuestionPlan(request.question, followUp ?? undefined);
521
522
  if (questionPlan.requestedShape.filters.length > 0) {
@@ -542,7 +543,18 @@ export async function buildLocalContextPack(projectRoot, request) {
542
543
  && request.conversationTopicRelation !== 'shift'
543
544
  ? runtimeCatalog.getContextPack(request.priorContextPackId)
544
545
  : null;
545
- const priorPackFresh = Boolean(priorPack && priorPack.freshness.fingerprint === catalog.state('fingerprint'));
546
+ const runtimeSchemaIdentityMatches = Boolean((priorPack?.freshness.runtimeSchemaConnectionId ?? undefined)
547
+ === (request.runtimeSchemaSnapshot?.connectionId ?? undefined)
548
+ && (priorPack?.freshness.runtimeSchemaScopeFingerprint ?? undefined)
549
+ === (request.runtimeSchemaSnapshot?.scopeFingerprint ?? undefined)
550
+ && (priorPack?.freshness.runtimeSchemaGenerationId ?? undefined)
551
+ === (request.runtimeSchemaSnapshot?.generationId ?? undefined)
552
+ && (priorPack?.freshness.runtimeSchemaCapturedAt ?? undefined)
553
+ === (request.runtimeSchemaSnapshot?.capturedAt ?? undefined));
554
+ const priorPackFresh = Boolean(priorPack
555
+ && priorPack.freshness.fingerprint === catalog.state('fingerprint')
556
+ && runtimeSchemaIdentityMatches
557
+ && (includeDraftBlocks || !priorPack.objects.some(isUncertifiedDqlBlock)));
546
558
  if (priorPack
547
559
  && priorPackFresh
548
560
  && request.conversationTopicRelation === 'refinement'
@@ -562,6 +574,18 @@ export async function buildLocalContextPack(projectRoot, request) {
562
574
  catalogPath: snapshotPath,
563
575
  builtAt: catalog.state('built_at'),
564
576
  fingerprint: catalog.state('fingerprint'),
577
+ ...(request.runtimeSchemaSnapshot?.connectionId
578
+ ? { runtimeSchemaConnectionId: request.runtimeSchemaSnapshot.connectionId }
579
+ : {}),
580
+ ...(request.runtimeSchemaSnapshot?.scopeFingerprint
581
+ ? { runtimeSchemaScopeFingerprint: request.runtimeSchemaSnapshot.scopeFingerprint }
582
+ : {}),
583
+ ...(request.runtimeSchemaSnapshot?.generationId
584
+ ? { runtimeSchemaGenerationId: request.runtimeSchemaSnapshot.generationId }
585
+ : {}),
586
+ ...(request.runtimeSchemaSnapshot?.capturedAt
587
+ ? { runtimeSchemaCapturedAt: request.runtimeSchemaSnapshot.capturedAt }
588
+ : {}),
565
589
  },
566
590
  };
567
591
  delete reusedPayload.id;
@@ -599,7 +623,8 @@ export async function buildLocalContextPack(projectRoot, request) {
599
623
  // Skill guidance is injected only through selectContextPackSkills below.
600
624
  // Leaving it in generic FTS results would bypass status/domain/area/exclusion
601
625
  // eligibility simply because a word in its body matched the question.
602
- const retrievalObjects = (rows) => scopeObjects(rows).filter((row) => row.objectType !== 'skill');
626
+ const retrievalObjects = (rows) => scopeObjects(rows).filter((row) => row.objectType !== 'skill'
627
+ && (includeDraftBlocks || !isUncertifiedDqlBlock(row)));
603
628
  const snapshotRetrieval = await retrieveMetadataSnapshotCandidates(catalog, {
604
629
  question: request.question,
605
630
  searchQueries,
@@ -793,6 +818,18 @@ export async function buildLocalContextPack(projectRoot, request) {
793
818
  catalogPath: snapshotPath,
794
819
  builtAt: catalog.state('built_at'),
795
820
  fingerprint: catalog.state('fingerprint'),
821
+ ...(request.runtimeSchemaSnapshot?.connectionId
822
+ ? { runtimeSchemaConnectionId: request.runtimeSchemaSnapshot.connectionId }
823
+ : {}),
824
+ ...(request.runtimeSchemaSnapshot?.scopeFingerprint
825
+ ? { runtimeSchemaScopeFingerprint: request.runtimeSchemaSnapshot.scopeFingerprint }
826
+ : {}),
827
+ ...(request.runtimeSchemaSnapshot?.generationId
828
+ ? { runtimeSchemaGenerationId: request.runtimeSchemaSnapshot.generationId }
829
+ : {}),
830
+ ...(request.runtimeSchemaSnapshot?.capturedAt
831
+ ? { runtimeSchemaCapturedAt: request.runtimeSchemaSnapshot.capturedAt }
832
+ : {}),
796
833
  },
797
834
  };
798
835
  const packPayload = { ...payload };
@@ -916,11 +953,18 @@ export function recordRuntimeSchemaSnapshot(projectRoot, snapshot) {
916
953
  catalog.close();
917
954
  }
918
955
  }
919
- /** The most-recent stored live-warehouse schema snapshot for a project, or null. */
920
- export function latestRuntimeSchemaSnapshotForProject(projectRoot) {
956
+ /**
957
+ * The most-recent stored live-warehouse schema snapshot for a project.
958
+ *
959
+ * When a connection id is supplied, never fall back to a snapshot captured for
960
+ * another connection. Ask may target a different warehouse connection than the
961
+ * project default, so a project-global "latest" snapshot is not safe evidence
962
+ * for planning or semantic table resolution.
963
+ */
964
+ export function latestRuntimeSchemaSnapshotForProject(projectRoot, connectionId) {
921
965
  const catalog = openMetadataCatalog(projectRoot);
922
966
  try {
923
- return catalog.latestRuntimeSchemaSnapshot();
967
+ return catalog.latestRuntimeSchemaSnapshot(connectionId);
924
968
  }
925
969
  finally {
926
970
  catalog.close();
@@ -2320,12 +2364,14 @@ export class MetadataCatalog {
2320
2364
  `);
2321
2365
  const txn = this.db.transaction(() => {
2322
2366
  insertSnapshot.run(id, cleanSnapshot.source ?? null, JSON.stringify(cleanSnapshot), capturedAt);
2323
- // Only the most-recent snapshot is ever read; rows otherwise accumulate one per
2324
- // question forever. Keep a small margin and prune the rest (P7).
2367
+ // Preserve a bounded history across multiple named connections. Ask
2368
+ // resolves the latest snapshot for its selected connection, so retaining
2369
+ // only five project-global rows could evict a valid but less-recent
2370
+ // warehouse as soon as another connection was refreshed repeatedly.
2325
2371
  this.db.prepare(`
2326
2372
  DELETE FROM runtime_schema_snapshots
2327
2373
  WHERE id NOT IN (
2328
- SELECT id FROM runtime_schema_snapshots ORDER BY captured_at DESC LIMIT 5
2374
+ SELECT id FROM runtime_schema_snapshots ORDER BY captured_at DESC LIMIT 50
2329
2375
  )
2330
2376
  `).run();
2331
2377
  this.db.prepare('DELETE FROM runtime_value_fts').run();
@@ -2376,14 +2422,21 @@ export class MetadataCatalog {
2376
2422
  const rows = [...andRows, ...runMatch(match.or).filter((row) => !seen.has(row.object_key))].slice(0, limit);
2377
2423
  return rows.map(rowToObject);
2378
2424
  }
2379
- latestRuntimeSchemaSnapshot() {
2380
- const row = this.db.prepare(`
2425
+ latestRuntimeSchemaSnapshot(connectionId) {
2426
+ const rows = this.db.prepare(`
2381
2427
  SELECT payload_json
2382
2428
  FROM runtime_schema_snapshots
2383
2429
  ORDER BY captured_at DESC
2384
- LIMIT 1
2385
- `).get();
2386
- return row ? safeRuntimeSchemaSnapshot(safeJson(row.payload_json, null)) : null;
2430
+ LIMIT 50
2431
+ `).all();
2432
+ for (const row of rows) {
2433
+ const snapshot = safeRuntimeSchemaSnapshot(safeJson(row.payload_json, null));
2434
+ if (!snapshot)
2435
+ continue;
2436
+ if (!connectionId || snapshot.connectionId === connectionId)
2437
+ return snapshot;
2438
+ }
2439
+ return null;
2387
2440
  }
2388
2441
  getContextPack(id) {
2389
2442
  const row = this.db.prepare('SELECT payload_json FROM context_packs WHERE id = ?').get(id);
@@ -4354,6 +4407,18 @@ function findExactCertifiedObject(question, intent, objects) {
4354
4407
  function isCertifiedMetadataObject(object) {
4355
4408
  return object.status === 'certified' || object.status === 'approved' || object.payload?.certification === 'certified';
4356
4409
  }
4410
+ function isUncertifiedDqlBlock(object) {
4411
+ return object.objectType === 'dql_block' && !isCertifiedMetadataObject(object);
4412
+ }
4413
+ function allowsDraftBlockRetrieval(request) {
4414
+ if (request.includeDraftBlocks === true)
4415
+ return true;
4416
+ if (request.surface === 'block')
4417
+ return true;
4418
+ if (request.mode && request.mode !== 'question')
4419
+ return true;
4420
+ return /\b(?:draft|review|edit|certif(?:y|ied|ication)|block studio|this block)\b/i.test(request.question);
4421
+ }
4357
4422
  function objectNameInQuestion(question, object) {
4358
4423
  const q = normalizeSearchText(question);
4359
4424
  const name = normalizeSearchText(object.name);
@@ -5770,12 +5835,26 @@ export function isFilterOnlyRefinement(prior, next) {
5770
5835
  return false;
5771
5836
  const priorShape = prior.requestedShape;
5772
5837
  const nextShape = next.requestedShape;
5838
+ // Every check below is a set comparison, so two plans the planner extracted
5839
+ // NOTHING from compared equal and were declared "the same query with
5840
+ // different filters". Two unrelated questions the vocabulary does not cover
5841
+ // then reused the earlier context pack wholesale — including its committed
5842
+ // route decision. Reuse requires actual evidence of sameness on both sides.
5843
+ if (!hasPlanSignal(prior) || !hasPlanSignal(next))
5844
+ return false;
5773
5845
  return setEqual(priorShape.measures, nextShape.measures)
5774
5846
  && setEqual(priorShape.dimensions, nextShape.dimensions)
5775
5847
  && setEqual(priorShape.requiredOutputs, nextShape.requiredOutputs)
5776
5848
  && (priorShape.grain ?? '') === (nextShape.grain ?? '')
5777
5849
  && setEqual(prior.entities.map((entity) => entity.text.toLowerCase()), next.entities.map((entity) => entity.text.toLowerCase()));
5778
5850
  }
5851
+ /** Did the planner actually read anything out of this question? */
5852
+ function hasPlanSignal(plan) {
5853
+ return plan.requestedShape.measures.length > 0
5854
+ || plan.requestedShape.dimensions.length > 0
5855
+ || plan.requestedShape.requiredOutputs.length > 0
5856
+ || plan.entities.length > 0;
5857
+ }
5779
5858
  function setEqual(a, b) {
5780
5859
  const setA = new Set(a.map((value) => value.toLowerCase()));
5781
5860
  const setB = new Set(b.map((value) => value.toLowerCase()));