@duckcodeailabs/dql-cli 1.14.2 → 1.14.4
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/args.d.ts +6 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +28 -0
- package/dist/args.js.map +1 -1
- package/dist/ask-runtime/analytical-planner.d.ts +14 -0
- package/dist/ask-runtime/analytical-planner.d.ts.map +1 -0
- package/dist/ask-runtime/analytical-planner.js +197 -0
- package/dist/ask-runtime/analytical-planner.js.map +1 -0
- package/dist/ask-runtime/readiness.d.ts +36 -0
- package/dist/ask-runtime/readiness.d.ts.map +1 -0
- package/dist/ask-runtime/readiness.js +65 -0
- package/dist/ask-runtime/readiness.js.map +1 -0
- package/dist/assets/dql-notebook/assets/{AgentLogPage-DKbGpRQS.js → AgentLogPage-XonDlOVv.js} +1 -1
- package/dist/assets/dql-notebook/assets/{AiBuildDialog-DPSu0Mly.js → AiBuildDialog-DwHVVFIS.js} +1 -1
- package/dist/assets/dql-notebook/assets/{AiBuildResult-1uaGnpi1.js → AiBuildResult-BImB4Wej.js} +1 -1
- package/dist/assets/dql-notebook/assets/{AiSidePanel-BwMREwa7.js → AiSidePanel-D7fFBhgc.js} +1 -1
- package/dist/assets/dql-notebook/assets/AnalyticsHome-CHvGWG92.js +6 -0
- package/dist/assets/dql-notebook/assets/{AppsView-CM1tPywy.js → AppsView-DNhs0MyO.js} +30 -35
- package/dist/assets/dql-notebook/assets/AskObservabilityPage-1WYjAf8-.js +1 -0
- package/dist/assets/dql-notebook/assets/AskTracePage-D6_RunIf.js +8 -0
- package/dist/assets/dql-notebook/assets/{BlockStudio--S6WFVO4.js → BlockStudio-DWMOCHy5.js} +9 -14
- package/dist/assets/dql-notebook/assets/BusinessArtifactView-guqlfQ0j.js +1 -0
- package/dist/assets/dql-notebook/assets/{DbtFirstModelingPage-CNyU5MBX.js → DbtFirstModelingPage-DE7ewjMK.js} +3 -3
- package/dist/assets/dql-notebook/assets/{GitPage-IcydAai3.js → GitPage-CM3cgHtf.js} +1 -1
- package/dist/assets/dql-notebook/assets/{GlobalAiRail-CSKW-5eD.js → GlobalAiRail-BWfeK8lb.js} +1 -1
- package/dist/assets/dql-notebook/assets/{GovernedContextPage-CFen0eFT.js → GovernedContextPage-2Ld4yIgE.js} +3 -3
- package/dist/assets/dql-notebook/assets/{HelpDocsPage-D0D9UCIz.js → HelpDocsPage-BxBzoxBO.js} +1 -1
- package/dist/assets/dql-notebook/assets/{HomePage-CmSxapR3.js → HomePage-D4ZjCFfB.js} +1 -1
- package/dist/assets/dql-notebook/assets/LineageDAG-DLdogZMo.js +1 -0
- package/dist/assets/dql-notebook/assets/LineageDetailView-CqPB_tFP.js +1 -0
- package/dist/assets/dql-notebook/assets/LineageDrawer-LZyR3zHf.js +1 -0
- package/dist/assets/dql-notebook/assets/{LineagePathBreadcrumb-CTZJp4_r.js → LineagePathBreadcrumb-BZ7EcIxp.js} +1 -1
- package/dist/assets/dql-notebook/assets/MiniLineageGraph-Be_kqIq2.js +1 -0
- package/dist/assets/dql-notebook/assets/{NewBlockModal-DMBFB7nE.js → NewBlockModal-C9MKCa6R.js} +1 -1
- package/dist/assets/dql-notebook/assets/{NewNotebookModal-DsC9CWlW.js → NewNotebookModal-ZxHbTU9u.js} +1 -1
- package/dist/assets/dql-notebook/assets/{NotebookEditor-hs-kw8v9.js → NotebookEditor-Bh39Vsg0.js} +25 -30
- package/dist/assets/dql-notebook/assets/{ReadinessPage-DJ83cMik.js → ReadinessPage-jKOBKkED.js} +1 -1
- package/dist/assets/dql-notebook/assets/{SetupOnboarding-B1Pu_Bvv.js → SetupOnboarding-BRut9nLO.js} +1 -1
- package/dist/assets/dql-notebook/assets/{SkillsPage-BHKDay8n.js → SkillsPage-D9msUOxY.js} +1 -1
- package/dist/assets/dql-notebook/assets/{TrustBadge-BkyGgob2.js → TrustBadge-D1CGSj0Y.js} +1 -1
- package/dist/assets/dql-notebook/assets/UnifiedAgentRunPanel-BexNjqJd.js +88 -0
- package/dist/assets/dql-notebook/assets/{answer-to-notebook-DmNiuLQA.js → answer-to-notebook-zHFOdR6E.js} +1 -1
- package/dist/assets/dql-notebook/assets/{arrow-left--1rsrxm8.js → arrow-left-C1tZBhgf.js} +1 -1
- package/dist/assets/dql-notebook/assets/{arrow-right-D5TdqY1G.js → arrow-right-BP5vPPNo.js} +1 -1
- package/dist/assets/dql-notebook/assets/{book-open-text-Bw7nHbzg.js → book-open-text-BD3-ATYI.js} +1 -1
- package/dist/assets/dql-notebook/assets/chevron-left-3opVgscY.js +6 -0
- package/dist/assets/dql-notebook/assets/{circle-x-DLe6NNM4.js → circle-x-Bg9-70KN.js} +1 -1
- package/dist/assets/dql-notebook/assets/clock-3-DLV5puGW.js +6 -0
- package/dist/assets/dql-notebook/assets/dagre.esm-B6nvU4OB.js +1 -0
- package/dist/assets/dql-notebook/assets/{external-link-C9Q97sA3.js → external-link-BjD8w9QU.js} +1 -1
- package/dist/assets/dql-notebook/assets/{grip-vertical-CztvkIgo.js → grip-vertical-DqIc09oX.js} +1 -1
- package/dist/assets/dql-notebook/assets/index-B_kaoARS.css +1 -0
- package/dist/assets/dql-notebook/assets/{index-zHHzDn6l.js → index-C9KfoqCR.js} +133 -128
- package/dist/assets/dql-notebook/assets/{link-2-CiKAvumL.js → link-2-5s0hUu6w.js} +1 -1
- package/dist/assets/dql-notebook/assets/{list-tree-BtnP2nQ5.js → list-tree-67yz_uCY.js} +1 -1
- package/dist/assets/dql-notebook/assets/{minimize-2-TSFGxcCP.js → minimize-2-BJw5tlPC.js} +1 -1
- package/dist/assets/dql-notebook/assets/{panel-right-open-BfXIUWy0.js → panel-right-open-CyhTG-tw.js} +1 -1
- package/dist/assets/dql-notebook/assets/{play-DVbSFJHD.js → play-CsY8D5M2.js} +1 -1
- package/dist/assets/dql-notebook/assets/{rotate-ccw-D_cesDcX.js → rotate-ccw-RvwtBcw9.js} +1 -1
- package/dist/assets/dql-notebook/assets/{semantic-fields-CoVStdYB.js → semantic-fields-EorgHwAj.js} +1 -1
- package/dist/assets/dql-notebook/assets/{sliders-horizontal-l7xV9K5A.js → sliders-horizontal-jQ_fUiYf.js} +1 -1
- package/dist/assets/dql-notebook/assets/{star-CSBS0H3b.js → star-N_C8YvbB.js} +1 -1
- package/dist/assets/dql-notebook/assets/style-D6AlWDHX.js +23 -0
- package/dist/assets/dql-notebook/assets/{triangle-alert-BTrnyY4q.js → triangle-alert-D1WefIrN.js} +1 -1
- package/dist/assets/dql-notebook/assets/{upload-sySLq9zb.js → upload-CFJjpPL4.js} +1 -1
- package/dist/assets/dql-notebook/assets/{usePersistedAgentThreadId-CzwgGdus.js → usePersistedAgentThreadId-B5pTglEr.js} +1 -1
- package/dist/assets/dql-notebook/assets/{user-round-ChlgXi9j.js → user-round-DL6DLw0m.js} +1 -1
- package/dist/assets/dql-notebook/assets/{wand-sparkles-CGw0ytyT.js → wand-sparkles-CNUjLDqT.js} +1 -1
- package/dist/assets/dql-notebook/assets/{workflow-C_RltiK5.js → workflow-0NUwpoQ4.js} +1 -1
- package/dist/assets/dql-notebook/assets/{wrench-D-wLfeu0.js → wrench-QNiznShi.js} +1 -1
- package/dist/assets/dql-notebook/assets/{x-B28hIJIC.js → x-BhTl5gZs.js} +1 -1
- package/dist/assets/dql-notebook/index.html +2 -2
- package/dist/commands/agent-eval-cassette.d.ts.map +1 -1
- package/dist/commands/agent-eval-cassette.js +15 -0
- package/dist/commands/agent-eval-cassette.js.map +1 -1
- package/dist/commands/agent-eval-runtime.d.ts +9 -0
- package/dist/commands/agent-eval-runtime.d.ts.map +1 -1
- package/dist/commands/agent-eval-runtime.js +7 -0
- package/dist/commands/agent-eval-runtime.js.map +1 -1
- package/dist/commands/agent-shadow-report.d.ts +17 -0
- package/dist/commands/agent-shadow-report.d.ts.map +1 -0
- package/dist/commands/agent-shadow-report.js +149 -0
- package/dist/commands/agent-shadow-report.js.map +1 -0
- package/dist/commands/agent-trace.d.ts +3 -0
- package/dist/commands/agent-trace.d.ts.map +1 -0
- package/dist/commands/agent-trace.js +169 -0
- package/dist/commands/agent-trace.js.map +1 -0
- package/dist/commands/agent.d.ts +28 -2
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +413 -36
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/notebook.d.ts +4 -1
- package/dist/commands/notebook.d.ts.map +1 -1
- package/dist/commands/notebook.js +12 -1
- package/dist/commands/notebook.js.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/providers/ask-v2-analyst-prompt.d.ts +32 -0
- package/dist/llm/providers/ask-v2-analyst-prompt.d.ts.map +1 -0
- package/dist/llm/providers/ask-v2-analyst-prompt.js +136 -0
- package/dist/llm/providers/ask-v2-analyst-prompt.js.map +1 -0
- package/dist/llm/providers/dql-agent-provider.d.ts +78 -2
- package/dist/llm/providers/dql-agent-provider.d.ts.map +1 -1
- package/dist/llm/providers/dql-agent-provider.js +5438 -330
- package/dist/llm/providers/dql-agent-provider.js.map +1 -1
- package/dist/llm/types.d.ts +144 -3
- package/dist/llm/types.d.ts.map +1 -1
- package/dist/local-runtime.d.ts +607 -35
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +7734 -702
- package/dist/local-runtime.js.map +1 -1
- package/dist/metricflow.d.ts.map +1 -1
- package/dist/metricflow.js +80 -11
- package/dist/metricflow.js.map +1 -1
- package/dist/package.json +10 -10
- package/dist/providers/oauth/claude-oauth.d.ts +14 -0
- package/dist/providers/oauth/claude-oauth.d.ts.map +1 -1
- package/dist/providers/oauth/claude-oauth.js +84 -23
- package/dist/providers/oauth/claude-oauth.js.map +1 -1
- package/dist/providers/oauth/codex-oauth.d.ts.map +1 -1
- package/dist/providers/oauth/codex-oauth.js +72 -44
- package/dist/providers/oauth/codex-oauth.js.map +1 -1
- package/dist/providers/subscription-cli.d.ts +20 -0
- package/dist/providers/subscription-cli.d.ts.map +1 -1
- package/dist/providers/subscription-cli.js +69 -11
- package/dist/providers/subscription-cli.js.map +1 -1
- package/dist/research-lineage-program.d.ts +29 -0
- package/dist/research-lineage-program.d.ts.map +1 -0
- package/dist/research-lineage-program.js +389 -0
- package/dist/research-lineage-program.js.map +1 -0
- package/dist/retrieval-health.d.ts.map +1 -1
- package/dist/retrieval-health.js +5 -2
- package/dist/retrieval-health.js.map +1 -1
- package/dist/semantic-runtime.d.ts.map +1 -1
- package/dist/semantic-runtime.js +73 -2
- package/dist/semantic-runtime.js.map +1 -1
- package/package.json +10 -10
- package/dist/assets/dql-notebook/assets/AnalyticsHome-BGfey_ve.js +0 -6
- package/dist/assets/dql-notebook/assets/BusinessArtifactView-BEAJ-yNW.js +0 -1
- package/dist/assets/dql-notebook/assets/LineageDAG-BGUcIt1B.js +0 -1
- package/dist/assets/dql-notebook/assets/LineageDetailView-Dx48Zfzb.js +0 -1
- package/dist/assets/dql-notebook/assets/LineageDrawer-zaBfSLZO.js +0 -1
- package/dist/assets/dql-notebook/assets/MiniLineageGraph-CdivNR1S.js +0 -1
- package/dist/assets/dql-notebook/assets/UnifiedAgentRunPanel-BYdrTaEW.js +0 -89
- package/dist/assets/dql-notebook/assets/dagre.esm-CW5QZdBt.js +0 -23
- package/dist/assets/dql-notebook/assets/index-B3shyZsg.css +0 -1
- /package/dist/assets/dql-notebook/assets/{dagre-BZV40eAE.css → style-BZV40eAE.css} +0 -0
package/dist/commands/agent.js
CHANGED
|
@@ -23,15 +23,18 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { answerFromRuntimeRun, driveViaRuntime, projectRuntimeRun, } from './agent-eval-runtime.js';
|
|
25
25
|
import { CassetteStore, cassetteEvidenceSummary, cassetteDirFor, evalCassetteCanonicalizationV2, withCassette, } from './agent-eval-cassette.js';
|
|
26
|
+
import { runAgentShadowReport } from './agent-shadow-report.js';
|
|
26
27
|
import { existsSync, readFileSync } from 'node:fs';
|
|
27
28
|
import { join, resolve } from 'node:path';
|
|
28
29
|
import { load as loadYaml } from 'js-yaml';
|
|
29
|
-
import { KGStore, MemoryStore, defaultKgPath, defaultMemoryPath, reindexProject, loadSkills, pickProvider, answer, resolveDomainContextEnvelope, buildAnalysisQuestionPlan, buildLocalContextPack, coerceReasoningEffort, contextRetrievalBudgetForQuestion, deriveGeneratedDraftSlug, loadAgentSemanticLayer, recordQueryRun, recordRuntimeSchemaSnapshot, upsertGeneratedDqlArtifactDraft, upsertGeneratedDraft, validateSqlAgainstLocalContext, } from '@duckcodeailabs/dql-agent';
|
|
30
|
+
import { AskTraceSqliteStoreV1, KGStore, MemoryStore, defaultKgPath, defaultMemoryPath, reindexProject, loadSkills, pickProvider, answer, resolveDomainContextEnvelope, buildAnalysisQuestionPlan, buildLocalContextPack, classifyProviderFailure, coerceReasoningEffort, contextRetrievalBudgetForQuestion, deriveGeneratedDraftSlug, loadAgentSemanticLayer, recordQueryRun, recordRuntimeSchemaSnapshot, upsertGeneratedDqlArtifactDraft, upsertGeneratedDraft, validateSqlAgainstLocalContext, createAskTraceObserverV1, defaultAskTraceSqlitePath, } from '@duckcodeailabs/dql-agent';
|
|
31
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
30
32
|
import { buildManifest, resolveDbtManifestPath } from '@duckcodeailabs/dql-core';
|
|
31
33
|
import { findProjectRoot } from '../local-runtime.js';
|
|
32
34
|
import { buildAnswerLoopTools, createGroundingContextExpander } from '../llm/answer-loop-tools.js';
|
|
33
35
|
import { judgeAnswer } from './eval-judge.js';
|
|
34
36
|
import { startProjectRuntime } from './notebook.js';
|
|
37
|
+
import { runAgentTrace } from './agent-trace.js';
|
|
35
38
|
/**
|
|
36
39
|
* Resolve the runtime the agent posts certified blocks / generated SQL to.
|
|
37
40
|
*
|
|
@@ -55,7 +58,56 @@ async function resolveAgentRuntime(projectRoot, flags) {
|
|
|
55
58
|
return { runtimeBase: base, close: async () => { } };
|
|
56
59
|
}
|
|
57
60
|
const handle = await startProjectRuntime(projectRoot, { preferredPort: 0 });
|
|
58
|
-
return { runtimeBase: handle.url, close: handle.close };
|
|
61
|
+
return { runtimeBase: handle.url, close: handle.close, askTraceCapability: handle.askTraceCapability };
|
|
62
|
+
}
|
|
63
|
+
function isLoopbackRuntimeUrl(runtimeBase) {
|
|
64
|
+
try {
|
|
65
|
+
const hostname = new URL(runtimeBase).hostname;
|
|
66
|
+
return hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '::1' || hostname === '[::1]';
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* An already-running local Notebook runtime mints a one-shot, loopback-only
|
|
74
|
+
* capability for this CLI request. Remote runtimes deliberately receive no
|
|
75
|
+
* capability and therefore cannot be relabelled as CLI by arbitrary text.
|
|
76
|
+
*/
|
|
77
|
+
export async function requestLoopbackCliAskTraceCapability(runtimeBase) {
|
|
78
|
+
if (!isLoopbackRuntimeUrl(runtimeBase))
|
|
79
|
+
return undefined;
|
|
80
|
+
try {
|
|
81
|
+
const response = await fetch(`${runtimeBase.replace(/\/$/, '')}/api/ask-traces/cli-capability`, {
|
|
82
|
+
headers: { Accept: 'application/json' },
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok)
|
|
85
|
+
return undefined;
|
|
86
|
+
const payload = await response.json();
|
|
87
|
+
return typeof payload.capability === 'string'
|
|
88
|
+
&& typeof payload.expiresAt === 'string'
|
|
89
|
+
&& payload.scope === 'agent-runs'
|
|
90
|
+
? payload.capability
|
|
91
|
+
: undefined;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// A pre-observability runtime remains usable. Its request stays browser
|
|
95
|
+
// attributed rather than fabricating a client-controlled CLI surface.
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function runtimeProviderForCliFlag(value) {
|
|
100
|
+
if (typeof value !== 'string' || !value.trim())
|
|
101
|
+
return undefined;
|
|
102
|
+
switch (value.trim().toLowerCase()) {
|
|
103
|
+
case 'claude': return 'anthropic';
|
|
104
|
+
case 'openai': return 'openai';
|
|
105
|
+
case 'gemini': return 'gemini';
|
|
106
|
+
case 'ollama': return 'ollama';
|
|
107
|
+
// Preserve an invalid explicit value through the host request so the
|
|
108
|
+
// canonical preflight can return a typed `model_not_found` diagnostic.
|
|
109
|
+
default: return value.trim().toLowerCase();
|
|
110
|
+
}
|
|
59
111
|
}
|
|
60
112
|
async function fetchRuntimeSchemaContext(runtimeBase) {
|
|
61
113
|
try {
|
|
@@ -142,6 +194,137 @@ function cliAnalysisDepth(flags) {
|
|
|
142
194
|
const value = flags.analysisDepth?.trim().toLowerCase();
|
|
143
195
|
return value === 'quick' || value === 'deep' ? value : undefined;
|
|
144
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Compatibility test adapter for a standalone provider boundary. Production
|
|
199
|
+
* `dql agent ask` no longer calls this: it uses the runtime AgentRun engine so
|
|
200
|
+
* the router, cascade, freeze, tools, SQL, and provider spans share one
|
|
201
|
+
* canonical trace. Keep this adapter truthful for lower-level provider tests
|
|
202
|
+
* without making it an alternate orchestration authority.
|
|
203
|
+
*/
|
|
204
|
+
export function createDirectCliAskTraceProvider(provider, trace) {
|
|
205
|
+
let attemptIndex = 0;
|
|
206
|
+
let lastFailedSpanId;
|
|
207
|
+
const pending = new Map();
|
|
208
|
+
const keyFor = (event) => `${event.provider}:${event.operation}:${event.attemptIndex}`;
|
|
209
|
+
const attempt = (event, retryOfSpanId) => ({
|
|
210
|
+
version: 1,
|
|
211
|
+
phase: 'generation',
|
|
212
|
+
physicalAttemptIndex: ++attemptIndex,
|
|
213
|
+
providerFingerprint: `sha256:${createHash('sha256').update(event.provider).digest('hex')}`,
|
|
214
|
+
...(event.model ? { modelFingerprint: `sha256:${createHash('sha256').update(event.model).digest('hex')}` } : {}),
|
|
215
|
+
...(retryOfSpanId ? { retryOfSpanId } : {}),
|
|
216
|
+
admission: 'admitted',
|
|
217
|
+
provenance: 'live',
|
|
218
|
+
});
|
|
219
|
+
const finish = (entry, outcome, error) => {
|
|
220
|
+
if (!entry.spanId)
|
|
221
|
+
return;
|
|
222
|
+
const diagnostic = outcome === 'ok' ? undefined : classifyProviderFailure({
|
|
223
|
+
phase: 'generation',
|
|
224
|
+
code: error && typeof error === 'object' ? String(error.code ?? '') : undefined,
|
|
225
|
+
message: error instanceof Error ? error.message : String(error ?? ''),
|
|
226
|
+
providerFingerprint: entry.attempt.providerFingerprint,
|
|
227
|
+
modelFingerprint: entry.attempt.modelFingerprint,
|
|
228
|
+
});
|
|
229
|
+
const finalAttempt = outcome === 'ok'
|
|
230
|
+
? entry.attempt
|
|
231
|
+
: {
|
|
232
|
+
...entry.attempt,
|
|
233
|
+
...(diagnostic?.httpStatusClass ? { httpStatusClass: diagnostic.httpStatusClass } : {}),
|
|
234
|
+
...(diagnostic ? { retryable: diagnostic.retryable, safeAction: diagnostic.safeAction } : {}),
|
|
235
|
+
cause: outcome === 'cancelled' ? 'cancelled' : diagnostic?.cause ?? 'unknown',
|
|
236
|
+
};
|
|
237
|
+
trace.finishSpan(entry.spanId, {
|
|
238
|
+
outcome: outcome === 'ok' ? 'ok' : outcome === 'cancelled' ? 'cancelled' : 'error',
|
|
239
|
+
reasonCode: outcome === 'ok' ? 'completed' : outcome === 'cancelled' ? 'cancelled' : 'provider_failure',
|
|
240
|
+
payload: { kind: 'provider', attempt: finalAttempt },
|
|
241
|
+
});
|
|
242
|
+
if (outcome !== 'ok')
|
|
243
|
+
lastFailedSpanId = entry.spanId;
|
|
244
|
+
};
|
|
245
|
+
const observedOptions = (options = {}) => ({
|
|
246
|
+
...options,
|
|
247
|
+
onProviderDispatch: (event) => {
|
|
248
|
+
const tracedAttempt = attempt(event, lastFailedSpanId);
|
|
249
|
+
const spanId = trace.startSpan({
|
|
250
|
+
name: 'provider.attempt',
|
|
251
|
+
stage: 'provider',
|
|
252
|
+
reasonCode: 'started',
|
|
253
|
+
payload: { kind: 'provider', attempt: tracedAttempt },
|
|
254
|
+
});
|
|
255
|
+
const key = keyFor(event);
|
|
256
|
+
pending.set(key, [...(pending.get(key) ?? []), { spanId, attempt: tracedAttempt }]);
|
|
257
|
+
return options.onProviderDispatch?.(event) ?? event.envelope;
|
|
258
|
+
},
|
|
259
|
+
onProviderDispatchComplete: (event) => {
|
|
260
|
+
const key = keyFor(event);
|
|
261
|
+
const entries = pending.get(key) ?? [];
|
|
262
|
+
const entry = entries[0];
|
|
263
|
+
if (entry && event.outcome === 'ok' && (event.settlement === 'transport' || event.settlement === 'process')) {
|
|
264
|
+
entry.attempt = {
|
|
265
|
+
...entry.attempt,
|
|
266
|
+
...(event.settlement === 'transport' ? { transportOutcome: 'ok' } : { processOutcome: 'ok' }),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
const closed = entries.shift();
|
|
271
|
+
if (entries.length > 0)
|
|
272
|
+
pending.set(key, entries);
|
|
273
|
+
else
|
|
274
|
+
pending.delete(key);
|
|
275
|
+
if (closed)
|
|
276
|
+
finish(closed, event.outcome, event.error ?? (typeof event.httpStatus === 'number' ? Object.assign(new Error(`HTTP ${event.httpStatus}`), { code: `HTTP_${event.httpStatus}` }) : undefined));
|
|
277
|
+
}
|
|
278
|
+
options.onProviderDispatchComplete?.(event);
|
|
279
|
+
},
|
|
280
|
+
onProviderDispatchRejected: (event) => {
|
|
281
|
+
const denied = trace.startSpan({
|
|
282
|
+
name: 'provider.attempt',
|
|
283
|
+
stage: 'provider',
|
|
284
|
+
reasonCode: 'provider_failure',
|
|
285
|
+
payload: {
|
|
286
|
+
kind: 'provider',
|
|
287
|
+
attempt: {
|
|
288
|
+
...attempt(event, lastFailedSpanId),
|
|
289
|
+
admission: 'denied',
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
trace.finishSpan(denied, { outcome: 'denied', reasonCode: 'provider_failure' });
|
|
294
|
+
lastFailedSpanId = denied;
|
|
295
|
+
options.onProviderDispatchRejected?.(event);
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
const invoke = async (options, call) => {
|
|
299
|
+
try {
|
|
300
|
+
const result = await call(observedOptions(options));
|
|
301
|
+
for (const entries of pending.values())
|
|
302
|
+
for (const entry of entries)
|
|
303
|
+
finish(entry, 'ok');
|
|
304
|
+
pending.clear();
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
const outcome = options?.signal?.aborted ? 'cancelled' : 'error';
|
|
309
|
+
for (const entries of pending.values())
|
|
310
|
+
for (const entry of entries)
|
|
311
|
+
finish(entry, outcome, error);
|
|
312
|
+
pending.clear();
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
name: provider.name,
|
|
318
|
+
available: () => provider.available(),
|
|
319
|
+
generate: (messages, options) => invoke(options, (observed) => provider.generate(messages, observed)),
|
|
320
|
+
...(provider.generateWithTools ? {
|
|
321
|
+
generateWithTools: (messages, tools, options) => invoke(options, (observed) => provider.generateWithTools(messages, tools, observed)),
|
|
322
|
+
} : {}),
|
|
323
|
+
...(provider.generateStream ? {
|
|
324
|
+
generateStream: (messages, options, onDelta) => invoke(options, (observed) => provider.generateStream(messages, observed, onDelta)),
|
|
325
|
+
} : {}),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
145
328
|
/** A DQL runtime answers `/api/connections` with a connector/connection payload. */
|
|
146
329
|
async function isDqlRuntime(base) {
|
|
147
330
|
try {
|
|
@@ -161,25 +344,53 @@ export async function runAgent(sub, rest, flags) {
|
|
|
161
344
|
return runAsk(rest, flags);
|
|
162
345
|
case 'threads':
|
|
163
346
|
return runThreads(flags);
|
|
347
|
+
case 'trace':
|
|
348
|
+
return runAgentTrace(rest, flags);
|
|
164
349
|
case 'reindex':
|
|
165
350
|
return runReindex(rest, flags);
|
|
166
351
|
case 'feedback':
|
|
167
352
|
return runFeedback(rest, flags);
|
|
168
353
|
case 'eval':
|
|
169
354
|
return runEval(rest, flags);
|
|
355
|
+
case 'shadow-report':
|
|
356
|
+
return runAgentShadowReport(rest, flags);
|
|
170
357
|
default:
|
|
171
|
-
throw new Error('Usage: dql agent <ask|threads|reindex|feedback|eval> [args]\n' +
|
|
358
|
+
throw new Error('Usage: dql agent <ask|threads|trace|reindex|feedback|eval|shadow-report> [args]\n' +
|
|
172
359
|
' dql agent ask "<question>" [--provider claude|openai|gemini|ollama] [--user <id>] [--domain <d>] [--purpose <approved-purpose>] [--thread <id>]\n' +
|
|
173
360
|
' dql agent threads [--runtime-url <url>]\n' +
|
|
361
|
+
' dql agent trace list|show|export|validate|replay|compare\n' +
|
|
174
362
|
' dql agent reindex [path]\n' +
|
|
175
363
|
' dql agent feedback up|down --block <id> --question "..."\n' +
|
|
176
|
-
' dql agent eval agent-evals.yml [--provider claude|openai|gemini|ollama] [--execute] [--save]'
|
|
364
|
+
' dql agent eval agent-evals.yml [--provider claude|openai|gemini|ollama] [--execute] [--save]\n' +
|
|
365
|
+
' dql agent shadow-report [path] [--json] [--limit <n>] Compare what V1 answered with what V2 would have done');
|
|
177
366
|
}
|
|
178
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Canonical CLI Ask entrypoint. Direct and threaded CLI questions use the
|
|
370
|
+
* exact local AgentRun engine as the browser, so trace evidence follows the
|
|
371
|
+
* router's candidate/cascade/freeze/execution authority rather than a legacy
|
|
372
|
+
* answer-loop approximation.
|
|
373
|
+
*/
|
|
179
374
|
async function runAsk(rest, flags) {
|
|
180
375
|
const question = rest.join(' ').trim();
|
|
181
376
|
if (!question)
|
|
182
377
|
throw new Error('Usage: dql agent ask "<question>"');
|
|
378
|
+
const threadId = flags.thread;
|
|
379
|
+
return threadId
|
|
380
|
+
? runThreadAsk(question, threadId, flags)
|
|
381
|
+
: runCanonicalCliAsk(question, undefined, flags);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Compatibility entrypoint retained for downstream imports during the CLI
|
|
385
|
+
* transition. It deliberately delegates before allocating any legacy state,
|
|
386
|
+
* so even an old internal caller gets the canonical AgentRun trace rather than
|
|
387
|
+
* an incomplete synthetic receipt.
|
|
388
|
+
*/
|
|
389
|
+
async function runLegacyDirectAsk(rest, flags) {
|
|
390
|
+
const question = rest.join(' ').trim();
|
|
391
|
+
if (!question)
|
|
392
|
+
throw new Error('Usage: dql agent ask "<question>"');
|
|
393
|
+
return runCanonicalCliAsk(question, flags.thread, flags);
|
|
183
394
|
// Thread-scoped ask: hand the question to the runtime's agent-run engine with
|
|
184
395
|
// the thread id, so the SERVER injects prior turns and persists this run as a
|
|
185
396
|
// new turn (the same conversation store the notebook UI uses).
|
|
@@ -187,8 +398,31 @@ async function runAsk(rest, flags) {
|
|
|
187
398
|
if (threadId)
|
|
188
399
|
return runThreadAsk(question, threadId, flags);
|
|
189
400
|
const projectRoot = findProjectRoot(process.cwd());
|
|
401
|
+
const traceStore = new AskTraceSqliteStoreV1({ path: defaultAskTraceSqlitePath(projectRoot) });
|
|
402
|
+
const trace = createAskTraceObserverV1({
|
|
403
|
+
store: traceStore,
|
|
404
|
+
runId: `cli-${randomUUID()}`,
|
|
405
|
+
surface: 'cli',
|
|
406
|
+
mode: 'ask',
|
|
407
|
+
questionFingerprint: `sha256:${createHash('sha256').update(question).digest('hex')}`,
|
|
408
|
+
});
|
|
409
|
+
const classifySpan = trace.startSpan({
|
|
410
|
+
name: 'request.classify',
|
|
411
|
+
stage: 'request',
|
|
412
|
+
reasonCode: 'started',
|
|
413
|
+
payload: { kind: 'stage', route: 'direct_cli_legacy' },
|
|
414
|
+
});
|
|
190
415
|
const kgPath = defaultKgPath(projectRoot);
|
|
191
|
-
|
|
416
|
+
try {
|
|
417
|
+
await reindexProject(projectRoot, { kgPath });
|
|
418
|
+
trace.finishSpan(classifySpan, { outcome: 'ok', reasonCode: 'completed' });
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
trace.finishSpan(classifySpan, { outcome: 'error', reasonCode: 'unknown' });
|
|
422
|
+
trace.finalize({ status: 'failed' });
|
|
423
|
+
traceStore.close();
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
192
426
|
const providerName = flags.provider;
|
|
193
427
|
const userId = flags.user;
|
|
194
428
|
const domain = flags.domain;
|
|
@@ -196,12 +430,68 @@ async function runAsk(rest, flags) {
|
|
|
196
430
|
const format = flags.format;
|
|
197
431
|
const reasoningEffort = cliReasoningEffort(flags);
|
|
198
432
|
const requestedDepth = cliAnalysisDepth(flags);
|
|
199
|
-
|
|
433
|
+
let provider;
|
|
434
|
+
try {
|
|
435
|
+
provider = await pickProvider(providerName);
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
trace.finalize({ status: 'failed' });
|
|
439
|
+
traceStore.close();
|
|
440
|
+
throw error;
|
|
441
|
+
}
|
|
200
442
|
const kg = new KGStore(kgPath);
|
|
201
443
|
const memory = new MemoryStore(defaultMemoryPath(projectRoot));
|
|
202
444
|
const { skills } = loadSkills(projectRoot);
|
|
203
445
|
let closeRuntime;
|
|
204
446
|
try {
|
|
447
|
+
const preflight = trace.startSpan({
|
|
448
|
+
name: 'provider.preflight',
|
|
449
|
+
stage: 'provider',
|
|
450
|
+
reasonCode: 'started',
|
|
451
|
+
payload: {
|
|
452
|
+
kind: 'provider',
|
|
453
|
+
attempt: {
|
|
454
|
+
version: 1,
|
|
455
|
+
phase: 'preflight',
|
|
456
|
+
physicalAttemptIndex: 0,
|
|
457
|
+
providerFingerprint: `sha256:${createHash('sha256').update(provider.name).digest('hex')}`,
|
|
458
|
+
readiness: 'unknown',
|
|
459
|
+
admission: 'unknown',
|
|
460
|
+
provenance: 'live',
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
let providerReady = false;
|
|
465
|
+
try {
|
|
466
|
+
providerReady = await provider.available();
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
providerReady = false;
|
|
470
|
+
}
|
|
471
|
+
trace.finishSpan(preflight, {
|
|
472
|
+
outcome: providerReady ? 'ok' : 'unavailable',
|
|
473
|
+
reasonCode: providerReady ? 'completed' : 'provider_preflight',
|
|
474
|
+
payload: {
|
|
475
|
+
kind: 'provider',
|
|
476
|
+
attempt: {
|
|
477
|
+
version: 1,
|
|
478
|
+
phase: 'preflight',
|
|
479
|
+
physicalAttemptIndex: 0,
|
|
480
|
+
providerFingerprint: `sha256:${createHash('sha256').update(provider.name).digest('hex')}`,
|
|
481
|
+
readiness: providerReady ? 'ready' : 'unavailable',
|
|
482
|
+
admission: 'unknown',
|
|
483
|
+
cause: providerReady ? undefined : 'authentication',
|
|
484
|
+
safeAction: providerReady ? undefined : 'fix_provider_configuration',
|
|
485
|
+
provenance: 'live',
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
});
|
|
489
|
+
if (!providerReady) {
|
|
490
|
+
throw Object.assign(new Error('The selected AI provider is not ready. Configure or sign in to the provider and retry.'), {
|
|
491
|
+
code: 'AUTHENTICATION_FAILED',
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
const tracedProvider = createDirectCliAskTraceProvider(provider, trace);
|
|
205
495
|
const memoryContext = memory.search({
|
|
206
496
|
query: question,
|
|
207
497
|
scopes: ['project', 'user', 'artifact'],
|
|
@@ -220,6 +510,12 @@ async function runAsk(rest, flags) {
|
|
|
220
510
|
closeRuntime = close;
|
|
221
511
|
const schemaContext = await fetchRuntimeSchemaContext(runtimeBase);
|
|
222
512
|
recordCliRuntimeSchemaSnapshot(projectRoot, schemaContext, 'direct CLI runtime schema');
|
|
513
|
+
const retrievalSpan = trace.startSpan({
|
|
514
|
+
name: 'retrieval',
|
|
515
|
+
stage: 'retrieval',
|
|
516
|
+
reasonCode: 'started',
|
|
517
|
+
payload: { kind: 'retrieval', candidateCount: 0 },
|
|
518
|
+
});
|
|
223
519
|
const contextPack = await buildLocalContextPack(projectRoot, {
|
|
224
520
|
question,
|
|
225
521
|
surface: 'cli',
|
|
@@ -233,10 +529,15 @@ async function runAsk(rest, flags) {
|
|
|
233
529
|
}
|
|
234
530
|
: undefined,
|
|
235
531
|
}).catch(() => undefined);
|
|
532
|
+
trace.finishSpan(retrievalSpan, {
|
|
533
|
+
outcome: 'ok',
|
|
534
|
+
reasonCode: 'completed',
|
|
535
|
+
payload: { kind: 'retrieval', candidateCount: contextPack?.objects.length ?? 0 },
|
|
536
|
+
});
|
|
236
537
|
const answerLoopTools = buildAnswerLoopTools(projectRoot);
|
|
237
538
|
const result = await answer({
|
|
238
539
|
question,
|
|
239
|
-
provider,
|
|
540
|
+
provider: tracedProvider,
|
|
240
541
|
kg,
|
|
241
542
|
manifest,
|
|
242
543
|
skills,
|
|
@@ -365,6 +666,7 @@ async function runAsk(rest, flags) {
|
|
|
365
666
|
});
|
|
366
667
|
},
|
|
367
668
|
});
|
|
669
|
+
trace.finalize({ status: 'completed' });
|
|
368
670
|
if (format === 'json') {
|
|
369
671
|
console.log(JSON.stringify(result, null, 2));
|
|
370
672
|
return;
|
|
@@ -379,17 +681,25 @@ async function runAsk(rest, flags) {
|
|
|
379
681
|
: '';
|
|
380
682
|
const footer = result.provenanceFooter ? `\n\n— ${result.provenanceFooter}` : '';
|
|
381
683
|
console.log(`${badge}\n\n${result.text}${footer}${cite}`);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
console.log(
|
|
684
|
+
const resultPayload = result.result;
|
|
685
|
+
if (resultPayload) {
|
|
686
|
+
console.log(`\nRows: ${resultPayload.rowCount}`);
|
|
687
|
+
console.log(JSON.stringify(resultPayload.rows.slice(0, 5), null, 2));
|
|
385
688
|
}
|
|
386
689
|
printDqlArtifactPreview(result);
|
|
387
690
|
}
|
|
691
|
+
catch (error) {
|
|
692
|
+
const cancelled = error instanceof Error && error.name === 'AbortError';
|
|
693
|
+
trace.finalize({ status: cancelled ? 'cancelled' : 'failed' });
|
|
694
|
+
throw error;
|
|
695
|
+
}
|
|
388
696
|
finally {
|
|
389
697
|
kg.close();
|
|
390
698
|
memory.close();
|
|
391
|
-
|
|
392
|
-
|
|
699
|
+
const close = closeRuntime;
|
|
700
|
+
if (close)
|
|
701
|
+
await close();
|
|
702
|
+
traceStore.close();
|
|
393
703
|
}
|
|
394
704
|
}
|
|
395
705
|
function printDqlArtifactPreview(result) {
|
|
@@ -410,56 +720,103 @@ function printDqlArtifactPreview(result) {
|
|
|
410
720
|
console.log(`Promote: ${result.promoteCommand}`);
|
|
411
721
|
}
|
|
412
722
|
}
|
|
723
|
+
function printCanonicalCliAskRun(run, threadId) {
|
|
724
|
+
const badge = run.trustState === 'certified'
|
|
725
|
+
? '✓ Certified'
|
|
726
|
+
: run.trustState === 'grounded'
|
|
727
|
+
? '✓ Verified (grounded)'
|
|
728
|
+
: run.trustState === 'review_required'
|
|
729
|
+
? '! AI-generated · review required'
|
|
730
|
+
: run.trustState === 'blocked'
|
|
731
|
+
? '✕ Blocked'
|
|
732
|
+
: '· Reply';
|
|
733
|
+
console.log(`${badge}\n\n${(run.answer ?? run.summary ?? '').trim()}`);
|
|
734
|
+
if (threadId)
|
|
735
|
+
console.log(`\nThread: ${threadId}`);
|
|
736
|
+
const trace = run.traceReference;
|
|
737
|
+
if (trace?.traceId) {
|
|
738
|
+
console.log(`\nTrace: ${trace.traceId} (${trace.recordingStatus ?? 'recording'})`);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
console.log('\nTrace: unavailable');
|
|
742
|
+
}
|
|
743
|
+
}
|
|
413
744
|
/**
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
745
|
+
* Submit every user-visible CLI Ask through the runtime AgentRun endpoint.
|
|
746
|
+
* The runtime owns run IDs, conversation hydration, candidate provenance,
|
|
747
|
+
* cascade/freeze authority, physical tool/SQL execution, and final trace
|
|
748
|
+
* reference. The CLI only supplies user intent and an optional host-minted
|
|
749
|
+
* surface capability.
|
|
419
750
|
*/
|
|
420
|
-
async function
|
|
751
|
+
export async function runCanonicalCliAsk(question, threadId, flags) {
|
|
421
752
|
const projectRoot = findProjectRoot(process.cwd());
|
|
422
753
|
const format = flags.format;
|
|
423
|
-
const { runtimeBase, close } = await resolveAgentRuntime(projectRoot, flags);
|
|
754
|
+
const { runtimeBase, close, askTraceCapability: embeddedCapability } = await resolveAgentRuntime(projectRoot, flags);
|
|
424
755
|
try {
|
|
756
|
+
const askTraceCapability = embeddedCapability ?? await requestLoopbackCliAskTraceCapability(runtimeBase);
|
|
425
757
|
const reasoningEffort = cliReasoningEffort(flags);
|
|
426
758
|
const analysisDepth = cliAnalysisDepth(flags);
|
|
759
|
+
const domain = flags.domain;
|
|
760
|
+
const purpose = flags.purpose || undefined;
|
|
761
|
+
const userId = flags.user;
|
|
762
|
+
const provider = runtimeProviderForCliFlag(flags.provider);
|
|
763
|
+
// `surface` is deliberately absent from public JSON. The runtime assigns
|
|
764
|
+
// trace surface only after consuming its own loopback capability; this
|
|
765
|
+
// context carries user intent, never attribution authority.
|
|
766
|
+
const workspaceContext = {
|
|
767
|
+
...(domain ? { domain } : {}),
|
|
768
|
+
...(purpose ? { purpose } : {}),
|
|
769
|
+
...(userId ? { userId } : {}),
|
|
770
|
+
...(provider ? { provider } : {}),
|
|
771
|
+
};
|
|
772
|
+
const hasWorkspaceContext = Object.keys(workspaceContext).length > 0;
|
|
427
773
|
const response = await fetch(`${runtimeBase.replace(/\/$/, '')}/api/agent-runs`, {
|
|
428
774
|
method: 'POST',
|
|
429
|
-
headers: {
|
|
775
|
+
headers: {
|
|
776
|
+
'Content-Type': 'application/json',
|
|
777
|
+
...(askTraceCapability ? { 'X-DQL-Ask-Trace-Capability': askTraceCapability } : {}),
|
|
778
|
+
},
|
|
430
779
|
body: JSON.stringify({
|
|
431
780
|
question,
|
|
432
|
-
threadId,
|
|
781
|
+
...(threadId ? { threadId } : {}),
|
|
433
782
|
...(reasoningEffort ? { reasoningEffort } : {}),
|
|
434
783
|
...(analysisDepth ? { analysisDepth } : {}),
|
|
784
|
+
...(hasWorkspaceContext ? { workspaceContext } : {}),
|
|
435
785
|
}),
|
|
436
786
|
});
|
|
437
787
|
if (!response.ok)
|
|
438
788
|
throw new Error(`Runtime returned ${response.status}: ${await response.text()}`);
|
|
439
789
|
const payload = (await response.json());
|
|
440
|
-
if (!payload.run)
|
|
441
|
-
throw new Error('Runtime did not return
|
|
790
|
+
if (!payload.run?.id)
|
|
791
|
+
throw new Error('Runtime did not return a canonical agent run.');
|
|
792
|
+
const run = payload.run;
|
|
442
793
|
if (format === 'json') {
|
|
443
|
-
|
|
794
|
+
// Preserve the established top-level run shape while adding compact,
|
|
795
|
+
// content-free trace discoverability for scripts and support bundles.
|
|
796
|
+
console.log(JSON.stringify({
|
|
797
|
+
...run,
|
|
798
|
+
runId: run.id,
|
|
799
|
+
...(run.traceReference?.traceId ? { traceId: run.traceReference.traceId } : {}),
|
|
800
|
+
traceRecordingStatus: run.traceReference?.recordingStatus ?? 'unavailable',
|
|
801
|
+
}, null, 2));
|
|
444
802
|
return;
|
|
445
803
|
}
|
|
446
|
-
|
|
447
|
-
const badge = run.trustState === 'certified'
|
|
448
|
-
? '✓ Certified'
|
|
449
|
-
: run.trustState === 'grounded'
|
|
450
|
-
? '✓ Verified (grounded)'
|
|
451
|
-
: run.trustState === 'review_required'
|
|
452
|
-
? '! AI-generated · review required'
|
|
453
|
-
: run.trustState === 'blocked'
|
|
454
|
-
? '✕ Blocked'
|
|
455
|
-
: '· Reply';
|
|
456
|
-
console.log(`${badge}\n\n${(run.answer ?? run.summary ?? '').trim()}`);
|
|
457
|
-
console.log(`\nThread: ${threadId}`);
|
|
804
|
+
printCanonicalCliAskRun(run, threadId);
|
|
458
805
|
}
|
|
459
806
|
finally {
|
|
460
807
|
await close();
|
|
461
808
|
}
|
|
462
809
|
}
|
|
810
|
+
/**
|
|
811
|
+
* `dql agent ask --thread <id>` — POST the question to the runtime's
|
|
812
|
+
* `/api/agent-runs` with the threadId in the body. The server injects the
|
|
813
|
+
* thread's prior turns into the conversation context and records the completed
|
|
814
|
+
* run as the next turn, so follow-ups resolve "those"/"that product" correctly
|
|
815
|
+
* across CLI invocations (and across the notebook UI, which shares the store).
|
|
816
|
+
*/
|
|
817
|
+
async function runThreadAsk(question, threadId, flags) {
|
|
818
|
+
return runCanonicalCliAsk(question, threadId, flags);
|
|
819
|
+
}
|
|
463
820
|
/** `dql agent threads` — list server-persisted conversation threads. */
|
|
464
821
|
async function runThreads(flags) {
|
|
465
822
|
const projectRoot = findProjectRoot(process.cwd());
|
|
@@ -757,6 +1114,7 @@ async function runEval(rest, flags) {
|
|
|
757
1114
|
&& Boolean(runtimeRun.answer?.trim()),
|
|
758
1115
|
meaningResolved: Boolean(runtimeRun.routeDecision?.meaningResolution),
|
|
759
1116
|
} : {}),
|
|
1117
|
+
...(runtimeProjection?.observability ? { observability: runtimeProjection.observability } : {}),
|
|
760
1118
|
intent: runtimeRun?.routeDecision?.category ?? result.contextPack?.routeDecision.intent,
|
|
761
1119
|
reviewStatus: result.reviewStatus,
|
|
762
1120
|
contextObjects: runtimeProjection?.retrievalCandidateCount ?? result.contextPack?.objects.length,
|
|
@@ -947,6 +1305,9 @@ function evaluateCase(testCase, result, runtime) {
|
|
|
947
1305
|
if (expected.terminalOutcomeKind && runtime?.terminalOutcome?.kind !== expected.terminalOutcomeKind) {
|
|
948
1306
|
failures.push(`terminal outcome expected ${expected.terminalOutcomeKind}, got ${runtime?.terminalOutcome?.kind ?? 'none'}`);
|
|
949
1307
|
}
|
|
1308
|
+
if (expected.traceRecordingStatus && runtime?.observability?.recordingStatus !== expected.traceRecordingStatus) {
|
|
1309
|
+
failures.push(`trace recording status expected ${expected.traceRecordingStatus}, got ${runtime?.observability?.recordingStatus ?? 'unavailable'}`);
|
|
1310
|
+
}
|
|
950
1311
|
for (const token of stringList(expected.sqlContains)) {
|
|
951
1312
|
if (!result.proposedSql?.toLowerCase().includes(token.toLowerCase()))
|
|
952
1313
|
failures.push(`SQL did not contain "${token}"`);
|
|
@@ -1338,6 +1699,22 @@ function buildEvalTrace(input) {
|
|
|
1338
1699
|
promoteCommand: result.promoteCommand,
|
|
1339
1700
|
},
|
|
1340
1701
|
},
|
|
1702
|
+
{
|
|
1703
|
+
stage: 'observability',
|
|
1704
|
+
status: runtime?.observability?.recordingStatus === 'complete'
|
|
1705
|
+
? 'passed'
|
|
1706
|
+
: runtime?.observability ? 'info' : 'not_run',
|
|
1707
|
+
message: runtime?.observability
|
|
1708
|
+
? `Local Ask trace recording ${runtime.observability.recordingStatus}.`
|
|
1709
|
+
: 'No runtime trace receipt was attached to this evaluation run.',
|
|
1710
|
+
payload: runtime?.observability
|
|
1711
|
+
? {
|
|
1712
|
+
recordingStatus: runtime.observability.recordingStatus,
|
|
1713
|
+
storeSchemaVersion: runtime.observability.storeSchemaVersion,
|
|
1714
|
+
...(runtime.observability.traceFingerprint ? { traceFingerprint: runtime.observability.traceFingerprint } : {}),
|
|
1715
|
+
}
|
|
1716
|
+
: undefined,
|
|
1717
|
+
},
|
|
1341
1718
|
{
|
|
1342
1719
|
stage: 'scoring',
|
|
1343
1720
|
status: evaluation.failures.length === 0 ? 'passed' : 'failed',
|