@duckcodeailabs/dql-agent 1.13.5 → 1.14.1

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 (158) hide show
  1. package/dist/agent-run-engine.d.ts +79 -4
  2. package/dist/agent-run-engine.d.ts.map +1 -1
  3. package/dist/agent-run-engine.js +457 -39
  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 +13 -0
  7. package/dist/agent-run-gates.js.map +1 -1
  8. package/dist/agent-run-store.d.ts.map +1 -1
  9. package/dist/agent-run-store.js +42 -25
  10. package/dist/agent-run-store.js.map +1 -1
  11. package/dist/agentic/analyst-loop.d.ts +91 -0
  12. package/dist/agentic/analyst-loop.d.ts.map +1 -0
  13. package/dist/agentic/analyst-loop.js +311 -0
  14. package/dist/agentic/analyst-loop.js.map +1 -0
  15. package/dist/agentic/assumptions.d.ts +62 -0
  16. package/dist/agentic/assumptions.d.ts.map +1 -0
  17. package/dist/agentic/assumptions.js +73 -0
  18. package/dist/agentic/assumptions.js.map +1 -0
  19. package/dist/agentic/business-explanation.d.ts +56 -0
  20. package/dist/agentic/business-explanation.d.ts.map +1 -0
  21. package/dist/agentic/business-explanation.js +130 -0
  22. package/dist/agentic/business-explanation.js.map +1 -0
  23. package/dist/agentic/identifier-ledger.d.ts +74 -0
  24. package/dist/agentic/identifier-ledger.d.ts.map +1 -0
  25. package/dist/agentic/identifier-ledger.js +151 -0
  26. package/dist/agentic/identifier-ledger.js.map +1 -0
  27. package/dist/agentic/ledger-tools.d.ts +68 -0
  28. package/dist/agentic/ledger-tools.d.ts.map +1 -0
  29. package/dist/agentic/ledger-tools.js +198 -0
  30. package/dist/agentic/ledger-tools.js.map +1 -0
  31. package/dist/agentic/orchestrator-policy.d.ts +60 -0
  32. package/dist/agentic/orchestrator-policy.d.ts.map +1 -0
  33. package/dist/agentic/orchestrator-policy.js +73 -0
  34. package/dist/agentic/orchestrator-policy.js.map +1 -0
  35. package/dist/agentic/orchestrator.d.ts +54 -0
  36. package/dist/agentic/orchestrator.d.ts.map +1 -0
  37. package/dist/agentic/orchestrator.js +67 -0
  38. package/dist/agentic/orchestrator.js.map +1 -0
  39. package/dist/agentic/preview-tool.d.ts +36 -0
  40. package/dist/agentic/preview-tool.d.ts.map +1 -0
  41. package/dist/agentic/preview-tool.js +71 -0
  42. package/dist/agentic/preview-tool.js.map +1 -0
  43. package/dist/agentic/rerank.d.ts +50 -0
  44. package/dist/agentic/rerank.d.ts.map +1 -0
  45. package/dist/agentic/rerank.js +140 -0
  46. package/dist/agentic/rerank.js.map +1 -0
  47. package/dist/agentic/research/hypothesis.d.ts +110 -0
  48. package/dist/agentic/research/hypothesis.d.ts.map +1 -0
  49. package/dist/agentic/research/hypothesis.js +125 -0
  50. package/dist/agentic/research/hypothesis.js.map +1 -0
  51. package/dist/agentic/research/synthesis.d.ts +32 -0
  52. package/dist/agentic/research/synthesis.d.ts.map +1 -0
  53. package/dist/agentic/research/synthesis.js +94 -0
  54. package/dist/agentic/research/synthesis.js.map +1 -0
  55. package/dist/agentic/research-agent.d.ts +54 -0
  56. package/dist/agentic/research-agent.d.ts.map +1 -0
  57. package/dist/agentic/research-agent.js +176 -0
  58. package/dist/agentic/research-agent.js.map +1 -0
  59. package/dist/agentic/sql-authorization.d.ts +131 -0
  60. package/dist/agentic/sql-authorization.d.ts.map +1 -0
  61. package/dist/agentic/sql-authorization.js +232 -0
  62. package/dist/agentic/sql-authorization.js.map +1 -0
  63. package/dist/agentic/tool-loop.d.ts +29 -0
  64. package/dist/agentic/tool-loop.d.ts.map +1 -1
  65. package/dist/agentic/tool-loop.js +129 -52
  66. package/dist/agentic/tool-loop.js.map +1 -1
  67. package/dist/agentic/toolset.d.ts.map +1 -1
  68. package/dist/agentic/toolset.js +155 -0
  69. package/dist/agentic/toolset.js.map +1 -1
  70. package/dist/agentic/turn-plan.d.ts +35 -0
  71. package/dist/agentic/turn-plan.d.ts.map +1 -0
  72. package/dist/agentic/turn-plan.js +108 -0
  73. package/dist/agentic/turn-plan.js.map +1 -0
  74. package/dist/agentic/value-probe.d.ts +89 -0
  75. package/dist/agentic/value-probe.d.ts.map +1 -0
  76. package/dist/agentic/value-probe.js +304 -0
  77. package/dist/agentic/value-probe.js.map +1 -0
  78. package/dist/analytical-orchestration.d.ts +336 -0
  79. package/dist/analytical-orchestration.d.ts.map +1 -0
  80. package/dist/analytical-orchestration.js +631 -0
  81. package/dist/analytical-orchestration.js.map +1 -0
  82. package/dist/analytical-request-policy.d.ts +26 -0
  83. package/dist/analytical-request-policy.d.ts.map +1 -0
  84. package/dist/analytical-request-policy.js +82 -0
  85. package/dist/analytical-request-policy.js.map +1 -0
  86. package/dist/analytical-result-facts.d.ts +14 -1
  87. package/dist/analytical-result-facts.d.ts.map +1 -1
  88. package/dist/analytical-result-facts.js +76 -1
  89. package/dist/analytical-result-facts.js.map +1 -1
  90. package/dist/answer-loop.d.ts +61 -16
  91. package/dist/answer-loop.d.ts.map +1 -1
  92. package/dist/answer-loop.js +256 -36
  93. package/dist/answer-loop.js.map +1 -1
  94. package/dist/cascade/budgets.d.ts.map +1 -1
  95. package/dist/cascade/budgets.js +8 -1
  96. package/dist/cascade/budgets.js.map +1 -1
  97. package/dist/cascade/packer.d.ts +88 -0
  98. package/dist/cascade/packer.d.ts.map +1 -0
  99. package/dist/cascade/packer.js +106 -0
  100. package/dist/cascade/packer.js.map +1 -0
  101. package/dist/conversation/result-ops.d.ts +18 -3
  102. package/dist/conversation/result-ops.d.ts.map +1 -1
  103. package/dist/conversation/result-ops.js +77 -5
  104. package/dist/conversation/result-ops.js.map +1 -1
  105. package/dist/conversation/rolling-summary.d.ts.map +1 -1
  106. package/dist/conversation/rolling-summary.js +7 -2
  107. package/dist/conversation/rolling-summary.js.map +1 -1
  108. package/dist/conversation/session-store.d.ts +3 -0
  109. package/dist/conversation/session-store.d.ts.map +1 -1
  110. package/dist/conversation/session-store.js +8 -4
  111. package/dist/conversation/session-store.js.map +1 -1
  112. package/dist/conversation/snapshot.d.ts.map +1 -1
  113. package/dist/conversation/snapshot.js +13 -1
  114. package/dist/conversation/snapshot.js.map +1 -1
  115. package/dist/conversation/turn-trust.d.ts.map +1 -1
  116. package/dist/conversation/turn-trust.js +6 -0
  117. package/dist/conversation/turn-trust.js.map +1 -1
  118. package/dist/hints/store.d.ts.map +1 -1
  119. package/dist/hints/store.js +15 -5
  120. package/dist/hints/store.js.map +1 -1
  121. package/dist/index.d.ts +27 -5
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +28 -4
  124. package/dist/index.js.map +1 -1
  125. package/dist/intent-controller.d.ts +8 -0
  126. package/dist/intent-controller.d.ts.map +1 -1
  127. package/dist/intent-controller.js +65 -0
  128. package/dist/intent-controller.js.map +1 -1
  129. package/dist/meaning-resolution.d.ts +7 -0
  130. package/dist/meaning-resolution.d.ts.map +1 -1
  131. package/dist/meaning-resolution.js.map +1 -1
  132. package/dist/metadata/block-fit.d.ts +18 -0
  133. package/dist/metadata/block-fit.d.ts.map +1 -1
  134. package/dist/metadata/block-fit.js +41 -1
  135. package/dist/metadata/block-fit.js.map +1 -1
  136. package/dist/metadata/catalog.d.ts +44 -23
  137. package/dist/metadata/catalog.d.ts.map +1 -1
  138. package/dist/metadata/catalog.js +363 -53
  139. package/dist/metadata/catalog.js.map +1 -1
  140. package/dist/metadata/meaning-evidence.d.ts.map +1 -1
  141. package/dist/metadata/meaning-evidence.js +101 -8
  142. package/dist/metadata/meaning-evidence.js.map +1 -1
  143. package/dist/metadata/metric-match.d.ts +32 -0
  144. package/dist/metadata/metric-match.d.ts.map +1 -1
  145. package/dist/metadata/metric-match.js +120 -9
  146. package/dist/metadata/metric-match.js.map +1 -1
  147. package/dist/research-loop.d.ts +33 -2
  148. package/dist/research-loop.d.ts.map +1 -1
  149. package/dist/research-loop.js +44 -4
  150. package/dist/research-loop.js.map +1 -1
  151. package/dist/resolved-analytical-plan.d.ts.map +1 -1
  152. package/dist/resolved-analytical-plan.js +92 -5
  153. package/dist/resolved-analytical-plan.js.map +1 -1
  154. package/dist/router.d.ts +36 -16
  155. package/dist/router.d.ts.map +1 -1
  156. package/dist/router.js +604 -25
  157. package/dist/router.js.map +1 -1
  158. package/package.json +4 -4
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Hypothesis-driven research state.
3
+ *
4
+ * `planResearch` emits a fixed three-step template — baseline, compare over
5
+ * time, break down — always bound to ONE metric, with dimensions scraped by
6
+ * `/\bby\s+([a-z_][a-z0-9_]*)/gi`. Its own comment says it is deterministic and
7
+ * offline, `RESEARCH_BUDGET.plannerCalls` is TYPED as the literal `1`, and the
8
+ * branches it fans out are frozen against the root plan.
9
+ *
10
+ * The consequence is the reported one: research answers a question instead of
11
+ * investigating it. A template cannot be wrong, so it never notices that its
12
+ * first finding ruled the premise out, and it never follows the thread that
13
+ * finding opened.
14
+ *
15
+ * What is missing is not more steps. It is the edge from an OBSERVATION back to
16
+ * the plan: a finding has to be able to refute a hypothesis, sharpen it, or
17
+ * spawn a new one. This module owns that edge as a pure state machine, so the
18
+ * part that decides what to investigate next is testable without a provider,
19
+ * a warehouse, or a clock.
20
+ */
21
+ export type HypothesisStatus = 'open' | 'supported' | 'refuted' | 'inconclusive';
22
+ export interface Hypothesis {
23
+ id: string;
24
+ /** A falsifiable statement, not a task ("revenue fell because enterprise churned"). */
25
+ statement: string;
26
+ /** Belief before any evidence, 0..1. Drives which hypothesis is tested next. */
27
+ priorConfidence: number;
28
+ status: HypothesisStatus;
29
+ /** Ids of observations that bear on this hypothesis. */
30
+ evidenceIds: string[];
31
+ /** Which hypothesis this was spawned from, when a finding opened a new thread. */
32
+ parentId?: string;
33
+ /** Why it reached its current status — carried into the final narrative. */
34
+ rationale?: string;
35
+ }
36
+ /** What one investigation step established. */
37
+ export interface HypothesisFinding {
38
+ id: string;
39
+ hypothesisId: string;
40
+ /**
41
+ * Whether the finding supports, refutes, or fails to settle the hypothesis.
42
+ * `inconclusive` is a real outcome, not a failure: an executed query that
43
+ * simply does not discriminate must not be recorded as support.
44
+ */
45
+ verdict: 'supports' | 'refutes' | 'inconclusive';
46
+ summary: string;
47
+ /** Confidence the finding itself carries, 0..1. */
48
+ strength: number;
49
+ /**
50
+ * A hypothesis this finding suggests testing next. The edge that a frozen
51
+ * branch plan cannot express.
52
+ */
53
+ spawns?: Array<{
54
+ statement: string;
55
+ priorConfidence: number;
56
+ }>;
57
+ }
58
+ export interface ResearchState {
59
+ rootQuestion: string;
60
+ hypotheses: Hypothesis[];
61
+ findings: HypothesisFinding[];
62
+ hopsUsed: number;
63
+ }
64
+ export interface ResearchLimits {
65
+ /** Total investigation steps. Bounded: an unbounded loop is an outage. */
66
+ maxHops: number;
67
+ /** Ceiling on live hypotheses, so spawning cannot fan out without end. */
68
+ maxOpenHypotheses: number;
69
+ }
70
+ export declare const DEFAULT_RESEARCH_LIMITS: ResearchLimits;
71
+ export declare function createResearchState(rootQuestion: string, initial: Array<Omit<Hypothesis, 'status' | 'evidenceIds'>>): ResearchState;
72
+ /**
73
+ * Which hypothesis to test next: the open one with the highest prior.
74
+ *
75
+ * Returns `undefined` when the budget is spent or nothing is open, which is how
76
+ * the caller learns to stop. Deliberately not "cheapest first" — the point of
77
+ * research is to resolve the question, and testing a likely explanation first is
78
+ * what lets a later hop be skipped entirely.
79
+ */
80
+ export declare function nextHypothesis(state: ResearchState, limits?: ResearchLimits): Hypothesis | undefined;
81
+ /**
82
+ * Fold a finding into the state — the replan edge.
83
+ *
84
+ * A refutation CLOSES its hypothesis rather than leaving it open to be retried:
85
+ * the template's failure was continuing to elaborate a premise its own evidence
86
+ * had already ruled out.
87
+ *
88
+ * Spawned hypotheses are admitted only while there is room, and never duplicate
89
+ * an existing statement — a loop that keeps re-proposing the same idea burns the
90
+ * whole hop budget without learning anything.
91
+ */
92
+ export declare function applyFinding(state: ResearchState, finding: HypothesisFinding, limits?: ResearchLimits): ResearchState;
93
+ export interface ResearchConclusion {
94
+ /** Hypotheses the evidence actually settled, strongest first. */
95
+ supported: Hypothesis[];
96
+ refuted: Hypothesis[];
97
+ /** Open or inconclusive — what the investigation could NOT establish. */
98
+ unresolved: Hypothesis[];
99
+ /** True when the hop budget ran out with hypotheses still open. */
100
+ exhausted: boolean;
101
+ }
102
+ /**
103
+ * Summarise what the investigation established.
104
+ *
105
+ * `unresolved` is reported as prominently as `supported` on purpose. A research
106
+ * answer that lists only what it confirmed reads as a complete explanation, and
107
+ * the one thing a bounded investigation cannot honestly claim is completeness.
108
+ */
109
+ export declare function concludeResearch(state: ResearchState, limits?: ResearchLimits): ResearchConclusion;
110
+ //# sourceMappingURL=hypothesis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hypothesis.d.ts","sourceRoot":"","sources":["../../../src/agentic/research/hypothesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,cAAc,CAAC;AAEjF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,gBAAgB,CAAC;IACzB,wDAAwD;IACxD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,UAAU,GAAG,SAAS,GAAG,cAAc,CAAC;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,uBAAuB,EAAE,cAGrC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,GAAG,aAAa,CAOnI;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,GAAE,cAAwC,GAAG,UAAU,GAAG,SAAS,CAK7H;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,GAAE,cAAwC,GAC/C,aAAa,CAuCf;AAED,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,yEAAyE;IACzE,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,GAAE,cAAwC,GAAG,kBAAkB,CAU3H"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Hypothesis-driven research state.
3
+ *
4
+ * `planResearch` emits a fixed three-step template — baseline, compare over
5
+ * time, break down — always bound to ONE metric, with dimensions scraped by
6
+ * `/\bby\s+([a-z_][a-z0-9_]*)/gi`. Its own comment says it is deterministic and
7
+ * offline, `RESEARCH_BUDGET.plannerCalls` is TYPED as the literal `1`, and the
8
+ * branches it fans out are frozen against the root plan.
9
+ *
10
+ * The consequence is the reported one: research answers a question instead of
11
+ * investigating it. A template cannot be wrong, so it never notices that its
12
+ * first finding ruled the premise out, and it never follows the thread that
13
+ * finding opened.
14
+ *
15
+ * What is missing is not more steps. It is the edge from an OBSERVATION back to
16
+ * the plan: a finding has to be able to refute a hypothesis, sharpen it, or
17
+ * spawn a new one. This module owns that edge as a pure state machine, so the
18
+ * part that decides what to investigate next is testable without a provider,
19
+ * a warehouse, or a clock.
20
+ */
21
+ export const DEFAULT_RESEARCH_LIMITS = {
22
+ maxHops: 12,
23
+ maxOpenHypotheses: 6,
24
+ };
25
+ export function createResearchState(rootQuestion, initial) {
26
+ return {
27
+ rootQuestion,
28
+ hypotheses: initial.map((hypothesis) => ({ ...hypothesis, status: 'open', evidenceIds: [] })),
29
+ findings: [],
30
+ hopsUsed: 0,
31
+ };
32
+ }
33
+ /**
34
+ * Which hypothesis to test next: the open one with the highest prior.
35
+ *
36
+ * Returns `undefined` when the budget is spent or nothing is open, which is how
37
+ * the caller learns to stop. Deliberately not "cheapest first" — the point of
38
+ * research is to resolve the question, and testing a likely explanation first is
39
+ * what lets a later hop be skipped entirely.
40
+ */
41
+ export function nextHypothesis(state, limits = DEFAULT_RESEARCH_LIMITS) {
42
+ if (state.hopsUsed >= limits.maxHops)
43
+ return undefined;
44
+ return [...state.hypotheses]
45
+ .filter((hypothesis) => hypothesis.status === 'open')
46
+ .sort((left, right) => right.priorConfidence - left.priorConfidence || left.id.localeCompare(right.id))[0];
47
+ }
48
+ /**
49
+ * Fold a finding into the state — the replan edge.
50
+ *
51
+ * A refutation CLOSES its hypothesis rather than leaving it open to be retried:
52
+ * the template's failure was continuing to elaborate a premise its own evidence
53
+ * had already ruled out.
54
+ *
55
+ * Spawned hypotheses are admitted only while there is room, and never duplicate
56
+ * an existing statement — a loop that keeps re-proposing the same idea burns the
57
+ * whole hop budget without learning anything.
58
+ */
59
+ export function applyFinding(state, finding, limits = DEFAULT_RESEARCH_LIMITS) {
60
+ const hypotheses = state.hypotheses.map((hypothesis) => {
61
+ if (hypothesis.id !== finding.hypothesisId)
62
+ return hypothesis;
63
+ const status = finding.verdict === 'supports'
64
+ ? 'supported'
65
+ : finding.verdict === 'refutes'
66
+ ? 'refuted'
67
+ : 'inconclusive';
68
+ return {
69
+ ...hypothesis,
70
+ status,
71
+ evidenceIds: [...hypothesis.evidenceIds, finding.id],
72
+ rationale: finding.summary,
73
+ };
74
+ });
75
+ const known = new Set(hypotheses.map((hypothesis) => normalizeStatement(hypothesis.statement)));
76
+ const openCount = () => hypotheses.filter((hypothesis) => hypothesis.status === 'open').length;
77
+ for (const spawn of finding.spawns ?? []) {
78
+ const key = normalizeStatement(spawn.statement);
79
+ if (!spawn.statement.trim() || known.has(key))
80
+ continue;
81
+ if (openCount() >= limits.maxOpenHypotheses)
82
+ break;
83
+ known.add(key);
84
+ hypotheses.push({
85
+ id: `${finding.hypothesisId}.${hypotheses.length + 1}`,
86
+ statement: spawn.statement,
87
+ priorConfidence: clamp01(spawn.priorConfidence),
88
+ status: 'open',
89
+ evidenceIds: [],
90
+ parentId: finding.hypothesisId,
91
+ });
92
+ }
93
+ return {
94
+ ...state,
95
+ hypotheses,
96
+ findings: [...state.findings, finding],
97
+ hopsUsed: state.hopsUsed + 1,
98
+ };
99
+ }
100
+ /**
101
+ * Summarise what the investigation established.
102
+ *
103
+ * `unresolved` is reported as prominently as `supported` on purpose. A research
104
+ * answer that lists only what it confirmed reads as a complete explanation, and
105
+ * the one thing a bounded investigation cannot honestly claim is completeness.
106
+ */
107
+ export function concludeResearch(state, limits = DEFAULT_RESEARCH_LIMITS) {
108
+ const byConfidence = (left, right) => right.priorConfidence - left.priorConfidence || left.id.localeCompare(right.id);
109
+ const open = state.hypotheses.filter((hypothesis) => hypothesis.status === 'open');
110
+ return {
111
+ supported: state.hypotheses.filter((h) => h.status === 'supported').sort(byConfidence),
112
+ refuted: state.hypotheses.filter((h) => h.status === 'refuted').sort(byConfidence),
113
+ unresolved: [...open, ...state.hypotheses.filter((h) => h.status === 'inconclusive')].sort(byConfidence),
114
+ exhausted: state.hopsUsed >= limits.maxHops && open.length > 0,
115
+ };
116
+ }
117
+ function normalizeStatement(value) {
118
+ return value.trim().toLowerCase().replace(/\s+/g, ' ');
119
+ }
120
+ function clamp01(value) {
121
+ if (!Number.isFinite(value))
122
+ return 0;
123
+ return Math.max(0, Math.min(1, value));
124
+ }
125
+ //# sourceMappingURL=hypothesis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hypothesis.js","sourceRoot":"","sources":["../../../src/agentic/research/hypothesis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Turn the branch outcomes into the story the dossier was missing.
3
+ *
4
+ * Measured on a live run: five grounded hypotheses were planned, all five
5
+ * branches executed, and the answer the reader got was a single fact from one
6
+ * of them — "2025-05-01T00:00:00.000Z is the largest order_month at 31.1K". The
7
+ * other four findings existed and were discarded. The real story was sitting in
8
+ * the data: one explanation was answerable, four were blocked by uncertified
9
+ * joins. That is a useful answer about the project, and it never surfaced.
10
+ *
11
+ * This layer is DELIBERATELY DETERMINISTIC. It reports what was tested and what
12
+ * each branch established or could not establish, and it never says which
13
+ * hypothesis is TRUE — that is a judgment the branch summaries do not license,
14
+ * and inventing it here would put an unverified causal claim into a governed
15
+ * dossier. Narration of the numbers stays with the verified-fact narrator.
16
+ */
17
+ import { type ResearchLimits } from './hypothesis.js';
18
+ export interface ResearchBranchOutcome {
19
+ /** The hypothesis this branch was testing. */
20
+ statement: string;
21
+ /** Did the branch actually produce data? */
22
+ produced: boolean;
23
+ /** The branch's own summary, used to explain a blocked branch. */
24
+ summary?: string;
25
+ status?: string;
26
+ }
27
+ export declare function synthesizeResearchNarrative(input: {
28
+ question: string;
29
+ branches: ResearchBranchOutcome[];
30
+ limits?: ResearchLimits;
31
+ }): string | undefined;
32
+ //# sourceMappingURL=synthesis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis.d.ts","sourceRoot":"","sources":["../../../src/agentic/research/synthesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,qBAAqB;IACpC,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAuBD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,GAAG,MAAM,GAAG,SAAS,CAwErB"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Turn the branch outcomes into the story the dossier was missing.
3
+ *
4
+ * Measured on a live run: five grounded hypotheses were planned, all five
5
+ * branches executed, and the answer the reader got was a single fact from one
6
+ * of them — "2025-05-01T00:00:00.000Z is the largest order_month at 31.1K". The
7
+ * other four findings existed and were discarded. The real story was sitting in
8
+ * the data: one explanation was answerable, four were blocked by uncertified
9
+ * joins. That is a useful answer about the project, and it never surfaced.
10
+ *
11
+ * This layer is DELIBERATELY DETERMINISTIC. It reports what was tested and what
12
+ * each branch established or could not establish, and it never says which
13
+ * hypothesis is TRUE — that is a judgment the branch summaries do not license,
14
+ * and inventing it here would put an unverified causal claim into a governed
15
+ * dossier. Narration of the numbers stays with the verified-fact narrator.
16
+ */
17
+ import { applyFinding, concludeResearch, createResearchState, } from './hypothesis.js';
18
+ /** Why a branch produced nothing, in the reader's language. */
19
+ function blockedReason(summary) {
20
+ if (!summary)
21
+ return undefined;
22
+ if (/isn't certified yet|not certified|uncertified/i.test(summary)) {
23
+ return 'the join it needs is not certified yet';
24
+ }
25
+ if (/not bound to any modeled entity|unmodelled|unmodeled/i.test(summary)) {
26
+ return 'it references data that is not modeled';
27
+ }
28
+ if (/missing|no result|0 rows|empty/i.test(summary)) {
29
+ return 'the query returned nothing to compare';
30
+ }
31
+ return undefined;
32
+ }
33
+ function sentenceList(items) {
34
+ if (items.length === 0)
35
+ return '';
36
+ if (items.length === 1)
37
+ return items[0];
38
+ return `${items.slice(0, -1).join('; ')}; and ${items[items.length - 1]}`;
39
+ }
40
+ export function synthesizeResearchNarrative(input) {
41
+ const branches = input.branches.filter((branch) => branch.statement.trim().length > 0);
42
+ if (branches.length === 0)
43
+ return undefined;
44
+ let state = createResearchState(input.question, branches.map((branch, index) => ({
45
+ id: `h${index + 1}`,
46
+ statement: branch.statement.trim(),
47
+ priorConfidence: 1 - index / (branches.length + 1),
48
+ })));
49
+ branches.forEach((branch, index) => {
50
+ state = applyFinding(state, {
51
+ id: `f${index + 1}`,
52
+ hypothesisId: `h${index + 1}`,
53
+ // `supports` would claim the observation MATCHED what the hypothesis
54
+ // predicted, and only the expectation can decide that. Producing rows
55
+ // means the branch was observed, so it is recorded as inconclusive with
56
+ // higher strength — the narrative below reports "investigated", never
57
+ // "confirmed", and the distinction has to hold in the data too.
58
+ verdict: 'inconclusive',
59
+ summary: branch.summary ?? '',
60
+ strength: branch.produced ? 0.6 : 0.1,
61
+ }, input.limits);
62
+ });
63
+ const conclusion = concludeResearch(state, input.limits);
64
+ // Everything lands in `unresolved` now that no branch claims support, so the
65
+ // split is by whether the branch produced observable evidence at all.
66
+ const producedBy = new Map(branches.map((branch) => [branch.statement.trim(), branch.produced]));
67
+ const investigated = conclusion.unresolved.filter((h) => producedBy.get(h.statement) === true);
68
+ const blocked = conclusion.unresolved.filter((h) => producedBy.get(h.statement) !== true);
69
+ const lines = [
70
+ `I tested ${branches.length} competing explanation${branches.length === 1 ? '' : 's'} for this question.`,
71
+ ];
72
+ if (investigated.length > 0) {
73
+ lines.push('', `**Investigated (${investigated.length}):**`, ...investigated.map((hypothesis) => `- ${hypothesis.statement}`));
74
+ }
75
+ if (blocked.length > 0) {
76
+ const reasons = new Set(blocked
77
+ .map((hypothesis) => {
78
+ const branch = branches.find((candidate) => candidate.statement.trim() === hypothesis.statement);
79
+ return blockedReason(branch?.summary);
80
+ })
81
+ .filter((reason) => Boolean(reason)));
82
+ lines.push('', `**Could not be settled (${blocked.length}):**`, ...blocked.map((hypothesis) => `- ${hypothesis.statement}`));
83
+ if (reasons.size > 0) {
84
+ lines.push('', `These were blocked because ${sentenceList([...reasons])}.`);
85
+ }
86
+ }
87
+ if (investigated.length === 0) {
88
+ // The honest headline when nothing could be established: say so first,
89
+ // rather than leading with a number from the one branch that ran.
90
+ lines.splice(1, 0, '', 'None of them could be settled with the governed model as it stands.');
91
+ }
92
+ return lines.join('\n');
93
+ }
94
+ //# sourceMappingURL=synthesis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesis.js","sourceRoot":"","sources":["../../../src/agentic/research/synthesis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Hypothesis-driven research planning.
3
+ *
4
+ * `planResearch` emits a fixed template — baseline, compare over time, break
5
+ * down by a dimension scraped out of the question with a regex — bound to one
6
+ * metric and frozen before any observation. That is why deep research answers
7
+ * one question instead of telling a story: the shape of the investigation is
8
+ * decided before the investigation starts, so nothing it learns can change what
9
+ * it does next.
10
+ *
11
+ * This produces HYPOTHESES instead: falsifiable statements about why the
12
+ * observed thing happened, each mapped to a step that would support or refute
13
+ * it. The existing executor runs them unchanged, because the output is still a
14
+ * `ResearchStep[]` — the strangler seam is the plan, not the runner.
15
+ *
16
+ * Grounding is unchanged and non-negotiable: every hypothesis must name a real
17
+ * metric, block, or dimension from the catalog. A hypothesis about an asset
18
+ * that does not exist cannot be investigated, and inventing one is how a
19
+ * research dossier ends up confidently discussing a table nobody has.
20
+ */
21
+ import type { ResearchStep } from '../research-loop.js';
22
+ /** The assets a hypothesis may reference. Nothing outside this may appear. */
23
+ export interface ResearchAssets {
24
+ metrics: string[];
25
+ blocks: string[];
26
+ dimensions: string[];
27
+ }
28
+ export interface ResearchHypothesis {
29
+ /** A falsifiable statement, not a task. */
30
+ statement: string;
31
+ /** Belief before evidence, 0..1 — decides what is tested first. */
32
+ priorConfidence: number;
33
+ /** The asset whose inspection would settle it. Must exist in ResearchAssets. */
34
+ target: string;
35
+ action: ResearchStep['action']['kind'];
36
+ /** What an observation must show for the statement to hold. */
37
+ expectation: string;
38
+ }
39
+ interface PlanProvider {
40
+ generate(messages: {
41
+ role: 'system' | 'user' | 'assistant';
42
+ content: string;
43
+ }[], options?: Record<string, unknown>): Promise<string>;
44
+ }
45
+ export declare function parseResearchHypotheses(raw: string, assets: ResearchAssets): ResearchHypothesis[];
46
+ /** One structured call. Returns [] on any failure, so the caller keeps its template. */
47
+ export declare function planResearchHypotheses(provider: PlanProvider, question: string, assets: ResearchAssets, options?: {
48
+ signal?: AbortSignal;
49
+ timeoutMs?: number;
50
+ }): Promise<ResearchHypothesis[]>;
51
+ /** Render hypotheses as the steps the existing executor already knows how to run. */
52
+ export declare function hypothesesToSteps(hypotheses: ResearchHypothesis[]): ResearchStep[];
53
+ export {};
54
+ //# sourceMappingURL=research-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"research-agent.d.ts","sourceRoot":"","sources":["../../src/agentic/research-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,QAAQ,CACN,QAAQ,EAAE;QAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,EACtE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB;AAiED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,kBAAkB,EAAE,CA+BjG;AAED,wFAAwF;AACxF,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,EACtB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA0B/B;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,EAAE,GAAG,YAAY,EAAE,CAQlF"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Hypothesis-driven research planning.
3
+ *
4
+ * `planResearch` emits a fixed template — baseline, compare over time, break
5
+ * down by a dimension scraped out of the question with a regex — bound to one
6
+ * metric and frozen before any observation. That is why deep research answers
7
+ * one question instead of telling a story: the shape of the investigation is
8
+ * decided before the investigation starts, so nothing it learns can change what
9
+ * it does next.
10
+ *
11
+ * This produces HYPOTHESES instead: falsifiable statements about why the
12
+ * observed thing happened, each mapped to a step that would support or refute
13
+ * it. The existing executor runs them unchanged, because the output is still a
14
+ * `ResearchStep[]` — the strangler seam is the plan, not the runner.
15
+ *
16
+ * Grounding is unchanged and non-negotiable: every hypothesis must name a real
17
+ * metric, block, or dimension from the catalog. A hypothesis about an asset
18
+ * that does not exist cannot be investigated, and inventing one is how a
19
+ * research dossier ends up confidently discussing a table nobody has.
20
+ */
21
+ const ACTION_KINDS = new Set([
22
+ 'lookup_metric', 'lookup_block', 'breakdown', 'compare_time', 'check_lineage', 'compose_app',
23
+ ]);
24
+ const PROMPT = `You plan a data investigation. Do not answer the question and do not write SQL.
25
+
26
+ Propose competing HYPOTHESES for what the data will show — falsifiable statements
27
+ about WHY, not a list of tasks. "Revenue fell because enterprise customers churned"
28
+ is a hypothesis. "Break revenue down by segment" is a task; do not write those.
29
+
30
+ Rules:
31
+ - Every hypothesis must name one asset from the catalog list you are given, exactly
32
+ as spelled there. A hypothesis about an asset that does not exist cannot be tested.
33
+ - Propose competing explanations, not one explanation in several phrasings. If two
34
+ hypotheses would be settled by the same observation, keep only the stronger.
35
+ - priorConfidence is your belief BEFORE evidence, 0..1. Do not make them all equal.
36
+ - expectation must state what an observation has to show for the statement to HOLD,
37
+ so that seeing the opposite refutes it.
38
+
39
+ Reply with ONLY a JSON object:
40
+ {"hypotheses":[{"statement":"...","priorConfidence":0.6,"target":"<asset>",
41
+ "action":"lookup_metric|lookup_block|breakdown|compare_time|check_lineage",
42
+ "expectation":"..."}]}
43
+ Between two and five hypotheses.`;
44
+ function extractJsonObject(raw) {
45
+ const trimmed = raw.trim();
46
+ const start = trimmed.indexOf('{');
47
+ if (start < 0)
48
+ return undefined;
49
+ let depth = 0;
50
+ let inString = false;
51
+ let escaped = false;
52
+ for (let i = start; i < trimmed.length; i += 1) {
53
+ const char = trimmed[i];
54
+ if (escaped) {
55
+ escaped = false;
56
+ continue;
57
+ }
58
+ if (char === '\\') {
59
+ escaped = true;
60
+ continue;
61
+ }
62
+ if (char === '"') {
63
+ inString = !inString;
64
+ continue;
65
+ }
66
+ if (inString)
67
+ continue;
68
+ if (char === '{')
69
+ depth += 1;
70
+ else if (char === '}') {
71
+ depth -= 1;
72
+ if (depth === 0) {
73
+ try {
74
+ return JSON.parse(trimmed.slice(start, i + 1));
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ }
80
+ }
81
+ }
82
+ return undefined;
83
+ }
84
+ /** Match a model-named asset to a real one, tolerating case and qualification. */
85
+ function resolveAsset(target, assets) {
86
+ const pool = [...assets.metrics, ...assets.blocks, ...assets.dimensions];
87
+ const wanted = target.trim().toLowerCase();
88
+ if (!wanted)
89
+ return undefined;
90
+ const exact = pool.find((asset) => asset.toLowerCase() === wanted);
91
+ if (exact)
92
+ return exact;
93
+ // `orders.revenue` offered as `revenue`, and the reverse.
94
+ return pool.find((asset) => {
95
+ const leaf = asset.toLowerCase().split('.').at(-1) ?? '';
96
+ return leaf === wanted || asset.toLowerCase() === wanted.split('.').at(-1);
97
+ });
98
+ }
99
+ export function parseResearchHypotheses(raw, assets) {
100
+ const parsed = extractJsonObject(raw);
101
+ if (!parsed || typeof parsed !== 'object')
102
+ return [];
103
+ const list = parsed.hypotheses;
104
+ if (!Array.isArray(list))
105
+ return [];
106
+ const seen = new Set();
107
+ const out = [];
108
+ for (const entry of list) {
109
+ if (!entry || typeof entry !== 'object')
110
+ continue;
111
+ const record = entry;
112
+ const statement = typeof record.statement === 'string' ? record.statement.trim() : '';
113
+ const expectation = typeof record.expectation === 'string' ? record.expectation.trim() : '';
114
+ if (!statement || !expectation)
115
+ continue;
116
+ // UNGROUNDED HYPOTHESES ARE DROPPED, not repaired. A statement about an
117
+ // asset nobody has cannot be investigated, and keeping it would put an
118
+ // invented table into a dossier that reads as governed.
119
+ const target = resolveAsset(typeof record.target === 'string' ? record.target : '', assets);
120
+ if (!target)
121
+ continue;
122
+ const action = typeof record.action === 'string' && ACTION_KINDS.has(record.action)
123
+ ? record.action
124
+ : 'lookup_metric';
125
+ const key = statement.toLowerCase().replace(/\s+/g, ' ');
126
+ if (seen.has(key))
127
+ continue;
128
+ seen.add(key);
129
+ const prior = typeof record.priorConfidence === 'number' && Number.isFinite(record.priorConfidence)
130
+ ? Math.max(0, Math.min(1, record.priorConfidence))
131
+ : 0.5;
132
+ out.push({ statement, priorConfidence: prior, target, action, expectation });
133
+ if (out.length >= 5)
134
+ break;
135
+ }
136
+ return out.sort((left, right) => right.priorConfidence - left.priorConfidence);
137
+ }
138
+ /** One structured call. Returns [] on any failure, so the caller keeps its template. */
139
+ export async function planResearchHypotheses(provider, question, assets, options = {}) {
140
+ if (assets.metrics.length === 0 && assets.blocks.length === 0)
141
+ return [];
142
+ const controller = new AbortController();
143
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 20_000);
144
+ const onAbort = () => controller.abort();
145
+ options.signal?.addEventListener('abort', onAbort, { once: true });
146
+ try {
147
+ const catalog = [
148
+ assets.metrics.length ? `metrics: ${assets.metrics.join(', ')}` : '',
149
+ assets.blocks.length ? `certified blocks: ${assets.blocks.join(', ')}` : '',
150
+ assets.dimensions.length ? `dimensions: ${assets.dimensions.join(', ')}` : '',
151
+ ].filter(Boolean).join('\n');
152
+ const raw = await provider.generate([
153
+ { role: 'system', content: `${PROMPT}\n\nCatalog:\n${catalog}` },
154
+ { role: 'user', content: question },
155
+ ], { signal: controller.signal });
156
+ return parseResearchHypotheses(raw, assets);
157
+ }
158
+ catch {
159
+ return [];
160
+ }
161
+ finally {
162
+ clearTimeout(timer);
163
+ options.signal?.removeEventListener('abort', onAbort);
164
+ }
165
+ }
166
+ /** Render hypotheses as the steps the existing executor already knows how to run. */
167
+ export function hypothesesToSteps(hypotheses) {
168
+ return hypotheses.map((hypothesis) => ({
169
+ // The thought IS the hypothesis, so the trace and the dossier show what is
170
+ // being tested rather than which tool is being called.
171
+ thought: hypothesis.statement,
172
+ action: { kind: hypothesis.action, target: hypothesis.target },
173
+ expectation: hypothesis.expectation,
174
+ }));
175
+ }
176
+ //# sourceMappingURL=research-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"research-agent.js","sourceRoot":"","sources":["../../src/agentic/research-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA8BH,MAAM,YAAY,GAAgD,IAAI,GAAG,CAAC;IACxE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa;CAC7F,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;iCAmBkB,CAAC;AAElC,SAAS,iBAAiB,CAAC,GAAW;IACpC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,OAAO,EAAE,CAAC;YAAC,OAAO,GAAG,KAAK,CAAC;YAAC,SAAS;QAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAAC,OAAO,GAAG,IAAI,CAAC;YAAC,SAAS;QAAC,CAAC;QAChD,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YAAC,QAAQ,GAAG,CAAC,QAAQ,CAAC;YAAC,SAAS;QAAC,CAAC;QACrD,IAAI,QAAQ;YAAE,SAAS;QACvB,IAAI,IAAI,KAAK,GAAG;YAAE,KAAK,IAAI,CAAC,CAAC;aACxB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,IAAI,CAAC,CAAC;YACX,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC;oBAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAAC,CAAC;gBAAC,MAAM,CAAC;oBAAC,OAAO,SAAS,CAAC;gBAAC,CAAC;YACrF,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,YAAY,CAAC,MAAc,EAAE,MAAsB;IAC1D,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;IACnE,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,0DAA0D;IAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzD,OAAO,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAW,EAAE,MAAsB;IACzE,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACrD,MAAM,IAAI,GAAI,MAAmC,CAAC,UAAU,CAAC;IAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QAClD,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,MAAM,SAAS,GAAG,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,WAAW,GAAG,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW;YAAE,SAAS;QACzC,wEAAwE;QACxE,uEAAuE;QACvE,wDAAwD;QACxD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC5F,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,MAAe,CAAC;YAC1F,CAAC,CAAC,MAAM,CAAC,MAAwC;YACjD,CAAC,CAAC,eAAe,CAAC;QACpB,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACzD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,MAAM,KAAK,GAAG,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC;YACjG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC;YAClD,CAAC,CAAC,GAAG,CAAC;QACR,GAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7E,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;YAAE,MAAM;IAC7B,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;AACjF,CAAC;AAED,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,QAAsB,EACtB,QAAgB,EAChB,MAAsB,EACtB,UAAwD,EAAE;IAE1D,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzC,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG;YACd,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACpE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YAC3E,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;SAC9E,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CACjC;YACE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,iBAAiB,OAAO,EAAE,EAAE;YAChE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;SACpC,EACD,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAC;QACF,OAAO,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACpB,OAAO,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,iBAAiB,CAAC,UAAgC;IAChE,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACrC,2EAA2E;QAC3E,uDAAuD;QACvD,OAAO,EAAE,UAAU,CAAC,SAAS;QAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;QAC9D,WAAW,EAAE,UAAU,CAAC,WAAW;KACpC,CAAC,CAAC,CAAC;AACN,CAAC"}