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
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const EVAL_SESSION_SOURCE = "eval";
|
|
2
|
+
export function isEvalSession(session) {
|
|
3
|
+
return session.source === EVAL_SESSION_SOURCE;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The definition an eval session runs on: the pinned revision with the eval's model, limits and capture, and with
|
|
7
|
+
* every side effect off (always-on, OTLP push, groundedness judge). Capture defaults to full so tool calls are recorded.
|
|
8
|
+
*/
|
|
9
|
+
export function applyEvalOverrides(base, overrides) {
|
|
10
|
+
const { definition } = overrides;
|
|
11
|
+
const limits = {
|
|
12
|
+
...base.limits,
|
|
13
|
+
...definition?.limits,
|
|
14
|
+
...(overrides.limits ? { cost_usd: null, ...overrides.limits } : {}),
|
|
15
|
+
always_on: false,
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
...base,
|
|
19
|
+
model: { ...base.model, ...definition?.model },
|
|
20
|
+
limits,
|
|
21
|
+
observability: {
|
|
22
|
+
...base.observability,
|
|
23
|
+
...definition?.observability,
|
|
24
|
+
capture: overrides.capture ?? definition?.observability?.capture ?? "full",
|
|
25
|
+
otlp: false,
|
|
26
|
+
},
|
|
27
|
+
evals: { ...base.evals, ...definition?.evals, groundedness: false },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -9,12 +9,15 @@ import type { ContactInfo } from "../channels/types.js";
|
|
|
9
9
|
import type { McpToolDeps } from "../mcp/deps.js";
|
|
10
10
|
import { AgentService, type AgentEnvironment } from "./service.js";
|
|
11
11
|
import type { ConversationBackend } from "./sessions.js";
|
|
12
|
+
import { EvalGateRegistry } from "./evalGate.js";
|
|
12
13
|
import { PublicWebChat } from "./webChat/publicChat.js";
|
|
13
14
|
export type AgentHostContext = {
|
|
14
15
|
service: AgentService;
|
|
15
16
|
inbound: AgentInboundRouter;
|
|
16
17
|
publicChat: PublicWebChat;
|
|
17
18
|
chat: AgentChatController;
|
|
19
|
+
/** Eval tool gates by session id; the eval runner registers a gate for each eval session it opens. */
|
|
20
|
+
evalGates: EvalGateRegistry;
|
|
18
21
|
backend: ConversationBackend;
|
|
19
22
|
/** Streams held open to AgentMail and iMessage; absent unless the Host listens (not in tests). */
|
|
20
23
|
channelListeners?: ChannelSupervisor;
|
|
@@ -12,6 +12,7 @@ import { buildToolkit } from "../toolkit/index.js";
|
|
|
12
12
|
import { createPiAgentRuntime } from "./runtime/piRuntime.js";
|
|
13
13
|
import { AgentService } from "./service.js";
|
|
14
14
|
import { getModelCatalog } from "../models/catalog.js";
|
|
15
|
+
import { EvalGateRegistry } from "./evalGate.js";
|
|
15
16
|
import { defaultAgentProjectRoot } from "./projectRoot.js";
|
|
16
17
|
import { PublicWebChat } from "./webChat/publicChat.js";
|
|
17
18
|
import { AgentStore } from "./store.js";
|
|
@@ -82,9 +83,11 @@ export function createAgentHostContext(options) {
|
|
|
82
83
|
}
|
|
83
84
|
: {}),
|
|
84
85
|
});
|
|
86
|
+
const evalGates = new EvalGateRegistry();
|
|
85
87
|
const chat = new AgentChatController({
|
|
86
88
|
service,
|
|
87
89
|
backend,
|
|
90
|
+
evalGates,
|
|
88
91
|
otlpSink: "otlpSink" in options ? options.otlpSink : otlpSinkFromEnv(),
|
|
89
92
|
logError: (message) => console.error(message),
|
|
90
93
|
});
|
|
@@ -147,7 +150,7 @@ export function createAgentHostContext(options) {
|
|
|
147
150
|
delivery.start();
|
|
148
151
|
if (options.listenOnChannels)
|
|
149
152
|
void inbound.resumeInterrupted().catch((error) => console.error(`agent resume failed: ${String(error)}`));
|
|
150
|
-
return { service, chat, backend, inbound, publicChat, channelContact, ...(channelListeners ? { channelListeners } : {}), delivery, stop: async () => {
|
|
153
|
+
return { service, chat, evalGates, backend, inbound, publicChat, channelContact, ...(channelListeners ? { channelListeners } : {}), delivery, stop: async () => {
|
|
151
154
|
delivery.stop();
|
|
152
155
|
await channelListeners?.stop();
|
|
153
156
|
// The Host owns every runtime session's lifetime: nothing outlives it.
|
|
@@ -34,7 +34,7 @@ export type OpenSessionInput = {
|
|
|
34
34
|
reason: string;
|
|
35
35
|
terminate?: boolean;
|
|
36
36
|
} | undefined>;
|
|
37
|
-
delegateTool?: (agentId: string, message: string) => Promise<string>;
|
|
37
|
+
delegateTool?: (agentId: string, message: string, callId: string) => Promise<string>;
|
|
38
38
|
/** Stageflow tools this agent is granted. */
|
|
39
39
|
stageflowTools?: ToolkitTool[];
|
|
40
40
|
memory?: StageMemory;
|
|
@@ -149,8 +149,8 @@ async function openPiSession(options, input) {
|
|
|
149
149
|
label: `Ask ${agentId}`,
|
|
150
150
|
description: `Hand a task to the "${agentId}" agent and get its reply.`,
|
|
151
151
|
parameters: Type.Object({ message: Type.String({ description: "The task or question for the agent." }) }),
|
|
152
|
-
execute: async (
|
|
153
|
-
const reply = await input.delegateTool(agentId, args.message);
|
|
152
|
+
execute: async (callId, args) => {
|
|
153
|
+
const reply = await input.delegateTool(agentId, args.message, callId);
|
|
154
154
|
return { content: [{ type: "text", text: reply }], details: {} };
|
|
155
155
|
},
|
|
156
156
|
}));
|
|
@@ -296,7 +296,7 @@ export function createPiAgentRuntime(options) {
|
|
|
296
296
|
hooks: () => state.hooks,
|
|
297
297
|
...(memory ? { memory } : {}),
|
|
298
298
|
...(stageflowTools.length > 0 ? { stageflowTools } : {}),
|
|
299
|
-
...(subAgents.length > 0 ? { delegateTool: (agentId, message) => state.hooks.delegate(agentId, message) } : {}),
|
|
299
|
+
...(subAgents.length > 0 ? { delegateTool: (agentId, message, callId) => state.hooks.delegate(agentId, message, callId) } : {}),
|
|
300
300
|
gate: async (call) => {
|
|
301
301
|
const hooks = state.hooks;
|
|
302
302
|
if (!hooks)
|
|
@@ -433,7 +433,7 @@ export function createPiAgentRuntime(options) {
|
|
|
433
433
|
const opened = await open({
|
|
434
434
|
projectRoot: input.projectRoot,
|
|
435
435
|
definition: { ...input.definition, tools: { ...input.definition.tools, builtin: [], builtin_tools: [], mcp: {}, skills: [] }, sub_agents: [] },
|
|
436
|
-
systemPrompt: "You are a strict evaluator. Answer only with the requested number.",
|
|
436
|
+
systemPrompt: input.systemPrompt ?? "You are a strict evaluator. Answer only with the requested number.",
|
|
437
437
|
toolNames: [],
|
|
438
438
|
gate: async () => ({ block: true, reason: "No tools" }),
|
|
439
439
|
hooks: () => undefined,
|
|
@@ -39,7 +39,7 @@ export type TurnHooks = {
|
|
|
39
39
|
model?: string;
|
|
40
40
|
}): void;
|
|
41
41
|
/** Run another agent for a `agent:<id>` call and return its reply. */
|
|
42
|
-
delegate(agentId: string, message: string): Promise<string>;
|
|
42
|
+
delegate(agentId: string, message: string, callId?: string): Promise<string>;
|
|
43
43
|
};
|
|
44
44
|
export type CompleteInput = {
|
|
45
45
|
sessionId: string;
|
|
@@ -64,6 +64,8 @@ export type ConversationBackend = {
|
|
|
64
64
|
projectRoot: string;
|
|
65
65
|
definition: AgentDefinition;
|
|
66
66
|
prompt: string;
|
|
67
|
+
/** Replaces the default "strict evaluator" system prompt. */
|
|
68
|
+
systemPrompt?: string;
|
|
67
69
|
signal: AbortSignal;
|
|
68
70
|
}): Promise<string>;
|
|
69
71
|
/** Drop any cached model session for a conversation session. */
|
package/dist/agents/service.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type AgentInboundMessage } from "./communications/port.js";
|
|
|
3
3
|
import { ApprovalBroker } from "./approvalBroker.js";
|
|
4
4
|
import { type DeliveryLedger, type ScheduleLedger } from "./ledgers.js";
|
|
5
5
|
import { type FinishInput } from "./turnLifecycle.js";
|
|
6
|
+
import { type EvalSessionOverrides } from "./evalSession.js";
|
|
6
7
|
import { type DiffLine } from "./lineDiff.js";
|
|
7
8
|
import { AgentStore, type AgentApproval, type AgentEvalScore, type AgentMessage, type AgentRevision, type AgentRevisionMeta, type AgentSession, type AgentSessionListItem, type AgentDelivery, type AgentSpan, type AgentTurn, type ApprovalActor, type RevisionSource, type SessionQuery, type SessionStats, type SessionStatus } from "./store.js";
|
|
8
9
|
/** Lookups outside the agents directory, used only to produce non-blocking warnings. */
|
|
@@ -88,6 +89,8 @@ export declare class AgentService {
|
|
|
88
89
|
private readonly environment;
|
|
89
90
|
private readonly now;
|
|
90
91
|
private readonly tails;
|
|
92
|
+
/** Overrides of open eval sessions. Memory only: eval sessions do not survive a Host restart. */
|
|
93
|
+
private readonly evalOverrides;
|
|
91
94
|
/** Wakes a turn paused at an ask-first tool when its approval is decided. */
|
|
92
95
|
readonly approvalBroker: ApprovalBroker;
|
|
93
96
|
/** Owns every legal change of a turn, its session and its approval. */
|
|
@@ -140,6 +143,25 @@ export declare class AgentService {
|
|
|
140
143
|
get(projectRoot: string, agentId: string): Promise<AgentDetail>;
|
|
141
144
|
/** The definition a session is pinned to. */
|
|
142
145
|
definitionAt(projectRoot: string, agentId: string, revision: number): Promise<AgentDefinition>;
|
|
146
|
+
/** The pinned definition, with an eval session's overrides applied. Real sessions get it unchanged. */
|
|
147
|
+
private effectiveDefinition;
|
|
148
|
+
/** The overrides an eval session was opened with (sub-agent sessions inherit them), or undefined for a real session. */
|
|
149
|
+
evalOverridesOf(sessionId: string): EvalSessionOverrides | undefined;
|
|
150
|
+
/** Every eval session below this one (sub-agents and theirs). */
|
|
151
|
+
listChildSessions(sessionId: string): AgentSession[];
|
|
152
|
+
/** Delete eval sessions and everything below them. Refuses a session that is not an eval session. */
|
|
153
|
+
deleteEvalSessions(projectRoot: string, sessionIds: string[]): Promise<string[]>;
|
|
154
|
+
/**
|
|
155
|
+
* Boot cleanup of eval sessions: those of the given (recovered) eval runs, and older root sessions no eval result
|
|
156
|
+
* references. Returns how many sessions were deleted, descendants included.
|
|
157
|
+
*/
|
|
158
|
+
sweepEvalSessions(input: {
|
|
159
|
+
runIds: string[];
|
|
160
|
+
olderThanMs: number;
|
|
161
|
+
isReferenced: (sessionId: string) => Promise<boolean> | boolean;
|
|
162
|
+
}): Promise<number>;
|
|
163
|
+
/** Forget a finished eval session's in-memory overrides. The rows stay readable. */
|
|
164
|
+
forgetEvalSession(sessionId: string): void;
|
|
143
165
|
private warningsFor;
|
|
144
166
|
/**
|
|
145
167
|
* Web chat defaults and links: a new agent starts with web chat on, an enabled block without a link
|
|
@@ -182,10 +204,11 @@ export declare class AgentService {
|
|
|
182
204
|
sourceRef?: string | null;
|
|
183
205
|
threadKey?: string | null;
|
|
184
206
|
title?: string | null;
|
|
207
|
+
eval?: EvalSessionOverrides;
|
|
185
208
|
}): Promise<AgentSession>;
|
|
186
209
|
/** Id of the session's pending approval, if a turn is waiting on a person. */
|
|
187
210
|
pendingApprovalFor(_projectRoot: string, sessionId: string): string | null;
|
|
188
|
-
listSessionsForRef(projectRoot: string, agentId: string, source: string, sourceRef: string, limit: number): AgentSession[];
|
|
211
|
+
listSessionsForRef(projectRoot: string, agentId: string, source: string, sourceRef: string, limit: number, includeEval?: boolean): AgentSession[];
|
|
189
212
|
private sessionInProject;
|
|
190
213
|
getSession(projectRoot: string, sessionId: string): Promise<AgentSessionDetail>;
|
|
191
214
|
listSessions(projectRoot: string, agentId: string, query: SessionQuery): Promise<{
|
|
@@ -274,7 +297,9 @@ export declare class AgentService {
|
|
|
274
297
|
turnId?: string | null;
|
|
275
298
|
}): Promise<AgentApproval>;
|
|
276
299
|
decideApproval(projectRoot: string, sessionId: string, decision: "approve" | "deny", actor: ApprovalActor): Promise<AgentApproval>;
|
|
277
|
-
pendingApprovals(projectRoot: string
|
|
300
|
+
pendingApprovals(projectRoot: string, options?: {
|
|
301
|
+
includeEval?: boolean;
|
|
302
|
+
}): Promise<Array<AgentApproval & {
|
|
278
303
|
agentId: string;
|
|
279
304
|
}>>;
|
|
280
305
|
receive(projectRoot: string, message: AgentInboundMessage): Promise<{
|
package/dist/agents/service.js
CHANGED
|
@@ -11,6 +11,7 @@ import { ApprovalBroker } from "./approvalBroker.js";
|
|
|
11
11
|
import { deliveryLedger, scheduleLedger } from "./ledgers.js";
|
|
12
12
|
import { TurnLifecycle } from "./turnLifecycle.js";
|
|
13
13
|
import { AgentError } from "./errors.js";
|
|
14
|
+
import { applyEvalOverrides, EVAL_SESSION_SOURCE, isEvalSession } from "./evalSession.js";
|
|
14
15
|
import { agentMemoryIssues } from "../memory/agentIssues.js";
|
|
15
16
|
import { diffLines } from "./lineDiff.js";
|
|
16
17
|
import { exportTurnsToOtlp } from "./otlpExport.js";
|
|
@@ -38,6 +39,8 @@ export class AgentService {
|
|
|
38
39
|
environment;
|
|
39
40
|
now;
|
|
40
41
|
tails = new Map();
|
|
42
|
+
/** Overrides of open eval sessions. Memory only: eval sessions do not survive a Host restart. */
|
|
43
|
+
evalOverrides = new Map();
|
|
41
44
|
/** Wakes a turn paused at an ask-first tool when its approval is decided. */
|
|
42
45
|
approvalBroker = new ApprovalBroker();
|
|
43
46
|
/** Owns every legal change of a turn, its session and its approval. */
|
|
@@ -311,6 +314,64 @@ export class AgentService {
|
|
|
311
314
|
throw new AgentError("agent.revision_not_found");
|
|
312
315
|
return found.definition;
|
|
313
316
|
}
|
|
317
|
+
/** The pinned definition, with an eval session's overrides applied. Real sessions get it unchanged. */
|
|
318
|
+
async effectiveDefinition(projectRoot, session) {
|
|
319
|
+
const base = await this.definitionAt(projectRoot, session.agentId, session.revision);
|
|
320
|
+
return isEvalSession(session) ? applyEvalOverrides(base, this.evalOverrides.get(session.id) ?? {}) : base;
|
|
321
|
+
}
|
|
322
|
+
/** The overrides an eval session was opened with (sub-agent sessions inherit them), or undefined for a real session. */
|
|
323
|
+
evalOverridesOf(sessionId) {
|
|
324
|
+
return this.evalOverrides.get(sessionId);
|
|
325
|
+
}
|
|
326
|
+
/** Every eval session below this one (sub-agents and theirs). */
|
|
327
|
+
listChildSessions(sessionId) {
|
|
328
|
+
return this.store.listChildSessions(sessionId);
|
|
329
|
+
}
|
|
330
|
+
/** Delete eval sessions and everything below them. Refuses a session that is not an eval session. */
|
|
331
|
+
async deleteEvalSessions(projectRoot, sessionIds) {
|
|
332
|
+
const roots = sessionIds.map((sessionId) => this.sessionInProject(projectRoot, sessionId));
|
|
333
|
+
const refused = roots.find((session) => !isEvalSession(session));
|
|
334
|
+
if (refused)
|
|
335
|
+
throw new AgentError("agent.invalid", `Session ${refused.id} is not an eval session`);
|
|
336
|
+
const all = new Set(roots.map((session) => session.id));
|
|
337
|
+
for (const root of roots)
|
|
338
|
+
for (const child of this.store.listChildSessions(root.id))
|
|
339
|
+
all.add(child.id);
|
|
340
|
+
const ids = [...all];
|
|
341
|
+
this.store.deleteSessions(ids);
|
|
342
|
+
for (const sessionId of ids)
|
|
343
|
+
this.evalOverrides.delete(sessionId);
|
|
344
|
+
return ids;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Boot cleanup of eval sessions: those of the given (recovered) eval runs, and older root sessions no eval result
|
|
348
|
+
* references. Returns how many sessions were deleted, descendants included.
|
|
349
|
+
*/
|
|
350
|
+
async sweepEvalSessions(input) {
|
|
351
|
+
const roots = new Map();
|
|
352
|
+
for (const session of this.store.listEvalRootSessions({ sourceRefs: input.runIds }))
|
|
353
|
+
roots.set(session.id, session);
|
|
354
|
+
const cutoff = new Date(this.clockMs() - input.olderThanMs).toISOString();
|
|
355
|
+
for (const session of this.store.listEvalRootSessions({ createdBefore: cutoff })) {
|
|
356
|
+
if (!roots.has(session.id) && !(await input.isReferenced(session.id)))
|
|
357
|
+
roots.set(session.id, session);
|
|
358
|
+
}
|
|
359
|
+
const all = new Set();
|
|
360
|
+
for (const root of roots.values()) {
|
|
361
|
+
all.add(root.id);
|
|
362
|
+
for (const child of this.store.listChildSessions(root.id))
|
|
363
|
+
all.add(child.id);
|
|
364
|
+
}
|
|
365
|
+
const ids = [...all];
|
|
366
|
+
this.store.deleteSessions(ids);
|
|
367
|
+
for (const sessionId of ids)
|
|
368
|
+
this.evalOverrides.delete(sessionId);
|
|
369
|
+
return ids.length;
|
|
370
|
+
}
|
|
371
|
+
/** Forget a finished eval session's in-memory overrides. The rows stay readable. */
|
|
372
|
+
forgetEvalSession(sessionId) {
|
|
373
|
+
this.evalOverrides.delete(sessionId);
|
|
374
|
+
}
|
|
314
375
|
/* ---------- validation ---------- */
|
|
315
376
|
async warningsFor(projectRoot, definition) {
|
|
316
377
|
const warnings = [];
|
|
@@ -636,10 +697,20 @@ export class AgentService {
|
|
|
636
697
|
}
|
|
637
698
|
/* ---------- sessions ---------- */
|
|
638
699
|
async openSession(projectRoot, agentId, input) {
|
|
700
|
+
if (input.eval && input.source !== EVAL_SESSION_SOURCE)
|
|
701
|
+
throw new AgentError("agent.invalid", "Eval overrides need an eval session");
|
|
639
702
|
return this.exclusive(projectRoot, async () => {
|
|
640
703
|
await this.sync(projectRoot);
|
|
641
|
-
const
|
|
642
|
-
|
|
704
|
+
const isEval = input.source === EVAL_SESSION_SOURCE;
|
|
705
|
+
const { revision: current } = this.currentRevision(projectRoot, agentId);
|
|
706
|
+
let revision = current;
|
|
707
|
+
if (input.eval?.revision !== undefined && input.eval.revision !== current.revision) {
|
|
708
|
+
const pinned = this.store.getRevision(agentProjectKey(projectRoot), agentId, input.eval.revision);
|
|
709
|
+
if (!pinned)
|
|
710
|
+
throw new AgentError("agent.revision_not_found");
|
|
711
|
+
revision = pinned;
|
|
712
|
+
}
|
|
713
|
+
if (!isEval && !revision.definition.enabled)
|
|
643
714
|
throw new AgentError("agent.disabled");
|
|
644
715
|
const now = this.iso();
|
|
645
716
|
const session = {
|
|
@@ -656,6 +727,8 @@ export class AgentService {
|
|
|
656
727
|
updatedAt: now,
|
|
657
728
|
};
|
|
658
729
|
this.store.insertSession(agentProjectKey(projectRoot), session);
|
|
730
|
+
if (isEval)
|
|
731
|
+
this.evalOverrides.set(session.id, input.eval ?? {});
|
|
659
732
|
return session;
|
|
660
733
|
});
|
|
661
734
|
}
|
|
@@ -663,8 +736,8 @@ export class AgentService {
|
|
|
663
736
|
pendingApprovalFor(_projectRoot, sessionId) {
|
|
664
737
|
return this.store.listApprovals(sessionId).find((approval) => approval.status === "pending")?.id ?? null;
|
|
665
738
|
}
|
|
666
|
-
listSessionsForRef(projectRoot, agentId, source, sourceRef, limit) {
|
|
667
|
-
return this.store.listSessionsForRef(agentProjectKey(projectRoot), agentId, source, sourceRef, limit);
|
|
739
|
+
listSessionsForRef(projectRoot, agentId, source, sourceRef, limit, includeEval) {
|
|
740
|
+
return this.store.listSessionsForRef(agentProjectKey(projectRoot), agentId, source, sourceRef, limit, includeEval);
|
|
668
741
|
}
|
|
669
742
|
sessionInProject(projectRoot, sessionId) {
|
|
670
743
|
const session = this.store.getSession(sessionId);
|
|
@@ -698,7 +771,7 @@ export class AgentService {
|
|
|
698
771
|
const since = new Date(this.now().getTime() - RECENT_WINDOW_MS).toISOString();
|
|
699
772
|
return {
|
|
700
773
|
...this.store.listSessions(projectKey, agentId, query),
|
|
701
|
-
stats: this.store.sessionStats(projectKey, agentId, since),
|
|
774
|
+
stats: this.store.sessionStats(projectKey, agentId, since, query.includeEval),
|
|
702
775
|
};
|
|
703
776
|
});
|
|
704
777
|
}
|
|
@@ -711,7 +784,7 @@ export class AgentService {
|
|
|
711
784
|
const since = new Date(this.now().getTime() - RECENT_WINDOW_MS).toISOString();
|
|
712
785
|
return {
|
|
713
786
|
...this.store.listSessions(projectKey, agentId, query),
|
|
714
|
-
stats: this.store.sessionStats(projectKey, agentId, since),
|
|
787
|
+
stats: this.store.sessionStats(projectKey, agentId, since, query.includeEval),
|
|
715
788
|
};
|
|
716
789
|
});
|
|
717
790
|
}
|
|
@@ -745,11 +818,11 @@ export class AgentService {
|
|
|
745
818
|
await this.sync(projectRoot);
|
|
746
819
|
const session = this.sessionInProject(projectRoot, sessionId);
|
|
747
820
|
const { revision: live } = this.currentRevision(projectRoot, session.agentId);
|
|
748
|
-
if (!live.definition.enabled)
|
|
821
|
+
if (!live.definition.enabled && !isEvalSession(session))
|
|
749
822
|
throw new AgentError("agent.disabled");
|
|
750
823
|
if (session.status === "running" || session.status === "waiting")
|
|
751
824
|
throw new AgentError("agent.session_busy");
|
|
752
|
-
const definition = await this.
|
|
825
|
+
const definition = await this.effectiveDefinition(projectRoot, session);
|
|
753
826
|
this.assertWithinLimits(definition, session);
|
|
754
827
|
const now = this.iso();
|
|
755
828
|
return this.store.transaction(() => {
|
|
@@ -930,9 +1003,9 @@ export class AgentService {
|
|
|
930
1003
|
this.expireApprovals();
|
|
931
1004
|
const session = this.sessionInProject(projectRoot, sessionId);
|
|
932
1005
|
const { revision: live } = this.currentRevision(projectRoot, session.agentId);
|
|
933
|
-
if (!live.definition.enabled)
|
|
1006
|
+
if (!live.definition.enabled && !isEvalSession(session))
|
|
934
1007
|
throw new AgentError("agent.disabled");
|
|
935
|
-
const definition = await this.
|
|
1008
|
+
const definition = await this.effectiveDefinition(projectRoot, session);
|
|
936
1009
|
if (!isToolGranted(definition, input.tool))
|
|
937
1010
|
throw new AgentError("agent.tool_not_granted");
|
|
938
1011
|
if (!requiresAskFirst(definition, input.tool))
|
|
@@ -975,7 +1048,9 @@ export class AgentService {
|
|
|
975
1048
|
return this.exclusive(projectRoot, async () => {
|
|
976
1049
|
await this.sync(projectRoot);
|
|
977
1050
|
const session = this.sessionInProject(projectRoot, sessionId);
|
|
978
|
-
|
|
1051
|
+
if (isEvalSession(session))
|
|
1052
|
+
throw new AgentError("agent.session_eval_readonly", "Eval sessions are read only");
|
|
1053
|
+
const definition = await this.effectiveDefinition(projectRoot, session);
|
|
979
1054
|
if (!canApprove(definition, actor))
|
|
980
1055
|
throw new AgentError("agent.approval_forbidden");
|
|
981
1056
|
const pending = this.store.getPendingApproval(sessionId);
|
|
@@ -997,9 +1072,9 @@ export class AgentService {
|
|
|
997
1072
|
return decided.approval;
|
|
998
1073
|
});
|
|
999
1074
|
}
|
|
1000
|
-
async pendingApprovals(projectRoot) {
|
|
1075
|
+
async pendingApprovals(projectRoot, options = {}) {
|
|
1001
1076
|
this.expireApprovals();
|
|
1002
|
-
return this.store.listPendingApprovals(agentProjectKey(projectRoot));
|
|
1077
|
+
return this.store.listPendingApprovals(agentProjectKey(projectRoot), options.includeEval);
|
|
1003
1078
|
}
|
|
1004
1079
|
/* ---------- communications ---------- */
|
|
1005
1080
|
async receive(projectRoot, message) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { EvalGateRegistry } from "./evalGate.js";
|
|
2
|
+
import { type EvalSessionOverrides } from "./evalSession.js";
|
|
1
3
|
import type { OtlpSink } from "./otlpSink.js";
|
|
2
4
|
import type { ConversationBackend } from "./runtime/types.js";
|
|
3
5
|
import type { AgentService, AgentSessionDetail } from "./service.js";
|
|
@@ -11,6 +13,10 @@ export type SendTurnInput = {
|
|
|
11
13
|
author?: string | null;
|
|
12
14
|
/** Where a new session came from: console, cli, mcp, schedule, or a provider id. */
|
|
13
15
|
source?: string;
|
|
16
|
+
/** Where a new session points to; defaults to the author. Eval sessions point at their eval run or parent session. */
|
|
17
|
+
sourceRef?: string | null;
|
|
18
|
+
/** Overrides for a new eval session (needs `source: "eval"`). */
|
|
19
|
+
eval?: EvalSessionOverrides;
|
|
14
20
|
onDelta?: (text: string) => void;
|
|
15
21
|
onSessionOpened?: (sessionId: string) => void;
|
|
16
22
|
/** Retry this earlier, interrupted turn: its user message is reused, not asked again. */
|
|
@@ -20,6 +26,8 @@ export type ConversationOptions = {
|
|
|
20
26
|
service: AgentService;
|
|
21
27
|
backend: ConversationBackend;
|
|
22
28
|
otlpSink?: OtlpSink | undefined;
|
|
29
|
+
/** Eval tool gates by session id. An eval session without one is denied every tool. */
|
|
30
|
+
evalGates?: EvalGateRegistry;
|
|
23
31
|
logError?: (message: string) => void;
|
|
24
32
|
};
|
|
25
33
|
/** One turn: open (if needed) → record user message → model + tools → guardrails → record reply. */
|
package/dist/agents/sessions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { assertDelegateAllowed } from "./delegate.js";
|
|
3
3
|
import { AgentError, isAgentError } from "./errors.js";
|
|
4
|
+
import { EVAL_SESSION_SOURCE, isEvalSession } from "./evalSession.js";
|
|
4
5
|
import { guardedStream } from "./guardrails.js";
|
|
5
6
|
import { fitHistory } from "./historyFit.js";
|
|
6
7
|
import { isToolGranted, requiresAskFirst } from "./policy.js";
|
|
@@ -51,7 +52,8 @@ export class AgentConversation {
|
|
|
51
52
|
if (!sessionId) {
|
|
52
53
|
const opened = await service.openSession(input.projectRoot, input.agentId, {
|
|
53
54
|
source: input.source ?? "console",
|
|
54
|
-
sourceRef: input.author ?? null,
|
|
55
|
+
sourceRef: input.sourceRef !== undefined ? input.sourceRef : (input.author ?? null),
|
|
56
|
+
...(input.eval ? { eval: input.eval } : {}),
|
|
55
57
|
});
|
|
56
58
|
sessionId = opened.id;
|
|
57
59
|
input.onSessionOpened?.(sessionId);
|
|
@@ -98,9 +100,31 @@ export class AgentConversation {
|
|
|
98
100
|
service.recordSpan(input.projectRoot, span);
|
|
99
101
|
};
|
|
100
102
|
const toolStarts = new Map();
|
|
103
|
+
const childSessions = new Map();
|
|
104
|
+
const childSessionOf = (call) => (isEvalSession(active.session) ? (childSessions.get(call.id) ?? childSessions.get(call.tool)) : undefined);
|
|
101
105
|
let stopReason;
|
|
102
106
|
let gateChain = Promise.resolve();
|
|
103
107
|
const gateOne = async (call) => {
|
|
108
|
+
if (active.session.source === EVAL_SESSION_SOURCE) {
|
|
109
|
+
const gate = this.options.evalGates?.get(sessionId);
|
|
110
|
+
if (!gate)
|
|
111
|
+
return { allow: false, reason: "No eval policy is registered for this session." };
|
|
112
|
+
const decision = gate.decide(call, definition);
|
|
113
|
+
if (gate.recordOf(call.id)?.policyOutcome === "would_ask_first") {
|
|
114
|
+
const at = new Date();
|
|
115
|
+
record({
|
|
116
|
+
turnId: turn.id,
|
|
117
|
+
parentSpanId: rootId,
|
|
118
|
+
name: `approval ${call.tool}`,
|
|
119
|
+
kind: "gate",
|
|
120
|
+
status: "error",
|
|
121
|
+
startedAt: at,
|
|
122
|
+
endedAt: at,
|
|
123
|
+
attributes: { "stageflow.approval.outcome": "would_ask_first", "gen_ai.tool.name": call.tool },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return decision;
|
|
127
|
+
}
|
|
104
128
|
if (!isToolGranted(definition, call.tool)) {
|
|
105
129
|
return { allow: false, reason: `Tool ${call.tool} is not granted to this agent.` };
|
|
106
130
|
}
|
|
@@ -162,6 +186,8 @@ export class AgentConversation {
|
|
|
162
186
|
toolStarts.set(call.id, new Date());
|
|
163
187
|
},
|
|
164
188
|
toolFinished: (call, result) => {
|
|
189
|
+
if (active.session.source === EVAL_SESSION_SOURCE)
|
|
190
|
+
this.options.evalGates?.get(sessionId)?.observeFinished(call, result);
|
|
165
191
|
const isAgent = call.tool.startsWith("agent:");
|
|
166
192
|
record({
|
|
167
193
|
turnId: turn.id,
|
|
@@ -171,7 +197,11 @@ export class AgentConversation {
|
|
|
171
197
|
status: result.ok ? "ok" : "error",
|
|
172
198
|
startedAt: toolStarts.get(call.id) ?? new Date(),
|
|
173
199
|
endedAt: new Date(),
|
|
174
|
-
attributes: {
|
|
200
|
+
attributes: {
|
|
201
|
+
"gen_ai.tool.name": call.tool,
|
|
202
|
+
...(isEvalSession(active.session) ? { "gen_ai.tool.call.id": call.id } : {}),
|
|
203
|
+
...(childSessionOf(call) ? { "stageflow.sub_agent.session_id": childSessionOf(call) } : {}),
|
|
204
|
+
},
|
|
175
205
|
input: toJson(call.input),
|
|
176
206
|
output: result.output,
|
|
177
207
|
});
|
|
@@ -193,16 +223,26 @@ export class AgentConversation {
|
|
|
193
223
|
},
|
|
194
224
|
});
|
|
195
225
|
},
|
|
196
|
-
delegate: async (agentId, message) => {
|
|
226
|
+
delegate: async (agentId, message, callId) => {
|
|
197
227
|
assertDelegateAllowed(definition, agentId, this.depth);
|
|
198
228
|
const child = new AgentConversation(this.options, this.depth + 1, controller.signal);
|
|
229
|
+
const inEval = isEvalSession(active.session);
|
|
230
|
+
const inherited = { ...service.evalOverridesOf(active.session.id) };
|
|
231
|
+
delete inherited.revision;
|
|
199
232
|
try {
|
|
200
233
|
const detail = await child.send({
|
|
201
234
|
projectRoot: input.projectRoot,
|
|
202
235
|
agentId,
|
|
203
236
|
text: message,
|
|
204
|
-
source: "agent",
|
|
237
|
+
source: inEval ? EVAL_SESSION_SOURCE : "agent",
|
|
205
238
|
author: active.session.agentId,
|
|
239
|
+
...(inEval ? { sourceRef: active.session.id, eval: inherited } : {}),
|
|
240
|
+
onSessionOpened: (childId) => {
|
|
241
|
+
childSessions.set(callId ?? `agent:${agentId}`, childId);
|
|
242
|
+
const parentGate = inEval ? this.options.evalGates?.get(sessionId) : undefined;
|
|
243
|
+
if (parentGate)
|
|
244
|
+
this.options.evalGates.set(childId, parentGate);
|
|
245
|
+
},
|
|
206
246
|
});
|
|
207
247
|
return [...detail.messages].reverse().find((m) => m.role === "assistant")?.text ?? "(no reply)";
|
|
208
248
|
}
|
|
@@ -230,7 +270,7 @@ export class AgentConversation {
|
|
|
230
270
|
const code = isAgentError(error) ? error.code : "agent.backend_failed";
|
|
231
271
|
record({ turnId: turn.id, name: `invoke_agent ${definition.id}`, kind: "agent", status: "error", startedAt, endedAt: new Date(), attributes: { "error.type": code } });
|
|
232
272
|
await service.completeTurn(input.projectRoot, turn.id, { status: "failed", errorCode: code });
|
|
233
|
-
this.exportLive(input.projectRoot, definition, turn.id);
|
|
273
|
+
this.exportLive(input.projectRoot, active.session, definition, turn.id);
|
|
234
274
|
throw error;
|
|
235
275
|
}
|
|
236
276
|
const cancelled = controller.signal.aborted;
|
|
@@ -264,10 +304,10 @@ export class AgentConversation {
|
|
|
264
304
|
errorCode: "agent.guardrail_blocked",
|
|
265
305
|
...(usage ? { usage, costUsd: usage.costUsd } : {}),
|
|
266
306
|
});
|
|
267
|
-
this.exportLive(input.projectRoot, definition, turn.id);
|
|
307
|
+
this.exportLive(input.projectRoot, active.session, definition, turn.id);
|
|
268
308
|
throw new AgentError("agent.guardrail_blocked", `Reply blocked by guardrail ${guard.pattern}`);
|
|
269
309
|
}
|
|
270
|
-
const evalScores = await this.score(input.projectRoot, definition, turn.id, rootId, result, controller.signal, cancelled || stopReason !== undefined);
|
|
310
|
+
const evalScores = await this.score(input.projectRoot, definition, turn.id, rootId, result, controller.signal, cancelled || stopReason !== undefined || isEvalSession(active.session));
|
|
271
311
|
const failed = stopReason !== undefined;
|
|
272
312
|
endRoot(cancelled ? "cancelled" : failed ? "error" : "ok");
|
|
273
313
|
const detail = await service.completeTurn(input.projectRoot, turn.id, {
|
|
@@ -277,7 +317,7 @@ export class AgentConversation {
|
|
|
277
317
|
...(usage ? { usage, costUsd: usage.costUsd } : {}),
|
|
278
318
|
...(evalScores.length > 0 ? { evalScores } : {}),
|
|
279
319
|
});
|
|
280
|
-
this.exportLive(input.projectRoot, definition, turn.id);
|
|
320
|
+
this.exportLive(input.projectRoot, active.session, definition, turn.id);
|
|
281
321
|
return detail;
|
|
282
322
|
}
|
|
283
323
|
async score(projectRoot, definition, turnId, rootId, result, signal, skip) {
|
|
@@ -305,9 +345,9 @@ export class AgentConversation {
|
|
|
305
345
|
}
|
|
306
346
|
}
|
|
307
347
|
/** Best-effort push to the configured OTLP collector; a collector outage never fails a turn. */
|
|
308
|
-
exportLive(projectRoot, definition, turnId) {
|
|
348
|
+
exportLive(projectRoot, session, definition, turnId) {
|
|
309
349
|
const sink = this.options.otlpSink;
|
|
310
|
-
if (!sink || !definition.observability.otlp || definition.observability.capture === "off")
|
|
350
|
+
if (!sink || isEvalSession(session) || !definition.observability.otlp || definition.observability.capture === "off")
|
|
311
351
|
return;
|
|
312
352
|
void (async () => {
|
|
313
353
|
try {
|
package/dist/agents/store.d.ts
CHANGED
|
@@ -149,6 +149,8 @@ export type SessionQuery = {
|
|
|
149
149
|
limit: number;
|
|
150
150
|
/** Opaque cursor from a previous page. */
|
|
151
151
|
cursor?: string;
|
|
152
|
+
/** Eval sessions are hidden unless an internal reader (eval read models, tests) asks for them. */
|
|
153
|
+
includeEval?: boolean;
|
|
152
154
|
};
|
|
153
155
|
export type SessionStats = {
|
|
154
156
|
total: number;
|
|
@@ -204,9 +206,18 @@ export declare class AgentStore {
|
|
|
204
206
|
nextCursor: string | null;
|
|
205
207
|
};
|
|
206
208
|
/** One visitor's sessions on one agent, newest first (public web chat). */
|
|
207
|
-
listSessionsForRef(projectKey: string, agentId: string, source: string, sourceRef: string, limit: number): AgentSession[];
|
|
209
|
+
listSessionsForRef(projectKey: string, agentId: string, source: string, sourceRef: string, limit: number, includeEval?: boolean): AgentSession[];
|
|
208
210
|
/** Stats for one agent, or for every agent when `agentId` is omitted. */
|
|
209
|
-
sessionStats(projectKey: string, agentId: string | undefined, since: string): SessionStats;
|
|
211
|
+
sessionStats(projectKey: string, agentId: string | undefined, since: string, includeEval?: boolean): SessionStats;
|
|
212
|
+
/** Eval sessions below a session or an eval run: those whose `source_ref` is it, and theirs, recursively. */
|
|
213
|
+
listChildSessions(parentId: string): AgentSession[];
|
|
214
|
+
/** Root eval sessions (those pointing at an eval run, not at a parent session), optionally of given runs or older than a time. */
|
|
215
|
+
listEvalRootSessions(filter?: {
|
|
216
|
+
sourceRefs?: string[];
|
|
217
|
+
createdBefore?: string;
|
|
218
|
+
}): AgentSession[];
|
|
219
|
+
/** Delete eval sessions; messages, turns, spans, scores and approvals go with them. Never touches other sessions. */
|
|
220
|
+
deleteSessions(sessionIds: string[]): void;
|
|
210
221
|
/** Ids of every session an agent has had, for releasing what a runtime holds for them. */
|
|
211
222
|
sessionIdsOf(projectKey: string, agentId: string): string[];
|
|
212
223
|
appendMessage(message: Omit<AgentMessage, "seq">): AgentMessage;
|
|
@@ -250,7 +261,7 @@ export declare class AgentStore {
|
|
|
250
261
|
getPendingApproval(sessionId: string): AgentApproval | undefined;
|
|
251
262
|
findApprovalByPayload(sessionId: string, payloadHash: string): AgentApproval | undefined;
|
|
252
263
|
listApprovals(sessionId: string): AgentApproval[];
|
|
253
|
-
listPendingApprovals(projectKey: string): Array<AgentApproval & {
|
|
264
|
+
listPendingApprovals(projectKey: string, includeEval?: boolean): Array<AgentApproval & {
|
|
254
265
|
agentId: string;
|
|
255
266
|
}>;
|
|
256
267
|
decideApproval(approvalId: string, patch: {
|