stageflow 0.40.0 → 0.42.0
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/README.md +3 -1
- package/dist/agents/authorChat.d.ts +4 -0
- package/dist/agents/authorChat.js +113 -12
- package/dist/agents/authorSessionStore.d.ts +35 -0
- package/dist/agents/authorSessionStore.js +152 -0
- package/dist/agents/chatTurn.d.ts +2 -0
- package/dist/agents/chatTurn.js +17 -1
- package/dist/agents/errors.d.ts +1 -1
- package/dist/agents/errors.js +1 -0
- package/dist/agents/evalGate.d.ts +61 -0
- package/dist/agents/evalGate.js +103 -0
- package/dist/agents/evalSession.d.ts +26 -0
- package/dist/agents/evalSession.js +29 -0
- package/dist/agents/hostContext.d.ts +3 -0
- package/dist/agents/hostContext.js +4 -1
- package/dist/agents/runtime/piRuntime.d.ts +1 -1
- package/dist/agents/runtime/piRuntime.js +4 -4
- package/dist/agents/runtime/types.d.ts +3 -1
- package/dist/agents/service.d.ts +27 -2
- package/dist/agents/service.js +88 -13
- package/dist/agents/sessions.d.ts +8 -0
- package/dist/agents/sessions.js +50 -10
- package/dist/agents/store.d.ts +14 -3
- package/dist/agents/store.js +45 -7
- package/dist/agents/toolRisk.d.ts +21 -0
- package/dist/agents/toolRisk.js +50 -0
- package/dist/cli/doctorCommand.js +26 -0
- package/dist/cli/evalCommand.d.ts +20 -0
- package/dist/cli/evalCommand.js +720 -0
- package/dist/cli/exportAllCommand.js +1 -1
- package/dist/cli/hostClient.d.ts +60 -0
- package/dist/cli/hostClient.js +71 -0
- package/dist/cli/validateOutput.d.ts +2 -2
- package/dist/cli/validateOutput.js +2 -2
- package/dist/cli.js +10 -0
- package/dist/config/atomicWrite.d.ts +15 -0
- package/dist/config/atomicWrite.js +43 -0
- package/dist/config/browseCatalog.d.ts +2 -0
- package/dist/config/browseCatalog.js +4 -2
- package/dist/config/csv.d.ts +9 -0
- package/dist/config/csv.js +81 -0
- package/dist/config/datasetAgentCheck.d.ts +18 -0
- package/dist/config/datasetAgentCheck.js +109 -0
- package/dist/config/datasetCandidates.d.ts +22 -0
- package/dist/config/datasetCandidates.js +86 -0
- package/dist/config/datasetFromSessions.d.ts +34 -0
- package/dist/config/datasetFromSessions.js +105 -0
- package/dist/config/datasetHash.d.ts +1 -0
- package/dist/config/datasetHash.js +4 -0
- package/dist/config/datasetImport.d.ts +21 -0
- package/dist/config/datasetImport.js +120 -0
- package/dist/config/datasetStageCheck.d.ts +9 -0
- package/dist/config/datasetStageCheck.js +17 -0
- package/dist/config/datasetTypes.d.ts +27 -0
- package/dist/config/datasetTypes.js +1 -0
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -1
- package/dist/config/ensureCatalogScanRoot.js +2 -6
- package/dist/config/evalCatalog.d.ts +22 -0
- package/dist/config/evalCatalog.js +67 -0
- package/dist/config/evalWriteRoots.d.ts +17 -0
- package/dist/config/evalWriteRoots.js +109 -0
- package/dist/config/hostConfig.js +1 -0
- package/dist/config/installEvalSample.d.ts +34 -0
- package/dist/config/installEvalSample.js +182 -0
- package/dist/config/loadDataset.d.ts +16 -0
- package/dist/config/loadDataset.js +318 -0
- package/dist/config/loadEval.d.ts +32 -0
- package/dist/config/loadEval.js +1085 -0
- package/dist/config/loadOutcome.d.ts +5 -0
- package/dist/config/loadStageflowManifest.js +64 -0
- package/dist/config/resolveAgentTarget.d.ts +32 -0
- package/dist/config/resolveAgentTarget.js +118 -0
- package/dist/config/resolveEvalTarget.d.ts +21 -0
- package/dist/config/resolveEvalTarget.js +89 -0
- package/dist/config/scanCatalogPaths.d.ts +1 -1
- package/dist/config/scanCatalogPaths.js +17 -5
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +9 -1
- package/dist/config/validateEval.d.ts +36 -0
- package/dist/config/validateEval.js +405 -0
- package/dist/config/writeDataset.d.ts +54 -0
- package/dist/config/writeDataset.js +186 -0
- package/dist/config/writeEval.d.ts +25 -0
- package/dist/config/writeEval.js +398 -0
- package/dist/diagnostics/checks.js +1 -1
- package/dist/evals/agentDiff.d.ts +13 -0
- package/dist/evals/agentDiff.js +11 -0
- package/dist/evals/canonical.d.ts +3 -0
- package/dist/evals/canonical.js +24 -0
- package/dist/evals/caseTask.d.ts +3 -0
- package/dist/evals/caseTask.js +9 -0
- package/dist/evals/compare.d.ts +94 -0
- package/dist/evals/compare.js +201 -0
- package/dist/evals/constants.d.ts +60 -0
- package/dist/evals/constants.js +95 -0
- package/dist/evals/engine/FakeEngine.d.ts +33 -0
- package/dist/evals/engine/FakeEngine.js +176 -0
- package/dist/evals/engine/index.d.ts +9 -0
- package/dist/evals/engine/index.js +19 -0
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +52 -0
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +311 -0
- package/dist/evals/engine/promptfoo/errors.d.ts +5 -0
- package/dist/evals/engine/promptfoo/errors.js +8 -0
- package/dist/evals/engine/promptfoo/generate.d.ts +30 -0
- package/dist/evals/engine/promptfoo/generate.js +342 -0
- package/dist/evals/engine/promptfoo/guard.d.ts +10 -0
- package/dist/evals/engine/promptfoo/guard.js +116 -0
- package/dist/evals/engine/promptfoo/install.d.ts +17 -0
- package/dist/evals/engine/promptfoo/install.js +73 -0
- package/dist/evals/engine/promptfoo/judgeProviders.d.ts +2 -0
- package/dist/evals/engine/promptfoo/judgeProviders.js +9 -0
- package/dist/evals/engine/promptfoo/judgeServices.d.ts +6 -0
- package/dist/evals/engine/promptfoo/judgeServices.js +41 -0
- package/dist/evals/engine/promptfoo/locate.d.ts +21 -0
- package/dist/evals/engine/promptfoo/locate.js +68 -0
- package/dist/evals/engine/promptfoo/nodeVersion.d.ts +7 -0
- package/dist/evals/engine/promptfoo/nodeVersion.js +14 -0
- package/dist/evals/engine/promptfoo/normalize.d.ts +66 -0
- package/dist/evals/engine/promptfoo/normalize.js +261 -0
- package/dist/evals/engine/promptfoo/pinned.d.ts +5 -0
- package/dist/evals/engine/promptfoo/pinned.js +5 -0
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +14 -0
- package/dist/evals/engine/promptfoo/rubricPrompt.js +103 -0
- package/dist/evals/engine/promptfoo/runTokens.d.ts +18 -0
- package/dist/evals/engine/promptfoo/runTokens.js +31 -0
- package/dist/evals/engine/promptfoo/status.d.ts +13 -0
- package/dist/evals/engine/promptfoo/status.js +16 -0
- package/dist/evals/estimate.d.ts +56 -0
- package/dist/evals/estimate.js +66 -0
- package/dist/evals/graders/codeGrader.d.ts +6 -0
- package/dist/evals/graders/codeGrader.js +85 -0
- package/dist/evals/graders/conversationCheckGrader.d.ts +6 -0
- package/dist/evals/graders/conversationCheckGrader.js +62 -0
- package/dist/evals/graders/fieldGrader.d.ts +11 -0
- package/dist/evals/graders/fieldGrader.js +117 -0
- package/dist/evals/graders/goal.d.ts +3 -0
- package/dist/evals/graders/goal.js +14 -0
- package/dist/evals/graders/index.d.ts +18 -0
- package/dist/evals/graders/index.js +34 -0
- package/dist/evals/graders/notApplicable.d.ts +5 -0
- package/dist/evals/graders/notApplicable.js +9 -0
- package/dist/evals/graders/path.d.ts +26 -0
- package/dist/evals/graders/path.js +75 -0
- package/dist/evals/graders/referenceGrader.d.ts +5 -0
- package/dist/evals/graders/referenceGrader.js +59 -0
- package/dist/evals/graders/schemaGrader.d.ts +5 -0
- package/dist/evals/graders/schemaGrader.js +29 -0
- package/dist/evals/graders/subject.d.ts +6 -0
- package/dist/evals/graders/subject.js +33 -0
- package/dist/evals/graders/toolCallsGrader.d.ts +6 -0
- package/dist/evals/graders/toolCallsGrader.js +100 -0
- package/dist/evals/graders/transcript.d.ts +12 -0
- package/dist/evals/graders/transcript.js +57 -0
- package/dist/evals/graders/types.d.ts +20 -0
- package/dist/evals/graders/types.js +1 -0
- package/dist/evals/judgeProviders.d.ts +16 -0
- package/dist/evals/judgeProviders.js +27 -0
- package/dist/evals/lineDiff.d.ts +5 -0
- package/dist/evals/lineDiff.js +34 -0
- package/dist/evals/listStatus.d.ts +31 -0
- package/dist/evals/listStatus.js +48 -0
- package/dist/evals/manager.d.ts +174 -0
- package/dist/evals/manager.js +787 -0
- package/dist/evals/plan.d.ts +58 -0
- package/dist/evals/plan.js +602 -0
- package/dist/evals/providerKeys.d.ts +1 -0
- package/dist/evals/providerKeys.js +21 -0
- package/dist/evals/read/agentTargets.d.ts +37 -0
- package/dist/evals/read/agentTargets.js +101 -0
- package/dist/evals/read/api.d.ts +196 -0
- package/dist/evals/read/api.js +358 -0
- package/dist/evals/read/compare.d.ts +4 -0
- package/dist/evals/read/compare.js +39 -0
- package/dist/evals/read/datasets.d.ts +105 -0
- package/dist/evals/read/datasets.js +318 -0
- package/dist/evals/read/list.d.ts +66 -0
- package/dist/evals/read/list.js +173 -0
- package/dist/evals/read/results.d.ts +46 -0
- package/dist/evals/read/results.js +107 -0
- package/dist/evals/read/runs.d.ts +149 -0
- package/dist/evals/read/runs.js +289 -0
- package/dist/evals/read/suggestions.d.ts +43 -0
- package/dist/evals/read/suggestions.js +73 -0
- package/dist/evals/runner/FakeAgentBackend.d.ts +40 -0
- package/dist/evals/runner/FakeAgentBackend.js +82 -0
- package/dist/evals/runner/agentCaseRunner.d.ts +24 -0
- package/dist/evals/runner/agentCaseRunner.js +388 -0
- package/dist/evals/runner/caseRunner.d.ts +7 -0
- package/dist/evals/runner/caseRunner.js +17 -0
- package/dist/evals/runner/conversationSubject.d.ts +18 -0
- package/dist/evals/runner/conversationSubject.js +123 -0
- package/dist/evals/runner/simulatorModel.d.ts +51 -0
- package/dist/evals/runner/simulatorModel.js +58 -0
- package/dist/evals/runner/simulatorPrompt.d.ts +29 -0
- package/dist/evals/runner/simulatorPrompt.js +59 -0
- package/dist/evals/runner/stageCaseRunner.d.ts +30 -0
- package/dist/evals/runner/stageCaseRunner.js +279 -0
- package/dist/evals/runner/userDriver.d.ts +71 -0
- package/dist/evals/runner/userDriver.js +104 -0
- package/dist/evals/scoring.d.ts +34 -0
- package/dist/evals/scoring.js +67 -0
- package/dist/evals/snapshot.d.ts +183 -0
- package/dist/evals/snapshot.js +65 -0
- package/dist/evals/stageDiff.d.ts +8 -0
- package/dist/evals/stageDiff.js +48 -0
- package/dist/evals/stats.d.ts +95 -0
- package/dist/evals/stats.js +220 -0
- package/dist/evals/statsAdapter.d.ts +4 -0
- package/dist/evals/statsAdapter.js +30 -0
- package/dist/evals/statsTypes.d.ts +51 -0
- package/dist/evals/statsTypes.js +18 -0
- package/dist/evals/storeError.d.ts +5 -0
- package/dist/evals/storeError.js +8 -0
- package/dist/evals/storeTypes.d.ts +207 -0
- package/dist/evals/storeTypes.js +1 -0
- package/dist/evals/tTable.d.ts +3 -0
- package/dist/evals/tTable.js +15 -0
- package/dist/evals/triage/constants.d.ts +26 -0
- package/dist/evals/triage/constants.js +33 -0
- package/dist/evals/triage/credentials.d.ts +13 -0
- package/dist/evals/triage/credentials.js +20 -0
- package/dist/evals/triage/jevClassifier.d.ts +14 -0
- package/dist/evals/triage/jevClassifier.js +124 -0
- package/dist/evals/triage/judgeClassifier.d.ts +10 -0
- package/dist/evals/triage/judgeClassifier.js +76 -0
- package/dist/evals/triage/prompts.d.ts +16 -0
- package/dist/evals/triage/prompts.js +64 -0
- package/dist/evals/triage/service.d.ts +79 -0
- package/dist/evals/triage/service.js +217 -0
- package/dist/evals/triage/stateBuilder.d.ts +19 -0
- package/dist/evals/triage/stateBuilder.js +125 -0
- package/dist/evals/triage/types.d.ts +60 -0
- package/dist/evals/triage/types.js +8 -0
- package/dist/evals/types.d.ts +347 -0
- package/dist/evals/types.js +1 -0
- package/dist/mcp/deps.d.ts +7 -0
- package/dist/mcp/evalTools.d.ts +3 -0
- package/dist/mcp/evalTools.js +280 -0
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +2 -0
- package/dist/models/response.d.ts +7 -2
- package/dist/models/response.js +6 -1
- package/dist/operatorAgent/agentAuthorContext.d.ts +1 -1
- package/dist/operatorAgent/agentAuthorContext.js +1 -1
- package/dist/operatorAgent/piModel.js +17 -4
- package/dist/operatorAgent/profiles/agentAuthor.d.ts +3 -1
- package/dist/operatorAgent/profiles/agentAuthor.js +145 -20
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +48 -15
- package/dist/operatorAgent/profiles/authorReadable.d.ts +2 -0
- package/dist/operatorAgent/profiles/authorReadable.js +26 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/runstore/port.d.ts +43 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +28 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +99 -5
- package/dist/runstore/sqlite/evalStore.d.ts +20 -0
- package/dist/runstore/sqlite/evalStore.js +541 -0
- package/dist/runstore/sqlite/migrations/015-evals.d.ts +12 -0
- package/dist/runstore/sqlite/migrations/015-evals.js +157 -0
- package/dist/runstore/sqlite/migrations/016-eval-subject-ref.d.ts +12 -0
- package/dist/runstore/sqlite/migrations/016-eval-subject-ref.js +20 -0
- package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/017-eval-result-suggestions.js +36 -0
- package/dist/runstore/sqlite/migrations/index.js +6 -0
- package/dist/runstore/sqlite/suggestionStore.d.ts +14 -0
- package/dist/runstore/sqlite/suggestionStore.js +132 -0
- package/dist/runtime/pipelineRunner.d.ts +2 -1
- package/dist/runtime/pipelineRunner.js +2 -0
- package/dist/runtime/runManager.d.ts +2 -1
- package/dist/runtime/runManager.js +8 -6
- package/dist/runtime/runRetentionSweep.js +2 -2
- package/dist/server/agentAuthorRoutes.js +50 -1
- package/dist/server/bootstrap.d.ts +8 -0
- package/dist/server/bootstrap.js +56 -0
- package/dist/server/controlToken.js +3 -0
- package/dist/server/evalInternalRoutes.d.ts +14 -0
- package/dist/server/evalInternalRoutes.js +87 -0
- package/dist/server/evalRouteContext.d.ts +46 -0
- package/dist/server/evalRouteContext.js +43 -0
- package/dist/server/evalRoutes.d.ts +5 -0
- package/dist/server/evalRoutes.js +1427 -0
- package/dist/server/evalTriageRoutes.d.ts +2 -0
- package/dist/server/evalTriageRoutes.js +95 -0
- package/dist/server/http.d.ts +5 -0
- package/dist/server/http.js +32 -2
- package/dist/server/mcpHost.js +3 -0
- package/dist/toolkit/meta.d.ts +1 -1
- package/dist/toolkit/meta.js +15 -0
- package/dist/toolkit/profiles.js +1 -1
- package/dist/types/stageflowManifest.d.ts +6 -0
- package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +9 -0
- package/dist/ui/assets/{MarkdownText-D7tYaIFO.js → MarkdownText-BTrOqu5J.js} +1 -1
- package/dist/ui/assets/chat-Df_wCpak.js +5 -0
- package/dist/ui/assets/chat-P7KQznHm.css +2 -0
- package/dist/ui/assets/{main-BFo79krC.css → main-CHlmTNJe.css} +1 -1
- package/dist/ui/assets/main-CvVfxmMd.js +271 -0
- package/dist/ui/chat.html +3 -3
- package/dist/ui/index.html +3 -3
- package/examples/README.md +2 -0
- package/examples/document-policy-review/README.md +35 -0
- package/examples/document-policy-review/agents/compliance.agent.yaml +42 -0
- package/examples/document-policy-review/documents/acme-vendor-sow.md +15 -0
- package/examples/document-policy-review/documents/support-runbook.md +13 -0
- package/examples/document-policy-review/policies/acceptable-use.md +13 -0
- package/examples/document-policy-review/policies/data-handling.md +17 -0
- package/examples/document-policy-review/policies/vendor-security.md +17 -0
- package/examples/evals/README.md +123 -0
- package/examples/evals/critique-sample.dataset.jsonl +8 -0
- package/examples/evals/critique-sample.eval.yaml +34 -0
- package/examples/evals/critique-sample.task.yaml +4 -0
- package/examples/evals/eval-sample.pipeline.yaml +35 -0
- package/examples/evals/support-sample.agent.yaml +20 -0
- package/examples/evals/support-sample.dataset.jsonl +6 -0
- package/examples/evals/support-sample.eval.yaml +38 -0
- package/examples/stageflow.yaml +6 -0
- package/package.json +1 -1
- package/skills/stageflow/SKILL.md +5 -2
- package/skills/stageflow/references/control-surface.md +4 -2
- package/skills/stageflow/references/evals.md +68 -0
- package/skills/stageflow-author/SKILL.md +4 -0
- package/skills/stageflow-run/SKILL.md +4 -0
- package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +0 -9
- package/dist/ui/assets/chat-BbLukq9W.js +0 -5
- package/dist/ui/assets/chat-zIZU_bP1.css +0 -2
- package/dist/ui/assets/main-CijYMeM0.js +0 -259
|
@@ -135,7 +135,7 @@ function parseExportArgs(args) {
|
|
|
135
135
|
}
|
|
136
136
|
export async function* iterateExportNdjson(options) {
|
|
137
137
|
yield `${JSON.stringify(buildExportHeader(options.filter, options.now ?? new Date()))}\n`;
|
|
138
|
-
const runs = await options.store.listRuns(options.filter);
|
|
138
|
+
const runs = await options.store.listRuns({ ...options.filter, origin: "any" });
|
|
139
139
|
for (const summary of runs) {
|
|
140
140
|
const detail = await options.store.readRun(summary.run_id);
|
|
141
141
|
const pipelineBody = await options.store.readPipelineBody(summary.run_id);
|
package/dist/cli/hostClient.d.ts
CHANGED
|
@@ -77,5 +77,65 @@ export type HttpListTriggersResult = {
|
|
|
77
77
|
export declare function httpFireTrigger(base: string, triggerId: string, task?: Record<string, unknown>): Promise<StartRunResult>;
|
|
78
78
|
export declare function httpListTriggers(base: string): Promise<HttpListTriggersResult>;
|
|
79
79
|
export declare function httpGetTrigger(base: string, triggerId: string): Promise<HttpTriggerLookupResult>;
|
|
80
|
+
export type HttpEvalResult<T> = {
|
|
81
|
+
ok: true;
|
|
82
|
+
body: T;
|
|
83
|
+
} | {
|
|
84
|
+
ok: false;
|
|
85
|
+
reason: string;
|
|
86
|
+
status: number;
|
|
87
|
+
code?: string;
|
|
88
|
+
findings?: unknown[];
|
|
89
|
+
};
|
|
90
|
+
export declare function httpListEvals(base: string, projectRoot?: string): Promise<HttpEvalResult<Record<string, unknown>>>;
|
|
91
|
+
export declare function httpGetEval(base: string, evalId: string, projectRoot?: string): Promise<HttpEvalResult<Record<string, unknown>>>;
|
|
92
|
+
export declare function httpValidateEval(base: string, input: {
|
|
93
|
+
project_root?: string;
|
|
94
|
+
yaml?: string;
|
|
95
|
+
path?: string;
|
|
96
|
+
}): Promise<HttpEvalResult<Record<string, unknown>>>;
|
|
97
|
+
export type HttpStartEvalRunInput = {
|
|
98
|
+
project_root?: string;
|
|
99
|
+
repeats?: number;
|
|
100
|
+
judge?: string;
|
|
101
|
+
model?: string;
|
|
102
|
+
user_model?: string;
|
|
103
|
+
allow_real_tools?: boolean;
|
|
104
|
+
max_cost_usd?: number;
|
|
105
|
+
case_ids?: string[];
|
|
106
|
+
tags?: string[];
|
|
107
|
+
label?: string;
|
|
108
|
+
started_via?: "console" | "cli" | "mcp";
|
|
109
|
+
};
|
|
110
|
+
export declare function httpStartEvalRun(base: string, evalId: string, input: HttpStartEvalRunInput): Promise<HttpEvalResult<{
|
|
111
|
+
eval_run_id: string;
|
|
112
|
+
status: string;
|
|
113
|
+
run_number?: number;
|
|
114
|
+
}>>;
|
|
115
|
+
export declare function httpGetEvalRun(base: string, evalRunId: string): Promise<HttpEvalResult<Record<string, any>>>;
|
|
116
|
+
export declare function httpCancelEvalRun(base: string, evalRunId: string): Promise<HttpEvalResult<Record<string, any>>>;
|
|
117
|
+
export declare function httpSortEvalFailures(base: string, evalRunId: string, input: {
|
|
118
|
+
classifier?: "auto" | "jev" | "judge";
|
|
119
|
+
only_unsorted?: boolean;
|
|
120
|
+
limit?: number;
|
|
121
|
+
}): Promise<HttpEvalResult<Record<string, any>>>;
|
|
122
|
+
export declare function httpListEvalSuggestions(base: string, evalRunId: string, status?: string): Promise<HttpEvalResult<{
|
|
123
|
+
items: Array<Record<string, any>>;
|
|
124
|
+
summary: Record<string, any>;
|
|
125
|
+
}>>;
|
|
126
|
+
export declare function httpListEvalRuns(base: string, query?: {
|
|
127
|
+
eval_id?: string;
|
|
128
|
+
project_root?: string;
|
|
129
|
+
limit?: number;
|
|
130
|
+
cursor?: string;
|
|
131
|
+
}): Promise<HttpEvalResult<{
|
|
132
|
+
items: Array<Record<string, unknown>>;
|
|
133
|
+
next_cursor: string | null;
|
|
134
|
+
}>>;
|
|
135
|
+
export declare function httpDeleteEvalRun(base: string, evalRunId: string): Promise<HttpEvalResult<null>>;
|
|
136
|
+
export declare function httpCompareEvalRuns(base: string, a: string, b: string): Promise<HttpEvalResult<Record<string, unknown>>>;
|
|
137
|
+
export declare function httpListDatasets(base: string, projectRoot?: string): Promise<HttpEvalResult<{
|
|
138
|
+
items: Array<Record<string, unknown>>;
|
|
139
|
+
}>>;
|
|
80
140
|
export declare function resolveAbsolute(cwd: string, maybeRelative: string): string;
|
|
81
141
|
export {};
|
package/dist/cli/hostClient.js
CHANGED
|
@@ -292,6 +292,77 @@ export async function httpGetTrigger(base, triggerId) {
|
|
|
292
292
|
}
|
|
293
293
|
return { ok: true, trigger: body };
|
|
294
294
|
}
|
|
295
|
+
function evalFailure(status, body) {
|
|
296
|
+
const rec = body && typeof body === "object" ? body : {};
|
|
297
|
+
return {
|
|
298
|
+
ok: false,
|
|
299
|
+
reason: extractError(body, status),
|
|
300
|
+
status,
|
|
301
|
+
...(typeof rec.code === "string" ? { code: rec.code } : {}),
|
|
302
|
+
...(Array.isArray(rec.findings) ? { findings: rec.findings } : {}),
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function evalQuery(params) {
|
|
306
|
+
const parts = [];
|
|
307
|
+
for (const [key, value] of Object.entries(params)) {
|
|
308
|
+
if (value === undefined || value === "")
|
|
309
|
+
continue;
|
|
310
|
+
parts.push(`${key}=${enc(String(value))}`);
|
|
311
|
+
}
|
|
312
|
+
return parts.length > 0 ? `?${parts.join("&")}` : "";
|
|
313
|
+
}
|
|
314
|
+
async function evalGet(base, urlPath, expected = 200) {
|
|
315
|
+
const { status, body } = await getJson(base, urlPath);
|
|
316
|
+
return status === expected ? { ok: true, body: body } : evalFailure(status, body);
|
|
317
|
+
}
|
|
318
|
+
export function httpListEvals(base, projectRoot) {
|
|
319
|
+
return evalGet(base, `/api/evals${evalQuery({ project_root: projectRoot })}`);
|
|
320
|
+
}
|
|
321
|
+
export function httpGetEval(base, evalId, projectRoot) {
|
|
322
|
+
return evalGet(base, `/api/evals/${enc(evalId)}${evalQuery({ project_root: projectRoot })}`);
|
|
323
|
+
}
|
|
324
|
+
export async function httpValidateEval(base, input) {
|
|
325
|
+
const { status, body } = await postJson(base, "/api/evals/validate", input);
|
|
326
|
+
return status === 200 ? { ok: true, body: body } : evalFailure(status, body);
|
|
327
|
+
}
|
|
328
|
+
export async function httpStartEvalRun(base, evalId, input) {
|
|
329
|
+
const { status, body } = await postJson(base, `/api/evals/${enc(evalId)}/runs`, input);
|
|
330
|
+
return status === 202
|
|
331
|
+
? { ok: true, body: body }
|
|
332
|
+
: evalFailure(status, body);
|
|
333
|
+
}
|
|
334
|
+
export function httpGetEvalRun(base, evalRunId) {
|
|
335
|
+
return evalGet(base, `/api/eval-runs/${enc(evalRunId)}`);
|
|
336
|
+
}
|
|
337
|
+
export async function httpCancelEvalRun(base, evalRunId) {
|
|
338
|
+
const { status, body } = await postJson(base, `/api/eval-runs/${enc(evalRunId)}/cancel`, {});
|
|
339
|
+
return status === 200 ? { ok: true, body: body } : evalFailure(status, body);
|
|
340
|
+
}
|
|
341
|
+
export async function httpSortEvalFailures(base, evalRunId, input) {
|
|
342
|
+
const { status, body } = await postJson(base, `/api/eval-runs/${enc(evalRunId)}/failures/sort`, input);
|
|
343
|
+
return status === 200 ? { ok: true, body: body } : evalFailure(status, body);
|
|
344
|
+
}
|
|
345
|
+
export function httpListEvalSuggestions(base, evalRunId, status) {
|
|
346
|
+
return evalGet(base, `/api/eval-runs/${enc(evalRunId)}/failures/suggestions${evalQuery({ status })}`);
|
|
347
|
+
}
|
|
348
|
+
export function httpListEvalRuns(base, query = {}) {
|
|
349
|
+
return evalGet(base, `/api/eval-runs${evalQuery(query)}`);
|
|
350
|
+
}
|
|
351
|
+
export async function httpDeleteEvalRun(base, evalRunId) {
|
|
352
|
+
const res = await fetch(`${base}/api/eval-runs/${enc(evalRunId)}`, {
|
|
353
|
+
method: "DELETE",
|
|
354
|
+
headers: { ...clientAuthorizationHeaders("DELETE") },
|
|
355
|
+
});
|
|
356
|
+
if (res.status === 204)
|
|
357
|
+
return { ok: true, body: null };
|
|
358
|
+
return evalFailure(res.status, await parseJsonBody(res));
|
|
359
|
+
}
|
|
360
|
+
export function httpCompareEvalRuns(base, a, b) {
|
|
361
|
+
return evalGet(base, `/api/eval-compare${evalQuery({ a, b })}`);
|
|
362
|
+
}
|
|
363
|
+
export function httpListDatasets(base, projectRoot) {
|
|
364
|
+
return evalGet(base, `/api/datasets${evalQuery({ project_root: projectRoot })}`);
|
|
365
|
+
}
|
|
295
366
|
export function resolveAbsolute(cwd, maybeRelative) {
|
|
296
367
|
return path.resolve(cwd, maybeRelative);
|
|
297
368
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ValidationResult } from "../config/validateCatalog.js";
|
|
2
|
-
export declare const VALIDATION_SCOPE_LINE = "Scope: catalog YAML (pipelines, stages, and
|
|
3
|
-
export declare const VALIDATION_CHECKS = "catalog YAML (pipelines, stages, tasks as selected by flags)";
|
|
2
|
+
export declare const VALIDATION_SCOPE_LINE = "Scope: catalog YAML (pipelines, stages, tasks, and evals as selected by flags). Provider auth and checkout paths are not checked.";
|
|
3
|
+
export declare const VALIDATION_CHECKS = "catalog YAML (pipelines, stages, tasks, evals as selected by flags)";
|
|
4
4
|
export declare function formatValidationHuman(result: ValidationResult, options?: {
|
|
5
5
|
strict?: boolean;
|
|
6
6
|
}): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { effectiveSeverity } from "../config/validateCatalog.js";
|
|
2
|
-
export const VALIDATION_SCOPE_LINE = "Scope: catalog YAML (pipelines, stages, and
|
|
3
|
-
export const VALIDATION_CHECKS = "catalog YAML (pipelines, stages, tasks as selected by flags)";
|
|
2
|
+
export const VALIDATION_SCOPE_LINE = "Scope: catalog YAML (pipelines, stages, tasks, and evals as selected by flags). Provider auth and checkout paths are not checked.";
|
|
3
|
+
export const VALIDATION_CHECKS = "catalog YAML (pipelines, stages, tasks, evals as selected by flags)";
|
|
4
4
|
function effectiveSeverityRank(finding, strict) {
|
|
5
5
|
return effectiveSeverity(finding, strict) === "error" ? 0 : 1;
|
|
6
6
|
}
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { RUN_STAGE_USAGE, runRunStageCommand } from "./cli/runStageCommand.js";
|
|
|
20
20
|
import { RUNS_USAGE, runRunsCommand } from "./cli/runsCommand.js";
|
|
21
21
|
import { AGENTS_USAGE, runAgentsCommand } from "./cli/agentsCommand.js";
|
|
22
22
|
import { TRIGGER_USAGE, runTriggerCommand } from "./cli/triggerCommand.js";
|
|
23
|
+
import { EVAL_USAGE, runEvalCommand } from "./cli/evalCommand.js";
|
|
23
24
|
import { resolveOperatorCatalog } from "./cli/operatorCatalog.js";
|
|
24
25
|
import { SKILLS_USAGE, runSkillsCommand } from "./cli/skillsCommand.js";
|
|
25
26
|
import { VALIDATE_USAGE, runValidateCommand } from "./cli/validateCommand.js";
|
|
@@ -125,6 +126,8 @@ ${RUNS_USAGE}
|
|
|
125
126
|
|
|
126
127
|
${TRIGGER_USAGE}
|
|
127
128
|
|
|
129
|
+
${EVAL_USAGE}
|
|
130
|
+
|
|
128
131
|
${AGENTS_USAGE}
|
|
129
132
|
|
|
130
133
|
${PROVIDERS_USAGE}
|
|
@@ -168,6 +171,7 @@ function parseArgs(argv) {
|
|
|
168
171
|
command === "export" ||
|
|
169
172
|
command === "runs" ||
|
|
170
173
|
command === "trigger" ||
|
|
174
|
+
command === "eval" ||
|
|
171
175
|
command === "agents" ||
|
|
172
176
|
command === "skills" ||
|
|
173
177
|
command === "browser") {
|
|
@@ -495,6 +499,12 @@ async function main(argv) {
|
|
|
495
499
|
cwd: ctx.invocationCwd,
|
|
496
500
|
});
|
|
497
501
|
}
|
|
502
|
+
if (parsed.command === "eval") {
|
|
503
|
+
return runEvalCommand(argv.slice(3), {
|
|
504
|
+
cwd: ctx.invocationCwd,
|
|
505
|
+
projectRoot: ctx.projectRoot,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
498
508
|
if (parsed.command === "agents") {
|
|
499
509
|
return runAgentsCommand(argv.slice(3), {
|
|
500
510
|
cwd: ctx.invocationCwd,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ValidationFinding } from "./validateCatalog.js";
|
|
2
|
+
export type EvalsWriteErrorCode = "EVAL_EXISTS" | "EVAL_NOT_FOUND" | "EVAL_INVALID" | "EVAL_DEFINITION_ID_MISMATCH" | "DATASET_EXISTS" | "DATASET_NOT_FOUND" | "DATASET_INVALID" | "DATASET_READ_ONLY" | "DATASET_CASE_OP_INVALID" | "DATASET_NAME_INVALID" | "SAMPLE_EXISTS" | "SAMPLE_SOURCE_MISSING" | "SAMPLE_NO_DEFAULT_MODEL" | "SAMPLE_AGENTS_UNAVAILABLE";
|
|
3
|
+
export declare class EvalsWriteError extends Error {
|
|
4
|
+
readonly code: EvalsWriteErrorCode;
|
|
5
|
+
readonly findings: ValidationFinding[];
|
|
6
|
+
constructor(code: EvalsWriteErrorCode, message: string, findings?: ValidationFinding[]);
|
|
7
|
+
}
|
|
8
|
+
export declare class FileChangedError extends Error {
|
|
9
|
+
readonly code: "FILE_CHANGED";
|
|
10
|
+
readonly currentHash: string;
|
|
11
|
+
constructor(currentHash: string);
|
|
12
|
+
}
|
|
13
|
+
export declare function contentHash(bytes: string | Uint8Array): string;
|
|
14
|
+
export declare function assertBaseHash(filePath: string, baseHash: string): Promise<string>;
|
|
15
|
+
export declare function writeFileAtomic(filePath: string, text: string): Promise<void>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { sha256Hex } from "../evals/canonical.js";
|
|
4
|
+
export class EvalsWriteError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
findings;
|
|
7
|
+
constructor(code, message, findings = []) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "EvalsWriteError";
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.findings = findings;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class FileChangedError extends Error {
|
|
15
|
+
code = "FILE_CHANGED";
|
|
16
|
+
currentHash;
|
|
17
|
+
constructor(currentHash) {
|
|
18
|
+
super("The file changed on disk since it was loaded");
|
|
19
|
+
this.name = "FileChangedError";
|
|
20
|
+
this.currentHash = currentHash;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function contentHash(bytes) {
|
|
24
|
+
return sha256Hex(bytes);
|
|
25
|
+
}
|
|
26
|
+
export async function assertBaseHash(filePath, baseHash) {
|
|
27
|
+
const current = contentHash(await readFile(filePath));
|
|
28
|
+
if (current !== baseHash)
|
|
29
|
+
throw new FileChangedError(current);
|
|
30
|
+
return current;
|
|
31
|
+
}
|
|
32
|
+
export async function writeFileAtomic(filePath, text) {
|
|
33
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
34
|
+
const tmp = `${filePath}.tmp-${process.pid}`;
|
|
35
|
+
try {
|
|
36
|
+
await writeFile(tmp, text, "utf8");
|
|
37
|
+
await rename(tmp, filePath);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
await rm(tmp, { force: true });
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -40,6 +40,8 @@ export type CatalogScanPaths = {
|
|
|
40
40
|
pipelinePaths: string[];
|
|
41
41
|
taskPaths: string[];
|
|
42
42
|
triggerPaths: string[];
|
|
43
|
+
evalPaths: string[];
|
|
44
|
+
datasetPaths: string[];
|
|
43
45
|
};
|
|
44
46
|
export declare function getCatalogScanPaths(ctx: CatalogContext): Promise<CatalogScanPaths | null>;
|
|
45
47
|
export declare function browseCatalog(invocationCwd: string | StageflowContext): Promise<CatalogBrowseResult>;
|
|
@@ -35,12 +35,14 @@ export async function getCatalogScanPaths(ctx) {
|
|
|
35
35
|
if (!catalogReady(ctx)) {
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
|
-
const [pipelinePaths, taskPaths, triggerPaths] = await Promise.all([
|
|
38
|
+
const [pipelinePaths, taskPaths, triggerPaths, evalPaths, datasetPaths] = await Promise.all([
|
|
39
39
|
scanCatalogPaths(ctx.manifest, "pipeline"),
|
|
40
40
|
scanCatalogPaths(ctx.manifest, "task"),
|
|
41
41
|
scanCatalogPaths(ctx.manifest, "trigger"),
|
|
42
|
+
scanCatalogPaths(ctx.manifest, "eval"),
|
|
43
|
+
scanCatalogPaths(ctx.manifest, "dataset"),
|
|
42
44
|
]);
|
|
43
|
-
return { pipelinePaths, taskPaths, triggerPaths };
|
|
45
|
+
return { pipelinePaths, taskPaths, triggerPaths, evalPaths, datasetPaths };
|
|
44
46
|
}
|
|
45
47
|
async function listTasksFromManifest(projectRoot, manifest, warnings) {
|
|
46
48
|
const filePaths = await scanCatalogPaths(manifest, "task");
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class CsvParseError extends Error {
|
|
2
|
+
readonly record: number;
|
|
3
|
+
constructor(message: string, record: number);
|
|
4
|
+
}
|
|
5
|
+
export type ParseCsvOptions = {
|
|
6
|
+
delimiter?: string;
|
|
7
|
+
};
|
|
8
|
+
/** RFC 4180 parser. Returns raw records; blank lines are kept as `[""]`. */
|
|
9
|
+
export declare function parseCsv(text: string, options?: ParseCsvOptions): string[][];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export class CsvParseError extends Error {
|
|
2
|
+
record;
|
|
3
|
+
constructor(message, record) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "CsvParseError";
|
|
6
|
+
this.record = record;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** RFC 4180 parser. Returns raw records; blank lines are kept as `[""]`. */
|
|
10
|
+
export function parseCsv(text, options = {}) {
|
|
11
|
+
const delimiter = options.delimiter ?? ",";
|
|
12
|
+
if (delimiter.length !== 1 || delimiter === '"' || delimiter === "\n" || delimiter === "\r") {
|
|
13
|
+
throw new Error(`Invalid CSV delimiter: ${JSON.stringify(delimiter)}`);
|
|
14
|
+
}
|
|
15
|
+
const src = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
|
|
16
|
+
const records = [];
|
|
17
|
+
let record = [];
|
|
18
|
+
let field = "";
|
|
19
|
+
let inQuotes = false;
|
|
20
|
+
let fieldStarted = false;
|
|
21
|
+
let i = 0;
|
|
22
|
+
const endField = () => {
|
|
23
|
+
record.push(field);
|
|
24
|
+
field = "";
|
|
25
|
+
fieldStarted = false;
|
|
26
|
+
};
|
|
27
|
+
const endRecord = () => {
|
|
28
|
+
endField();
|
|
29
|
+
records.push(record);
|
|
30
|
+
record = [];
|
|
31
|
+
};
|
|
32
|
+
while (i < src.length) {
|
|
33
|
+
const ch = src[i];
|
|
34
|
+
if (inQuotes) {
|
|
35
|
+
if (ch === '"') {
|
|
36
|
+
if (src[i + 1] === '"') {
|
|
37
|
+
field += '"';
|
|
38
|
+
i += 2;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
inQuotes = false;
|
|
42
|
+
i += 1;
|
|
43
|
+
const next = src[i];
|
|
44
|
+
if (next !== undefined && next !== delimiter && next !== "\n" && next !== "\r") {
|
|
45
|
+
throw new CsvParseError(`unexpected character after closing quote in row ${records.length + 1}`, records.length + 1);
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
field += ch;
|
|
50
|
+
i += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (ch === '"') {
|
|
54
|
+
if (fieldStarted) {
|
|
55
|
+
throw new CsvParseError(`unexpected quote inside unquoted field in row ${records.length + 1}`, records.length + 1);
|
|
56
|
+
}
|
|
57
|
+
inQuotes = true;
|
|
58
|
+
fieldStarted = true;
|
|
59
|
+
i += 1;
|
|
60
|
+
}
|
|
61
|
+
else if (ch === delimiter) {
|
|
62
|
+
endField();
|
|
63
|
+
i += 1;
|
|
64
|
+
}
|
|
65
|
+
else if (ch === "\n" || ch === "\r") {
|
|
66
|
+
endRecord();
|
|
67
|
+
i += ch === "\r" && src[i + 1] === "\n" ? 2 : 1;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
field += ch;
|
|
71
|
+
fieldStarted = true;
|
|
72
|
+
i += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (inQuotes) {
|
|
76
|
+
throw new CsvParseError(`unterminated quoted field in row ${records.length + 1}`, records.length + 1);
|
|
77
|
+
}
|
|
78
|
+
if (fieldStarted || field !== "" || record.length > 0)
|
|
79
|
+
endRecord();
|
|
80
|
+
return records;
|
|
81
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ConversationMode } from "../evals/types.js";
|
|
2
|
+
export type DatasetAgentNote = {
|
|
3
|
+
code: "dataset.scenario_unknown_field" | "dataset.expected_invalid";
|
|
4
|
+
message: string;
|
|
5
|
+
};
|
|
6
|
+
export type DatasetAgentCheckResult = {
|
|
7
|
+
caseId: string;
|
|
8
|
+
valid: boolean;
|
|
9
|
+
message?: string;
|
|
10
|
+
notes: DatasetAgentNote[];
|
|
11
|
+
};
|
|
12
|
+
export declare function checkDatasetAgainstAgent(cases: ReadonlyArray<{
|
|
13
|
+
id: string;
|
|
14
|
+
input: Record<string, unknown>;
|
|
15
|
+
expected?: unknown;
|
|
16
|
+
}>, conversation?: {
|
|
17
|
+
mode?: ConversationMode;
|
|
18
|
+
}): DatasetAgentCheckResult[];
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const INPUT_KEYS = ["mode", "script", "opening", "persona", "goal", "facts", "tool_mocks"];
|
|
2
|
+
const MOCK_MAX_BYTES = 20 * 1024;
|
|
3
|
+
function isPlainObject(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
function boundedString(value, min, max) {
|
|
7
|
+
return typeof value === "string" && value.length >= min && value.length <= max;
|
|
8
|
+
}
|
|
9
|
+
function stringList(value, maxItems, maxLength) {
|
|
10
|
+
return (Array.isArray(value) &&
|
|
11
|
+
value.length <= maxItems &&
|
|
12
|
+
value.every((item) => typeof item === "string" && (maxLength === undefined || item.length <= maxLength)));
|
|
13
|
+
}
|
|
14
|
+
function toolMocksProblem(mocks) {
|
|
15
|
+
if (!isPlainObject(mocks))
|
|
16
|
+
return "scenario tool_mocks must be an object";
|
|
17
|
+
const entries = Object.entries(mocks);
|
|
18
|
+
if (entries.length > 50)
|
|
19
|
+
return "scenario tool_mocks has more than 50 entries";
|
|
20
|
+
for (const [tool, mock] of entries) {
|
|
21
|
+
if (tool.length < 1 || tool.length > 128 || /\s/.test(tool)) {
|
|
22
|
+
return `scenario tool_mocks key ${JSON.stringify(tool)} must be 1-128 characters with no whitespace`;
|
|
23
|
+
}
|
|
24
|
+
if (!isPlainObject(mock))
|
|
25
|
+
return `scenario tool_mocks "${tool}" must be an object`;
|
|
26
|
+
const hasResult = "result" in mock;
|
|
27
|
+
const hasError = "error" in mock;
|
|
28
|
+
if (hasResult === hasError || Object.keys(mock).length !== 1) {
|
|
29
|
+
return `scenario tool_mocks "${tool}" must have exactly one of result or error`;
|
|
30
|
+
}
|
|
31
|
+
if (hasError && !boundedString(mock.error, 0, 1000)) {
|
|
32
|
+
return `scenario tool_mocks "${tool}" error must be text of at most 1000 characters`;
|
|
33
|
+
}
|
|
34
|
+
if (Buffer.byteLength(JSON.stringify(mock) ?? "", "utf8") > MOCK_MAX_BYTES) {
|
|
35
|
+
return `scenario tool_mocks "${tool}" is larger than 20 KB`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
function scenarioProblem(input, defaultMode) {
|
|
41
|
+
let mode = defaultMode;
|
|
42
|
+
if (input.mode !== undefined) {
|
|
43
|
+
if (input.mode !== "script" && input.mode !== "simulated") {
|
|
44
|
+
return `scenario mode must be "script" or "simulated"`;
|
|
45
|
+
}
|
|
46
|
+
mode = input.mode;
|
|
47
|
+
}
|
|
48
|
+
if (mode === "script") {
|
|
49
|
+
const { script } = input;
|
|
50
|
+
if (!Array.isArray(script) ||
|
|
51
|
+
script.length < 1 ||
|
|
52
|
+
script.length > 40 ||
|
|
53
|
+
!script.every((item) => boundedString(item, 1, 4000))) {
|
|
54
|
+
return "scenario script must be 1-40 messages of 1-4000 characters (script mode)";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
if (!boundedString(input.opening, 1, 2000)) {
|
|
59
|
+
return "scenario opening must be a message of 1-2000 characters (simulated mode)";
|
|
60
|
+
}
|
|
61
|
+
if (!boundedString(input.persona, 1, 1000)) {
|
|
62
|
+
return "scenario persona must be 1-1000 characters (simulated mode)";
|
|
63
|
+
}
|
|
64
|
+
if (!boundedString(input.goal, 1, 1000)) {
|
|
65
|
+
return "scenario goal must be 1-1000 characters (simulated mode)";
|
|
66
|
+
}
|
|
67
|
+
if (input.facts !== undefined && !stringList(input.facts, 30, 300)) {
|
|
68
|
+
return "scenario facts must be at most 30 strings of at most 300 characters";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (input.tool_mocks !== undefined)
|
|
72
|
+
return toolMocksProblem(input.tool_mocks);
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
function expectedNotes(caseId, expected) {
|
|
76
|
+
if (!isPlainObject(expected))
|
|
77
|
+
return [];
|
|
78
|
+
const notes = [];
|
|
79
|
+
const note = (message) => {
|
|
80
|
+
notes.push({ code: "dataset.expected_invalid", message: `case ${caseId}: ${message}` });
|
|
81
|
+
};
|
|
82
|
+
if (expected.outcome !== undefined && !boundedString(expected.outcome, 0, 500)) {
|
|
83
|
+
note("expected.outcome must be a string of at most 500 characters");
|
|
84
|
+
}
|
|
85
|
+
for (const key of ["tools", "forbidden_tools"]) {
|
|
86
|
+
if (expected[key] !== undefined && !stringList(expected[key], 50)) {
|
|
87
|
+
note(`expected.${key} must be an array of at most 50 strings`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return notes;
|
|
91
|
+
}
|
|
92
|
+
export function checkDatasetAgainstAgent(cases, conversation = {}) {
|
|
93
|
+
const defaultMode = conversation.mode ?? "script";
|
|
94
|
+
return cases.map((c) => {
|
|
95
|
+
const notes = [];
|
|
96
|
+
const unknown = Object.keys(c.input).filter((key) => !INPUT_KEYS.includes(key));
|
|
97
|
+
if (unknown.length > 0) {
|
|
98
|
+
notes.push({
|
|
99
|
+
code: "dataset.scenario_unknown_field",
|
|
100
|
+
message: `case ${c.id}: scenario has unknown field(s): ${unknown.join(", ")}`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
notes.push(...expectedNotes(c.id, c.expected));
|
|
104
|
+
const problem = scenarioProblem(c.input, defaultMode);
|
|
105
|
+
return problem === undefined
|
|
106
|
+
? { caseId: c.id, valid: true, notes }
|
|
107
|
+
: { caseId: c.id, valid: false, message: problem, notes };
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { RunStore } from "../runstore/port.js";
|
|
2
|
+
import type { NewDatasetCase } from "./writeDataset.js";
|
|
3
|
+
export type CandidateTarget = {
|
|
4
|
+
stageId: string;
|
|
5
|
+
pipelinePath?: string;
|
|
6
|
+
};
|
|
7
|
+
export type DatasetCandidate = {
|
|
8
|
+
runId: string;
|
|
9
|
+
finishedAt: string;
|
|
10
|
+
preview: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function standalonePipelineId(stageId: string): string;
|
|
13
|
+
export declare function listDatasetCandidates(input: {
|
|
14
|
+
store: RunStore;
|
|
15
|
+
target: CandidateTarget;
|
|
16
|
+
limit: number;
|
|
17
|
+
}): Promise<DatasetCandidate[]>;
|
|
18
|
+
export declare function casesFromRuns(input: {
|
|
19
|
+
store: RunStore;
|
|
20
|
+
runIds: readonly string[];
|
|
21
|
+
target: CandidateTarget;
|
|
22
|
+
}): Promise<NewDatasetCase[]>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { parse as parseYaml } from "yaml";
|
|
3
|
+
import { EvalsWriteError } from "./atomicWrite.js";
|
|
4
|
+
const PREVIEW_CHARS = 160;
|
|
5
|
+
const SHORT_ID_CHARS = 8;
|
|
6
|
+
export function standalonePipelineId(stageId) {
|
|
7
|
+
return `standalone-${stageId}`;
|
|
8
|
+
}
|
|
9
|
+
function isPlain(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function isCandidateRun(meta, target) {
|
|
13
|
+
if (meta.origin === "eval" || meta.status !== "succeeded")
|
|
14
|
+
return false;
|
|
15
|
+
if (meta.pipeline_id === standalonePipelineId(target.stageId))
|
|
16
|
+
return true;
|
|
17
|
+
if (target.pipelinePath === undefined || meta.pipeline_path === undefined)
|
|
18
|
+
return false;
|
|
19
|
+
if (path.resolve(meta.pipeline_path) !== path.resolve(target.pipelinePath))
|
|
20
|
+
return false;
|
|
21
|
+
return meta.pipeline_dag?.roots.includes(target.stageId) ?? false;
|
|
22
|
+
}
|
|
23
|
+
async function recordedInput(store, runId) {
|
|
24
|
+
const detail = await store.readRun(runId);
|
|
25
|
+
let task;
|
|
26
|
+
try {
|
|
27
|
+
task = parseYaml(detail.task_yaml);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (!isPlain(task) || !isPlain(task.input))
|
|
33
|
+
return undefined;
|
|
34
|
+
return task.input;
|
|
35
|
+
}
|
|
36
|
+
export async function listDatasetCandidates(input) {
|
|
37
|
+
const { store, target, limit } = input;
|
|
38
|
+
const pipelines = [standalonePipelineId(target.stageId)];
|
|
39
|
+
if (target.pipelinePath !== undefined)
|
|
40
|
+
pipelines.push(target.pipelinePath);
|
|
41
|
+
const summaries = (await Promise.all(pipelines.map((pipeline) => store.listRuns({ pipeline, status: "succeeded" })))).flat();
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const ordered = summaries
|
|
44
|
+
.filter((s) => (seen.has(s.run_id) ? false : (seen.add(s.run_id), true)))
|
|
45
|
+
.sort((a, b) => (b.finished_at ?? b.created_at).localeCompare(a.finished_at ?? a.created_at));
|
|
46
|
+
const items = [];
|
|
47
|
+
for (const summary of ordered) {
|
|
48
|
+
if (items.length >= limit)
|
|
49
|
+
break;
|
|
50
|
+
const meta = await store.readRunMeta(summary.run_id);
|
|
51
|
+
if (!isCandidateRun(meta, target))
|
|
52
|
+
continue;
|
|
53
|
+
const recorded = await recordedInput(store, summary.run_id);
|
|
54
|
+
if (recorded === undefined)
|
|
55
|
+
continue;
|
|
56
|
+
items.push({
|
|
57
|
+
runId: summary.run_id,
|
|
58
|
+
finishedAt: summary.finished_at ?? summary.created_at,
|
|
59
|
+
preview: JSON.stringify(recorded).slice(0, PREVIEW_CHARS),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return items;
|
|
63
|
+
}
|
|
64
|
+
export async function casesFromRuns(input) {
|
|
65
|
+
const { store, target } = input;
|
|
66
|
+
const cases = [];
|
|
67
|
+
for (const runId of input.runIds) {
|
|
68
|
+
let meta;
|
|
69
|
+
try {
|
|
70
|
+
meta = await store.readRunMeta(runId);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
throw new EvalsWriteError("DATASET_CASE_OP_INVALID", `run ${runId} not found`);
|
|
74
|
+
}
|
|
75
|
+
const recorded = isCandidateRun(meta, target) ? await recordedInput(store, runId) : undefined;
|
|
76
|
+
if (recorded === undefined) {
|
|
77
|
+
throw new EvalsWriteError("DATASET_CASE_OP_INVALID", `run ${runId} is not a completed run of stage "${target.stageId}" with a recorded input`);
|
|
78
|
+
}
|
|
79
|
+
cases.push({
|
|
80
|
+
title: `Run ${runId.slice(0, SHORT_ID_CHARS)}`,
|
|
81
|
+
input: recorded,
|
|
82
|
+
metadata: { source_run: runId },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return cases;
|
|
86
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AgentSessionDetail } from "../agents/service.js";
|
|
2
|
+
import type { AgentSessionListItem, SessionQuery } from "../agents/store.js";
|
|
3
|
+
import type { NewDatasetCase } from "./writeDataset.js";
|
|
4
|
+
/** The slice of `AgentService` that turns past sessions into scenarios. */
|
|
5
|
+
export type SessionsSource = {
|
|
6
|
+
listSessions(projectRoot: string, agentId: string, query: SessionQuery): Promise<{
|
|
7
|
+
sessions: AgentSessionListItem[];
|
|
8
|
+
nextCursor: string | null;
|
|
9
|
+
}>;
|
|
10
|
+
getSession(projectRoot: string, sessionId: string): Promise<AgentSessionDetail>;
|
|
11
|
+
};
|
|
12
|
+
export type SessionCandidate = {
|
|
13
|
+
session_id: string;
|
|
14
|
+
updated_at: string;
|
|
15
|
+
preview: string;
|
|
16
|
+
turns: number;
|
|
17
|
+
tools: string[];
|
|
18
|
+
};
|
|
19
|
+
export declare class SessionCaseError extends Error {
|
|
20
|
+
}
|
|
21
|
+
/** Finished (idle or closed), non-eval sessions of the agent that have at least one user message, newest first. */
|
|
22
|
+
export declare function listSessionCandidates(input: {
|
|
23
|
+
sessions: SessionsSource;
|
|
24
|
+
projectRoot: string;
|
|
25
|
+
agentId: string;
|
|
26
|
+
limit: number;
|
|
27
|
+
}): Promise<SessionCandidate[]>;
|
|
28
|
+
/** One `script` scenario per session: its user messages, plus the tools it called as the expected tools. */
|
|
29
|
+
export declare function casesFromSessions(input: {
|
|
30
|
+
sessions: SessionsSource;
|
|
31
|
+
projectRoot: string;
|
|
32
|
+
agentId: string;
|
|
33
|
+
sessionIds: readonly string[];
|
|
34
|
+
}): Promise<NewDatasetCase[]>;
|