@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 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-tools.js","sourceRoot":"","sources":["../../src/agentic/ledger-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which orchestrator handles a turn.
|
|
3
|
+
*
|
|
4
|
+
* The rebuild is a strangler, not a rewrite: the new loop runs BESIDE the
|
|
5
|
+
* 10k-line answer loop and takes traffic one lane at a time. `answer-loop.ts`
|
|
6
|
+
* grew from 4,532 to 10,105 lines over 300 commits because every fix had to land
|
|
7
|
+
* inside it; the only way that stops is for new behaviour to have somewhere else
|
|
8
|
+
* to go while the old path keeps serving.
|
|
9
|
+
*
|
|
10
|
+
* Default is `legacy` on purpose. A flag that defaults on is not a migration
|
|
11
|
+
* control, it is a release — and this one changes how every question is answered.
|
|
12
|
+
*/
|
|
13
|
+
export type OrchestratorMode = 'legacy' | 'shadow' | 'agentic';
|
|
14
|
+
/**
|
|
15
|
+
* Lanes migrate independently, cheapest risk first. `certified` and `semantic`
|
|
16
|
+
* go early precisely because the agentic path for them is a BYPASS (no planner,
|
|
17
|
+
* no tools) — it is the <5s fast lane, not new reasoning.
|
|
18
|
+
*/
|
|
19
|
+
export type AgenticLane = 'conversational' | 'definition' | 'certified' | 'semantic' | 'generated' | 'research';
|
|
20
|
+
export declare const AGENTIC_LANES: readonly AgenticLane[];
|
|
21
|
+
export interface OrchestratorPolicy {
|
|
22
|
+
mode: OrchestratorMode;
|
|
23
|
+
lanes: ReadonlySet<AgenticLane>;
|
|
24
|
+
maxIterations: number;
|
|
25
|
+
/** Fall back to the legacy loop when the agentic path throws. */
|
|
26
|
+
fallbackOnError: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Bounded by default: an agent loop without a ceiling is an outage waiting to happen. */
|
|
29
|
+
export declare const DEFAULT_MAX_ITERATIONS = 8;
|
|
30
|
+
export declare const LEGACY_ORCHESTRATOR_POLICY: OrchestratorPolicy;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the policy from project config plus an optional host override.
|
|
33
|
+
*
|
|
34
|
+
* Malformed input resolves to `legacy` rather than to a partial agentic policy.
|
|
35
|
+
* A typo in `dql.config.json` must not silently route real questions through an
|
|
36
|
+
* unproven path.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveOrchestratorPolicy(input?: {
|
|
39
|
+
config?: {
|
|
40
|
+
mode?: unknown;
|
|
41
|
+
lanes?: unknown;
|
|
42
|
+
maxIterations?: unknown;
|
|
43
|
+
fallbackOnError?: unknown;
|
|
44
|
+
} | null;
|
|
45
|
+
/** Host-owned per-request override; never parsed from user-facing request fields. */
|
|
46
|
+
override?: {
|
|
47
|
+
mode?: unknown;
|
|
48
|
+
lanes?: unknown;
|
|
49
|
+
} | null;
|
|
50
|
+
}): OrchestratorPolicy;
|
|
51
|
+
/**
|
|
52
|
+
* Does this lane run on the agentic path?
|
|
53
|
+
*
|
|
54
|
+
* `shadow` deliberately answers NO. Shadow runs the new loop for comparison only;
|
|
55
|
+
* letting it serve the user would make "observe before switching" meaningless.
|
|
56
|
+
*/
|
|
57
|
+
export declare function laneUsesAgenticOrchestrator(policy: OrchestratorPolicy, lane: AgenticLane): boolean;
|
|
58
|
+
/** Should the new loop run purely for comparison on this lane? */
|
|
59
|
+
export declare function laneRunsShadowComparison(policy: OrchestratorPolicy, lane: AgenticLane): boolean;
|
|
60
|
+
//# sourceMappingURL=orchestrator-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-policy.d.ts","sourceRoot":"","sources":["../../src/agentic/orchestrator-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/D;;;;GAIG;AACH,MAAM,MAAM,WAAW,GACnB,gBAAgB,GAChB,YAAY,GACZ,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,CAAC;AAEf,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAE/C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,eAAO,MAAM,0BAA0B,EAAE,kBAKxC,CAAC;AAgBF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,GAAE;IAC/C,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACxG,qFAAqF;IACrF,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAClD,GAAG,kBAAkB,CAa1B;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAElG;AAED,kEAAkE;AAClE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAE/F"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which orchestrator handles a turn.
|
|
3
|
+
*
|
|
4
|
+
* The rebuild is a strangler, not a rewrite: the new loop runs BESIDE the
|
|
5
|
+
* 10k-line answer loop and takes traffic one lane at a time. `answer-loop.ts`
|
|
6
|
+
* grew from 4,532 to 10,105 lines over 300 commits because every fix had to land
|
|
7
|
+
* inside it; the only way that stops is for new behaviour to have somewhere else
|
|
8
|
+
* to go while the old path keeps serving.
|
|
9
|
+
*
|
|
10
|
+
* Default is `legacy` on purpose. A flag that defaults on is not a migration
|
|
11
|
+
* control, it is a release — and this one changes how every question is answered.
|
|
12
|
+
*/
|
|
13
|
+
export const AGENTIC_LANES = [
|
|
14
|
+
'conversational', 'definition', 'certified', 'semantic', 'generated', 'research',
|
|
15
|
+
];
|
|
16
|
+
/** Bounded by default: an agent loop without a ceiling is an outage waiting to happen. */
|
|
17
|
+
export const DEFAULT_MAX_ITERATIONS = 8;
|
|
18
|
+
export const LEGACY_ORCHESTRATOR_POLICY = {
|
|
19
|
+
mode: 'legacy',
|
|
20
|
+
lanes: new Set(),
|
|
21
|
+
maxIterations: DEFAULT_MAX_ITERATIONS,
|
|
22
|
+
fallbackOnError: true,
|
|
23
|
+
};
|
|
24
|
+
function parseMode(value) {
|
|
25
|
+
return value === 'legacy' || value === 'shadow' || value === 'agentic' ? value : undefined;
|
|
26
|
+
}
|
|
27
|
+
function parseLanes(value) {
|
|
28
|
+
if (!Array.isArray(value))
|
|
29
|
+
return undefined;
|
|
30
|
+
const lanes = new Set();
|
|
31
|
+
for (const entry of value) {
|
|
32
|
+
if (typeof entry !== 'string')
|
|
33
|
+
continue;
|
|
34
|
+
if (AGENTIC_LANES.includes(entry))
|
|
35
|
+
lanes.add(entry);
|
|
36
|
+
}
|
|
37
|
+
return lanes;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the policy from project config plus an optional host override.
|
|
41
|
+
*
|
|
42
|
+
* Malformed input resolves to `legacy` rather than to a partial agentic policy.
|
|
43
|
+
* A typo in `dql.config.json` must not silently route real questions through an
|
|
44
|
+
* unproven path.
|
|
45
|
+
*/
|
|
46
|
+
export function resolveOrchestratorPolicy(input = {}) {
|
|
47
|
+
const mode = parseMode(input.override?.mode) ?? parseMode(input.config?.mode) ?? 'legacy';
|
|
48
|
+
const lanes = parseLanes(input.override?.lanes) ?? parseLanes(input.config?.lanes) ?? new Set();
|
|
49
|
+
const rawIterations = input.config?.maxIterations;
|
|
50
|
+
const maxIterations = typeof rawIterations === 'number' && Number.isFinite(rawIterations) && rawIterations > 0
|
|
51
|
+
? Math.min(Math.floor(rawIterations), 40)
|
|
52
|
+
: DEFAULT_MAX_ITERATIONS;
|
|
53
|
+
return {
|
|
54
|
+
mode,
|
|
55
|
+
lanes,
|
|
56
|
+
maxIterations,
|
|
57
|
+
fallbackOnError: input.config?.fallbackOnError !== false,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Does this lane run on the agentic path?
|
|
62
|
+
*
|
|
63
|
+
* `shadow` deliberately answers NO. Shadow runs the new loop for comparison only;
|
|
64
|
+
* letting it serve the user would make "observe before switching" meaningless.
|
|
65
|
+
*/
|
|
66
|
+
export function laneUsesAgenticOrchestrator(policy, lane) {
|
|
67
|
+
return policy.mode === 'agentic' && policy.lanes.has(lane);
|
|
68
|
+
}
|
|
69
|
+
/** Should the new loop run purely for comparison on this lane? */
|
|
70
|
+
export function laneRunsShadowComparison(policy, lane) {
|
|
71
|
+
return policy.mode === 'shadow' && policy.lanes.has(lane);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=orchestrator-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator-policy.js","sourceRoot":"","sources":["../../src/agentic/orchestrator-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiBH,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU;CACjF,CAAC;AAUF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,0BAA0B,GAAuB;IAC5D,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,IAAI,GAAG,EAAe;IAC7B,aAAa,EAAE,sBAAsB;IACrC,eAAe,EAAE,IAAI;CACtB,CAAC;AAEF,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7F,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAe,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QACxC,IAAK,aAAmC,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,KAAoB,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAItC,EAAE;IACJ,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC1F,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,IAAI,GAAG,EAAe,CAAC;IAC7G,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC;IAClD,MAAM,aAAa,GAAG,OAAO,aAAa,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,GAAG,CAAC;QAC5G,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;QACzC,CAAC,CAAC,sBAAsB,CAAC;IAC3B,OAAO;QACL,IAAI;QACJ,KAAK;QACL,aAAa;QACb,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,eAAe,KAAK,KAAK;KACzD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAA0B,EAAE,IAAiB;IACvF,OAAO,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,wBAAwB,CAAC,MAA0B,EAAE,IAAiB;IACpF,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The strangler seam.
|
|
3
|
+
*
|
|
4
|
+
* `answer-loop.ts` grew from 4,532 to 10,105 lines over 300 commits because
|
|
5
|
+
* every fix had to land inside it — 12% of all commits in that window touched
|
|
6
|
+
* that one file. New behaviour only stops accreting there once it has somewhere
|
|
7
|
+
* else to go WHILE the old path keeps serving.
|
|
8
|
+
*
|
|
9
|
+
* `answerAgentic` has the same signature as `answer`, so the two are
|
|
10
|
+
* interchangeable at a single call site. Which one runs is a per-lane config
|
|
11
|
+
* decision, and the default is legacy: this file is a migration control, not a
|
|
12
|
+
* release.
|
|
13
|
+
*/
|
|
14
|
+
import type { AgentAnswer, AnswerLoopInput } from '../answer-loop.js';
|
|
15
|
+
import { type AgenticLane, type OrchestratorPolicy } from './orchestrator-policy.js';
|
|
16
|
+
/** The legacy loop, injected so this module never imports the 10k-line file's runtime. */
|
|
17
|
+
export type LegacyAnswerFn = (input: AnswerLoopInput) => Promise<AgentAnswer>;
|
|
18
|
+
/** The agentic path for one lane. Absent lanes fall through to legacy. */
|
|
19
|
+
export type AgenticLaneHandler = (input: AnswerLoopInput) => Promise<AgentAnswer>;
|
|
20
|
+
export interface AnswerAgenticOptions {
|
|
21
|
+
policy: OrchestratorPolicy;
|
|
22
|
+
/** Which lane this turn belongs to, decided by triage before dispatch. */
|
|
23
|
+
lane: AgenticLane;
|
|
24
|
+
legacy: LegacyAnswerFn;
|
|
25
|
+
/** Registered agentic handlers. A lane enabled with no handler falls back. */
|
|
26
|
+
handlers?: Partial<Record<AgenticLane, AgenticLaneHandler>>;
|
|
27
|
+
/** Non-fatal diagnostics, so a silent fallback cannot hide a broken lane. */
|
|
28
|
+
onDiagnostic?: (event: OrchestratorDiagnostic) => void;
|
|
29
|
+
}
|
|
30
|
+
export interface OrchestratorDiagnostic {
|
|
31
|
+
kind: 'fallback' | 'dispatch';
|
|
32
|
+
lane: AgenticLane;
|
|
33
|
+
mode: OrchestratorPolicy['mode'];
|
|
34
|
+
reason?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Marker appended to the answer's route evidence when the agentic path bailed. */
|
|
37
|
+
export declare const ORCHESTRATOR_FALLBACK_STEP = "orchestrator_fallback";
|
|
38
|
+
/**
|
|
39
|
+
* Route one turn to the agentic loop or the legacy answer loop.
|
|
40
|
+
*
|
|
41
|
+
* Fallback is RECORDED on the answer's evidence rather than swallowed. A
|
|
42
|
+
* silently-degrading migration looks exactly like a working one until someone
|
|
43
|
+
* notices the new path never actually ran, so `orchestratorFallbackRate` has to
|
|
44
|
+
* be observable from the run itself.
|
|
45
|
+
*/
|
|
46
|
+
export declare function answerAgentic(input: AnswerLoopInput, options: AnswerAgenticOptions): Promise<AgentAnswer>;
|
|
47
|
+
/**
|
|
48
|
+
* Stamp the fallback onto the answer's route evidence.
|
|
49
|
+
*
|
|
50
|
+
* Prepended, not appended: the first thing a reader of the trace should see is
|
|
51
|
+
* that this answer did not come from the path the config selected.
|
|
52
|
+
*/
|
|
53
|
+
export declare function withFallbackEvidence(answer: AgentAnswer, lane: AgenticLane, reason: string): AgentAnswer;
|
|
54
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/agentic/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAElC,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAE9E,0EAA0E;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;AAElF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,0EAA0E;IAC1E,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC5D,6EAA6E;IAC7E,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC9B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mFAAmF;AACnF,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,WAAW,CAAC,CAqBtB;AAQD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAkBxG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { laneUsesAgenticOrchestrator, } from './orchestrator-policy.js';
|
|
2
|
+
/** Marker appended to the answer's route evidence when the agentic path bailed. */
|
|
3
|
+
export const ORCHESTRATOR_FALLBACK_STEP = 'orchestrator_fallback';
|
|
4
|
+
/**
|
|
5
|
+
* Route one turn to the agentic loop or the legacy answer loop.
|
|
6
|
+
*
|
|
7
|
+
* Fallback is RECORDED on the answer's evidence rather than swallowed. A
|
|
8
|
+
* silently-degrading migration looks exactly like a working one until someone
|
|
9
|
+
* notices the new path never actually ran, so `orchestratorFallbackRate` has to
|
|
10
|
+
* be observable from the run itself.
|
|
11
|
+
*/
|
|
12
|
+
export async function answerAgentic(input, options) {
|
|
13
|
+
const { policy, lane, legacy, handlers, onDiagnostic } = options;
|
|
14
|
+
const handler = handlers?.[lane];
|
|
15
|
+
if (!laneUsesAgenticOrchestrator(policy, lane) || !handler) {
|
|
16
|
+
return legacy(input);
|
|
17
|
+
}
|
|
18
|
+
onDiagnostic?.({ kind: 'dispatch', lane, mode: policy.mode });
|
|
19
|
+
try {
|
|
20
|
+
return await handler(input);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
// A cancellation is the user's decision, not a lane failure: re-running the
|
|
24
|
+
// legacy loop would ignore an abort the caller already made.
|
|
25
|
+
if (isCancellation(error))
|
|
26
|
+
throw error;
|
|
27
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
28
|
+
onDiagnostic?.({ kind: 'fallback', lane, mode: policy.mode, reason });
|
|
29
|
+
if (!policy.fallbackOnError)
|
|
30
|
+
throw error;
|
|
31
|
+
const answer = await legacy(input);
|
|
32
|
+
return withFallbackEvidence(answer, lane, reason);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function isCancellation(error) {
|
|
36
|
+
if (!error || typeof error !== 'object')
|
|
37
|
+
return false;
|
|
38
|
+
const name = error.name;
|
|
39
|
+
return name === 'AbortError' || name === 'CancellationError';
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Stamp the fallback onto the answer's route evidence.
|
|
43
|
+
*
|
|
44
|
+
* Prepended, not appended: the first thing a reader of the trace should see is
|
|
45
|
+
* that this answer did not come from the path the config selected.
|
|
46
|
+
*/
|
|
47
|
+
export function withFallbackEvidence(answer, lane, reason) {
|
|
48
|
+
const evidence = answer.evidence;
|
|
49
|
+
if (!evidence)
|
|
50
|
+
return answer;
|
|
51
|
+
return {
|
|
52
|
+
...answer,
|
|
53
|
+
evidence: {
|
|
54
|
+
...evidence,
|
|
55
|
+
route: [
|
|
56
|
+
{
|
|
57
|
+
tool: ORCHESTRATOR_FALLBACK_STEP,
|
|
58
|
+
status: 'failed',
|
|
59
|
+
label: `Agentic orchestration fell back to the legacy answer loop (${lane})`,
|
|
60
|
+
detail: reason,
|
|
61
|
+
},
|
|
62
|
+
...(evidence.route ?? []),
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/agentic/orchestrator.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,2BAA2B,GAG5B,MAAM,0BAA0B,CAAC;AA0BlC,mFAAmF;AACnF,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAuB,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAsB,EACtB,OAA6B;IAE7B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IACjE,MAAM,OAAO,GAAG,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,CAAC,2BAA2B,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4EAA4E;QAC5E,6DAA6D;QAC7D,IAAI,cAAc,CAAC,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;QACvC,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,YAAY,EAAE,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,eAAe;YAAE,MAAM,KAAK,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,IAAI,GAAI,KAA4B,CAAC,IAAI,CAAC;IAChD,OAAO,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,mBAAmB,CAAC;AAC/D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAmB,EAAE,IAAiB,EAAE,MAAc;IACzF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACjC,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC7B,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,EAAE;YACR,GAAG,QAAQ;YACX,KAAK,EAAE;gBACL;oBACE,IAAI,EAAE,0BAA0B;oBAChC,MAAM,EAAE,QAAiB;oBACzB,KAAK,EAAE,8DAA8D,IAAI,GAAG;oBAC5E,MAAM,EAAE,MAAM;iBACf;gBACD,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;aAC1B;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `preview_query` — the tool that lets the loop ESTABLISH identifiers.
|
|
3
|
+
*
|
|
4
|
+
* The ledger can only admit names a tool returned, so without a way to run
|
|
5
|
+
* something the loop is limited to whatever search and compile happened to
|
|
6
|
+
* surface. That makes it a verifier of other tools' output rather than an
|
|
7
|
+
* investigator: it can reject a wrong column but never discover the right one.
|
|
8
|
+
*
|
|
9
|
+
* A bounded preview closes that. It executes the candidate SQL against the real
|
|
10
|
+
* warehouse and returns the COLUMN NAMES the engine actually produced — the
|
|
11
|
+
* strongest evidence a name exists short of the compiler emitting it, because
|
|
12
|
+
* the database itself resolved it.
|
|
13
|
+
*
|
|
14
|
+
* It returns no cell VALUES. The loop needs to know a column exists, not what is
|
|
15
|
+
* in it, and shipping rows here would route warehouse data to a provider outside
|
|
16
|
+
* the egress policy that governs narration.
|
|
17
|
+
*/
|
|
18
|
+
import type { AgentToolDefinition } from '../providers/types.js';
|
|
19
|
+
export interface PreviewExecutor {
|
|
20
|
+
(sql: string): Promise<{
|
|
21
|
+
columns: unknown[];
|
|
22
|
+
rows: unknown[];
|
|
23
|
+
rowCount: number;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wrap the candidate in a bounded outer SELECT.
|
|
28
|
+
*
|
|
29
|
+
* Wrapping rather than appending `LIMIT`: the candidate may already carry its
|
|
30
|
+
* own LIMIT, an ORDER BY, or a trailing comment, and appending to any of those
|
|
31
|
+
* produces either a syntax error or a silently different query. A subselect
|
|
32
|
+
* bounds it without rewriting what the model wrote.
|
|
33
|
+
*/
|
|
34
|
+
export declare function boundedPreviewSql(sql: string, limit?: number): string;
|
|
35
|
+
export declare function buildPreviewQueryTool(execute: PreviewExecutor, limit?: number): AgentToolDefinition;
|
|
36
|
+
//# sourceMappingURL=preview-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-tool.d.ts","sourceRoot":"","sources":["../../src/agentic/preview-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QAAC,IAAI,EAAE,OAAO,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnF;AAgBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAGhE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,SAAI,GAAG,mBAAmB,CA0C9F"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** Statements a read-only preview may run. */
|
|
2
|
+
const READ_ONLY_START_RE = /^\s*(select|with)\b/i;
|
|
3
|
+
const MUTATION_RE = /\b(insert|update|delete|drop|alter|create|truncate|grant|revoke|copy|attach|install|load|pragma|call|merge)\b/i;
|
|
4
|
+
/** Column name from whatever shape the driver returns. */
|
|
5
|
+
function columnName(column) {
|
|
6
|
+
if (typeof column === 'string')
|
|
7
|
+
return column;
|
|
8
|
+
if (column && typeof column === 'object') {
|
|
9
|
+
const name = column.name;
|
|
10
|
+
if (typeof name === 'string')
|
|
11
|
+
return name;
|
|
12
|
+
}
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Wrap the candidate in a bounded outer SELECT.
|
|
17
|
+
*
|
|
18
|
+
* Wrapping rather than appending `LIMIT`: the candidate may already carry its
|
|
19
|
+
* own LIMIT, an ORDER BY, or a trailing comment, and appending to any of those
|
|
20
|
+
* produces either a syntax error or a silently different query. A subselect
|
|
21
|
+
* bounds it without rewriting what the model wrote.
|
|
22
|
+
*/
|
|
23
|
+
export function boundedPreviewSql(sql, limit = 5) {
|
|
24
|
+
const trimmed = sql.trim().replace(/;\s*$/, '');
|
|
25
|
+
return `SELECT * FROM (\n${trimmed}\n) AS dql_preview LIMIT ${Math.max(1, Math.min(limit, 50))}`;
|
|
26
|
+
}
|
|
27
|
+
export function buildPreviewQueryTool(execute, limit = 5) {
|
|
28
|
+
return {
|
|
29
|
+
name: 'preview_query',
|
|
30
|
+
description: 'Run candidate SQL against the real warehouse with a small row limit and get back the COLUMN NAMES it produced, plus whether it executed. Use this to confirm a query compiles and to learn the exact output column names before composing the final answer. Returns no cell values.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
required: ['sql'],
|
|
35
|
+
properties: {
|
|
36
|
+
sql: { type: 'string', description: 'A single read-only SELECT or WITH statement.' },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
run: async (args) => {
|
|
40
|
+
const input = (args && typeof args === 'object' ? args : {});
|
|
41
|
+
const sql = typeof input.sql === 'string' ? input.sql.trim() : '';
|
|
42
|
+
if (!sql)
|
|
43
|
+
return { error: 'Pass the SQL to preview.' };
|
|
44
|
+
if (!READ_ONLY_START_RE.test(sql) || MUTATION_RE.test(sql)) {
|
|
45
|
+
return { error: 'preview_query runs one read-only SELECT or WITH statement. It cannot modify data.' };
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const result = await execute(boundedPreviewSql(sql, limit));
|
|
49
|
+
const columns = (result.columns ?? [])
|
|
50
|
+
.map(columnName)
|
|
51
|
+
.filter((name) => Boolean(name));
|
|
52
|
+
return {
|
|
53
|
+
executed: true,
|
|
54
|
+
// Names only — never cell values. See the module comment.
|
|
55
|
+
columns,
|
|
56
|
+
rowCount: typeof result.rowCount === 'number' ? result.rowCount : (result.rows?.length ?? 0),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
// A failure is INFORMATION, not an outage: the message names the column
|
|
61
|
+
// or table the warehouse rejected, which is exactly what the loop needs
|
|
62
|
+
// to correct itself. Swallowing it would leave the model guessing again.
|
|
63
|
+
return {
|
|
64
|
+
executed: false,
|
|
65
|
+
error: error instanceof Error ? error.message : String(error),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=preview-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-tool.js","sourceRoot":"","sources":["../../src/agentic/preview-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An LLM reranker over the fused candidate list.
|
|
3
|
+
*
|
|
4
|
+
* Retrieval fuses lanes with RRF and then applies a hand-tuned additive score.
|
|
5
|
+
* Neither reads the QUESTION: they rank by lexical overlap, vector distance,
|
|
6
|
+
* and type weights, so the object that actually answers the turn can sit at
|
|
7
|
+
* rank 30 behind ten near-synonyms and be cut by a top-N that never considered
|
|
8
|
+
* what was asked. A cross-encoder pass is the cheapest thing that reads both
|
|
9
|
+
* sides at once.
|
|
10
|
+
*
|
|
11
|
+
* Advisory by construction. It may REORDER what retrieval found and nothing
|
|
12
|
+
* else — it cannot introduce an id retrieval did not return, so it can never
|
|
13
|
+
* invent context, and any failure, timeout, or malformed reply leaves today's
|
|
14
|
+
* ordering exactly as it was. That property is what makes it safe to put in
|
|
15
|
+
* front of every governed answer.
|
|
16
|
+
*/
|
|
17
|
+
export interface RerankCandidate {
|
|
18
|
+
id: string;
|
|
19
|
+
/** One line the model ranks on: name, type, and description if there is one. */
|
|
20
|
+
summary: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RerankOutcome {
|
|
23
|
+
/** Candidate ids, best first. Always a permutation of a subset of the input. */
|
|
24
|
+
order: string[];
|
|
25
|
+
/** Why the model put an id where it did, for the prompt and the trace. */
|
|
26
|
+
reasons: Map<string, string>;
|
|
27
|
+
}
|
|
28
|
+
interface RerankProvider {
|
|
29
|
+
generate(messages: {
|
|
30
|
+
role: 'system' | 'user' | 'assistant';
|
|
31
|
+
content: string;
|
|
32
|
+
}[], options?: Record<string, unknown>): Promise<string>;
|
|
33
|
+
}
|
|
34
|
+
export declare function parseRerankReply(raw: string, allowed: ReadonlySet<string>): RerankOutcome | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Reorder candidates, or return undefined and leave the caller's order alone.
|
|
37
|
+
*
|
|
38
|
+
* Bounded by a short timeout in the same spirit as `confirmMediumCertifiedFit`:
|
|
39
|
+
* retrieval quality is worth a couple of seconds, an answer is not worth
|
|
40
|
+
* waiting on a reranker that is not coming back.
|
|
41
|
+
*/
|
|
42
|
+
export declare function rerankCandidates(provider: RerankProvider, question: string, candidates: readonly RerankCandidate[], options?: {
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
maxCandidates?: number;
|
|
46
|
+
}): Promise<RerankOutcome | undefined>;
|
|
47
|
+
/** Apply an outcome to the caller's list: ranked ids first, everything else after. */
|
|
48
|
+
export declare function applyRerank<T>(items: readonly T[], idOf: (item: T) => string, outcome: RerankOutcome | undefined): T[];
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=rerank.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rerank.d.ts","sourceRoot":"","sources":["../../src/agentic/rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0EAA0E;IAC1E,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,UAAU,cAAc;IACtB,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;AAoCD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,aAAa,GAAG,SAAS,CAqBrG;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACjF,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CA4BpC;AAED,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EACzB,OAAO,EAAE,aAAa,GAAG,SAAS,GACjC,CAAC,EAAE,CAUL"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An LLM reranker over the fused candidate list.
|
|
3
|
+
*
|
|
4
|
+
* Retrieval fuses lanes with RRF and then applies a hand-tuned additive score.
|
|
5
|
+
* Neither reads the QUESTION: they rank by lexical overlap, vector distance,
|
|
6
|
+
* and type weights, so the object that actually answers the turn can sit at
|
|
7
|
+
* rank 30 behind ten near-synonyms and be cut by a top-N that never considered
|
|
8
|
+
* what was asked. A cross-encoder pass is the cheapest thing that reads both
|
|
9
|
+
* sides at once.
|
|
10
|
+
*
|
|
11
|
+
* Advisory by construction. It may REORDER what retrieval found and nothing
|
|
12
|
+
* else — it cannot introduce an id retrieval did not return, so it can never
|
|
13
|
+
* invent context, and any failure, timeout, or malformed reply leaves today's
|
|
14
|
+
* ordering exactly as it was. That property is what makes it safe to put in
|
|
15
|
+
* front of every governed answer.
|
|
16
|
+
*/
|
|
17
|
+
const PROMPT = `Rank the candidates by how directly each one would help answer the question.
|
|
18
|
+
|
|
19
|
+
Reply with ONLY a JSON object:
|
|
20
|
+
{"ranked":[{"id":"<candidate id>","why":"<one short clause>"}]}
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
- Use ONLY ids from the list. An id that is not in the list is discarded.
|
|
24
|
+
- Rank at most 15. Omit anything irrelevant rather than padding the list.
|
|
25
|
+
- "why" is one clause about THIS question, not a restatement of the description.`;
|
|
26
|
+
function extractJsonObject(raw) {
|
|
27
|
+
const trimmed = raw.trim();
|
|
28
|
+
const start = trimmed.indexOf('{');
|
|
29
|
+
if (start < 0)
|
|
30
|
+
return undefined;
|
|
31
|
+
let depth = 0;
|
|
32
|
+
let inString = false;
|
|
33
|
+
let escaped = false;
|
|
34
|
+
for (let i = start; i < trimmed.length; i += 1) {
|
|
35
|
+
const char = trimmed[i];
|
|
36
|
+
if (escaped) {
|
|
37
|
+
escaped = false;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (char === '\\') {
|
|
41
|
+
escaped = true;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (char === '"') {
|
|
45
|
+
inString = !inString;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (inString)
|
|
49
|
+
continue;
|
|
50
|
+
if (char === '{')
|
|
51
|
+
depth += 1;
|
|
52
|
+
else if (char === '}') {
|
|
53
|
+
depth -= 1;
|
|
54
|
+
if (depth === 0) {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(trimmed.slice(start, i + 1));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
export function parseRerankReply(raw, allowed) {
|
|
67
|
+
const parsed = extractJsonObject(raw);
|
|
68
|
+
const ranked = parsed?.ranked;
|
|
69
|
+
if (!Array.isArray(ranked))
|
|
70
|
+
return undefined;
|
|
71
|
+
const order = [];
|
|
72
|
+
const reasons = new Map();
|
|
73
|
+
const seen = new Set();
|
|
74
|
+
for (const entry of ranked) {
|
|
75
|
+
if (!entry || typeof entry !== 'object')
|
|
76
|
+
continue;
|
|
77
|
+
const record = entry;
|
|
78
|
+
const id = typeof record.id === 'string' ? record.id.trim() : '';
|
|
79
|
+
// An id retrieval did not return cannot enter the pack. This is the whole
|
|
80
|
+
// safety property: the reranker reorders, it never introduces.
|
|
81
|
+
if (!id || !allowed.has(id) || seen.has(id))
|
|
82
|
+
continue;
|
|
83
|
+
seen.add(id);
|
|
84
|
+
order.push(id);
|
|
85
|
+
const why = typeof record.why === 'string' ? record.why.trim() : '';
|
|
86
|
+
if (why)
|
|
87
|
+
reasons.set(id, why);
|
|
88
|
+
if (order.length >= 15)
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
return order.length > 0 ? { order, reasons } : undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reorder candidates, or return undefined and leave the caller's order alone.
|
|
95
|
+
*
|
|
96
|
+
* Bounded by a short timeout in the same spirit as `confirmMediumCertifiedFit`:
|
|
97
|
+
* retrieval quality is worth a couple of seconds, an answer is not worth
|
|
98
|
+
* waiting on a reranker that is not coming back.
|
|
99
|
+
*/
|
|
100
|
+
export async function rerankCandidates(provider, question, candidates, options = {}) {
|
|
101
|
+
const pool = candidates.slice(0, options.maxCandidates ?? 40);
|
|
102
|
+
// Below a handful there is nothing to reorder that a top-N would get wrong.
|
|
103
|
+
if (pool.length < 5)
|
|
104
|
+
return undefined;
|
|
105
|
+
const controller = new AbortController();
|
|
106
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 2_500);
|
|
107
|
+
const onAbort = () => controller.abort();
|
|
108
|
+
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
109
|
+
try {
|
|
110
|
+
const raw = await provider.generate([
|
|
111
|
+
{ role: 'system', content: PROMPT },
|
|
112
|
+
{
|
|
113
|
+
role: 'user',
|
|
114
|
+
content: `Question: ${question}\n\nCandidates:\n${pool.map((candidate) => `- ${candidate.id} :: ${candidate.summary}`).join('\n')}`,
|
|
115
|
+
},
|
|
116
|
+
], { signal: controller.signal });
|
|
117
|
+
return parseRerankReply(raw, new Set(pool.map((candidate) => candidate.id)));
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
clearTimeout(timer);
|
|
124
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/** Apply an outcome to the caller's list: ranked ids first, everything else after. */
|
|
128
|
+
export function applyRerank(items, idOf, outcome) {
|
|
129
|
+
if (!outcome)
|
|
130
|
+
return [...items];
|
|
131
|
+
const position = new Map(outcome.order.map((id, index) => [id, index]));
|
|
132
|
+
// Anything the model omitted keeps its original order BEHIND what it ranked.
|
|
133
|
+
// Dropping omissions would let one bad reply silently shrink the context.
|
|
134
|
+
return [...items].sort((left, right) => {
|
|
135
|
+
const leftRank = position.get(idOf(left)) ?? Number.MAX_SAFE_INTEGER;
|
|
136
|
+
const rightRank = position.get(idOf(right)) ?? Number.MAX_SAFE_INTEGER;
|
|
137
|
+
return leftRank - rightRank;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=rerank.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rerank.js","sourceRoot":"","sources":["../../src/agentic/rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAsBH,MAAM,MAAM,GAAG;;;;;;;;iFAQkE,CAAC;AAElF,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,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAA4B;IACxE,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,MAAM,GAAI,MAA2C,EAAE,MAAM,CAAC;IACpE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QAClD,MAAM,MAAM,GAAG,KAAwC,CAAC;QACxD,MAAM,EAAE,GAAG,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,0EAA0E;QAC1E,+DAA+D;QAC/D,IAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QACtD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,MAAM,GAAG,GAAG,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,GAAG;YAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE;YAAE,MAAM;IAChC,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAwB,EACxB,QAAgB,EAChB,UAAsC,EACtC,UAAgF,EAAE;IAElF,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;IAC9D,4EAA4E;IAC5E,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACtC,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,KAAK,CAAC,CAAC;IAC/E,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,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CACjC;YACE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;YACnC;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,aAAa,QAAQ,oBAC5B,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAChF,EAAE;aACH;SACF,EACD,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAC;QACF,OAAO,gBAAgB,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,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,sFAAsF;AACtF,MAAM,UAAU,WAAW,CACzB,KAAmB,EACnB,IAAyB,EACzB,OAAkC;IAElC,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACxE,6EAA6E;IAC7E,0EAA0E;IAC1E,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC;QACrE,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC;QACvE,OAAO,QAAQ,GAAG,SAAS,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC"}
|