@duckcodeailabs/dql-agent 1.14.0 → 1.14.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.
- package/dist/agent-run-engine.d.ts +68 -2
- package/dist/agent-run-engine.d.ts.map +1 -1
- package/dist/agent-run-engine.js +520 -26
- package/dist/agent-run-engine.js.map +1 -1
- package/dist/agent-run-gates.d.ts.map +1 -1
- package/dist/agent-run-gates.js +25 -0
- package/dist/agent-run-gates.js.map +1 -1
- package/dist/agentic/analyst-loop.d.ts +91 -0
- package/dist/agentic/analyst-loop.d.ts.map +1 -0
- package/dist/agentic/analyst-loop.js +331 -0
- package/dist/agentic/analyst-loop.js.map +1 -0
- package/dist/agentic/assumptions.d.ts +62 -0
- package/dist/agentic/assumptions.d.ts.map +1 -0
- package/dist/agentic/assumptions.js +73 -0
- package/dist/agentic/assumptions.js.map +1 -0
- package/dist/agentic/business-explanation.d.ts +56 -0
- package/dist/agentic/business-explanation.d.ts.map +1 -0
- package/dist/agentic/business-explanation.js +130 -0
- package/dist/agentic/business-explanation.js.map +1 -0
- package/dist/agentic/identifier-ledger.d.ts +74 -0
- package/dist/agentic/identifier-ledger.d.ts.map +1 -0
- package/dist/agentic/identifier-ledger.js +151 -0
- package/dist/agentic/identifier-ledger.js.map +1 -0
- package/dist/agentic/ledger-tools.d.ts +68 -0
- package/dist/agentic/ledger-tools.d.ts.map +1 -0
- package/dist/agentic/ledger-tools.js +198 -0
- package/dist/agentic/ledger-tools.js.map +1 -0
- package/dist/agentic/orchestrator-policy.d.ts +60 -0
- package/dist/agentic/orchestrator-policy.d.ts.map +1 -0
- package/dist/agentic/orchestrator-policy.js +73 -0
- package/dist/agentic/orchestrator-policy.js.map +1 -0
- package/dist/agentic/orchestrator.d.ts +54 -0
- package/dist/agentic/orchestrator.d.ts.map +1 -0
- package/dist/agentic/orchestrator.js +67 -0
- package/dist/agentic/orchestrator.js.map +1 -0
- package/dist/agentic/preview-tool.d.ts +36 -0
- package/dist/agentic/preview-tool.d.ts.map +1 -0
- package/dist/agentic/preview-tool.js +71 -0
- package/dist/agentic/preview-tool.js.map +1 -0
- package/dist/agentic/rerank.d.ts +50 -0
- package/dist/agentic/rerank.d.ts.map +1 -0
- package/dist/agentic/rerank.js +140 -0
- package/dist/agentic/rerank.js.map +1 -0
- package/dist/agentic/research/hypothesis.d.ts +110 -0
- package/dist/agentic/research/hypothesis.d.ts.map +1 -0
- package/dist/agentic/research/hypothesis.js +125 -0
- package/dist/agentic/research/hypothesis.js.map +1 -0
- package/dist/agentic/research/synthesis.d.ts +36 -0
- package/dist/agentic/research/synthesis.d.ts.map +1 -0
- package/dist/agentic/research/synthesis.js +109 -0
- package/dist/agentic/research/synthesis.js.map +1 -0
- package/dist/agentic/research-agent.d.ts +54 -0
- package/dist/agentic/research-agent.d.ts.map +1 -0
- package/dist/agentic/research-agent.js +177 -0
- package/dist/agentic/research-agent.js.map +1 -0
- package/dist/agentic/sql-authorization.d.ts +131 -0
- package/dist/agentic/sql-authorization.d.ts.map +1 -0
- package/dist/agentic/sql-authorization.js +460 -0
- package/dist/agentic/sql-authorization.js.map +1 -0
- package/dist/agentic/tool-loop.d.ts +29 -0
- package/dist/agentic/tool-loop.d.ts.map +1 -1
- package/dist/agentic/tool-loop.js +129 -52
- package/dist/agentic/tool-loop.js.map +1 -1
- package/dist/agentic/toolset.d.ts.map +1 -1
- package/dist/agentic/toolset.js +155 -0
- package/dist/agentic/toolset.js.map +1 -1
- package/dist/agentic/turn-plan.d.ts +35 -0
- package/dist/agentic/turn-plan.d.ts.map +1 -0
- package/dist/agentic/turn-plan.js +108 -0
- package/dist/agentic/turn-plan.js.map +1 -0
- package/dist/agentic/value-probe.d.ts +89 -0
- package/dist/agentic/value-probe.d.ts.map +1 -0
- package/dist/agentic/value-probe.js +304 -0
- package/dist/agentic/value-probe.js.map +1 -0
- package/dist/analytical-frame.d.ts.map +1 -1
- package/dist/analytical-frame.js +10 -1
- package/dist/analytical-frame.js.map +1 -1
- package/dist/analytical-orchestration.d.ts +382 -0
- package/dist/analytical-orchestration.d.ts.map +1 -1
- package/dist/analytical-orchestration.js +782 -6
- package/dist/analytical-orchestration.js.map +1 -1
- package/dist/analytical-request-policy.d.ts +26 -0
- package/dist/analytical-request-policy.d.ts.map +1 -0
- package/dist/analytical-request-policy.js +82 -0
- package/dist/analytical-request-policy.js.map +1 -0
- package/dist/analytical-result-facts.d.ts +13 -0
- package/dist/analytical-result-facts.d.ts.map +1 -1
- package/dist/analytical-result-facts.js +37 -1
- package/dist/analytical-result-facts.js.map +1 -1
- package/dist/answer-loop.d.ts +105 -16
- package/dist/answer-loop.d.ts.map +1 -1
- package/dist/answer-loop.js +833 -108
- package/dist/answer-loop.js.map +1 -1
- package/dist/answer-shape.d.ts +32 -1
- package/dist/answer-shape.d.ts.map +1 -1
- package/dist/answer-shape.js +49 -3
- package/dist/answer-shape.js.map +1 -1
- package/dist/cascade/budgets.d.ts.map +1 -1
- package/dist/cascade/budgets.js +8 -1
- package/dist/cascade/budgets.js.map +1 -1
- package/dist/cascade/packer.d.ts +88 -0
- package/dist/cascade/packer.d.ts.map +1 -0
- package/dist/cascade/packer.js +106 -0
- package/dist/cascade/packer.js.map +1 -0
- package/dist/conversation/result-ops.d.ts +18 -3
- package/dist/conversation/result-ops.d.ts.map +1 -1
- package/dist/conversation/result-ops.js +77 -5
- package/dist/conversation/result-ops.js.map +1 -1
- package/dist/conversation/rolling-summary.d.ts.map +1 -1
- package/dist/conversation/rolling-summary.js +7 -2
- package/dist/conversation/rolling-summary.js.map +1 -1
- package/dist/conversation/session-store.d.ts +3 -0
- package/dist/conversation/session-store.d.ts.map +1 -1
- package/dist/conversation/session-store.js +8 -4
- package/dist/conversation/session-store.js.map +1 -1
- package/dist/conversation/snapshot.d.ts +20 -0
- package/dist/conversation/snapshot.d.ts.map +1 -1
- package/dist/conversation/snapshot.js +40 -2
- package/dist/conversation/snapshot.js.map +1 -1
- package/dist/fixtures/ask-ai-office-shaped.d.ts +153 -0
- package/dist/fixtures/ask-ai-office-shaped.d.ts.map +1 -0
- package/dist/fixtures/ask-ai-office-shaped.js +94 -0
- package/dist/fixtures/ask-ai-office-shaped.js.map +1 -0
- package/dist/hints/store.d.ts.map +1 -1
- package/dist/hints/store.js +15 -5
- package/dist/hints/store.js.map +1 -1
- package/dist/index.d.ts +29 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -6
- package/dist/index.js.map +1 -1
- package/dist/intent-controller.d.ts +36 -0
- package/dist/intent-controller.d.ts.map +1 -1
- package/dist/intent-controller.js +95 -0
- package/dist/intent-controller.js.map +1 -1
- package/dist/meaning-resolution.d.ts +69 -2
- package/dist/meaning-resolution.d.ts.map +1 -1
- package/dist/meaning-resolution.js +128 -7
- package/dist/meaning-resolution.js.map +1 -1
- package/dist/metadata/analysis-planner.d.ts.map +1 -1
- package/dist/metadata/analysis-planner.js +124 -7
- package/dist/metadata/analysis-planner.js.map +1 -1
- package/dist/metadata/block-fit.d.ts +36 -0
- package/dist/metadata/block-fit.d.ts.map +1 -1
- package/dist/metadata/block-fit.js +290 -38
- package/dist/metadata/block-fit.js.map +1 -1
- package/dist/metadata/catalog.d.ts +20 -23
- package/dist/metadata/catalog.d.ts.map +1 -1
- package/dist/metadata/catalog.js +193 -22
- package/dist/metadata/catalog.js.map +1 -1
- package/dist/metadata/meaning-evidence.d.ts +10 -1
- package/dist/metadata/meaning-evidence.d.ts.map +1 -1
- package/dist/metadata/meaning-evidence.js +275 -53
- package/dist/metadata/meaning-evidence.js.map +1 -1
- package/dist/metadata/metric-match.d.ts +32 -0
- package/dist/metadata/metric-match.d.ts.map +1 -1
- package/dist/metadata/metric-match.js +120 -9
- package/dist/metadata/metric-match.js.map +1 -1
- package/dist/research-loop.d.ts +33 -2
- package/dist/research-loop.d.ts.map +1 -1
- package/dist/research-loop.js +66 -4
- package/dist/research-loop.js.map +1 -1
- package/dist/resolved-analytical-plan.d.ts +7 -0
- package/dist/resolved-analytical-plan.d.ts.map +1 -1
- package/dist/resolved-analytical-plan.js +11 -4
- package/dist/resolved-analytical-plan.js.map +1 -1
- package/dist/router.d.ts +32 -19
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +1977 -73
- package/dist/router.js.map +1 -1
- package/dist/semantic-bridge/member-select.d.ts.map +1 -1
- package/dist/semantic-bridge/member-select.js +39 -21
- package/dist/semantic-bridge/member-select.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One structured planning call, made before the analyst loop starts acting.
|
|
3
|
+
*
|
|
4
|
+
* The loop can already sequence its own tools, so this is not what makes it
|
|
5
|
+
* work — it is what makes it legible. Without a plan the trace can only emit a
|
|
6
|
+
* hardcoded "working on it" string, and the user waits in silence exactly as
|
|
7
|
+
* they do today. With one, the trace names what the agent intends to establish
|
|
8
|
+
* before it establishes it, which is the difference between a progress bar and
|
|
9
|
+
* an analyst thinking out loud.
|
|
10
|
+
*
|
|
11
|
+
* It is therefore strictly optional: any failure, timeout, or malformed reply
|
|
12
|
+
* returns `undefined` and the loop proceeds exactly as it would have. A
|
|
13
|
+
* planning call that blocked an answer would be a bad trade.
|
|
14
|
+
*/
|
|
15
|
+
const PLAN_PROMPT = `You are planning one analytical turn. Do not answer the question.
|
|
16
|
+
Reply with ONLY a JSON object:
|
|
17
|
+
{"restatement": "<the question in your own words, one sentence>",
|
|
18
|
+
"mustEstablish": ["<fact to verify before writing SQL>", "..."],
|
|
19
|
+
"openingTool": "<the tool you will call first>"}
|
|
20
|
+
List at most four things under mustEstablish. Each must be something a tool can
|
|
21
|
+
check — a metric exists, a column exists, a value appears in a column, two
|
|
22
|
+
members are compatible. Never list something you would assume.`;
|
|
23
|
+
/** Pull the first JSON object out of a reply that may be fenced or prefaced. */
|
|
24
|
+
function extractJsonObject(raw) {
|
|
25
|
+
const trimmed = raw.trim();
|
|
26
|
+
const start = trimmed.indexOf('{');
|
|
27
|
+
if (start < 0)
|
|
28
|
+
return undefined;
|
|
29
|
+
let depth = 0;
|
|
30
|
+
let inString = false;
|
|
31
|
+
let escaped = false;
|
|
32
|
+
for (let i = start; i < trimmed.length; i += 1) {
|
|
33
|
+
const char = trimmed[i];
|
|
34
|
+
if (escaped) {
|
|
35
|
+
escaped = false;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (char === '\\') {
|
|
39
|
+
escaped = true;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (char === '"') {
|
|
43
|
+
inString = !inString;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (inString)
|
|
47
|
+
continue;
|
|
48
|
+
if (char === '{')
|
|
49
|
+
depth += 1;
|
|
50
|
+
else if (char === '}') {
|
|
51
|
+
depth -= 1;
|
|
52
|
+
if (depth === 0) {
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(trimmed.slice(start, i + 1));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
export function parseAnalystTurnPlan(raw, toolNames = []) {
|
|
65
|
+
const parsed = extractJsonObject(raw);
|
|
66
|
+
if (!parsed || typeof parsed !== 'object')
|
|
67
|
+
return undefined;
|
|
68
|
+
const record = parsed;
|
|
69
|
+
const restatement = typeof record.restatement === 'string' ? record.restatement.trim() : '';
|
|
70
|
+
if (!restatement)
|
|
71
|
+
return undefined;
|
|
72
|
+
const mustEstablish = Array.isArray(record.mustEstablish)
|
|
73
|
+
? record.mustEstablish
|
|
74
|
+
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
75
|
+
.map((entry) => entry.trim())
|
|
76
|
+
.slice(0, 4)
|
|
77
|
+
: [];
|
|
78
|
+
// Only echo a tool the model can actually call. A hallucinated name in the
|
|
79
|
+
// trace would promise the user a step that never happens.
|
|
80
|
+
const openingTool = typeof record.openingTool === 'string'
|
|
81
|
+
&& toolNames.includes(record.openingTool.trim())
|
|
82
|
+
? record.openingTool.trim()
|
|
83
|
+
: undefined;
|
|
84
|
+
return { restatement, mustEstablish, ...(openingTool ? { openingTool } : {}) };
|
|
85
|
+
}
|
|
86
|
+
export async function planAnalystTurn(provider, question, toolNames, options = {}) {
|
|
87
|
+
const timeoutMs = options.timeoutMs ?? 2_500;
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
90
|
+
const onAbort = () => controller.abort();
|
|
91
|
+
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
92
|
+
try {
|
|
93
|
+
const raw = await provider.generate([
|
|
94
|
+
{ role: 'system', content: `${PLAN_PROMPT}\n\nTools available: ${toolNames.join(', ')}` },
|
|
95
|
+
{ role: 'user', content: question },
|
|
96
|
+
], { signal: controller.signal });
|
|
97
|
+
return parseAnalystTurnPlan(raw, toolNames);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Planning is decoration on a working loop. Never let it fail the turn.
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=turn-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-plan.js","sourceRoot":"","sources":["../../src/agentic/turn-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `search_values` — bind a literal the user named to a real column value.
|
|
3
|
+
*
|
|
4
|
+
* The recorded highest-severity defect in this program: asking about a specific
|
|
5
|
+
* member returned every row instead of that member's, and the narration then
|
|
6
|
+
* described the truncated result as if the member were absent. The chain was
|
|
7
|
+
* `runtime_value_index` empty -> no member grounding -> empty filters -> plan
|
|
8
|
+
* froze filterless -> 200 of 500 rows -> "no such customer".
|
|
9
|
+
*
|
|
10
|
+
* The persisted index was deleted for a good reason (SEC-003: warehouse cell
|
|
11
|
+
* values must not sit in a rebuildable metadata database). The fix is not to
|
|
12
|
+
* bring it back but to look the value up ON DEMAND, bounded, and only in columns
|
|
13
|
+
* a project has agreed may be searched.
|
|
14
|
+
*
|
|
15
|
+
* Two independent gates, and BOTH must pass:
|
|
16
|
+
* 1. a hard deny-list that no configuration can override — secrets and
|
|
17
|
+
* free-text payloads are never probed, however a project is set up
|
|
18
|
+
* 2. an allow-list of column-name shapes that plausibly hold an identifier
|
|
19
|
+
*
|
|
20
|
+
* The deny-list is first and unconditional on purpose. An allow-list alone
|
|
21
|
+
* eventually admits something it should not, because it grows by exception.
|
|
22
|
+
*/
|
|
23
|
+
import type { AgentToolDefinition } from '../providers/types.js';
|
|
24
|
+
export interface ProbeColumn {
|
|
25
|
+
name: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ProbeRelation {
|
|
29
|
+
relation: string;
|
|
30
|
+
columns: ProbeColumn[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* May this column be probed for a literal?
|
|
34
|
+
*
|
|
35
|
+
* Canonical implementation — the host's `isAgentValueProbeColumn` delegates here
|
|
36
|
+
* so the deny-list has exactly one definition. Two copies of a security rule
|
|
37
|
+
* drift, and the one that drifts is the one nobody is looking at.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isProbeSafeColumn(column: ProbeColumn): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Build a bounded DISTINCT lookup for one column.
|
|
42
|
+
*
|
|
43
|
+
* Exact match first, then a prefix match on the longer tokens. Prefix rather
|
|
44
|
+
* than `%term%`: a leading wildcard cannot use an index, and on a large
|
|
45
|
+
* dimension table that is the difference between a probe and an outage.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildValueProbeSql(relation: string, column: string, terms: readonly string[], limit?: number): string | undefined;
|
|
48
|
+
export interface SearchValuesOptions {
|
|
49
|
+
execute: (sql: string) => Promise<{
|
|
50
|
+
rows: unknown[];
|
|
51
|
+
}>;
|
|
52
|
+
relations: readonly ProbeRelation[];
|
|
53
|
+
/** Probing is opt-in per project; disabled means the tool reports why. */
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
/** Max relations probed per call, so one question cannot scan the warehouse. */
|
|
56
|
+
maxRelations?: number;
|
|
57
|
+
/** Hard ceiling across columns, not per relation. Never expose more than this many queries. */
|
|
58
|
+
maxColumnQueries?: number;
|
|
59
|
+
}
|
|
60
|
+
export type ValueProbeCoverageStatus = 'complete' | 'partial' | 'disabled' | 'budget_exhausted' | 'unknown_relation';
|
|
61
|
+
/**
|
|
62
|
+
* Redacted coverage is the evidence contract for a value lookup. It says what
|
|
63
|
+
* was attempted without leaking query text, warehouse errors, or values that
|
|
64
|
+
* were not already supplied by the caller.
|
|
65
|
+
*/
|
|
66
|
+
export interface ValueProbeCoverageV1 {
|
|
67
|
+
version: 1;
|
|
68
|
+
status: ValueProbeCoverageStatus;
|
|
69
|
+
queryLimit: number;
|
|
70
|
+
queriesAttempted: number;
|
|
71
|
+
relationsRequested: string[];
|
|
72
|
+
relationsSearched: string[];
|
|
73
|
+
relationsWithNoSearchableColumn: string[];
|
|
74
|
+
/** Approved relation/column identifiers that could not form ANSI probe SQL. */
|
|
75
|
+
relationsWithUnbuildableIdentifier: string[];
|
|
76
|
+
failedRelations: string[];
|
|
77
|
+
unknownRelations: string[];
|
|
78
|
+
}
|
|
79
|
+
/** The total maximum value-probe queries a single tool call may issue. */
|
|
80
|
+
export declare const MAX_VALUE_PROBE_COLUMN_QUERIES = 12;
|
|
81
|
+
/**
|
|
82
|
+
* A tool that answers "does this literal exist, and in which column?".
|
|
83
|
+
*
|
|
84
|
+
* Returns the matched VALUES — which is the point, since the loop needs the
|
|
85
|
+
* exact stored spelling to build a filter — but only from columns that passed
|
|
86
|
+
* both gates, and only values the caller already named.
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildSearchValuesTool(options: SearchValuesOptions): AgentToolDefinition;
|
|
89
|
+
//# sourceMappingURL=value-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-probe.d.ts","sourceRoot":"","sources":["../../src/agentic/value-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAkFD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAY9D;AAoBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,SAAK,GAAG,MAAM,GAAG,SAAS,CAqB7H;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;IACvD,SAAS,EAAE,SAAS,aAAa,EAAE,CAAC;IACpC,0EAA0E;IAC1E,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAErH;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,wBAAwB,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,+BAA+B,EAAE,MAAM,EAAE,CAAC;IAC1C,+EAA+E;IAC/E,kCAAkC,EAAE,MAAM,EAAE,CAAC;IAC7C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,0EAA0E;AAC1E,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,mBAAmB,GAAG,mBAAmB,CA2IvF"}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/** Values that must never be probed, whatever the configuration says. */
|
|
2
|
+
/**
|
|
3
|
+
* Hard deny. No configuration overrides this.
|
|
4
|
+
*
|
|
5
|
+
* Three groups, and the reason each is here:
|
|
6
|
+
* SECRETS — a probe returns literal values, so one match leaks the secret.
|
|
7
|
+
* FREE TEXT — a note or description can contain anything, including all of
|
|
8
|
+
* the above, so its shape gives no safety.
|
|
9
|
+
* DIRECT AND REGULATED IDENTIFIERS — payment, government, contact, health,
|
|
10
|
+
* and compensation fields. A probe over these is a data-protection
|
|
11
|
+
* incident even when the query is otherwise correct, and "the model asked
|
|
12
|
+
* for it" is not a defence. Added after a live run answered a request for
|
|
13
|
+
* credit-card numbers and home addresses from the nearest certified block.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately broad. A false deny costs one value lookup; a false allow
|
|
16
|
+
* cannot be undone once the values have left the warehouse.
|
|
17
|
+
*/
|
|
18
|
+
const DENY_RE = /\b(password|passwd|secret|token|credential|apikey|api key|private key|hash|salt|signature|session|cookie|auth|otp|pin)\b|\b(notes?|comments?|description|message|body|payload|content|remarks?|feedback|reason)\b|\b(ssn|social security|social insurance|sin\b|dob|date of birth|birth date|birthdate|national id|government id|government identifier|tax id|taxpayer id|taxpayer identification|tin\b|itin\b|ein\b|medicare|medicaid|passport|license|licence|driver license|visa|nric|aadhaar)\b|\b(card|cardnumber|card number|credit card|debit card|cvv|cvc|iban|swift|bic|routing|account number|acct|sort code|bank)\b|\b(address|street|postal|postcode|zip|zipcode|latitude|longitude|geo|coordinates?)\b|\b(phone|mobile|telephone|fax|contact number)\b|\b(salary|compensation|wage|payroll|bonus|income|net pay|gross pay)\b|\b(medical|diagnosis|patient|health|insurance|prescription|disability|biometric|fingerprint|race|ethnicity|religion|gender|sexual)\b/;
|
|
19
|
+
/** Email is denied separately: it is an identifier, but also direct PII. */
|
|
20
|
+
const EMAIL_RE = /\bemail\b/;
|
|
21
|
+
/** Name shapes that plausibly identify an entity rather than describe one. */
|
|
22
|
+
const IDENTIFIER_TOKENS = new Set([
|
|
23
|
+
'account', 'category', 'channel', 'city', 'code', 'country', 'customer',
|
|
24
|
+
'full', 'id', 'key', 'member', 'name', 'number', 'product', 'region',
|
|
25
|
+
'segment', 'sku', 'state', 'status', 'subscriber', 'tier', 'type', 'user',
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* Token-level aliases that must remain denied even when a connector exposes
|
|
29
|
+
* them with underscores, dashes, or camel case rather than the prose phrases
|
|
30
|
+
* above. The phrase regex is intentionally broad, but `tax_number` and
|
|
31
|
+
* `customerBirthDt` never contain the literal phrase "tax id" or "birth
|
|
32
|
+
* date". Normalise the identifier into tokens before the allow-list gets a
|
|
33
|
+
* chance to treat its `number` / `customer` part as a business key.
|
|
34
|
+
*/
|
|
35
|
+
const SENSITIVE_IDENTIFIER_PREFIXES = new Set([
|
|
36
|
+
'government', 'govt', 'national', 'tax', 'taxpayer',
|
|
37
|
+
]);
|
|
38
|
+
const SENSITIVE_IDENTIFIER_SUFFIXES = new Set([
|
|
39
|
+
'id', 'identifier', 'number', 'no', 'num',
|
|
40
|
+
]);
|
|
41
|
+
// Connector metadata often elides separators inside an otherwise ordinary
|
|
42
|
+
// entity identifier (for example `customer_taxnumber`). Match only a
|
|
43
|
+
// sensitive alias at the end of the compact identifier: this catches the
|
|
44
|
+
// sensitive suffix without turning `customer_id` or `product_number` into a
|
|
45
|
+
// false positive.
|
|
46
|
+
const COMPACT_SENSITIVE_IDENTIFIER_ALIAS_RE = /(?:taxpayer|tax|government|govt|national)(?:id|identifier|number|no|num)$/;
|
|
47
|
+
const COMPACT_BIRTH_DATE_ALIAS_RE = /(?:birth(?:date|dt|day|dob|on)|dateofbirth|birthday)$/;
|
|
48
|
+
/** Types that can hold a searchable literal. */
|
|
49
|
+
const TEXTUAL_TYPE_RE = /\b(char|character|clob|string|text|uuid|varchar|nvarchar)\b/;
|
|
50
|
+
function tokenize(name) {
|
|
51
|
+
return new Set(name
|
|
52
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
53
|
+
.replace(/[_\-.]+/g, ' ')
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.split(/\s+/)
|
|
56
|
+
.filter(Boolean));
|
|
57
|
+
}
|
|
58
|
+
function isSensitiveIdentifierAlias(tokens) {
|
|
59
|
+
const has = (...values) => values.some((value) => tokens.has(value));
|
|
60
|
+
const compact = [...tokens].join('');
|
|
61
|
+
if (COMPACT_SENSITIVE_IDENTIFIER_ALIAS_RE.test(compact) || COMPACT_BIRTH_DATE_ALIAS_RE.test(compact)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
// `date_of_birth`, `customer_birth_dt`, and `customerDOB` are all direct
|
|
65
|
+
// personal identifiers despite their otherwise identifier-shaped names.
|
|
66
|
+
if (has('dob') || (has('birth') && has('date', 'dt', 'day', 'on')))
|
|
67
|
+
return true;
|
|
68
|
+
// Treat a government/tax qualifier plus an identifier suffix as sensitive.
|
|
69
|
+
// This intentionally does not deny ordinary business identifiers such as
|
|
70
|
+
// `customer_id`, `product_number`, or `order_code`.
|
|
71
|
+
return has(...SENSITIVE_IDENTIFIER_PREFIXES)
|
|
72
|
+
&& has(...SENSITIVE_IDENTIFIER_SUFFIXES);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* May this column be probed for a literal?
|
|
76
|
+
*
|
|
77
|
+
* Canonical implementation — the host's `isAgentValueProbeColumn` delegates here
|
|
78
|
+
* so the deny-list has exactly one definition. Two copies of a security rule
|
|
79
|
+
* drift, and the one that drifts is the one nobody is looking at.
|
|
80
|
+
*/
|
|
81
|
+
export function isProbeSafeColumn(column) {
|
|
82
|
+
const normalized = column.name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_\-.]+/g, ' ').toLowerCase();
|
|
83
|
+
if (DENY_RE.test(normalized))
|
|
84
|
+
return false;
|
|
85
|
+
if (EMAIL_RE.test(normalized))
|
|
86
|
+
return false;
|
|
87
|
+
const tokens = tokenize(column.name);
|
|
88
|
+
if (isSensitiveIdentifierAlias(tokens))
|
|
89
|
+
return false;
|
|
90
|
+
if (![...tokens].some((token) => IDENTIFIER_TOKENS.has(token)))
|
|
91
|
+
return false;
|
|
92
|
+
const type = column.type?.toLowerCase() ?? '';
|
|
93
|
+
// An unknown type is allowed: many drivers omit it, and the name gates already
|
|
94
|
+
// passed. A KNOWN non-textual type is not — a literal cannot live in a float.
|
|
95
|
+
if (!type)
|
|
96
|
+
return true;
|
|
97
|
+
return TEXTUAL_TYPE_RE.test(type);
|
|
98
|
+
}
|
|
99
|
+
/** Escape a single-quoted SQL literal. */
|
|
100
|
+
function sqlLiteral(value) {
|
|
101
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
102
|
+
}
|
|
103
|
+
/** Quote an identifier ANSI-style, rejecting anything that is not a plain name. */
|
|
104
|
+
function quoteIdentifier(value) {
|
|
105
|
+
// Identifiers come from the SCHEMA, never from the user, so anything exotic
|
|
106
|
+
// here means a caller is passing something it should not.
|
|
107
|
+
if (!/^[A-Za-z_][A-Za-z0-9_$]*$/.test(value))
|
|
108
|
+
return undefined;
|
|
109
|
+
return `"${value}"`;
|
|
110
|
+
}
|
|
111
|
+
function quoteRelation(relation) {
|
|
112
|
+
const parts = relation.split('.').map(quoteIdentifier);
|
|
113
|
+
return parts.every(Boolean) ? parts.join('.') : undefined;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a bounded DISTINCT lookup for one column.
|
|
117
|
+
*
|
|
118
|
+
* Exact match first, then a prefix match on the longer tokens. Prefix rather
|
|
119
|
+
* than `%term%`: a leading wildcard cannot use an index, and on a large
|
|
120
|
+
* dimension table that is the difference between a probe and an outage.
|
|
121
|
+
*/
|
|
122
|
+
export function buildValueProbeSql(relation, column, terms, limit = 25) {
|
|
123
|
+
const quotedRelation = quoteRelation(relation);
|
|
124
|
+
const quotedColumn = quoteIdentifier(column);
|
|
125
|
+
if (!quotedRelation || !quotedColumn)
|
|
126
|
+
return undefined;
|
|
127
|
+
const cast = `LOWER(CAST(${quotedColumn} AS VARCHAR))`;
|
|
128
|
+
const predicates = [];
|
|
129
|
+
for (const term of terms) {
|
|
130
|
+
const normalized = term.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
131
|
+
if (!normalized)
|
|
132
|
+
continue;
|
|
133
|
+
predicates.push(`${cast} = ${sqlLiteral(normalized)}`);
|
|
134
|
+
for (const token of normalized.split(' ').filter((part) => part.length >= 4).slice(0, 2)) {
|
|
135
|
+
predicates.push(`${cast} LIKE ${sqlLiteral(`${token.replace(/[%_\\]/g, '\\$&')}%`)} ESCAPE '\\'`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (predicates.length === 0)
|
|
139
|
+
return undefined;
|
|
140
|
+
return [
|
|
141
|
+
`SELECT DISTINCT CAST(${quotedColumn} AS VARCHAR) AS value`,
|
|
142
|
+
`FROM ${quotedRelation}`,
|
|
143
|
+
`WHERE ${quotedColumn} IS NOT NULL AND (${[...new Set(predicates)].slice(0, 8).join(' OR ')})`,
|
|
144
|
+
`LIMIT ${Math.max(1, Math.min(limit, 50))}`,
|
|
145
|
+
].join('\n');
|
|
146
|
+
}
|
|
147
|
+
/** The total maximum value-probe queries a single tool call may issue. */
|
|
148
|
+
export const MAX_VALUE_PROBE_COLUMN_QUERIES = 12;
|
|
149
|
+
/**
|
|
150
|
+
* A tool that answers "does this literal exist, and in which column?".
|
|
151
|
+
*
|
|
152
|
+
* Returns the matched VALUES — which is the point, since the loop needs the
|
|
153
|
+
* exact stored spelling to build a filter — but only from columns that passed
|
|
154
|
+
* both gates, and only values the caller already named.
|
|
155
|
+
*/
|
|
156
|
+
export function buildSearchValuesTool(options) {
|
|
157
|
+
const maxRelations = options.maxRelations ?? 6;
|
|
158
|
+
const maxColumnQueries = Math.max(1, Math.min(options.maxColumnQueries ?? MAX_VALUE_PROBE_COLUMN_QUERIES, MAX_VALUE_PROBE_COLUMN_QUERIES));
|
|
159
|
+
return {
|
|
160
|
+
name: 'search_values',
|
|
161
|
+
description: 'Check whether a literal the question names (a customer, product, region, status) exists as a value in the data, and get its exact stored spelling. Use it BEFORE filtering on a name, so a filter is built from a real value rather than a guess. Only searches columns approved for value lookup.',
|
|
162
|
+
inputSchema: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
additionalProperties: false,
|
|
165
|
+
required: ['terms'],
|
|
166
|
+
properties: {
|
|
167
|
+
terms: { type: 'array', items: { type: 'string' }, description: 'Literals named in the question, e.g. ["Wesley Jenkins"].' },
|
|
168
|
+
relations: { type: 'array', items: { type: 'string' }, description: 'Optional relations to restrict the search to.' },
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
run: async (args) => {
|
|
172
|
+
const input = (args && typeof args === 'object' ? args : {});
|
|
173
|
+
const terms = Array.isArray(input.terms)
|
|
174
|
+
? input.terms.filter((term) => typeof term === 'string' && term.trim().length > 0)
|
|
175
|
+
: [];
|
|
176
|
+
if (terms.length === 0)
|
|
177
|
+
return { error: 'Pass the literal(s) to look up, e.g. ["Wesley Jenkins"].' };
|
|
178
|
+
if (!options.enabled) {
|
|
179
|
+
// Say WHY, and name the setting. A silent empty result here is what
|
|
180
|
+
// produced the false-absence defect: the loop concluded the value did
|
|
181
|
+
// not exist when it had simply never been allowed to look.
|
|
182
|
+
return {
|
|
183
|
+
searched: false,
|
|
184
|
+
reason: 'Value lookup is disabled for this project. Enable agent.runtimeValueGrounding in dql.config.json to let DQL confirm a named value before filtering on it.',
|
|
185
|
+
matches: [],
|
|
186
|
+
coverage: {
|
|
187
|
+
version: 1,
|
|
188
|
+
status: 'disabled',
|
|
189
|
+
queryLimit: maxColumnQueries,
|
|
190
|
+
queriesAttempted: 0,
|
|
191
|
+
relationsRequested: [],
|
|
192
|
+
relationsSearched: [],
|
|
193
|
+
relationsWithNoSearchableColumn: [],
|
|
194
|
+
relationsWithUnbuildableIdentifier: [],
|
|
195
|
+
failedRelations: [],
|
|
196
|
+
unknownRelations: [],
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const requestedRelations = Array.isArray(input.relations)
|
|
201
|
+
? [...new Set(input.relations.filter((r) => typeof r === 'string' && r.trim().length > 0).map((r) => r.trim()))]
|
|
202
|
+
: [];
|
|
203
|
+
const wanted = requestedRelations.length > 0
|
|
204
|
+
? new Set(requestedRelations.map((relation) => relation.toLowerCase()))
|
|
205
|
+
: undefined;
|
|
206
|
+
const knownRelations = new Set(options.relations.map((relation) => relation.relation.toLowerCase()));
|
|
207
|
+
const unknownRelations = requestedRelations.filter((relation) => !knownRelations.has(relation.toLowerCase()));
|
|
208
|
+
const matches = [];
|
|
209
|
+
const searched = [];
|
|
210
|
+
const skipped = [];
|
|
211
|
+
const unbuildableRelations = new Set();
|
|
212
|
+
const failedRelations = new Set();
|
|
213
|
+
let queriesAttempted = 0;
|
|
214
|
+
let relationBudgetExceeded = false;
|
|
215
|
+
let queryBudgetExceeded = false;
|
|
216
|
+
let relationsConsidered = 0;
|
|
217
|
+
for (const relation of options.relations) {
|
|
218
|
+
if (wanted && !wanted.has(relation.relation.toLowerCase()))
|
|
219
|
+
continue;
|
|
220
|
+
if (relationsConsidered >= maxRelations) {
|
|
221
|
+
relationBudgetExceeded = true;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
relationsConsidered += 1;
|
|
225
|
+
const safe = relation.columns.filter(isProbeSafeColumn);
|
|
226
|
+
if (safe.length === 0) {
|
|
227
|
+
skipped.push(relation.relation);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
for (const column of safe) {
|
|
231
|
+
if (queriesAttempted >= maxColumnQueries) {
|
|
232
|
+
queryBudgetExceeded = true;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
const sql = buildValueProbeSql(relation.relation, column.name, terms);
|
|
236
|
+
if (!sql) {
|
|
237
|
+
// Metadata identifiers are not automatically executable SQL
|
|
238
|
+
// identifiers. Never turn an unquotable schema name into a
|
|
239
|
+
// zero-query "not found" claim.
|
|
240
|
+
unbuildableRelations.add(relation.relation);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (!searched.includes(relation.relation))
|
|
244
|
+
searched.push(relation.relation);
|
|
245
|
+
queriesAttempted += 1;
|
|
246
|
+
try {
|
|
247
|
+
const result = await options.execute(sql);
|
|
248
|
+
const values = (result.rows ?? [])
|
|
249
|
+
.map((row) => (Array.isArray(row) ? row[0] : row?.value))
|
|
250
|
+
.filter((value) => typeof value === 'string');
|
|
251
|
+
if (values.length > 0)
|
|
252
|
+
matches.push({ relation: relation.relation, column: column.name, values });
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// One unreadable relation must not fail the whole probe; a permission
|
|
256
|
+
// error on a single table is normal in a governed warehouse.
|
|
257
|
+
failedRelations.add(relation.relation);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (queryBudgetExceeded)
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
const complete = unknownRelations.length === 0
|
|
264
|
+
&& failedRelations.size === 0
|
|
265
|
+
&& skipped.length === 0
|
|
266
|
+
&& unbuildableRelations.size === 0
|
|
267
|
+
&& !relationBudgetExceeded
|
|
268
|
+
&& !queryBudgetExceeded;
|
|
269
|
+
const status = unknownRelations.length > 0
|
|
270
|
+
? 'unknown_relation'
|
|
271
|
+
: queryBudgetExceeded || relationBudgetExceeded
|
|
272
|
+
? 'budget_exhausted'
|
|
273
|
+
: complete
|
|
274
|
+
? 'complete'
|
|
275
|
+
: 'partial';
|
|
276
|
+
const coverage = {
|
|
277
|
+
version: 1,
|
|
278
|
+
status,
|
|
279
|
+
queryLimit: maxColumnQueries,
|
|
280
|
+
queriesAttempted,
|
|
281
|
+
relationsRequested: requestedRelations,
|
|
282
|
+
relationsSearched: searched,
|
|
283
|
+
relationsWithNoSearchableColumn: skipped,
|
|
284
|
+
relationsWithUnbuildableIdentifier: [...unbuildableRelations],
|
|
285
|
+
failedRelations: [...failedRelations],
|
|
286
|
+
unknownRelations,
|
|
287
|
+
};
|
|
288
|
+
return {
|
|
289
|
+
searched: searched.length > 0,
|
|
290
|
+
terms,
|
|
291
|
+
matches,
|
|
292
|
+
relationsSearched: searched,
|
|
293
|
+
...(skipped.length > 0 ? { relationsWithNoSearchableColumn: skipped } : {}),
|
|
294
|
+
coverage,
|
|
295
|
+
// Absence is a claim, not a default for an empty array. Only an
|
|
296
|
+
// exhaustive, error-free scan of the approved scope may support it.
|
|
297
|
+
...(matches.length === 0 && complete
|
|
298
|
+
? { absence: 'not_found', note: 'Searched the approved columns and found no match for these literals.' }
|
|
299
|
+
: {}),
|
|
300
|
+
};
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=value-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-probe.js","sourceRoot":"","sources":["../../src/agentic/value-probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytical-frame.d.ts","sourceRoot":"","sources":["../src/analytical-frame.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAwE,KAAK,yBAAyB,EAAiC,MAAM,0BAA0B,CAAC;AAC/K,OAAO,EAAwB,KAAK,sBAAsB,EAAE,KAAK,sBAAsB,EAA2B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5K,OAAO,KAAK,EAAE,sBAAsB,EAA6B,MAAM,+BAA+B,CAAC;AAEvG;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,WAAW,EAAE,yBAAyB,CAAC;CACxC,GAAG,yBAAyB,
|
|
1
|
+
{"version":3,"file":"analytical-frame.d.ts","sourceRoot":"","sources":["../src/analytical-frame.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAwE,KAAK,yBAAyB,EAAiC,MAAM,0BAA0B,CAAC;AAC/K,OAAO,EAAwB,KAAK,sBAAsB,EAAE,KAAK,sBAAsB,EAA2B,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC5K,OAAO,KAAK,EAAE,sBAAsB,EAA6B,MAAM,+BAA+B,CAAC;AAEvG;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,WAAW,EAAE,yBAAyB,CAAC;CACxC,GAAG,yBAAyB,CA8F5B;AA0BD,wBAAgB,iCAAiC,CAAC,KAAK,EAAE;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,eAAe,EAAE,sBAAsB,CAAC;IACxC,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC5C,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACtC,GAAG,yBAAyB,GAAG,SAAS,CAsOxC"}
|
package/dist/analytical-frame.js
CHANGED
|
@@ -24,7 +24,16 @@ export function projectResolvedAnalyticalFrame(input) {
|
|
|
24
24
|
...sourceFrame.metricConceptIds.filter((metricId) => metricId !== sourceFrame.metricConceptIds[0]),
|
|
25
25
|
])
|
|
26
26
|
: unique(resolvedMeasureIds);
|
|
27
|
-
const
|
|
27
|
+
const sourceTimeDimensionId = sourceFrame.timeContext?.timeDimensionId;
|
|
28
|
+
const sourceTimeIsGrouped = Boolean(sourceTimeDimensionId && sourceFrame.dimensions.some((binding) => binding.dimensionId === sourceTimeDimensionId && binding.role === 'group_by'));
|
|
29
|
+
const groupedDimensionIds = unique(plan.query.dimensions.flatMap((binding) => binding.status === 'resolved' && binding.qualifiedId
|
|
30
|
+
// The ordinary RAP query list intentionally carries the time phrase for
|
|
31
|
+
// binding/audit. It must not silently turn a V2 time_axis into a
|
|
32
|
+
// group_by role when the source frame did not request a time-series
|
|
33
|
+
// output; that changes a current-vs-prior ranking into per-day rows.
|
|
34
|
+
&& (binding.qualifiedId !== sourceTimeDimensionId || sourceTimeIsGrouped)
|
|
35
|
+
? [binding.qualifiedId]
|
|
36
|
+
: []));
|
|
28
37
|
const rankingRequested = Boolean(sourceFrame.ranking || plan.query.order || plan.query.limit !== undefined);
|
|
29
38
|
const dimensions = groupedDimensionIds.flatMap((dimensionId, index) => [
|
|
30
39
|
{ dimensionId, role: 'group_by' },
|