@duckcodeailabs/dql-agent 1.10.2 → 1.10.3

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.
@@ -50,6 +50,68 @@ import { buildAnalyticalResultFacts, renderDeterministicAnalyticalNarrative, val
50
50
  import { resolveAnalyticalPeriods, } from './analytical-period-resolution.js';
51
51
  import { classifyAnalyticalFailure, createAnalyticalFailure, } from './analytical-failure-repair.js';
52
52
  import { QUICK_PROMPT_CONTEXT_BUDGET, canUseLaneRepair, cascadeBudgetTrace, createCascadeBudgetState, deepAlternativeCountForQuestion, promptContextBudgetForQuestion, proposalToolBudgetForQuestion, recordLaneRepair, } from './cascade/budgets.js';
53
+ function semanticCompilerFailure(error) {
54
+ const record = error && typeof error === 'object' ? error : undefined;
55
+ const message = error instanceof Error ? error.message : String(error);
56
+ const details = record?.details && typeof record.details === 'object'
57
+ ? record.details
58
+ : undefined;
59
+ const trace = record?.semanticTrace && typeof record.semanticTrace === 'object'
60
+ ? record.semanticTrace
61
+ : details?.semanticTrace && typeof details.semanticTrace === 'object'
62
+ ? details.semanticTrace
63
+ : undefined;
64
+ const rawCandidates = Array.isArray(details?.candidates)
65
+ ? details.candidates
66
+ : Array.isArray(trace?.failure?.candidates)
67
+ ? trace.failure.candidates
68
+ : [];
69
+ const candidates = rawCandidates.flatMap((candidate) => {
70
+ if (!candidate || typeof candidate !== 'object')
71
+ return [];
72
+ const value = candidate;
73
+ if (typeof value.id !== 'string' || typeof value.label !== 'string')
74
+ return [];
75
+ return [{
76
+ id: value.id,
77
+ label: value.label,
78
+ ...(typeof value.description === 'string' ? { description: value.description } : {}),
79
+ kind: 'semantic_entity_path',
80
+ }];
81
+ });
82
+ return {
83
+ message,
84
+ ...(typeof record?.code === 'string' ? { code: record.code } : {}),
85
+ ...(trace ? { trace } : {}),
86
+ ...(candidates.length > 0 ? { candidates } : {}),
87
+ };
88
+ }
89
+ function semanticTraceAfterExecution(trace, input) {
90
+ if (!trace)
91
+ return undefined;
92
+ const executionStatus = input.error ? 'failed' : input.executed ? 'completed' : 'not_started';
93
+ const executionDetail = input.error
94
+ ? `Warehouse execution failed: ${input.error}`
95
+ : input.executed
96
+ ? 'The authorized warehouse query executed and returned a result.'
97
+ : 'The compiler produced SQL, but execution was not requested.';
98
+ return {
99
+ ...trace,
100
+ status: input.error ? 'failed' : trace.status,
101
+ steps: trace.steps.map((step) => step.id === 'execute_query'
102
+ ? { ...step, status: executionStatus, detail: executionDetail }
103
+ : step),
104
+ ...(input.error
105
+ ? {
106
+ failure: {
107
+ code: 'EXECUTION_FAILED',
108
+ phase: 'execution',
109
+ message: input.error,
110
+ },
111
+ }
112
+ : {}),
113
+ };
114
+ }
53
115
  /**
54
116
  * Physical column names whose sampled runtime values include `value`. Used by the
55
117
  * semantic bridge to bind a filter literal to the dimension that actually carries
@@ -1623,6 +1685,7 @@ async function runAnswerLoop(input) {
1623
1685
  const semanticBridgeToolCalls = [];
1624
1686
  let semanticBridgeAnswer;
1625
1687
  let semanticRuntimeFailure;
1688
+ let semanticExecutionTrace;
1626
1689
  let semanticRuntimeCompiledAnswer = false;
1627
1690
  if (authoritativeSemanticBinding && input.semanticLayer) {
1628
1691
  const selection = authoritativeSemanticBinding.selection;
@@ -1636,6 +1699,7 @@ async function runAnswerLoop(input) {
1636
1699
  if (!semanticBridgeAnswer && input.semanticQueryCompiler) {
1637
1700
  try {
1638
1701
  const compiled = await input.semanticQueryCompiler(selection);
1702
+ semanticExecutionTrace = compiled.trace;
1639
1703
  semanticBridgeAnswer = composeSemanticQueryFromCompiledMembers({
1640
1704
  semanticLayer: input.semanticLayer,
1641
1705
  question,
@@ -1645,7 +1709,8 @@ async function runAnswerLoop(input) {
1645
1709
  semanticRuntimeCompiledAnswer = Boolean(semanticBridgeAnswer && compiled.engine !== 'native');
1646
1710
  }
1647
1711
  catch (error) {
1648
- semanticRuntimeFailure = error instanceof Error ? error.message : String(error);
1712
+ semanticRuntimeFailure = semanticCompilerFailure(error);
1713
+ semanticExecutionTrace = semanticRuntimeFailure.trace;
1649
1714
  }
1650
1715
  }
1651
1716
  if (semanticBridgeAnswer) {
@@ -1658,7 +1723,9 @@ async function runAnswerLoop(input) {
1658
1723
  });
1659
1724
  }
1660
1725
  else if (!semanticRuntimeFailure) {
1661
- semanticRuntimeFailure = `The exact plan ${authoritativeSemanticBinding.planId} is not composable by the pinned semantic runtime.`;
1726
+ semanticRuntimeFailure = {
1727
+ message: `The exact plan ${authoritativeSemanticBinding.planId} is not composable by the pinned semantic runtime.`,
1728
+ };
1662
1729
  }
1663
1730
  }
1664
1731
  if (!authoritativeSemanticBinding && input.semanticLayer && semanticMetricMatch) {
@@ -1688,6 +1755,7 @@ async function runAnswerLoop(input) {
1688
1755
  const selection = { metrics: [matchedName], dimensions: [] };
1689
1756
  try {
1690
1757
  const compiled = await input.semanticQueryCompiler(selection);
1758
+ semanticExecutionTrace = compiled.trace;
1691
1759
  semanticBridgeAnswer = composeSemanticQueryFromCompiledMembers({
1692
1760
  semanticLayer: input.semanticLayer,
1693
1761
  question,
@@ -1706,7 +1774,8 @@ async function runAnswerLoop(input) {
1706
1774
  }
1707
1775
  }
1708
1776
  catch (error) {
1709
- semanticRuntimeFailure = error instanceof Error ? error.message : String(error);
1777
+ semanticRuntimeFailure = semanticCompilerFailure(error);
1778
+ semanticExecutionTrace = semanticRuntimeFailure.trace;
1710
1779
  }
1711
1780
  }
1712
1781
  }
@@ -1740,6 +1809,7 @@ async function runAnswerLoop(input) {
1740
1809
  if (!composed && input.semanticQueryCompiler) {
1741
1810
  try {
1742
1811
  const compiled = await input.semanticQueryCompiler(selection);
1812
+ semanticExecutionTrace = compiled.trace;
1743
1813
  composed = composeSemanticQueryFromCompiledMembers({
1744
1814
  semanticLayer: bridgeLayer,
1745
1815
  question,
@@ -1758,7 +1828,8 @@ async function runAnswerLoop(input) {
1758
1828
  }
1759
1829
  }
1760
1830
  catch (error) {
1761
- semanticRuntimeFailure = error instanceof Error ? error.message : String(error);
1831
+ semanticRuntimeFailure = semanticCompilerFailure(error);
1832
+ semanticExecutionTrace = semanticRuntimeFailure.trace;
1762
1833
  }
1763
1834
  }
1764
1835
  return composed;
@@ -1812,7 +1883,11 @@ async function runAnswerLoop(input) {
1812
1883
  }
1813
1884
  }
1814
1885
  if (!semanticBridgeAnswer && semanticRuntimeFailure) {
1815
- const text = `The governed semantic metric was found, but its semantic runtime could not compile the request: ${compactSemanticRuntimeFailure(semanticRuntimeFailure)}`;
1886
+ const isPathAmbiguity = semanticRuntimeFailure.code === 'SEMANTIC_PATH_AMBIGUOUS'
1887
+ || semanticRuntimeFailure.trace?.failure?.code === 'SEMANTIC_PATH_AMBIGUOUS';
1888
+ const text = isPathAmbiguity
1889
+ ? semanticRuntimeFailure.message
1890
+ : `The governed semantic metric was found, but its semantic runtime could not compile the request: ${compactSemanticRuntimeFailure(semanticRuntimeFailure.message)}`;
1816
1891
  return {
1817
1892
  kind: 'no_answer',
1818
1893
  sourceTier: 'no_answer',
@@ -1821,10 +1896,17 @@ async function runAnswerLoop(input) {
1821
1896
  confidence: 0,
1822
1897
  text,
1823
1898
  answer: text,
1824
- refusalCode: 'modeling_gap',
1899
+ refusalCode: isPathAmbiguity ? 'ambiguous' : 'modeling_gap',
1825
1900
  // The answer shows the compact business-readable failure; the FULL compiler
1826
1901
  // output stays here for Inspect/debugging.
1827
- refusalDetails: { code: 'semantic_runtime_required', message: semanticRuntimeFailure },
1902
+ refusalDetails: {
1903
+ code: isPathAmbiguity ? 'semantic_path_ambiguous' : 'semantic_runtime_required',
1904
+ message: semanticRuntimeFailure.message,
1905
+ },
1906
+ ...(semanticExecutionTrace ? { semanticExecutionTrace } : {}),
1907
+ ...(semanticRuntimeFailure.candidates?.length
1908
+ ? { clarificationOptions: semanticRuntimeFailure.candidates.map((candidate) => ({ ...candidate, question })) }
1909
+ : {}),
1828
1910
  citations: [],
1829
1911
  memoryContext: input.memoryContext,
1830
1912
  evidence: buildNoAnswerEvidence({
@@ -2935,6 +3017,10 @@ async function runAnswerLoop(input) {
2935
3017
  : undefined;
2936
3018
  const certifiedMetricAnswer = semanticMetricCertification === 'certified' || semanticMetricCertification === 'reviewed';
2937
3019
  const governedMetricExecutionFailure = governedMetricAnswer && Boolean(executionError);
3020
+ const finalSemanticExecutionTrace = semanticTraceAfterExecution(semanticExecutionTrace, {
3021
+ executed: Boolean(result),
3022
+ ...(executionError ? { error: executionError } : {}),
3023
+ });
2938
3024
  return {
2939
3025
  kind: governedMetricExecutionFailure ? 'no_answer' : 'uncertified',
2940
3026
  sourceTier: governedMetricExecutionFailure ? 'no_answer' : governedMetricAnswer ? 'semantic_layer' : activeTier,
@@ -2948,6 +3034,7 @@ async function runAnswerLoop(input) {
2948
3034
  sql: parsed.sql,
2949
3035
  result,
2950
3036
  executionError,
3037
+ ...(finalSemanticExecutionTrace ? { semanticExecutionTrace: finalSemanticExecutionTrace } : {}),
2951
3038
  ...(governedMetricExecutionFailure ? { refusalCode: 'grounding_gap' } : {}),
2952
3039
  suggestedViz: parsed.viz ?? 'table',
2953
3040
  dqlArtifact: answerDqlArtifact,
@@ -3138,6 +3225,7 @@ async function executeSemanticAnalyticalGraph(input) {
3138
3225
  const sourceResults = {};
3139
3226
  const compiledSql = [];
3140
3227
  const artifacts = [];
3228
+ let semanticExecutionTrace;
3141
3229
  for (const invocation of input.binding.invocations) {
3142
3230
  let composed = composeSemanticQueryFromMembers({
3143
3231
  semanticLayer: layer,
@@ -3149,6 +3237,7 @@ async function executeSemanticAnalyticalGraph(input) {
3149
3237
  if (!composed && input.input.semanticQueryCompiler) {
3150
3238
  try {
3151
3239
  const compiled = await input.input.semanticQueryCompiler(invocation.selection);
3240
+ semanticExecutionTrace = compiled.trace;
3152
3241
  composed = composeSemanticQueryFromCompiledMembers({
3153
3242
  semanticLayer: layer,
3154
3243
  question: input.input.question,
@@ -3157,9 +3246,34 @@ async function executeSemanticAnalyticalGraph(input) {
3157
3246
  });
3158
3247
  }
3159
3248
  catch (error) {
3249
+ const failure = semanticCompilerFailure(error);
3250
+ if (failure.candidates?.length) {
3251
+ return {
3252
+ kind: 'no_answer',
3253
+ sourceTier: 'no_answer',
3254
+ certification: 'analyst_review_required',
3255
+ reviewStatus: 'none',
3256
+ confidence: 0,
3257
+ text: failure.message,
3258
+ answer: failure.message,
3259
+ refusalCode: 'ambiguous',
3260
+ refusalDetails: { code: 'semantic_path_ambiguous', message: failure.message },
3261
+ ...(failure.trace ? { semanticExecutionTrace: failure.trace } : {}),
3262
+ clarificationOptions: failure.candidates.map((candidate) => ({
3263
+ ...candidate,
3264
+ question: input.input.question,
3265
+ })),
3266
+ analyticalExecutionGraph: input.graph,
3267
+ citations: contextPackCitations(input.input.contextPack, 8),
3268
+ considered: input.considered,
3269
+ contextPack: input.input.contextPack,
3270
+ providerUsed: input.providerName,
3271
+ };
3272
+ }
3160
3273
  return analyticalGraphFailureAnswer(input, 'COMPILATION_FAILED', error instanceof Error ? error.message : String(error), {
3161
3274
  phase: 'compilation',
3162
3275
  ...(compiledSql.length ? { compiledSql: renderAnalyticalStatements(compiledSql) } : {}),
3276
+ ...(failure.trace ? { semanticExecutionTrace: failure.trace } : {}),
3163
3277
  });
3164
3278
  }
3165
3279
  }
@@ -3184,7 +3298,13 @@ async function executeSemanticAnalyticalGraph(input) {
3184
3298
  result = await executor();
3185
3299
  }
3186
3300
  catch (error) {
3187
- return analyticalGraphFailureAnswer(input, 'EXECUTION_FAILED', error instanceof Error ? error.message : String(error), { phase: 'execution', dqlArtifact: composed.dqlArtifact, compiledSql: composed.sql });
3301
+ const message = error instanceof Error ? error.message : String(error);
3302
+ return analyticalGraphFailureAnswer(input, 'EXECUTION_FAILED', message, {
3303
+ phase: 'execution',
3304
+ dqlArtifact: composed.dqlArtifact,
3305
+ compiledSql: composed.sql,
3306
+ semanticExecutionTrace: semanticTraceAfterExecution(semanticExecutionTrace, { executed: false, error: message }),
3307
+ });
3188
3308
  }
3189
3309
  const normalized = normalizeAnalyticalSourceResult({
3190
3310
  result,
@@ -3219,6 +3339,9 @@ async function executeSemanticAnalyticalGraph(input) {
3219
3339
  sql,
3220
3340
  ...(artifacts.length === 1 ? { dqlArtifact: artifacts[0] } : {}),
3221
3341
  analyticalExecutionGraph: input.graph,
3342
+ ...(semanticExecutionTrace
3343
+ ? { semanticExecutionTrace: semanticTraceAfterExecution(semanticExecutionTrace, { executed: false }) }
3344
+ : {}),
3222
3345
  citations: contextPackCitations(input.input.contextPack, 8),
3223
3346
  considered: input.considered,
3224
3347
  contextPack: input.input.contextPack,
@@ -3263,6 +3386,9 @@ async function executeSemanticAnalyticalGraph(input) {
3263
3386
  analyticalExecutionReceipt: executed.receipt,
3264
3387
  analyticalFacts: story.factSet,
3265
3388
  analyticalNarrative: story.narrative,
3389
+ ...(semanticExecutionTrace
3390
+ ? { semanticExecutionTrace: semanticTraceAfterExecution(semanticExecutionTrace, { executed: true }) }
3391
+ : {}),
3266
3392
  citations: contextPackCitations(input.input.contextPack, 8),
3267
3393
  considered: input.considered,
3268
3394
  contextPack: input.input.contextPack,
@@ -3472,6 +3598,7 @@ function analyticalGraphFailureAnswer(input, code, reason, artifacts = {}) {
3472
3598
  analyticalExecutionGraph: input.graph,
3473
3599
  ...(artifacts.compiledSql ? { proposedSql: artifacts.compiledSql, sql: artifacts.compiledSql } : {}),
3474
3600
  ...(artifacts.dqlArtifact ? { dqlArtifact: artifacts.dqlArtifact } : {}),
3601
+ ...(artifacts.semanticExecutionTrace ? { semanticExecutionTrace: artifacts.semanticExecutionTrace } : {}),
3475
3602
  citations: contextPackCitations(input.input.contextPack, 8),
3476
3603
  considered: input.considered,
3477
3604
  contextPack: input.input.contextPack,