stageflow 0.42.0 → 0.46.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 +12 -3
- package/dist/agent/activity.d.ts +18 -0
- package/dist/agent/claudeAdapter.js +7 -0
- package/dist/agent/claudeTools.d.ts +27 -18
- package/dist/agent/claudeTools.js +54 -15
- package/dist/agent/compactionEvents.d.ts +34 -0
- package/dist/agent/compactionEvents.js +37 -0
- package/dist/agent/openRouterRouting.d.ts +7 -0
- package/dist/agent/openRouterRouting.js +23 -0
- package/dist/agent/piAdapter.d.ts +6 -0
- package/dist/agent/piAdapter.js +128 -27
- package/dist/agent/piSettings.d.ts +7 -0
- package/dist/agent/piSettings.js +9 -0
- package/dist/agent/sandboxPiTools.d.ts +3 -1
- package/dist/agent/sandboxPiTools.js +8 -2
- package/dist/agent/stageTurnDriver.d.ts +11 -2
- package/dist/agent/stageTurnDriver.js +45 -4
- package/dist/agent/toolOutputBudget.d.ts +15 -1
- package/dist/agent/toolOutputBudget.js +18 -0
- package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
- package/dist/agent/toolOutputBudgetExtension.js +40 -3
- package/dist/agents/authorChat.d.ts +1 -0
- package/dist/agents/authorChat.js +7 -0
- package/dist/agents/authorSessionStore.d.ts +3 -0
- package/dist/agents/authorSessionStore.js +17 -2
- package/dist/agents/evalGate.js +1 -0
- package/dist/agents/hostContext.d.ts +1 -1
- package/dist/agents/runtime/piRuntime.d.ts +5 -1
- package/dist/agents/runtime/piRuntime.js +46 -12
- package/dist/agents/service.js +3 -2
- package/dist/agents/sessions.js +3 -1
- package/dist/cli/evalCommand.d.ts +1 -1
- package/dist/cli/evalCommand.js +39 -2
- package/dist/cli/hostClient.d.ts +6 -0
- package/dist/cli/hostClient.js +4 -0
- package/dist/compaction/directives.d.ts +18 -0
- package/dist/compaction/directives.js +119 -0
- package/dist/compaction/extension.d.ts +20 -0
- package/dist/compaction/extension.js +78 -0
- package/dist/compaction/mask.d.ts +18 -0
- package/dist/compaction/mask.js +155 -0
- package/dist/compaction/pin.d.ts +21 -0
- package/dist/compaction/pin.js +270 -0
- package/dist/compaction/scrub.d.ts +7 -0
- package/dist/compaction/scrub.js +26 -0
- package/dist/compaction/sessionWiring.d.ts +22 -0
- package/dist/compaction/sessionWiring.js +26 -0
- package/dist/compaction/summarize.d.ts +79 -0
- package/dist/compaction/summarize.js +171 -0
- package/dist/compaction/toolPolicy.d.ts +3 -0
- package/dist/compaction/toolPolicy.js +33 -0
- package/dist/compaction/types.d.ts +45 -0
- package/dist/compaction/types.js +7 -0
- package/dist/compaction/workingState.d.ts +56 -0
- package/dist/compaction/workingState.js +198 -0
- package/dist/config/createPipeline.js +2 -0
- package/dist/config/createTrigger.js +7 -1
- package/dist/config/ensureCatalogScanRoot.d.ts +2 -0
- package/dist/config/ensureCatalogScanRoot.js +6 -0
- package/dist/config/evalCatalog.js +30 -2
- package/dist/config/githubTriggerAction.d.ts +8 -0
- package/dist/config/githubTriggerAction.js +29 -0
- package/dist/config/hostConfig.js +2 -0
- package/dist/config/loadEval.d.ts +3 -1
- package/dist/config/loadEval.js +96 -10
- package/dist/config/pipelineNeeds.d.ts +2 -0
- package/dist/config/pipelineNeeds.js +16 -3
- package/dist/config/pipelineRoute.js +5 -4
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +12 -0
- package/dist/config/validateEval.js +60 -3
- package/dist/config/writeEval.js +2 -2
- package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
- package/dist/envelope/assertEmittedArtifacts.js +43 -0
- package/dist/envelope/preEmitChecks.d.ts +3 -0
- package/dist/evals/calibration.d.ts +21 -0
- package/dist/evals/calibration.js +69 -0
- package/dist/evals/calibrationSuggest.d.ts +29 -0
- package/dist/evals/calibrationSuggest.js +72 -0
- package/dist/evals/calibrator.d.ts +46 -0
- package/dist/evals/calibrator.js +148 -0
- package/dist/evals/compare.d.ts +1 -1
- package/dist/evals/compare.js +3 -0
- package/dist/evals/constants.d.ts +7 -3
- package/dist/evals/constants.js +7 -1
- package/dist/evals/engine/FakeEngine.d.ts +2 -1
- package/dist/evals/engine/FakeEngine.js +9 -3
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +4 -2
- package/dist/evals/engine/promptfoo/generate.d.ts +3 -1
- package/dist/evals/engine/promptfoo/generate.js +43 -23
- package/dist/evals/engine/promptfoo/judgeProviders.js +2 -1
- package/dist/evals/engine/promptfoo/normalize.d.ts +4 -1
- package/dist/evals/engine/promptfoo/normalize.js +16 -3
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +3 -1
- package/dist/evals/engine/promptfoo/rubricPrompt.js +15 -5
- package/dist/evals/errors.d.ts +7 -0
- package/dist/evals/errors.js +10 -0
- package/dist/evals/judgeProviders.d.ts +6 -0
- package/dist/evals/judgeProviders.js +14 -0
- package/dist/evals/judged.d.ts +7 -0
- package/dist/evals/judged.js +7 -0
- package/dist/evals/manager.d.ts +27 -8
- package/dist/evals/manager.js +73 -12
- package/dist/evals/plan.d.ts +10 -1
- package/dist/evals/plan.js +33 -13
- package/dist/evals/planInternalAgent.d.ts +19 -0
- package/dist/evals/planInternalAgent.js +201 -0
- package/dist/evals/read/api.d.ts +18 -0
- package/dist/evals/read/api.js +10 -1
- package/dist/evals/read/labelQueue.d.ts +45 -0
- package/dist/evals/read/labelQueue.js +83 -0
- package/dist/evals/read/list.js +10 -1
- package/dist/evals/read/runs.d.ts +5 -0
- package/dist/evals/read/runs.js +7 -1
- package/dist/evals/runner/caseRunner.d.ts +2 -1
- package/dist/evals/runner/caseRunner.js +16 -5
- package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
- package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
- package/dist/evals/snapshot.d.ts +10 -2
- package/dist/evals/snapshot.js +8 -3
- package/dist/evals/stats.d.ts +40 -0
- package/dist/evals/stats.js +69 -0
- package/dist/evals/storeTypes.d.ts +42 -0
- package/dist/evals/types.d.ts +25 -2
- package/dist/evals/types.js +4 -1
- package/dist/evals/votes.d.ts +10 -0
- package/dist/evals/votes.js +60 -0
- package/dist/guide/cardContract.d.ts +133 -0
- package/dist/guide/cardContract.js +156 -0
- package/dist/guide/chat.d.ts +45 -0
- package/dist/guide/chat.js +378 -0
- package/dist/guide/knowledge/index.d.ts +14 -0
- package/dist/guide/knowledge/index.js +109 -0
- package/dist/guide/knowledge/topics/agents.d.ts +2 -0
- package/dist/guide/knowledge/topics/agents.js +58 -0
- package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
- package/dist/guide/knowledge/topics/bestPractices.js +67 -0
- package/dist/guide/knowledge/topics/connections.d.ts +2 -0
- package/dist/guide/knowledge/topics/connections.js +66 -0
- package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
- package/dist/guide/knowledge/topics/consoleMap.js +55 -0
- package/dist/guide/knowledge/topics/evals.d.ts +2 -0
- package/dist/guide/knowledge/topics/evals.js +72 -0
- package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
- package/dist/guide/knowledge/topics/limitations.js +84 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
- package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
- package/dist/guide/knowledge/topics/memories.d.ts +2 -0
- package/dist/guide/knowledge/topics/memories.js +63 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
- package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
- package/dist/guide/knowledge/topics/overview.d.ts +2 -0
- package/dist/guide/knowledge/topics/overview.js +56 -0
- package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
- package/dist/guide/knowledge/topics/pipelines.js +93 -0
- package/dist/guide/knowledge/topics/stages.d.ts +2 -0
- package/dist/guide/knowledge/topics/stages.js +54 -0
- package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
- package/dist/guide/knowledge/topics/tasks.js +52 -0
- package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
- package/dist/guide/knowledge/topics/triggers.js +68 -0
- package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
- package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
- package/dist/guide/knowledgeTools.d.ts +2 -0
- package/dist/guide/knowledgeTools.js +56 -0
- package/dist/guide/showUi.d.ts +6 -0
- package/dist/guide/showUi.js +546 -0
- package/dist/guide/threadStore.d.ts +48 -0
- package/dist/guide/threadStore.js +189 -0
- package/dist/guide/writeRoot.d.ts +11 -0
- package/dist/guide/writeRoot.js +70 -0
- package/dist/hosted/translate.js +2 -0
- package/dist/mcp/agentTools.js +12 -0
- package/dist/mcp/catalogTools.js +18 -20
- package/dist/mcp/catalogWriteTools.d.ts +8 -0
- package/dist/mcp/catalogWriteTools.js +225 -0
- package/dist/mcp/connectionTools.d.ts +3 -0
- package/dist/mcp/connectionTools.js +85 -0
- package/dist/mcp/controlTools.js +34 -1
- package/dist/mcp/deps.d.ts +9 -0
- package/dist/mcp/evalTools.js +723 -21
- package/dist/mcp/memoryHostTools.d.ts +3 -0
- package/dist/mcp/memoryHostTools.js +72 -0
- package/dist/mcp/pipelineAuthorTools.js +14 -1
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +6 -0
- package/dist/mcp/triggerTools.js +77 -31
- package/dist/operatorAgent/evalGate.d.ts +22 -0
- package/dist/operatorAgent/evalGate.js +77 -0
- package/dist/operatorAgent/fakeHost.js +10 -2
- package/dist/operatorAgent/host.js +18 -2
- package/dist/operatorAgent/index.d.ts +1 -0
- package/dist/operatorAgent/index.js +1 -0
- package/dist/operatorAgent/internalAgents.d.ts +11 -0
- package/dist/operatorAgent/internalAgents.js +13 -0
- package/dist/operatorAgent/piModel.d.ts +5 -1
- package/dist/operatorAgent/piModel.js +15 -10
- package/dist/operatorAgent/profiles/agentAuthor.js +66 -22
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +1 -1
- package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
- package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
- package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
- package/dist/operatorAgent/profiles/guideTools.js +123 -0
- package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
- package/dist/operatorAgent/profiles/stageflowGuide.js +133 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
- package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
- package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
- package/dist/operatorAgent/types.d.ts +23 -0
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/runstore/port.d.ts +13 -1
- package/dist/runstore/retention.d.ts +2 -1
- package/dist/runstore/retention.js +3 -7
- package/dist/runstore/runStatusClock.d.ts +17 -0
- package/dist/runstore/runStatusClock.js +19 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +11 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +70 -45
- package/dist/runstore/sqlite/calibrationStore.d.ts +10 -0
- package/dist/runstore/sqlite/calibrationStore.js +106 -0
- package/dist/runstore/sqlite/evalStore.d.ts +5 -0
- package/dist/runstore/sqlite/evalStore.js +7 -0
- package/dist/runstore/sqlite/migrations/018-eval-grader-labels.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/018-eval-grader-labels.js +43 -0
- package/dist/runstore/sqlite/migrations/index.js +2 -0
- package/dist/runstore/workspaceLayout.js +6 -1
- package/dist/runtime/artifactDiskInspect.d.ts +14 -0
- package/dist/runtime/artifactDiskInspect.js +52 -0
- package/dist/runtime/artifactPath.d.ts +24 -0
- package/dist/runtime/artifactPath.js +84 -0
- package/dist/runtime/completionCheckRunner.js +15 -43
- package/dist/runtime/githubPollSource.d.ts +22 -4
- package/dist/runtime/githubPollSource.js +93 -8
- package/dist/runtime/priorArtifactGrants.d.ts +8 -0
- package/dist/runtime/priorArtifactGrants.js +105 -0
- package/dist/runtime/runActionEligibility.d.ts +46 -0
- package/dist/runtime/runActionEligibility.js +123 -0
- package/dist/runtime/runManager.d.ts +4 -1
- package/dist/runtime/runManager.js +52 -10
- package/dist/runtime/runRetryCoordinator.d.ts +2 -14
- package/dist/runtime/runRetryCoordinator.js +3 -67
- package/dist/runtime/sandboxContainer.d.ts +7 -0
- package/dist/runtime/sandboxContainer.js +48 -6
- package/dist/runtime/sandboxDesk.d.ts +2 -1
- package/dist/runtime/sandboxDesk.js +11 -12
- package/dist/runtime/stageEnvironment.js +1 -0
- package/dist/runtime/stageRoots.d.ts +12 -0
- package/dist/runtime/stageSandbox.d.ts +2 -1
- package/dist/runtime/stageSandbox.js +18 -2
- package/dist/runtime/stageWorker.js +20 -0
- package/dist/server/agentAuthorRoutes.js +12 -3
- package/dist/server/bootstrap.d.ts +5 -0
- package/dist/server/bootstrap.js +14 -1
- package/dist/server/evalRoutes.js +251 -12
- package/dist/server/guideRoutes.d.ts +5 -0
- package/dist/server/guideRoutes.js +166 -0
- package/dist/server/http.d.ts +10 -0
- package/dist/server/http.js +35 -1
- package/dist/server/internalAgentRoutes.d.ts +6 -0
- package/dist/server/internalAgentRoutes.js +12 -0
- package/dist/server/mcpHost.js +2 -0
- package/dist/toolkit/meta.d.ts +1 -1
- package/dist/toolkit/meta.js +41 -1
- package/dist/toolkit/profiles.d.ts +5 -0
- package/dist/toolkit/profiles.js +12 -0
- package/dist/tools/askOperator.js +2 -1
- package/dist/tools/emitStageEnvelope.d.ts +17 -16
- package/dist/tools/emitStageEnvelope.js +46 -32
- package/dist/tools/stageToolNames.d.ts +4 -0
- package/dist/tools/stageToolNames.js +4 -0
- package/dist/tools/workingState.d.ts +40 -0
- package/dist/tools/workingState.js +108 -0
- package/dist/tools/writeStageArtifact.d.ts +0 -9
- package/dist/tools/writeStageArtifact.js +2 -1
- package/dist/ui/assets/{MarkdownText-BTrOqu5J.js → MarkdownText-BS2BBbCx.js} +2 -2
- package/dist/ui/assets/adapters-DPD-cAsy.js +17 -0
- package/dist/ui/assets/chat-BD1-VTT6.js +2 -0
- package/dist/ui/assets/chat-DXnQv9st.css +2 -0
- package/dist/ui/assets/main-AX5XNLtX.js +278 -0
- package/dist/ui/assets/{main-CHlmTNJe.css → main-CFX0_n8J.css} +1 -1
- package/dist/ui/chat.html +3 -4
- package/dist/ui/index.html +3 -4
- package/dist/workshop/chatTurn.js +1 -1
- package/dist/workshop/workshopPin.d.ts +3 -3
- package/dist/workshop/workshopPin.js +16 -15
- package/examples/compaction-stress/README.md +30 -0
- package/examples/compaction-stress/check-run.mjs +53 -0
- package/examples/compaction-stress/collect-evidence.yaml +60 -0
- package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
- package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
- package/examples/compaction-stress/generate-evidence.mjs +110 -0
- package/examples/compaction-stress/root-cause.yaml +26 -0
- package/examples/compaction-stress/stageflow.yaml +9 -0
- package/examples/compaction-stress/write-postmortem.yaml +40 -0
- package/examples/evals/README.md +18 -0
- package/examples/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/evals/guide-behavior.eval.yaml +35 -0
- package/examples/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/evals/guide-depth.eval.yaml +169 -0
- package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
- package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
- package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
- package/examples/memory/evals/guide-depth.eval.yaml +169 -0
- package/package.json +1 -1
- package/skills/stageflow/references/control-surface.md +1 -1
- package/skills/stageflow/references/evals.md +1 -0
- package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +0 -9
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
- package/dist/ui/assets/chat-Df_wCpak.js +0 -5
- package/dist/ui/assets/chat-P7KQznHm.css +0 -2
- package/dist/ui/assets/main-CvVfxmMd.js +0 -271
|
@@ -16,10 +16,12 @@ import { resolveSeededExamplesPath } from "../config/seededCatalog.js";
|
|
|
16
16
|
import { applyCaseOps, appendOrReplaceCases, convertDatasetToJsonl, createDatasetFile, } from "../config/writeDataset.js";
|
|
17
17
|
import { createEvalFile, previewEvalUpdate, renderEvalCreateYaml, updateEvalFile, } from "../config/writeEval.js";
|
|
18
18
|
import { CompareMismatchError } from "../evals/compare.js";
|
|
19
|
+
import { suggestExamples } from "../evals/calibrationSuggest.js";
|
|
19
20
|
import { EVAL_LIMITS, EVAL_REVIEW_LABELS, EVAL_STARTED_VIA } from "../evals/constants.js";
|
|
20
21
|
import { PINNED_PROMPTFOO_VERSION } from "../evals/engine/promptfoo/pinned.js";
|
|
21
22
|
import { AGENT_ESTIMATE_ASSUMPTIONS, estimateRun, } from "../evals/estimate.js";
|
|
22
23
|
import { EvalRunError, } from "../evals/manager.js";
|
|
24
|
+
import { buildLabelQueue, buildLabelSummary } from "../evals/read/labelQueue.js";
|
|
23
25
|
import { buildEvalPlan } from "../evals/plan.js";
|
|
24
26
|
import { buildEvalDetail, buildResultDetail, buildResultsPage, DEFAULT_LIMIT, ENGINE_NAME, engineCheck as engineCheckStatus, EvalApiError, evalScopeRoots, listEvalRunsPage, loadAggregatedEvalList, locateDataset, locateEval, locateEvalRoot, wireRootOf, MAX_LIMIT, planFindings as planFindingsShared, rel, validateEvalText, } from "../evals/read/api.js";
|
|
25
27
|
import { listAgentTargets } from "../evals/read/agentTargets.js";
|
|
@@ -31,6 +33,7 @@ import { EvalStoreError } from "../evals/storeError.js";
|
|
|
31
33
|
import { audit, bad, isRecord, optStringArray, readOptionalBody, runByIdOr404, } from "./evalRouteContext.js";
|
|
32
34
|
import { matchEvalTriageRoute } from "./evalTriageRoutes.js";
|
|
33
35
|
import { callerIdFromRequestAuth } from "./requestAuthContext.js";
|
|
36
|
+
import { isJudged, isJudgedType } from "../evals/judged.js";
|
|
34
37
|
const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
35
38
|
const CANCEL_WAIT_MS = 5000;
|
|
36
39
|
const WRITE_ERROR_STATUS = {
|
|
@@ -57,6 +60,8 @@ const RUN_ERROR_STATUS = {
|
|
|
57
60
|
EVAL_ENGINE_UNAVAILABLE: 503,
|
|
58
61
|
EVAL_NODE_TOO_OLD: 503,
|
|
59
62
|
EVAL_TAGS_ON_PASSED_RESULT: 400,
|
|
63
|
+
EVAL_CALIBRATION_NO_LABELS: 422,
|
|
64
|
+
EVAL_CALIBRATION_CANCELLED: 409,
|
|
60
65
|
};
|
|
61
66
|
function sendError(c, status, code, message, extra = {}) {
|
|
62
67
|
c.json(c.res, status, { error: message, code, ...extra });
|
|
@@ -141,7 +146,8 @@ function agentsOf(c) {
|
|
|
141
146
|
}
|
|
142
147
|
function agentsInput(c) {
|
|
143
148
|
const agents = agentsOf(c);
|
|
144
|
-
|
|
149
|
+
const internalAgents = c.evalRunManager.visibleInternalAgents();
|
|
150
|
+
return { ...(agents ? { agents } : {}), ...(internalAgents.length > 0 ? { internalAgents } : {}) };
|
|
145
151
|
}
|
|
146
152
|
function engineCheck(c) {
|
|
147
153
|
engineCheckStatus(c.engineStatus());
|
|
@@ -254,11 +260,30 @@ function parseDefinitionOrYaml(body) {
|
|
|
254
260
|
throw bad(`"definition" must be an object`);
|
|
255
261
|
return { definition: body.definition };
|
|
256
262
|
}
|
|
263
|
+
function validateEvalId(input) {
|
|
264
|
+
if (isRecord(input.definition) && typeof input.definition.id === "string")
|
|
265
|
+
return input.definition.id;
|
|
266
|
+
if (typeof input.yaml !== "string")
|
|
267
|
+
return undefined;
|
|
268
|
+
const match = /^id:\s*["']?([A-Za-z0-9][A-Za-z0-9._-]{0,63})["']?\s*$/m.exec(input.yaml);
|
|
269
|
+
return match?.[1];
|
|
270
|
+
}
|
|
271
|
+
async function existingEvalFile(c, wire, id) {
|
|
272
|
+
try {
|
|
273
|
+
const located = await evalRootFor(c, wire, id);
|
|
274
|
+
return { projectRoot: located.projectRoot, absPath: located.ref.absPath };
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
if (err instanceof EvalApiError && err.status === 404)
|
|
278
|
+
return undefined;
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
257
282
|
async function handleEvalValidate(c) {
|
|
258
283
|
const body = await readBody(c);
|
|
259
284
|
const input = parseDefinitionOrYaml(body);
|
|
260
|
-
const
|
|
261
|
-
|
|
285
|
+
const wire = wireFromBody(body);
|
|
286
|
+
let projectRoot = await projectRootFor(c, wire);
|
|
262
287
|
const suppliedPath = optString(body, "path");
|
|
263
288
|
const datasetCases = optDatasetCases(body);
|
|
264
289
|
let evalAbs;
|
|
@@ -267,10 +292,18 @@ async function handleEvalValidate(c) {
|
|
|
267
292
|
assertInsideProject(projectRoot, evalAbs, "eval path");
|
|
268
293
|
}
|
|
269
294
|
else {
|
|
270
|
-
const rawId =
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
295
|
+
const rawId = validateEvalId(input);
|
|
296
|
+
const located = rawId !== undefined && ID_RE.test(rawId) ? await existingEvalFile(c, wire, rawId) : undefined;
|
|
297
|
+
if (located) {
|
|
298
|
+
projectRoot = located.projectRoot;
|
|
299
|
+
evalAbs = located.absPath;
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
const manifest = await manifestForWrite(projectRoot);
|
|
303
|
+
const dir = await resolveWriteDir(projectRoot, manifest, "evals");
|
|
304
|
+
const fileName = rawId !== undefined && ID_RE.test(rawId) ? `${rawId}.eval.yaml` : "new.eval.yaml";
|
|
305
|
+
evalAbs = path.join(dir.absDir, fileName);
|
|
306
|
+
}
|
|
274
307
|
}
|
|
275
308
|
let derived;
|
|
276
309
|
if (input.yaml !== undefined) {
|
|
@@ -639,7 +672,7 @@ async function handleRunEstimate(c, id) {
|
|
|
639
672
|
resultsExecuted: stats.results_executed,
|
|
640
673
|
rubricGradesGraded: results
|
|
641
674
|
.flatMap((r) => r.grades)
|
|
642
|
-
.filter((g) => (g.graderType
|
|
675
|
+
.filter((g) => isJudgedType(g.graderType) && g.status === "graded").length,
|
|
643
676
|
wallSeconds: last.startedAt !== null && last.finishedAt !== null
|
|
644
677
|
? Math.max(0, (Date.parse(last.finishedAt) - Date.parse(last.startedAt)) / 1000)
|
|
645
678
|
: null,
|
|
@@ -664,7 +697,7 @@ async function agentEstimateBlock(c, plan) {
|
|
|
664
697
|
}
|
|
665
698
|
}
|
|
666
699
|
const count = Math.max(1, plan.cases.length);
|
|
667
|
-
const judge = plan.graders.find(
|
|
700
|
+
const judge = plan.graders.find(isJudged);
|
|
668
701
|
const judgeModel = judge !== undefined && "judge" in judge && judge.judge !== "" ? judge.judge : undefined;
|
|
669
702
|
const wanted = [plan.stageModel, plan.userModel ?? undefined, judgeModel].filter((id) => typeof id === "string" && id !== "");
|
|
670
703
|
const prices = (await c.loadPrices?.([...new Set(wanted)], plan.projectRoot).catch(() => undefined)) ?? new Map();
|
|
@@ -681,7 +714,7 @@ async function sendEstimate(c, plan, previous) {
|
|
|
681
714
|
const agent = plan.target.kind === "agent" ? await agentEstimateBlock(c, plan) : undefined;
|
|
682
715
|
const estimate = estimateRun({
|
|
683
716
|
resultsTotal: plan.cases.length * plan.repeats,
|
|
684
|
-
rubricGraderCount: plan.graders.
|
|
717
|
+
rubricGraderCount: plan.graders.reduce((calls, g) => (isJudged(g) ? calls + (g.judgeSettings?.votes ?? 1) : calls), 0),
|
|
685
718
|
previous,
|
|
686
719
|
recentStageCosts: await recentStageCosts(c, {
|
|
687
720
|
...(plan.target.kind === "stage" && plan.target.pipelinePath !== undefined ? { pipelinePath: plan.target.pipelinePath } : {}),
|
|
@@ -806,6 +839,10 @@ async function handleResultsList(c, id) {
|
|
|
806
839
|
async function handleResultDetail(c, id, caseId) {
|
|
807
840
|
c.json(c.res, 200, await buildResultDetail(c.store, id, caseId));
|
|
808
841
|
}
|
|
842
|
+
async function handleLabelQueue(c, id, graderId) {
|
|
843
|
+
const summary = c.url.searchParams.get("summary") === "true";
|
|
844
|
+
c.json(c.res, 200, summary ? await buildLabelSummary(c.store, id, graderId) : await buildLabelQueue(c.store, id, graderId));
|
|
845
|
+
}
|
|
809
846
|
async function handleReviewPut(c, id, caseId, repeat) {
|
|
810
847
|
const body = await readBody(c);
|
|
811
848
|
await runByIdOr404(c, id);
|
|
@@ -842,6 +879,191 @@ async function handleReviewPut(c, id, caseId, repeat) {
|
|
|
842
879
|
throw err;
|
|
843
880
|
}
|
|
844
881
|
}
|
|
882
|
+
const CALIBRATION_SPLITS = ["all", "dev", "held_out"];
|
|
883
|
+
function candidateFrom(raw) {
|
|
884
|
+
if (raw === undefined || raw === null)
|
|
885
|
+
return undefined;
|
|
886
|
+
if (!isRecord(raw))
|
|
887
|
+
throw bad(`"candidate" must be an object`);
|
|
888
|
+
const out = {};
|
|
889
|
+
if (raw.judge_settings !== undefined) {
|
|
890
|
+
if (!isRecord(raw.judge_settings))
|
|
891
|
+
throw bad(`"candidate.judge_settings" must be an object`);
|
|
892
|
+
const js = raw.judge_settings;
|
|
893
|
+
const settings = {};
|
|
894
|
+
if (js.temperature !== undefined) {
|
|
895
|
+
if (typeof js.temperature !== "number" || js.temperature < 0 || js.temperature > 1) {
|
|
896
|
+
throw bad(`"candidate.judge_settings.temperature" must be a number from 0 to 1`);
|
|
897
|
+
}
|
|
898
|
+
settings.temperature = js.temperature;
|
|
899
|
+
}
|
|
900
|
+
if (js.reasoning !== undefined) {
|
|
901
|
+
if (typeof js.reasoning !== "boolean")
|
|
902
|
+
throw bad(`"candidate.judge_settings.reasoning" must be a boolean`);
|
|
903
|
+
settings.reasoning = js.reasoning;
|
|
904
|
+
}
|
|
905
|
+
if (js.votes !== undefined) {
|
|
906
|
+
if (typeof js.votes !== "number" || ![1, 3, 5].includes(js.votes))
|
|
907
|
+
throw bad(`"candidate.judge_settings.votes" must be 1, 3 or 5`);
|
|
908
|
+
settings.votes = js.votes;
|
|
909
|
+
}
|
|
910
|
+
out.judgeSettings = settings;
|
|
911
|
+
}
|
|
912
|
+
if (raw.rubric !== undefined) {
|
|
913
|
+
if (typeof raw.rubric !== "string" || raw.rubric.trim() === "")
|
|
914
|
+
throw bad(`"candidate.rubric" must be a non-empty string`);
|
|
915
|
+
out.rubric = raw.rubric;
|
|
916
|
+
}
|
|
917
|
+
if (raw.judge !== undefined) {
|
|
918
|
+
if (typeof raw.judge !== "string" || raw.judge.trim() === "")
|
|
919
|
+
throw bad(`"candidate.judge" must be a non-empty string`);
|
|
920
|
+
out.judge = raw.judge;
|
|
921
|
+
}
|
|
922
|
+
if (raw.examples !== undefined) {
|
|
923
|
+
if (!Array.isArray(raw.examples) || raw.examples.length > EVAL_LIMITS.rubricExamplesMax) {
|
|
924
|
+
throw bad(`"candidate.examples" must be an array of at most ${EVAL_LIMITS.rubricExamplesMax}`);
|
|
925
|
+
}
|
|
926
|
+
out.examples = raw.examples.map((e) => {
|
|
927
|
+
if (!isRecord(e) || typeof e.output !== "string")
|
|
928
|
+
throw bad(`Each candidate example needs an "output" string`);
|
|
929
|
+
const reason = typeof e.reason === "string" ? { reason: e.reason } : {};
|
|
930
|
+
if (e.verdict === "pass" || e.verdict === "fail")
|
|
931
|
+
return { verdict: e.verdict, output: e.output, ...reason };
|
|
932
|
+
if (typeof e.score === "number" && Number.isInteger(e.score) && e.score >= 1 && e.score <= 5) {
|
|
933
|
+
return { score: e.score, output: e.output, ...reason };
|
|
934
|
+
}
|
|
935
|
+
throw bad(`Each candidate example needs a verdict (pass or fail) or a score from 1 to 5`);
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
return out;
|
|
939
|
+
}
|
|
940
|
+
async function handleGraderLabelPut(c, id, caseId, repeat, graderId) {
|
|
941
|
+
const body = await readBody(c);
|
|
942
|
+
await runByIdOr404(c, id);
|
|
943
|
+
let label;
|
|
944
|
+
if (body.label === null)
|
|
945
|
+
label = null;
|
|
946
|
+
else if (typeof body.label === "string" && EVAL_REVIEW_LABELS.includes(body.label)) {
|
|
947
|
+
label = body.label;
|
|
948
|
+
}
|
|
949
|
+
else
|
|
950
|
+
throw bad(`"label" must be pass, fail or null`);
|
|
951
|
+
if (body.note !== undefined && body.note !== null) {
|
|
952
|
+
if (typeof body.note !== "string" || body.note.length > EVAL_LIMITS.reviewNoteMaxChars) {
|
|
953
|
+
throw bad(`"note" must be a string of at most ${EVAL_LIMITS.reviewNoteMaxChars} characters or null`);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
const results = await c.store.getEvalResultsForCase(id, caseId);
|
|
957
|
+
const result = results.find((r) => r.repeatIndex === repeat);
|
|
958
|
+
if (!result)
|
|
959
|
+
throw new EvalStoreError("EVAL_RUN_NOT_FOUND", `No result for ${caseId}#${repeat} in ${id}`);
|
|
960
|
+
const grade = result.grades.find((g) => g.graderId === graderId);
|
|
961
|
+
if (!grade || !isJudgedType(grade.graderType)) {
|
|
962
|
+
throw bad(`Grader ${graderId} is not a judged grader on this result`);
|
|
963
|
+
}
|
|
964
|
+
const row = await c.store.putEvalGraderLabel(id, caseId, repeat, graderId, {
|
|
965
|
+
label,
|
|
966
|
+
...(body.note !== undefined ? { note: body.note } : {}),
|
|
967
|
+
});
|
|
968
|
+
audit(c, "eval_grader_label", "ok", id);
|
|
969
|
+
c.json(c.res, 200, row === null ? { label: null, note: null } : { label: row.label, note: row.note });
|
|
970
|
+
}
|
|
971
|
+
function calibrationToWire(r) {
|
|
972
|
+
return {
|
|
973
|
+
id: r.id,
|
|
974
|
+
grader_id: r.graderId,
|
|
975
|
+
grader_hash: r.graderHash,
|
|
976
|
+
judge: r.judge,
|
|
977
|
+
prompt_version: r.promptVersion,
|
|
978
|
+
split: r.split,
|
|
979
|
+
candidate: r.candidate,
|
|
980
|
+
stats: r.stats,
|
|
981
|
+
disagreements: r.disagreements.map((d) => ({
|
|
982
|
+
...(d.evalRunId !== undefined ? { eval_run_id: d.evalRunId } : {}),
|
|
983
|
+
case_id: d.caseId,
|
|
984
|
+
repeat_index: d.repeatIndex,
|
|
985
|
+
label: d.label,
|
|
986
|
+
judge: d.judge,
|
|
987
|
+
reason: d.reason,
|
|
988
|
+
})),
|
|
989
|
+
cost_usd: r.costUsd,
|
|
990
|
+
created_at: r.createdAt,
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
async function handleCalibrationList(c, id, graderId) {
|
|
994
|
+
const root = await locateEvalRoot(rootOptions(c), wireFromQuery(c), id);
|
|
995
|
+
const candidates = c.url.searchParams.get("include_candidates") === "true";
|
|
996
|
+
const items = await c.store.listEvalCalibrations(root.path, id, graderId, candidates);
|
|
997
|
+
c.json(c.res, 200, { items: items.map(calibrationToWire), next_cursor: null });
|
|
998
|
+
}
|
|
999
|
+
async function handleSuggestExamples(c, id, graderId) {
|
|
1000
|
+
const body = await readBody(c);
|
|
1001
|
+
if (body.calibration_id !== undefined && typeof body.calibration_id !== "string") {
|
|
1002
|
+
throw bad(`"calibration_id" must be a string`);
|
|
1003
|
+
}
|
|
1004
|
+
const { projectRoot, ref } = await evalRootFor(c, wireFromBody(body), id);
|
|
1005
|
+
const outcome = await loadEvalOutcome(ref.absPath, projectRoot);
|
|
1006
|
+
if (!outcome.ok)
|
|
1007
|
+
throw new EvalApiError(422, "EVAL_INVALID", "Eval definition is invalid");
|
|
1008
|
+
const grader = outcome.value.graders.find((g) => g.id === graderId);
|
|
1009
|
+
if (!grader || grader.type !== "rubric") {
|
|
1010
|
+
throw new EvalApiError(422, "EVAL_INVALID", `Grader ${graderId} is not a rubric grader of this eval`);
|
|
1011
|
+
}
|
|
1012
|
+
const calibrations = await c.store.listEvalCalibrations(projectRoot, id, graderId, true, 50);
|
|
1013
|
+
const calibration = body.calibration_id !== undefined
|
|
1014
|
+
? calibrations.find((x) => x.id === body.calibration_id)
|
|
1015
|
+
: calibrations.find((x) => !x.candidate);
|
|
1016
|
+
if (!calibration) {
|
|
1017
|
+
throw new EvalApiError(404, "EVAL_RUN_NOT_FOUND", "No calibration to suggest examples from; check the judge against your labels first");
|
|
1018
|
+
}
|
|
1019
|
+
const items = await suggestExamples(c.store, {
|
|
1020
|
+
projectRoot,
|
|
1021
|
+
evalId: id,
|
|
1022
|
+
graderId,
|
|
1023
|
+
scale: grader.scale,
|
|
1024
|
+
calibration,
|
|
1025
|
+
});
|
|
1026
|
+
c.json(c.res, 200, { calibration_id: calibration.id, items });
|
|
1027
|
+
}
|
|
1028
|
+
async function handleCalibrate(c, id, graderId) {
|
|
1029
|
+
const body = await readBody(c);
|
|
1030
|
+
const split = body.split === undefined ? "all" : body.split;
|
|
1031
|
+
if (typeof split !== "string" || !CALIBRATION_SPLITS.includes(split)) {
|
|
1032
|
+
throw bad(`"split" must be one of ${CALIBRATION_SPLITS.join(", ")}`);
|
|
1033
|
+
}
|
|
1034
|
+
if (body.max_cost_usd !== undefined && (typeof body.max_cost_usd !== "number" || !(body.max_cost_usd > 0))) {
|
|
1035
|
+
throw bad(`"max_cost_usd" must be a positive number`);
|
|
1036
|
+
}
|
|
1037
|
+
const candidate = candidateFrom(body.candidate);
|
|
1038
|
+
if (body.stability !== undefined && typeof body.stability !== "boolean")
|
|
1039
|
+
throw bad(`"stability" must be a boolean`);
|
|
1040
|
+
const { projectRoot, ref } = await evalRootFor(c, wireFromBody(body), id);
|
|
1041
|
+
engineCheck(c);
|
|
1042
|
+
const closed = new AbortController();
|
|
1043
|
+
const onClose = () => closed.abort();
|
|
1044
|
+
c.res.once("close", onClose);
|
|
1045
|
+
try {
|
|
1046
|
+
const out = await c.evalRunManager.calibrate({
|
|
1047
|
+
signal: closed.signal,
|
|
1048
|
+
projectRoot,
|
|
1049
|
+
evalPath: ref.absPath,
|
|
1050
|
+
graderId,
|
|
1051
|
+
split: split,
|
|
1052
|
+
...(candidate !== undefined ? { candidate } : {}),
|
|
1053
|
+
...(body.max_cost_usd !== undefined ? { maxCostUsd: body.max_cost_usd } : {}),
|
|
1054
|
+
...(body.stability === true ? { stability: true } : {}),
|
|
1055
|
+
});
|
|
1056
|
+
audit(c, "eval_calibrate", "ok");
|
|
1057
|
+
c.json(c.res, 200, calibrationToWire(out.calibration));
|
|
1058
|
+
}
|
|
1059
|
+
catch (err) {
|
|
1060
|
+
audit(c, "eval_calibrate", "error", undefined, err instanceof EvalRunError ? err.code : "internal_error");
|
|
1061
|
+
throw err;
|
|
1062
|
+
}
|
|
1063
|
+
finally {
|
|
1064
|
+
c.res.off("close", onClose);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
845
1067
|
async function handleFailureTypes(c, id) {
|
|
846
1068
|
const root = await locateEvalRoot(rootOptions(c), wireFromQuery(c), id);
|
|
847
1069
|
c.json(c.res, 200, { items: await c.store.listFailureTypes(root.path, id), next_cursor: null });
|
|
@@ -955,7 +1177,7 @@ async function datasetDetailFor(c, projectRoot, id, absPath, evalId, query) {
|
|
|
955
1177
|
let inputSchema;
|
|
956
1178
|
let agent;
|
|
957
1179
|
if (useEval !== undefined) {
|
|
958
|
-
if (useEval.loaded.file.target.kind === "agent") {
|
|
1180
|
+
if (useEval.loaded.file.target.kind === "agent" || useEval.loaded.file.target.kind === "internal_agent") {
|
|
959
1181
|
agent = { mode: resolveConversation(useEval.loaded.file.conversation).mode };
|
|
960
1182
|
}
|
|
961
1183
|
else {
|
|
@@ -1014,7 +1236,8 @@ async function conversationModeOf(c, body) {
|
|
|
1014
1236
|
return undefined;
|
|
1015
1237
|
const { projectRoot, ref } = await evalRootFor(c, wireFromBody(body), evalId);
|
|
1016
1238
|
const outcome = await loadEvalOutcome(ref.absPath, projectRoot);
|
|
1017
|
-
|
|
1239
|
+
const kind = outcome.ok ? outcome.value.file.target.kind : undefined;
|
|
1240
|
+
return outcome.ok && (kind === "agent" || kind === "internal_agent")
|
|
1018
1241
|
? resolveConversation(outcome.value.file.conversation).mode
|
|
1019
1242
|
: undefined;
|
|
1020
1243
|
}
|
|
@@ -1370,6 +1593,15 @@ export async function handleEvalRoutes(req, res, deps) {
|
|
|
1370
1593
|
match = m(/^\/api\/evals\/([^/]+)\/runs$/);
|
|
1371
1594
|
if (method === "POST" && match)
|
|
1372
1595
|
return run(() => handleRunStart(c, seg(match[1])));
|
|
1596
|
+
match = m(/^\/api\/evals\/([^/]+)\/graders\/([^/]+)\/calibrations$/);
|
|
1597
|
+
if (method === "GET" && match)
|
|
1598
|
+
return run(() => handleCalibrationList(c, seg(match[1]), seg(match[2])));
|
|
1599
|
+
match = m(/^\/api\/evals\/([^/]+)\/graders\/([^/]+)\/suggest-examples$/);
|
|
1600
|
+
if (method === "POST" && match)
|
|
1601
|
+
return run(() => handleSuggestExamples(c, seg(match[1]), seg(match[2])));
|
|
1602
|
+
match = m(/^\/api\/evals\/([^/]+)\/graders\/([^/]+)\/calibrate$/);
|
|
1603
|
+
if (method === "POST" && match)
|
|
1604
|
+
return run(() => handleCalibrate(c, seg(match[1]), seg(match[2])));
|
|
1373
1605
|
match = m(/^\/api\/evals\/([^/]+)\/failure-types$/);
|
|
1374
1606
|
if (method === "GET" && match)
|
|
1375
1607
|
return run(() => handleFailureTypes(c, seg(match[1])));
|
|
@@ -1401,6 +1633,13 @@ export async function handleEvalRoutes(req, res, deps) {
|
|
|
1401
1633
|
if (method === "PUT" && match) {
|
|
1402
1634
|
return run(() => handleReviewPut(c, seg(match[1]), seg(match[2]), Number(match[3])));
|
|
1403
1635
|
}
|
|
1636
|
+
match = m(/^\/api\/eval-runs\/([^/]+)\/results\/([^/]+)\/(\d+)\/graders\/([^/]+)\/label$/);
|
|
1637
|
+
if (method === "PUT" && match) {
|
|
1638
|
+
return run(() => handleGraderLabelPut(c, seg(match[1]), seg(match[2]), Number(match[3]), seg(match[4])));
|
|
1639
|
+
}
|
|
1640
|
+
match = m(/^\/api\/eval-runs\/([^/]+)\/graders\/([^/]+)\/label-queue$/);
|
|
1641
|
+
if (method === "GET" && match)
|
|
1642
|
+
return run(() => handleLabelQueue(c, seg(match[1]), seg(match[2])));
|
|
1404
1643
|
const triageRoute = matchEvalTriageRoute(c, seg);
|
|
1405
1644
|
if (triageRoute)
|
|
1406
1645
|
return run(triageRoute);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { OperatorAgentHost } from "../operatorAgent/index.js";
|
|
3
|
+
type Json = (res: ServerResponse, status: number, body: unknown) => void;
|
|
4
|
+
export declare function handleGuideRoutes(req: IncomingMessage, method: string, pathname: string, host: OperatorAgentHost, res: ServerResponse, json: Json): Promise<boolean>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { abortGuideTurn, GuideError, guideAgentInfo, isGuideThreadRunning, streamGuideTurn, } from "../guide/chat.js";
|
|
2
|
+
import { createGuideThread, listGuideThreads, readGuideThread, setGuideThreadModel, } from "../guide/threadStore.js";
|
|
3
|
+
async function readBody(req) {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
let size = 0;
|
|
6
|
+
for await (const chunk of req) {
|
|
7
|
+
const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
8
|
+
size += buffer.length;
|
|
9
|
+
if (size > 1_500_000)
|
|
10
|
+
return { __tooLarge: true };
|
|
11
|
+
chunks.push(buffer);
|
|
12
|
+
}
|
|
13
|
+
if (chunks.length === 0)
|
|
14
|
+
return {};
|
|
15
|
+
try {
|
|
16
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
17
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
18
|
+
? parsed
|
|
19
|
+
: { __invalid: true };
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { __invalid: true };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function threadSummary(record) {
|
|
26
|
+
return { id: record.id, title: record.title, updatedAt: record.updatedAt };
|
|
27
|
+
}
|
|
28
|
+
function canWrite(res) {
|
|
29
|
+
return !res.writableEnded && !res.destroyed;
|
|
30
|
+
}
|
|
31
|
+
export async function handleGuideRoutes(req, method, pathname, host, res, json) {
|
|
32
|
+
const root = pathname === "/api/guide";
|
|
33
|
+
const threads = pathname === "/api/guide/threads";
|
|
34
|
+
const threadMatch = /^\/api\/guide\/threads\/([^/]+)$/.exec(pathname);
|
|
35
|
+
const messageMatch = /^\/api\/guide\/threads\/([^/]+)\/messages$/.exec(pathname);
|
|
36
|
+
const stopMatch = /^\/api\/guide\/threads\/([^/]+)\/stop$/.exec(pathname);
|
|
37
|
+
if (!root && !threads && !threadMatch && !messageMatch && !stopMatch)
|
|
38
|
+
return false;
|
|
39
|
+
if (root && method === "GET") {
|
|
40
|
+
json(res, 200, { agent: guideAgentInfo(host) });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (threads && method === "GET") {
|
|
44
|
+
json(res, 200, {
|
|
45
|
+
threads: listGuideThreads().map((thread) => ({
|
|
46
|
+
...thread,
|
|
47
|
+
status: isGuideThreadRunning(thread.id) ? "running" : "open",
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (threads && method === "POST") {
|
|
53
|
+
const record = createGuideThread();
|
|
54
|
+
json(res, 201, { thread: threadSummary(record) });
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
if (stopMatch && method === "POST") {
|
|
58
|
+
const threadId = decodeURIComponent(stopMatch[1] ?? "");
|
|
59
|
+
const record = readGuideThread(threadId);
|
|
60
|
+
if (!record) {
|
|
61
|
+
json(res, 404, { code: "guide.not_found", message: "" });
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
json(res, 200, { ok: true, stopped: abortGuideTurn(threadId) });
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (threadMatch && method === "GET") {
|
|
68
|
+
const threadId = decodeURIComponent(threadMatch[1] ?? "");
|
|
69
|
+
const record = readGuideThread(threadId);
|
|
70
|
+
if (!record) {
|
|
71
|
+
json(res, 404, { code: "guide.not_found", message: "" });
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
json(res, 200, {
|
|
75
|
+
thread: threadSummary(record),
|
|
76
|
+
status: isGuideThreadRunning(record.id) ? "running" : "open",
|
|
77
|
+
messages: record.messages,
|
|
78
|
+
model: record.model ?? null,
|
|
79
|
+
});
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (threadMatch && method === "PATCH") {
|
|
83
|
+
const threadId = decodeURIComponent(threadMatch[1] ?? "");
|
|
84
|
+
const body = await readBody(req);
|
|
85
|
+
if (body.__tooLarge || body.__invalid) {
|
|
86
|
+
json(res, 400, { code: "guide.invalid", message: "" });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
let record = readGuideThread(threadId);
|
|
90
|
+
if (!record) {
|
|
91
|
+
json(res, 404, { code: "guide.not_found", message: "" });
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if ("model" in body) {
|
|
95
|
+
if (typeof body.model === "string") {
|
|
96
|
+
const next = setGuideThreadModel(threadId, body.model.trim() || null);
|
|
97
|
+
if (!next) {
|
|
98
|
+
json(res, 404, { code: "guide.not_found", message: "" });
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
record = next;
|
|
102
|
+
}
|
|
103
|
+
else if (body.model === null) {
|
|
104
|
+
const next = setGuideThreadModel(threadId, null);
|
|
105
|
+
if (!next) {
|
|
106
|
+
json(res, 404, { code: "guide.not_found", message: "" });
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
record = next;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
json(res, 400, { code: "guide.invalid", message: "" });
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
json(res, 200, { thread: threadSummary(record), model: record.model ?? null });
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (messageMatch && method === "POST") {
|
|
120
|
+
const threadId = decodeURIComponent(messageMatch[1] ?? "");
|
|
121
|
+
const body = await readBody(req);
|
|
122
|
+
if (body.__tooLarge || body.__invalid) {
|
|
123
|
+
json(res, 400, { code: "guide.invalid", message: "" });
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
const text = typeof body.text === "string" ? body.text : "";
|
|
127
|
+
let started = false;
|
|
128
|
+
try {
|
|
129
|
+
for await (const frame of streamGuideTurn({
|
|
130
|
+
host,
|
|
131
|
+
threadId,
|
|
132
|
+
text,
|
|
133
|
+
attachments: body.attachments,
|
|
134
|
+
model: typeof body.model === "string" ? body.model : undefined,
|
|
135
|
+
})) {
|
|
136
|
+
if (!canWrite(res))
|
|
137
|
+
continue;
|
|
138
|
+
if (!started) {
|
|
139
|
+
started = true;
|
|
140
|
+
res.writeHead(200, {
|
|
141
|
+
"Content-Type": "application/x-ndjson; charset=utf-8",
|
|
142
|
+
"Cache-Control": "no-store",
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
res.write(`${JSON.stringify(frame)}\n`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
const code = err instanceof GuideError ? err.code : "guide.failed";
|
|
150
|
+
const status = err instanceof GuideError ? err.status : 500;
|
|
151
|
+
if (!started && canWrite(res))
|
|
152
|
+
json(res, status, { code, message: "" });
|
|
153
|
+
else if (started && canWrite(res))
|
|
154
|
+
res.write(`${JSON.stringify({ type: "error", code, message: "" })}\n`);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
if (!res.headersSent && canWrite(res))
|
|
158
|
+
json(res, 200, { code: "guide.failed", message: "" });
|
|
159
|
+
else if (canWrite(res))
|
|
160
|
+
res.end();
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
json(res, 405, { code: "guide.invalid", message: "" });
|
|
165
|
+
return true;
|
|
166
|
+
}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { StagePort } from "../agent/port.js";
|
|
2
2
|
import { type ProviderAuthContext } from "../agent/providerAuth.js";
|
|
3
|
+
import type { ChannelService } from "../channels/service.js";
|
|
3
4
|
import type { EvalRunManager } from "../evals/manager.js";
|
|
5
|
+
import type { MemoryHost } from "../memory/host.js";
|
|
4
6
|
import { type LiveViewRoutesOptions } from "./liveViewRoutes.js";
|
|
5
7
|
import { WorkshopChatSessionRegistry } from "../workshop/chatTurn.js";
|
|
6
8
|
import { type AgentPort } from "../operatorAgent/index.js";
|
|
@@ -70,9 +72,17 @@ export type OperatorRouteDeps = {
|
|
|
70
72
|
agentConversationBackend?: ConversationBackend;
|
|
71
73
|
/** Shared with MCP when set by bootstrap. */
|
|
72
74
|
agentHost?: AgentHostContext;
|
|
75
|
+
/** Bootstrap fills this once the operator host exists, so evals can run against it. */
|
|
76
|
+
operatorHostSlot?: {
|
|
77
|
+
current?: import("../operatorAgent/types.js").OperatorAgentHost;
|
|
78
|
+
};
|
|
73
79
|
evalRunManager?: EvalRunManager;
|
|
74
80
|
/** Wired by the eval manager; until then the internal eval callback answers 404. */
|
|
75
81
|
evalServices?: EvalServices;
|
|
82
|
+
/** Host connections. Guide and MCP use the same service the console does. */
|
|
83
|
+
channels?: ChannelService;
|
|
84
|
+
/** Host memories. Guide and MCP use the same host the console does. */
|
|
85
|
+
memories?: MemoryHost;
|
|
76
86
|
};
|
|
77
87
|
/**
|
|
78
88
|
* The full operator-console route surface: REST API (runs, stages,
|
package/dist/server/http.js
CHANGED
|
@@ -8,6 +8,7 @@ import { mapProviderAuthError } from "../agent/providerInspect.js";
|
|
|
8
8
|
import { handleProviderRoutes } from "./providerRoutes.js";
|
|
9
9
|
import { handleProjectMcpRoutes } from "./projectMcpRoutes.js";
|
|
10
10
|
import { handleTriggerRoutes } from "./triggerRoutes.js";
|
|
11
|
+
import { guideWriteRoot } from "../guide/writeRoot.js";
|
|
11
12
|
import { handleEvalRoutes } from "./evalRoutes.js";
|
|
12
13
|
import { defaultLoadJudgePrices } from "../evals/engine/promptfoo/judgeServices.js";
|
|
13
14
|
import { engineStatus as promptfooEngineStatus } from "../evals/engine/promptfoo/status.js";
|
|
@@ -62,6 +63,8 @@ import { buildModelsResponse } from "../models/response.js";
|
|
|
62
63
|
import { createAgentHostContext } from "../agents/hostContext.js";
|
|
63
64
|
import { AgentScheduleSource, agentScheduleTickIntervalMsFromEnv, } from "../agents/scheduleSource.js";
|
|
64
65
|
import { handleAgentAuthorRoutes } from "./agentAuthorRoutes.js";
|
|
66
|
+
import { handleGuideRoutes } from "./guideRoutes.js";
|
|
67
|
+
import { handleInternalAgentRoutes } from "./internalAgentRoutes.js";
|
|
65
68
|
import { handleAgentRoutes } from "./agentRoutes.js";
|
|
66
69
|
import { handleChannelRoutes } from "./channelRoutes.js";
|
|
67
70
|
import { handleEvalInternalRoutes, isEvalInternalPath } from "./evalInternalRoutes.js";
|
|
@@ -217,7 +220,27 @@ export function createOperatorRoutes(deps) {
|
|
|
217
220
|
resolveAgentPort({
|
|
218
221
|
cwd,
|
|
219
222
|
projectRoot: cwd,
|
|
223
|
+
guideDeps: {
|
|
224
|
+
manager,
|
|
225
|
+
store,
|
|
226
|
+
cwd,
|
|
227
|
+
agentDir,
|
|
228
|
+
projectRoot: guideWriteRoot(rootDir),
|
|
229
|
+
...(providerAuthContext ? { providerAuthContext } : {}),
|
|
230
|
+
...(deps.evalRunManager ? { evalRunManager: deps.evalRunManager } : {}),
|
|
231
|
+
...(deps.channels ? { channels: deps.channels } : {}),
|
|
232
|
+
...(deps.memories ? { memories: deps.memories } : {}),
|
|
233
|
+
...(agentHost
|
|
234
|
+
? {
|
|
235
|
+
agentService: agentHost.service,
|
|
236
|
+
agentChat: agentHost.chat,
|
|
237
|
+
agentConversationBackend: agentHost.backend,
|
|
238
|
+
}
|
|
239
|
+
: {}),
|
|
240
|
+
},
|
|
220
241
|
});
|
|
242
|
+
if (deps.operatorHostSlot)
|
|
243
|
+
deps.operatorHostSlot.current = operatorHost;
|
|
221
244
|
const workshopChatRegistry = deps.workshopChatRegistry ?? new WorkshopChatSessionRegistry(operatorHost);
|
|
222
245
|
const workshopSessionStoreRoot = () => resolveWorkshopSessionStoreRoot();
|
|
223
246
|
const workshopBuildStoreRoot = () => resolveWorkshopBuildStoreRoot();
|
|
@@ -263,6 +286,12 @@ export function createOperatorRoutes(deps) {
|
|
|
263
286
|
if (await handleAgentAuthorRoutes(req, method, pathname, cwd, operatorHost, res, json))
|
|
264
287
|
return true;
|
|
265
288
|
}
|
|
289
|
+
if (pathname === "/api/guide" || pathname.startsWith("/api/guide/")) {
|
|
290
|
+
if (await handleGuideRoutes(req, method, pathname, operatorHost, res, json))
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (handleInternalAgentRoutes(method, pathname, operatorHost, res, json))
|
|
294
|
+
return true;
|
|
266
295
|
if (PublicWebChat.owns(pathname)) {
|
|
267
296
|
if (!agentHost) {
|
|
268
297
|
json(res, 503, { code: "web_chat.unavailable" });
|
|
@@ -1064,7 +1093,9 @@ export function createOperatorRoutes(deps) {
|
|
|
1064
1093
|
await readJsonBody(req);
|
|
1065
1094
|
const runId = decodeURIComponent(retryMatch[1] ?? "");
|
|
1066
1095
|
const stageId = decodeURIComponent(retryMatch[2] ?? "");
|
|
1067
|
-
const result = await manager.retryStage(runId, stageId
|
|
1096
|
+
const result = await manager.retryStage(runId, stageId, {
|
|
1097
|
+
awaitRoot: false,
|
|
1098
|
+
});
|
|
1068
1099
|
if (!result.ok) {
|
|
1069
1100
|
json(res, result.status ?? 500, mapRetryStageFailure(result));
|
|
1070
1101
|
return true;
|
|
@@ -3178,8 +3209,11 @@ export async function startUiServer(options) {
|
|
|
3178
3209
|
? { workshopOperatorHost: options.workshopOperatorHost }
|
|
3179
3210
|
: {}),
|
|
3180
3211
|
...(boot.agentHost ? { agentHost: boot.agentHost } : {}),
|
|
3212
|
+
...(boot.operatorHostSlot ? { operatorHostSlot: boot.operatorHostSlot } : {}),
|
|
3181
3213
|
...(boot.evalRunManager ? { evalRunManager: boot.evalRunManager } : {}),
|
|
3182
3214
|
...(boot.evalServices ? { evalServices: boot.evalServices } : {}),
|
|
3215
|
+
...(boot.channels ? { channels: boot.channels } : {}),
|
|
3216
|
+
...(boot.memories ? { memories: boot.memories } : {}),
|
|
3183
3217
|
...(options.agentConversationBackend
|
|
3184
3218
|
? { agentConversationBackend: options.agentConversationBackend }
|
|
3185
3219
|
: {}),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
import type { OperatorAgentHost } from "../operatorAgent/index.js";
|
|
3
|
+
type Json = (res: ServerResponse, status: number, body: unknown) => void;
|
|
4
|
+
export declare const INTERNAL_AGENTS_PATH = "/api/internal-agents";
|
|
5
|
+
export declare function handleInternalAgentRoutes(method: string, pathname: string, host: OperatorAgentHost, res: ServerResponse, json: Json, env?: NodeJS.ProcessEnv): boolean;
|
|
6
|
+
export {};
|