@duckcodeailabs/dql-agent 1.10.8 → 1.11.0

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 (46) hide show
  1. package/dist/agent-run-engine.d.ts +74 -0
  2. package/dist/agent-run-engine.d.ts.map +1 -1
  3. package/dist/agent-run-engine.js +225 -13
  4. package/dist/agent-run-engine.js.map +1 -1
  5. package/dist/agent-run-store.d.ts +11 -1
  6. package/dist/agent-run-store.d.ts.map +1 -1
  7. package/dist/agent-run-store.js +152 -0
  8. package/dist/agent-run-store.js.map +1 -1
  9. package/dist/analytical-compatibility.d.ts +3 -1
  10. package/dist/analytical-compatibility.d.ts.map +1 -1
  11. package/dist/analytical-compatibility.js +157 -12
  12. package/dist/analytical-compatibility.js.map +1 -1
  13. package/dist/analytical-frame.d.ts +2 -0
  14. package/dist/analytical-frame.d.ts.map +1 -1
  15. package/dist/analytical-frame.js +37 -26
  16. package/dist/analytical-frame.js.map +1 -1
  17. package/dist/answer-loop.d.ts +1 -1
  18. package/dist/answer-loop.d.ts.map +1 -1
  19. package/dist/answer-loop.js +16 -10
  20. package/dist/answer-loop.js.map +1 -1
  21. package/dist/conversation/session-store.d.ts +2 -0
  22. package/dist/conversation/session-store.d.ts.map +1 -1
  23. package/dist/conversation/session-store.js +6 -3
  24. package/dist/conversation/session-store.js.map +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/metadata/sql-context-validation.d.ts.map +1 -1
  29. package/dist/metadata/sql-context-validation.js +16 -8
  30. package/dist/metadata/sql-context-validation.js.map +1 -1
  31. package/dist/plan-execution-adapter.d.ts.map +1 -1
  32. package/dist/plan-execution-adapter.js +48 -8
  33. package/dist/plan-execution-adapter.js.map +1 -1
  34. package/dist/resolved-analytical-plan.d.ts.map +1 -1
  35. package/dist/resolved-analytical-plan.js +9 -2
  36. package/dist/resolved-analytical-plan.js.map +1 -1
  37. package/dist/router.d.ts.map +1 -1
  38. package/dist/router.js +108 -4
  39. package/dist/router.js.map +1 -1
  40. package/dist/semantic-bridge/compose.d.ts.map +1 -1
  41. package/dist/semantic-bridge/compose.js +47 -2
  42. package/dist/semantic-bridge/compose.js.map +1 -1
  43. package/dist/synthesize.d.ts.map +1 -1
  44. package/dist/synthesize.js +32 -10
  45. package/dist/synthesize.js.map +1 -1
  46. package/package.json +4 -4
@@ -750,8 +750,10 @@ export async function answer(input) {
750
750
  const analyticalAdapterId = analyticalCapability && analyticalRoute
751
751
  ? analyticalCapability.executionCapabilities.find((candidate) => candidate.route === analyticalRoute)?.adapterId
752
752
  : undefined;
753
+ const multiMetricPlan = (normalizedInput.resolvedAnalyticalPlan?.analyticalFrame?.metricConceptIds.length ?? 0) > 1;
753
754
  const analyticalGraphBuild = normalizedInput.resolvedAnalyticalPlan?.schemaVersion === 2
754
755
  && normalizedInput.resolvedAnalyticalPlan.analyticalFrame
756
+ && !multiMetricPlan
755
757
  && !normalizedInput.analyticalPeriodResolutionFailure
756
758
  && analyticalCapability
757
759
  && analyticalRoute
@@ -766,6 +768,7 @@ export async function answer(input) {
766
768
  ? analyticalGraphBuild.graph
767
769
  : undefined;
768
770
  const analyticalExecutionGraphFailure = normalizedInput.resolvedAnalyticalPlan?.schemaVersion === 2
771
+ && !multiMetricPlan
769
772
  ? analyticalGraphBuild?.status === 'blocked'
770
773
  ? {
771
774
  code: analyticalGraphBuild.code,
@@ -2566,6 +2569,8 @@ async function runAnswerLoop(input) {
2566
2569
  'For every required grouping alias, select the best matching inspected business column, project it with that exact alias, and include the same expression in GROUP BY.',
2567
2570
  'When the warehouse uses a different physical name (for example a location field for a requested region), keep the inspected physical column and alias it to the requested business name. Do not silently drop the grouping.',
2568
2571
  'Preserve every requested dimension and measure that was already correct; change only what the validation error requires.',
2572
+ 'Qualify every source column in every SELECT and CTE scope when more than one in-scope relation owns that column name. A select-list alias may remain unqualified only where the SQL dialect permits that output alias.',
2573
+ 'Never infer an ambiguous column owner from FROM/JOIN order. Use the inspected relation-column ownership and join path; if ownership is still not unique, do not guess.',
2569
2574
  'For amount calculations, preserve DECIMAL/NUMERIC inputs, aggregate at the proven native grain, apply COALESCE to the aggregate, and ROUND only the outer final result. Never repair by rounding rows before SUM/AVG or casting money to FLOAT/DOUBLE/REAL.',
2570
2575
  'Correct it using ONLY the relations and columns from the inspected context above.',
2571
2576
  'If a needed column lives on a different relation, JOIN that relation using the suggested join paths.',
@@ -6015,6 +6020,8 @@ async function requestSqlRepair(input) {
6015
6020
  'The SQL preview for the review-required DQL artifact failed during bounded preview execution.',
6016
6021
  `Question: ${input.question}`,
6017
6022
  `Execution error: ${input.executionError}`,
6023
+ 'Qualify every source column independently inside each SELECT/CTE scope. Do not repair an ambiguous column by choosing the first FROM relation; use the runtime schema to identify its unique owner, or leave the query unresolved when no unique owner is proven.',
6024
+ 'Preserve every requested output measure and dimension while repairing the failing reference.',
6018
6025
  'Return one corrected read-only SQL query using only the runtime schema below, as a single ```json fenced object with summary, sql, viz, outputs, and optional dql metadata fields.',
6019
6026
  schema,
6020
6027
  ].join('\n\n'),
@@ -6415,11 +6422,10 @@ function buildModelingGapRefusal(input) {
6415
6422
  };
6416
6423
  }
6417
6424
  function repairGeneratedSqlLocally(sql, error, schemaContext) {
6418
- // Ambiguous column: a bare column exists in more than one joined table (e.g. a
6419
- // conformed `report_as_of_dt` on both the fact and a joined dimension), and the
6420
- // generated SQL referenced it unqualified. Qualify every UNQUALIFIED occurrence
6421
- // with the DRIVING table (first FROM) when it owns the column the fact grain
6422
- // is the intended one, and it's exactly what the semantic compiler would emit.
6425
+ // Ambiguous-column repair is intentionally conservative. It is allowed only
6426
+ // when the inspected schema proves one owner; otherwise the validation repair
6427
+ // must use the resolved plan instead of guessing that the first FROM relation
6428
+ // owns the user's requested time/entity role.
6423
6429
  const ambiguousRepair = repairAmbiguousColumn(sql, error, schemaContext);
6424
6430
  if (ambiguousRepair)
6425
6431
  return ambiguousRepair;
@@ -6443,7 +6449,7 @@ function repairGeneratedSqlLocally(sql, error, schemaContext) {
6443
6449
  }
6444
6450
  /**
6445
6451
  * Qualify an ambiguous bare column (Snowflake/DuckDB "ambiguous column name X")
6446
- * with the driving table's alias. Conservative: only touches occurrences that
6452
+ * with the uniquely proven owner alias. Conservative: only touches occurrences that
6447
6453
  * are NOT already qualified (`alias.X`) and NOT an output alias (`AS X`), and
6448
6454
  * only when a joined table actually owns the column. Returns undefined when it
6449
6455
  * can't safely repair, so the LLM repair path still runs.
@@ -6455,11 +6461,11 @@ export function repairAmbiguousColumn(sql, error, schemaContext) {
6455
6461
  return undefined;
6456
6462
  const aliasToRelation = extractSqlAliases(sql);
6457
6463
  const owners = aliasesWithColumn(aliasToRelation, schemaContext, column);
6458
- // Prefer the first FROM table's alias when it owns the column (the fact grain).
6459
- const firstFrom = /\bfrom\s+[A-Za-z_][\w.]*(?:\s+as)?\s+([A-Za-z_]\w*)/i.exec(sql)?.[1];
6460
- const target = firstFrom && owners.includes(firstFrom) ? firstFrom : owners[0];
6461
- if (!target)
6464
+ // More than one owner is the ambiguity itself. Never infer semantic ownership
6465
+ // from FROM order: relationship order is not time/entity-role proof.
6466
+ if (owners.length !== 1)
6462
6467
  return undefined;
6468
+ const target = owners[0];
6463
6469
  const bare = new RegExp(`(?<![\\w.])${escapeRegex(column)}\\b`, 'gi');
6464
6470
  let changed = false;
6465
6471
  const repaired = sql.replace(bare, (m, offset, whole) => {