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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
1
2
|
import { parse as parseYaml } from "yaml";
|
|
2
3
|
import { peekDefaultModel } from "../../models/catalog.js";
|
|
3
4
|
import { validateDraftPackage, } from "../../config/draftPackage.js";
|
|
@@ -157,9 +158,13 @@ export function buildTaskAddProposal(draft, userText) {
|
|
|
157
158
|
affectedStageIds: [],
|
|
158
159
|
};
|
|
159
160
|
}
|
|
161
|
+
const closed = { additionalProperties: false };
|
|
162
|
+
const jsonObject = Type.Record(Type.String(), Type.Unknown());
|
|
163
|
+
const emptyParams = Type.Object({}, closed);
|
|
160
164
|
const readDraftTool = {
|
|
161
165
|
name: "read_draft",
|
|
162
166
|
description: "Read the current Workshop virtual draft package",
|
|
167
|
+
parameters: emptyParams,
|
|
163
168
|
handler(_args, ctx) {
|
|
164
169
|
return {
|
|
165
170
|
ok: true,
|
|
@@ -199,6 +204,18 @@ function coercePlainObject(value) {
|
|
|
199
204
|
const proposeDraftTool = {
|
|
200
205
|
name: "propose_draft",
|
|
201
206
|
description: "Legacy bulk draft replace. Prefer create_*/edit_* tools. Applies immediately (Accept confirms; Reject soft-undos when unchanged).",
|
|
207
|
+
parameters: Type.Union([
|
|
208
|
+
Type.Object({
|
|
209
|
+
draft: jsonObject,
|
|
210
|
+
summary: Type.Optional(Type.String()),
|
|
211
|
+
}, closed),
|
|
212
|
+
Type.Object({
|
|
213
|
+
pipeline: jsonObject,
|
|
214
|
+
stages: Type.Optional(Type.Array(Type.Unknown())),
|
|
215
|
+
task: Type.Optional(jsonObject),
|
|
216
|
+
summary: Type.Optional(Type.String()),
|
|
217
|
+
}, closed),
|
|
218
|
+
]),
|
|
202
219
|
handler(args, ctx) {
|
|
203
220
|
const summary = typeof args.summary === "string" && args.summary.trim()
|
|
204
221
|
? args.summary.trim()
|
|
@@ -244,6 +261,7 @@ const proposeDraftTool = {
|
|
|
244
261
|
const validateDraftTool = {
|
|
245
262
|
name: "validate_draft",
|
|
246
263
|
description: "Run catalog validation against the current draft",
|
|
264
|
+
parameters: emptyParams,
|
|
247
265
|
async handler(_args, ctx) {
|
|
248
266
|
const draft = readDraftFromContext(ctx.getContext());
|
|
249
267
|
const result = await validateDraftPackage(draft, { strict: true });
|
|
@@ -254,6 +272,11 @@ function createRetrieveDocsTool(retriever) {
|
|
|
254
272
|
return {
|
|
255
273
|
name: "retrieve_docs",
|
|
256
274
|
description: "Retrieve current public Stageflow docs/examples snippets by query. Falls back gracefully when retrieval fails — keep using the baked playbook.",
|
|
275
|
+
parameters: Type.Object({
|
|
276
|
+
query: Type.String({ minLength: 1 }),
|
|
277
|
+
kind: Type.Optional(Type.Union([Type.Literal("docs"), Type.Literal("examples"), Type.Literal("any")])),
|
|
278
|
+
limit: Type.Optional(Type.Number()),
|
|
279
|
+
}, closed),
|
|
257
280
|
async handler(args) {
|
|
258
281
|
const query = typeof args.query === "string" && args.query.trim()
|
|
259
282
|
? args.query.trim()
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* guidance and public YAML catalog concepts. First-class Workshop editors
|
|
4
4
|
* cover the core path; advanced topics are explain-only.
|
|
5
5
|
*/
|
|
6
|
-
export declare const WORKSHOP_AUTHOR_PLAYBOOK = "You are the Stageflow Workshop Author: a colleague designing a workflow with the operator. You are not a task runner and not a documentation bot.\n\n## How you talk\n- Sound like a working conversation. Short turns, plain words, present tense.\n- Default length is one to four sentences. No headings, no outlines, no catalog recitation, no multi-step plans unless they ask for a plan or a deeper explanation.\n- One move per turn: reflect what you heard, ask the one question that changes the draft, or make a small edit and say what you assumed.\n- Mirror their words. Refer back to decisions already made. If they correct you, drop the old assumption and continue.\n- Do not narrate tools (\"I'll call create_stage\"). The studio shows the draft. Say what changed in plain language.\n- The reference below is private. Use it when you edit. Do not recite it.\n\n## When you ask, when you edit\n- Clarify before you create when a missing detail would change the stages, the wiring, the goal, or a gate. Do not invent that detail.\n- Ask the single most useful question. Add a second only when both answers block the next edit and they don't depend on each other.\n- Make the question specific (\"Should review block shipping until someone accepts?\") rather than open (\"Tell me more\").\n- Skip questions you can default: names, ordinary linear order, a pipeline model when one is already set. Say the assumption in the same breath as the edit.\n- When the request is already specific, edit. Do not ask permission to do what they just asked.\n- Ask before a second pipeline when one is already open. If the answer is still ambiguous, ask once more.\n- When nothing is selected, create an untitled build and focus it.\n- When the operator names an existing pipeline, focus it rather than create a new one.\n- After an edit, one sentence on what landed, then the next open question if one remains. Do not paste YAML unless they ask to see it.\n\nGood: \"A release that waits for review, or one that publishes as soon as checks pass?\"\nBad: a paragraph of pipeline theory, a numbered plan, and three questions at once.\n\n## Tools\n- Never invent a disk path; never use bash/write/edit.\n- Tools (prefer these): list_builds, focus_build, create_build, create_pipeline / edit_pipeline, create_stage / edit_stage, create_task / edit_task, read_draft, validate_draft, save. propose_draft is legacy bulk replace \u2014 avoid unless the operator asks for a full replace. Do not wait for Accept before mutating; propose\u2192Accept gating is superseded by immediate mutate + soft undo.\n- list_builds returns the same rows as the studio and does not create a build; use catalogListed before telling the operator a pipeline or task appears on Tasks or Pipelines. focus_build moves this chat onto a build id, or onto a disk pipeline by project root and path. create_build persists a new untitled build and focuses it, including when another build is already open. Do not refuse create_build.\n- Build tie (projectRoot + relativePath on a row) is the last saved catalog anchor for that build id \u2014 not every path on disk counts for Tasks (e.g. image package roots or paths outside stageflow.yaml scan). When the operator asks what is on disk for Run/Tasks, cite the last successful save tool result (published.project_root_path, published.pipeline_path, published.task_path) or a catalogListed row. Draft-only task changes are not on disk until save returns task_path.\n- Mutations apply to the in-memory draft immediately (studio updates before Accept). Accept confirms; Reject soft-undos that mutation when the draft fingerprint is unchanged. Soft undo does not reverse a successful save to disk.\n- Chat History/New threads persist under workshop/sessions (transcript + session id + activeBuildId). The draft persists as a build under workshop/builds and is not embedded in the session blob. The studio picker lists open builds and on-disk pipelines.\n- Always read_draft before mutating. Prefer uses: ./id.yaml file-backed stages and Author dialect (io / verify / on_verify_fail, route / entry).\n- Validate with validate_draft; fix hard errors. Warnings like pipeline.model_applies or pipeline.route_all_gated may be intentional.\n- save writes catalog YAML only when the operator asks to persist. If they do not name a folder, omit directory (the host writes workshop/<pipeline-id> and registers that folder so Run lists the pipeline and task). If they name a folder, pass that directory. Do not ask for a path before saving. validate-then-write; allowInvalid only if they explicitly request saving invalid YAML. After save, use published.* paths in the tool result \u2014 not list_builds tie alone \u2014 to answer where files landed and whether a task file was written.\n- Stages are domain-agnostic configurable workflows (releases, research, ops, SDLC, \u2026) \u2014 not product stage types.\n- Use retrieve_docs when the operator asks for current docs/examples or when refining against public guidance. If retrieval fails, continue with this playbook alone.\n- Core path = first-class Workshop editors. Advanced topics below are explain-only \u2014 do not invent Workshop editors for them.\n\n## Core: DAG / linear stages\n- Pipeline needs id + non-empty stages. Set model on pipeline (or stage / stageflow.yaml); empty at all tiers fails load.\n- Wire on the source only: entry: true on \u22651 root; forward route: [{ to }]. Never author needs, fork, top-level feedback_loop, route_select, or allow_none.\n- Linear A\u2192B; fan-out = multiple to: (all run); Join = several parents to: the same child; exclusive branch = mutually exclusive ifs on required payload fields (agent emits a discriminator, not successor ids).\n- if: leaf {field,op,value} or all/any/not; ops eq|ne|gt|gte|lt|lte|in|not_in. Path segments must be required in the producer io.output.schema.\n- on: is skip-cascade policy only (default succeeded); it does not launch from failed/skipped.\n- Consumer io.input \u2286 each parent's io.output. Prefer external stages when shared or larger than a tiny draft.\n\n## Core: prompts\n- Required system_prompt. Last tool call of an attempt is emit_stage_envelope (or ask_operator while waiting on HITL).\n- Optional skill: belongs on the stage body (create_stage / edit_stage body or stage file) \u2014 never on a uses: wrapper.\n- Name required io.output.schema fields in the prompt. summary/payload carry outcomes and artifact pointers only.\n- Land required files with write_stage_artifact (attempt dir). Checkout edits are not after-phase artifact proof.\n- Gated sequence: write artifact \u2192 ask_operator \u2192 emit only after accept; revise on reject in the same attempt.\n- Prefer a configured provider model; siblings after fan-out share a family unless the operator asks otherwise.\n\n## Core: io / verify / on_verify_fail\n- Always author both io.input.schema and io.output.schema (object roots). Success payload is validated on emit.\n- Write Author keys only \u2014 not legacy payload_schema / pre_emit_checks / completion / recovery (those are IR after load).\n- verify lives on the stage body; when: [emit] | [after] | both. Defaults: gate\u2192emit; command/checkout_changes/checklist/payload_schema\u2192after; artifact must set when.\n- Types: gate (+ kind), artifact, command, checklist, payload_schema, checkout_changes (+ path_fields).\n- Emit-phase fail = soft reject (retry same turn). After-phase = verified stage execution hard proof.\n- on_verify_fail on the pipeline entry (beside uses:); needs \u22651 after-phase verify. Prefer repair (idempotent, max_attempts) vs manual (side-effecting publish).\n\n## Core: HITL (ask_operator)\n- gate_kinds omit/[] \u2192 tool off; non-empty allowlist \u2192 tool on (confirm, free_text, artifact_backed, multi_question).\n- Load-bearing gate: body verify type: gate (default emit) \u2014 success emit needs a matching accept / answered exchange.\n- ask_operator does not complete the stage \u2014 only emit_stage_envelope does.\n- artifact_backed paths come from write_stage_artifact (run-relative), not checkout paths.\n\n## Core: artifacts / envelopes\n- Envelope: status, non-empty summary, artifacts (may be []), success payload vs io.output.schema.\n- One advancing emit per attempt. Downstream reads envelopes, not chat. Fan-in Join gets priorEnvelopesByStage.\n- Catalog routing \u2260 agent fork_choice. Rejected: envelope clone_forks.\n\n## Optional task\n- A task (id + goal) may be attached or created for the package; pipeline-only drafts remain valid without one.\n\n## Explain-only (no first-class Workshop editors)\n\n### Clone Chain\nSealed emitter \u2192 clone child \u2192 Join. One named $ref array on the emitter; the child's whole input is that $ref. clone_cap + clone_mode on the emitter pipeline entry only. Empty/over-cap fails emitter emit. Never author clonable, clone_forks, or emit-time skip|once|fanout. Point operators at docs/yaml-catalog Clone Chain and examples/feature-loop.\n\n### Feedback loops\n{ type: loop, to, max_replays, on_max_replays, replay_session } inside source route (forward DAG stays acyclic). Success emit must include envelope feedback_loop: continue | send_back. replay_safe: false blocks replay. Prefer a forward review \u2192 address-feedback \u2192 approve when a separate fix stage is clearer. See examples/feedback-loop.\n\n### Stage MCP\nmcp: [names] on the pipeline entry; project-root .mcp.json; curated stage env interpolation; reserved name stageflow; builtins always available. Validate checks shape/names/PATH; connect/env fail at run. Explain and retrieve docs/examples (e.g. examples/stage-mcp); do not offer a Workshop MCP editor.\n\n### Complex recovery\nBeyond basic repair/manual: operator sf runs recover / MCP recover_manual_stage; after-phase gates/artifacts are history- and disk-aware. Point at verified-stage-execution docs; do not offer Workshop recovery editors.\n\n## Anti-patterns\n- Never needs / fork / top-level feedback_loop \u2192 use route / { type: loop }.\n- Never legacy contract keys \u2192 use io / verify / on_verify_fail.\n- Never omit io or leave model empty at all tiers \u2192 both schemas; pipeline model minimum.\n- Never emit before HITL accept \u2192 verify gate + prompt sequence.\n- Never ambient Host secrets \u2192 stage secrets:.\n- Never clonable / clone_forks \u2192 sealed Clone Chain.\n\nReview-with-blockers: wire review \u2192 address-feedback \u2192 approve/ship; put verdict / blocking_findings in review io.output.schema.\n";
|
|
6
|
+
export declare const WORKSHOP_AUTHOR_PLAYBOOK = "You are the Stageflow Workshop Author: a colleague designing a workflow with the operator. You are not a task runner and not a documentation bot.\n\n## How you talk\n- Sound like a working conversation. Short turns, plain words, present tense.\n- Default length is one to four sentences. No headings, no outlines, no catalog recitation, no multi-step plans unless they ask for a plan or a deeper explanation.\n- One move per turn: reflect what you heard, ask the one question that changes the draft, or make a small edit and say what you assumed.\n- Mirror their words. Refer back to decisions already made. If they correct you, drop the old assumption and continue.\n- Do not narrate tools (\"I'll call create_stage\"). The studio shows the draft. Say what changed in plain language.\n- The reference below is private. Use it when you edit. Do not recite it.\n\n## When you ask, when you edit\n- Clarify before you create when a missing detail would change the stages, the wiring, the goal, or a gate. Do not invent that detail.\n- Ask the single most useful question. Add a second only when both answers block the next edit and they don't depend on each other.\n- Make the question specific (\"Should review block shipping until someone accepts?\") rather than open (\"Tell me more\").\n- Skip questions you can default: names, ordinary linear order, a pipeline model when one is already set. Say the assumption in the same breath as the edit.\n- When the request is already specific, edit. Do not ask permission to do what they just asked.\n- Ask before a second pipeline when one is already open. If the answer is still ambiguous, ask once more.\n- When nothing is selected, create an untitled build and focus it.\n- When the operator names an existing pipeline, focus it rather than create a new one.\n- The pipeline already open in the studio is the one to edit. read_draft returns that draft. Do not ask which pipeline, and do not pick a different row from list_builds.\n- After an edit, one sentence on what landed, then the next open question if one remains. Do not paste YAML unless they ask to see it.\n\nGood: \"A release that waits for review, or one that publishes as soon as checks pass?\"\nBad: a paragraph of pipeline theory, a numbered plan, and three questions at once.\n\n## Tools\n- Never invent a disk path; never use bash/write/edit.\n- Tools (prefer these): list_builds, focus_build, create_build, create_pipeline / edit_pipeline, create_stage / edit_stage, create_task / edit_task, read_draft, validate_draft, save. propose_draft is legacy bulk replace \u2014 avoid unless the operator asks for a full replace. Do not wait for Accept before mutating; propose\u2192Accept gating is superseded by immediate mutate + soft undo.\n- list_builds returns the same rows as the studio and does not create a build; use catalogListed before telling the operator a pipeline or task appears on Tasks or Pipelines. focus_build moves this chat onto a build id, or onto a disk pipeline by project root and path (mid-turn, the mutation pin moves with it). create_build persists a new untitled build only when none is pinned; if a build is already pinned it returns that build. edit_pipeline stages wiring must match existing stage bodies \u2014 use create_stage / edit_stage to add or remove stages.\n- Build tie (projectRoot + relativePath on a row) is the last saved catalog anchor for that build id \u2014 not every path on disk counts for Tasks (e.g. image package roots or paths outside stageflow.yaml scan). When the operator asks what is on disk for Run/Tasks, cite the last successful save tool result (published.project_root_path, published.pipeline_path, published.task_path) or a catalogListed row. Draft-only task changes are not on disk until save returns task_path.\n- Mutations apply to the in-memory draft immediately (studio updates before Accept). Accept confirms; Reject soft-undos that mutation when the draft fingerprint is unchanged. Soft undo does not reverse a successful save to disk.\n- Chat History/New threads persist under workshop/sessions (transcript + session id + activeBuildId). The draft persists as a build under workshop/builds and is not embedded in the session blob. The studio picker lists open builds and on-disk pipelines.\n- Always read_draft before mutating. Prefer uses: ./id.yaml file-backed stages and Author dialect (io / verify / on_verify_fail, route / entry).\n- Validate with validate_draft; fix hard errors. Warnings like pipeline.model_applies or pipeline.route_all_gated may be intentional.\n- save writes catalog YAML only when the operator asks to persist. If they do not name a folder, omit directory (the host writes workshop/<pipeline-id> and registers that folder so Run lists the pipeline and task). If they name a folder, pass that directory. Do not ask for a path before saving. validate-then-write; allowInvalid only if they explicitly request saving invalid YAML. After save, use published.* paths in the tool result \u2014 not list_builds tie alone \u2014 to answer where files landed and whether a task file was written.\n- Stages are domain-agnostic configurable workflows (releases, research, ops, SDLC, \u2026) \u2014 not product stage types.\n- Use retrieve_docs when the operator asks for current docs/examples or when refining against public guidance. If retrieval fails, continue with this playbook alone.\n- Core path = first-class Workshop editors. Advanced topics below are explain-only \u2014 do not invent Workshop editors for them.\n\n## Core: DAG / linear stages\n- Pipeline needs id + non-empty stages. Set model on pipeline (or stage / stageflow.yaml); empty at all tiers fails load.\n- Wire on the source only: entry: true on \u22651 root; forward route: [{ to }]. Never author needs, fork, top-level feedback_loop, route_select, or allow_none.\n- Linear A\u2192B; fan-out = multiple to: (all run); Join = several parents to: the same child; exclusive branch = mutually exclusive ifs on required payload fields (agent emits a discriminator, not successor ids).\n- if: leaf {field,op,value} or all/any/not; ops eq|ne|gt|gte|lt|lte|in|not_in. Path segments must be required in the producer io.output.schema.\n- on: is skip-cascade policy only (default succeeded); it does not launch from failed/skipped.\n- Consumer io.input \u2286 each parent's io.output. Prefer external stages when shared or larger than a tiny draft.\n\n## Core: prompts\n- Required system_prompt. Last tool call of an attempt is emit_stage_envelope (or ask_operator while waiting on HITL).\n- Optional skill: belongs on the stage body (create_stage / edit_stage body or stage file) \u2014 never on a uses: wrapper.\n- Name required io.output.schema fields in the prompt. summary/payload carry outcomes and artifact pointers only.\n- Land required files with write_stage_artifact (attempt dir). Checkout edits are not after-phase artifact proof.\n- Under sandbox: the stage assignment lists each prior file at /workspace/grants/<stage>/\u2026 (that path is the file). Consumer prompts read those paths or payload fields, never stages/<id>/attempts/\u2026/artifacts host paths; /workspace/work is scratch only.\n- Gated sequence: write artifact \u2192 ask_operator \u2192 emit only after accept; revise on reject in the same attempt.\n- Prefer a configured provider model; siblings after fan-out share a family unless the operator asks otherwise.\n\n## Core: io / verify / on_verify_fail\n- Always author both io.input.schema and io.output.schema (object roots). Success payload is validated on emit.\n- Write Author keys only \u2014 not legacy payload_schema / pre_emit_checks / completion / recovery (those are IR after load).\n- verify lives on the stage body; when: [emit] | [after] | both. Defaults: gate\u2192emit; command/checkout_changes/checklist/payload_schema\u2192after; artifact must set when.\n- Types: gate (+ kind), artifact, command, checklist, payload_schema, checkout_changes (+ path_fields).\n- Emit-phase fail = soft reject (retry same turn). After-phase = verified stage execution hard proof.\n- on_verify_fail on the pipeline entry (beside uses:); needs \u22651 after-phase verify. Prefer repair (idempotent, max_attempts) vs manual (side-effecting publish).\n\n## Core: HITL (ask_operator)\n- gate_kinds omit/[] \u2192 tool off; non-empty allowlist \u2192 tool on (confirm, free_text, artifact_backed, multi_question).\n- Load-bearing gate: body verify type: gate (default emit) \u2014 success emit needs a matching accept / answered exchange.\n- ask_operator does not complete the stage \u2014 only emit_stage_envelope does.\n- artifact_backed paths come from write_stage_artifact (run-relative), not checkout paths.\n\n## Core: artifacts / envelopes\n- Artifact contract: durable writes only via write_stage_artifact; emit artifacts[] \u2260 disk until emit disk-truth accepts each listed path under this attempt; empty [] is fine.\n- Facts in payload (required io.output fields). Files via write_stage_artifact then list returned run-relative paths on emit.\n- Sandbox next stage: read the granted file at /workspace/grants/<stage>/\u2026 from the assignment, or payload \u2014 never stages/.../artifacts host paths; never treat /workspace/work as handoff.\n- Do not inject after-phase verify type: artifact on every create_stage; add only when an explicit basename needs hard proof.\n- Envelope: status, non-empty summary, artifacts (may be []), success payload vs io.output.schema.\n- One advancing emit per attempt. Downstream reads envelopes, not chat. Fan-in Join gets priorEnvelopesByStage.\n- Catalog routing \u2260 agent fork_choice. Rejected: envelope clone_forks.\n\n## Optional task\n- A task (id + goal) may be attached or created for the package; pipeline-only drafts remain valid without one.\n\n## Explain-only (no first-class Workshop editors)\n\n### Clone Chain\nSealed emitter \u2192 clone child \u2192 Join. One named $ref array on the emitter; the child's whole input is that $ref. clone_cap + clone_mode on the emitter pipeline entry only. Empty/over-cap fails emitter emit. Never author clonable, clone_forks, or emit-time skip|once|fanout. Point operators at docs/yaml-catalog Clone Chain and examples/feature-loop.\n\n### Feedback loops\n{ type: loop, to, max_replays, on_max_replays, replay_session } inside source route (forward DAG stays acyclic). Success emit must include envelope feedback_loop: continue | send_back. replay_safe: false blocks replay. Prefer a forward review \u2192 address-feedback \u2192 approve when a separate fix stage is clearer. See examples/feedback-loop.\n\n### Stage MCP\nmcp: [names] on the pipeline entry; project-root .mcp.json; curated stage env interpolation; reserved name stageflow; builtins always available. Validate checks shape/names/PATH; connect/env fail at run. Explain and retrieve docs/examples (e.g. examples/stage-mcp); do not offer a Workshop MCP editor.\n\n### Complex recovery\nBeyond basic repair/manual: operator sf runs recover / MCP recover_manual_stage; after-phase gates/artifacts are history- and disk-aware. Point at verified-stage-execution docs; do not offer Workshop recovery editors.\n\n## Anti-patterns\n- Never needs / fork / top-level feedback_loop \u2192 use route / { type: loop }.\n- Never legacy contract keys \u2192 use io / verify / on_verify_fail.\n- Never omit io or leave model empty at all tiers \u2192 both schemas; pipeline model minimum.\n- Never emit before HITL accept \u2192 verify gate + prompt sequence.\n- Never ambient Host secrets \u2192 stage secrets:.\n- Never clonable / clone_forks \u2192 sealed Clone Chain.\n- Never cross-stage handoff via stages/.../artifacts host paths or /workspace/work under sandbox \u2192 write_stage_artifact + grants/payload.\n- Never blanket after-phase artifact verify on every create_stage.\n\nReview-with-blockers: wire review \u2192 address-feedback \u2192 approve/ship; put verdict / blocking_findings in review io.output.schema.\n";
|
|
@@ -22,6 +22,7 @@ export const WORKSHOP_AUTHOR_PLAYBOOK = `You are the Stageflow Workshop Author:
|
|
|
22
22
|
- Ask before a second pipeline when one is already open. If the answer is still ambiguous, ask once more.
|
|
23
23
|
- When nothing is selected, create an untitled build and focus it.
|
|
24
24
|
- When the operator names an existing pipeline, focus it rather than create a new one.
|
|
25
|
+
- The pipeline already open in the studio is the one to edit. read_draft returns that draft. Do not ask which pipeline, and do not pick a different row from list_builds.
|
|
25
26
|
- After an edit, one sentence on what landed, then the next open question if one remains. Do not paste YAML unless they ask to see it.
|
|
26
27
|
|
|
27
28
|
Good: "A release that waits for review, or one that publishes as soon as checks pass?"
|
|
@@ -30,7 +31,7 @@ Bad: a paragraph of pipeline theory, a numbered plan, and three questions at onc
|
|
|
30
31
|
## Tools
|
|
31
32
|
- Never invent a disk path; never use bash/write/edit.
|
|
32
33
|
- Tools (prefer these): list_builds, focus_build, create_build, create_pipeline / edit_pipeline, create_stage / edit_stage, create_task / edit_task, read_draft, validate_draft, save. propose_draft is legacy bulk replace — avoid unless the operator asks for a full replace. Do not wait for Accept before mutating; propose→Accept gating is superseded by immediate mutate + soft undo.
|
|
33
|
-
- list_builds returns the same rows as the studio and does not create a build; use catalogListed before telling the operator a pipeline or task appears on Tasks or Pipelines. focus_build moves this chat onto a build id, or onto a disk pipeline by project root and path. create_build persists a new untitled build
|
|
34
|
+
- list_builds returns the same rows as the studio and does not create a build; use catalogListed before telling the operator a pipeline or task appears on Tasks or Pipelines. focus_build moves this chat onto a build id, or onto a disk pipeline by project root and path (mid-turn, the mutation pin moves with it). create_build persists a new untitled build only when none is pinned; if a build is already pinned it returns that build. edit_pipeline stages wiring must match existing stage bodies — use create_stage / edit_stage to add or remove stages.
|
|
34
35
|
- Build tie (projectRoot + relativePath on a row) is the last saved catalog anchor for that build id — not every path on disk counts for Tasks (e.g. image package roots or paths outside stageflow.yaml scan). When the operator asks what is on disk for Run/Tasks, cite the last successful save tool result (published.project_root_path, published.pipeline_path, published.task_path) or a catalogListed row. Draft-only task changes are not on disk until save returns task_path.
|
|
35
36
|
- Mutations apply to the in-memory draft immediately (studio updates before Accept). Accept confirms; Reject soft-undos that mutation when the draft fingerprint is unchanged. Soft undo does not reverse a successful save to disk.
|
|
36
37
|
- Chat History/New threads persist under workshop/sessions (transcript + session id + activeBuildId). The draft persists as a build under workshop/builds and is not embedded in the session blob. The studio picker lists open builds and on-disk pipelines.
|
|
@@ -54,6 +55,7 @@ Bad: a paragraph of pipeline theory, a numbered plan, and three questions at onc
|
|
|
54
55
|
- Optional skill: belongs on the stage body (create_stage / edit_stage body or stage file) — never on a uses: wrapper.
|
|
55
56
|
- Name required io.output.schema fields in the prompt. summary/payload carry outcomes and artifact pointers only.
|
|
56
57
|
- Land required files with write_stage_artifact (attempt dir). Checkout edits are not after-phase artifact proof.
|
|
58
|
+
- Under sandbox: the stage assignment lists each prior file at /workspace/grants/<stage>/… (that path is the file). Consumer prompts read those paths or payload fields, never stages/<id>/attempts/…/artifacts host paths; /workspace/work is scratch only.
|
|
57
59
|
- Gated sequence: write artifact → ask_operator → emit only after accept; revise on reject in the same attempt.
|
|
58
60
|
- Prefer a configured provider model; siblings after fan-out share a family unless the operator asks otherwise.
|
|
59
61
|
|
|
@@ -72,6 +74,10 @@ Bad: a paragraph of pipeline theory, a numbered plan, and three questions at onc
|
|
|
72
74
|
- artifact_backed paths come from write_stage_artifact (run-relative), not checkout paths.
|
|
73
75
|
|
|
74
76
|
## Core: artifacts / envelopes
|
|
77
|
+
- Artifact contract: durable writes only via write_stage_artifact; emit artifacts[] ≠ disk until emit disk-truth accepts each listed path under this attempt; empty [] is fine.
|
|
78
|
+
- Facts in payload (required io.output fields). Files via write_stage_artifact then list returned run-relative paths on emit.
|
|
79
|
+
- Sandbox next stage: read the granted file at /workspace/grants/<stage>/… from the assignment, or payload — never stages/.../artifacts host paths; never treat /workspace/work as handoff.
|
|
80
|
+
- Do not inject after-phase verify type: artifact on every create_stage; add only when an explicit basename needs hard proof.
|
|
75
81
|
- Envelope: status, non-empty summary, artifacts (may be []), success payload vs io.output.schema.
|
|
76
82
|
- One advancing emit per attempt. Downstream reads envelopes, not chat. Fan-in Join gets priorEnvelopesByStage.
|
|
77
83
|
- Catalog routing ≠ agent fork_choice. Rejected: envelope clone_forks.
|
|
@@ -100,6 +106,8 @@ Beyond basic repair/manual: operator sf runs recover / MCP recover_manual_stage;
|
|
|
100
106
|
- Never emit before HITL accept → verify gate + prompt sequence.
|
|
101
107
|
- Never ambient Host secrets → stage secrets:.
|
|
102
108
|
- Never clonable / clone_forks → sealed Clone Chain.
|
|
109
|
+
- Never cross-stage handoff via stages/.../artifacts host paths or /workspace/work under sandbox → write_stage_artifact + grants/payload.
|
|
110
|
+
- Never blanket after-phase artifact verify on every create_stage.
|
|
103
111
|
|
|
104
112
|
Review-with-blockers: wire review → address-feedback → approve/ship; put verdict / blocking_findings in review io.output.schema.
|
|
105
113
|
`;
|
|
@@ -26,6 +26,8 @@ export declare function buildCreatePipelineDraft(draft: DraftPackage, args: Reco
|
|
|
26
26
|
ok: false;
|
|
27
27
|
error: string;
|
|
28
28
|
};
|
|
29
|
+
/** Refuse stages wiring that diverges from draft.stages bodies (no silent prune). */
|
|
30
|
+
export declare function validateEditPipelineStagesWiring(draft: DraftPackage, nextStages: Array<Record<string, unknown>>): string | null;
|
|
29
31
|
export declare function buildEditPipelineDraft(draft: DraftPackage, args: Record<string, unknown>): {
|
|
30
32
|
ok: true;
|
|
31
33
|
nextDraft: DraftPackage;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { Type } from "typebox";
|
|
2
3
|
import { peekDefaultModel } from "../../models/catalog.js";
|
|
3
4
|
import { parse as parseYaml } from "yaml";
|
|
4
5
|
import { CatalogPathError, resolveDefaultWriteRoot, } from "../../config/catalogRelativePath.js";
|
|
5
6
|
import { defaultWorkshopPackageDirectory } from "../../config/ensureCatalogScanRoot.js";
|
|
7
|
+
import { canonicalizeNeedTerminalState } from "../../config/pipelineNeeds.js";
|
|
6
8
|
import { publishDraftPackage } from "../../config/publishDraftPackage.js";
|
|
7
9
|
import { globalStageflowHome } from "../../project/globalHome.js";
|
|
8
10
|
import { emptyDraftPackage, isWorkshopDraftContext, readDraftFromContext, withDraft, } from "../draftContext.js";
|
|
@@ -34,6 +36,9 @@ export const WORKSHOP_AUTHOR_TOOL_NAMES = [
|
|
|
34
36
|
"retrieve_docs",
|
|
35
37
|
];
|
|
36
38
|
export const WORKSHOP_FORBIDDEN_AGENT_TOOLS = ["bash", "write", "edit"];
|
|
39
|
+
const closed = { additionalProperties: false };
|
|
40
|
+
const jsonObject = Type.Record(Type.String(), Type.Unknown());
|
|
41
|
+
const emptyParams = Type.Object({}, closed);
|
|
37
42
|
const REQUIRED_IO = {
|
|
38
43
|
io: {
|
|
39
44
|
input: { schema: { type: "object" } },
|
|
@@ -82,6 +87,9 @@ function stringArg(args, key) {
|
|
|
82
87
|
const value = args[key];
|
|
83
88
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
84
89
|
}
|
|
90
|
+
function isStringList(value) {
|
|
91
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
92
|
+
}
|
|
85
93
|
function applyMutation(ctx, summary, nextDraft) {
|
|
86
94
|
const current = readDraftFromContext(ctx.getContext());
|
|
87
95
|
const proposal = {
|
|
@@ -174,6 +182,52 @@ async function resolveSaveWriteTarget(ctx, options) {
|
|
|
174
182
|
await store.close();
|
|
175
183
|
}
|
|
176
184
|
}
|
|
185
|
+
function normalizeRouteOnField(on) {
|
|
186
|
+
if (Array.isArray(on)) {
|
|
187
|
+
return on.map((item) => canonicalizeNeedTerminalState(item) ?? item);
|
|
188
|
+
}
|
|
189
|
+
const one = canonicalizeNeedTerminalState(on);
|
|
190
|
+
return one ?? on;
|
|
191
|
+
}
|
|
192
|
+
function normalizeRouteEntries(route) {
|
|
193
|
+
if (!Array.isArray(route))
|
|
194
|
+
return route;
|
|
195
|
+
return route.map((entry) => {
|
|
196
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
197
|
+
return entry;
|
|
198
|
+
const rec = entry;
|
|
199
|
+
if (rec.on === undefined)
|
|
200
|
+
return entry;
|
|
201
|
+
return { ...rec, on: normalizeRouteOnField(rec.on) };
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
function isInlinePipelineStageBody(stage) {
|
|
205
|
+
return stage.system_prompt !== undefined || stage.uses === undefined;
|
|
206
|
+
}
|
|
207
|
+
function normalizePipelineStagesRouteOn(stages, options) {
|
|
208
|
+
const next = stages.map((stage) => {
|
|
209
|
+
if (!stage || typeof stage !== "object")
|
|
210
|
+
return stage;
|
|
211
|
+
let out = { ...stage };
|
|
212
|
+
if (Array.isArray(out.route)) {
|
|
213
|
+
out = {
|
|
214
|
+
...out,
|
|
215
|
+
route: normalizeRouteEntries(out.route),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (isInlinePipelineStageBody(out) && out.io === undefined) {
|
|
219
|
+
out = { ...out, ...REQUIRED_IO };
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
});
|
|
223
|
+
if (options?.ensureEntry &&
|
|
224
|
+
next.length > 0 &&
|
|
225
|
+
!next.some((stage) => stage?.entry === true)) {
|
|
226
|
+
const first = next[0];
|
|
227
|
+
next[0] = { ...first, entry: true };
|
|
228
|
+
}
|
|
229
|
+
return next;
|
|
230
|
+
}
|
|
177
231
|
export function buildCreateStageDraft(draft, args) {
|
|
178
232
|
const existingIds = new Set(draft.pipeline.stages.map((s) => (typeof s.id === "string" ? s.id : "")));
|
|
179
233
|
let stageId = stringArg(args, "id") ??
|
|
@@ -211,7 +265,7 @@ export function buildCreateStageDraft(draft, args) {
|
|
|
211
265
|
...(entry ? { entry: true } : {}),
|
|
212
266
|
};
|
|
213
267
|
if (Array.isArray(args.route)) {
|
|
214
|
-
pipelineEntry.route = args.route;
|
|
268
|
+
pipelineEntry.route = normalizeRouteEntries(args.route);
|
|
215
269
|
}
|
|
216
270
|
const nextDraft = {
|
|
217
271
|
...draft,
|
|
@@ -244,7 +298,7 @@ export function buildEditStageDraft(draft, args) {
|
|
|
244
298
|
if (typeof args.entry === "boolean")
|
|
245
299
|
next.entry = args.entry;
|
|
246
300
|
if (Array.isArray(args.route))
|
|
247
|
-
next.route = args.route;
|
|
301
|
+
next.route = normalizeRouteEntries(args.route);
|
|
248
302
|
if (stringArg(args, "uses"))
|
|
249
303
|
next.uses = stringArg(args, "uses");
|
|
250
304
|
return next;
|
|
@@ -317,7 +371,16 @@ export function buildCreatePipelineDraft(draft, args) {
|
|
|
317
371
|
ok: true,
|
|
318
372
|
nextDraft: {
|
|
319
373
|
...draft,
|
|
320
|
-
pipeline: {
|
|
374
|
+
pipeline: {
|
|
375
|
+
...pipeline,
|
|
376
|
+
id: pipeline.id.trim(),
|
|
377
|
+
model: typeof pipeline.model === "string" && pipeline.model.trim()
|
|
378
|
+
? pipeline.model
|
|
379
|
+
: stringArg(args, "model") ?? peekDefaultModel(),
|
|
380
|
+
stages: normalizePipelineStagesRouteOn(pipeline.stages, {
|
|
381
|
+
ensureEntry: true,
|
|
382
|
+
}),
|
|
383
|
+
},
|
|
321
384
|
...(Array.isArray(args.stages)
|
|
322
385
|
? { stages: args.stages }
|
|
323
386
|
: {}),
|
|
@@ -331,15 +394,51 @@ export function buildCreatePipelineDraft(draft, args) {
|
|
|
331
394
|
pipeline: {
|
|
332
395
|
...draft.pipeline,
|
|
333
396
|
id,
|
|
334
|
-
|
|
397
|
+
model: stringArg(args, "model") ?? peekDefaultModel(),
|
|
335
398
|
...(args.agent !== undefined ? { agent: args.agent } : {}),
|
|
336
399
|
...(Array.isArray(args.stages)
|
|
337
|
-
? {
|
|
400
|
+
? {
|
|
401
|
+
stages: normalizePipelineStagesRouteOn(args.stages, { ensureEntry: true }),
|
|
402
|
+
}
|
|
338
403
|
: {}),
|
|
339
404
|
},
|
|
340
405
|
},
|
|
341
406
|
};
|
|
342
407
|
}
|
|
408
|
+
function normalizeDraftStagePath(stagePath) {
|
|
409
|
+
return stagePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
410
|
+
}
|
|
411
|
+
function stageWiringMatchesArtifact(stage, artifact) {
|
|
412
|
+
const id = typeof stage.id === "string" ? stage.id : "";
|
|
413
|
+
const uses = typeof stage.uses === "string" ? stage.uses : "";
|
|
414
|
+
const bodyId = typeof artifact.body.id === "string" ? artifact.body.id : "";
|
|
415
|
+
return ((uses.length > 0 &&
|
|
416
|
+
normalizeDraftStagePath(artifact.path) ===
|
|
417
|
+
normalizeDraftStagePath(uses)) ||
|
|
418
|
+
(id.length > 0 && bodyId === id));
|
|
419
|
+
}
|
|
420
|
+
/** Refuse stages wiring that diverges from draft.stages bodies (no silent prune). */
|
|
421
|
+
export function validateEditPipelineStagesWiring(draft, nextStages) {
|
|
422
|
+
const artifacts = draft.stages ?? [];
|
|
423
|
+
for (const stage of nextStages) {
|
|
424
|
+
const matched = artifacts.some((artifact) => stageWiringMatchesArtifact(stage, artifact));
|
|
425
|
+
if (!matched) {
|
|
426
|
+
const label = (typeof stage.id === "string" && stage.id) ||
|
|
427
|
+
(typeof stage.uses === "string" && stage.uses) ||
|
|
428
|
+
"(unnamed)";
|
|
429
|
+
return `edit_pipeline stages wiring references "${label}" without a matching stage body — use create_stage / edit_stage to add or change stage files`;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
for (const artifact of artifacts) {
|
|
433
|
+
const stillWired = nextStages.some((stage) => stageWiringMatchesArtifact(stage, artifact));
|
|
434
|
+
if (!stillWired) {
|
|
435
|
+
const label = (typeof artifact.body.id === "string" && artifact.body.id) ||
|
|
436
|
+
artifact.path;
|
|
437
|
+
return `edit_pipeline stages wiring drops stage body "${label}" — use create_stage / edit_stage to change stage files; wiring-only remove is refused`;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
343
442
|
export function buildEditPipelineDraft(draft, args) {
|
|
344
443
|
const patch = isPlainObject(args.patch) ? args.patch : args;
|
|
345
444
|
const nextPipeline = {
|
|
@@ -352,12 +451,30 @@ export function buildEditPipelineDraft(draft, args) {
|
|
|
352
451
|
if (patch.agent !== undefined)
|
|
353
452
|
nextPipeline.agent = patch.agent;
|
|
354
453
|
if (Array.isArray(patch.stages)) {
|
|
355
|
-
|
|
454
|
+
const nextStages = normalizePipelineStagesRouteOn(patch.stages);
|
|
455
|
+
const wiringError = validateEditPipelineStagesWiring(draft, nextStages);
|
|
456
|
+
if (wiringError)
|
|
457
|
+
return { ok: false, error: wiringError };
|
|
458
|
+
nextPipeline.stages = nextStages;
|
|
356
459
|
}
|
|
357
460
|
if (patch.schemas !== undefined)
|
|
358
461
|
nextPipeline.schemas = patch.schemas;
|
|
359
462
|
if (patch.requires !== undefined)
|
|
360
463
|
nextPipeline.requires = patch.requires;
|
|
464
|
+
if (isStringList(patch.memories)) {
|
|
465
|
+
if (patch.memories.length === 0)
|
|
466
|
+
delete nextPipeline.memories;
|
|
467
|
+
else
|
|
468
|
+
nextPipeline.memories = patch.memories;
|
|
469
|
+
}
|
|
470
|
+
if (patch.channels !== undefined) {
|
|
471
|
+
if (Array.isArray(patch.channels) && patch.channels.length === 0) {
|
|
472
|
+
delete nextPipeline.channels;
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
nextPipeline.channels = patch.channels;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
361
478
|
return {
|
|
362
479
|
ok: true,
|
|
363
480
|
nextDraft: { ...draft, pipeline: nextPipeline },
|
|
@@ -428,6 +545,7 @@ export function createWorkshopBuildTools() {
|
|
|
428
545
|
const listBuildsTool = {
|
|
429
546
|
name: "list_builds",
|
|
430
547
|
description: "List the same workshop rows as the studio picker (open builds and unbound disk pipelines). Each row includes catalogListed (whether Tasks/Pipelines would list that pipeline path). Does not create a build. Works when no build is focused.",
|
|
548
|
+
parameters: emptyParams,
|
|
431
549
|
async handler(_args, ctx) {
|
|
432
550
|
const live = liveWorkshopBinding(ctx);
|
|
433
551
|
if (!live) {
|
|
@@ -458,7 +576,14 @@ export function createWorkshopBuildTools() {
|
|
|
458
576
|
};
|
|
459
577
|
const focusBuildTool = {
|
|
460
578
|
name: "focus_build",
|
|
461
|
-
description: "Move this chat onto a build by id, or onto an unbound disk pipeline by projectRoot and relativePath. A failed open returns the error, creates nothing, and leaves the pointer unchanged.",
|
|
579
|
+
description: "Move this chat onto a build by id, or onto an unbound disk pipeline by projectRoot and relativePath. Mid-turn, the mutation pin moves with the focus so studio and draft tools stay on the same build. A failed open returns the error, creates nothing, and leaves the pointer unchanged.",
|
|
580
|
+
parameters: Type.Union([
|
|
581
|
+
Type.Object({ id: Type.String({ minLength: 1 }) }, closed),
|
|
582
|
+
Type.Object({
|
|
583
|
+
projectRoot: Type.String({ minLength: 1 }),
|
|
584
|
+
relativePath: Type.String({ minLength: 1 }),
|
|
585
|
+
}, closed),
|
|
586
|
+
]),
|
|
462
587
|
async handler(args, ctx) {
|
|
463
588
|
const live = liveWorkshopBinding(ctx);
|
|
464
589
|
if (!live) {
|
|
@@ -530,7 +655,8 @@ export function createWorkshopBuildTools() {
|
|
|
530
655
|
};
|
|
531
656
|
const createBuildTool = {
|
|
532
657
|
name: "create_build",
|
|
533
|
-
description: "Persist a new untitled build and focus it
|
|
658
|
+
description: "Persist a new untitled build and focus it when none is pinned. When a build is already pinned, returns that build without creating another. No build id argument.",
|
|
659
|
+
parameters: emptyParams,
|
|
534
660
|
async handler(_args, ctx) {
|
|
535
661
|
const live = liveWorkshopBinding(ctx);
|
|
536
662
|
if (!live) {
|
|
@@ -551,6 +677,13 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
551
677
|
const createPipelineTool = {
|
|
552
678
|
name: "create_pipeline",
|
|
553
679
|
description: "Create or replace the draft pipeline (id, optional model/stages). Mutates the in-memory draft immediately.",
|
|
680
|
+
parameters: Type.Object({
|
|
681
|
+
id: Type.String({ minLength: 1 }),
|
|
682
|
+
model: Type.Optional(Type.String()),
|
|
683
|
+
agent: Type.Optional(Type.Unknown()),
|
|
684
|
+
stages: Type.Optional(Type.Array(jsonObject)),
|
|
685
|
+
pipeline: Type.Optional(jsonObject),
|
|
686
|
+
}, closed),
|
|
554
687
|
handler(args, ctx) {
|
|
555
688
|
const built = buildCreatePipelineDraft(readDraftFromContext(ctx.getContext()), args);
|
|
556
689
|
if (!built.ok)
|
|
@@ -561,7 +694,18 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
561
694
|
};
|
|
562
695
|
const editPipelineTool = {
|
|
563
696
|
name: "edit_pipeline",
|
|
564
|
-
description: "Edit pipeline fields on the current draft (id, model, stages wiring, etc.). Mutates immediately.",
|
|
697
|
+
description: "Edit pipeline fields on the current draft (id, model, stages wiring, etc.). Stages wiring must match existing stage bodies — use create_stage / edit_stage to add or remove stages. Mutates immediately.",
|
|
698
|
+
parameters: Type.Object({
|
|
699
|
+
id: Type.Optional(Type.String()),
|
|
700
|
+
model: Type.Optional(Type.String()),
|
|
701
|
+
agent: Type.Optional(Type.Unknown()),
|
|
702
|
+
stages: Type.Optional(Type.Array(jsonObject)),
|
|
703
|
+
schemas: Type.Optional(Type.Unknown()),
|
|
704
|
+
requires: Type.Optional(Type.Unknown()),
|
|
705
|
+
memories: Type.Optional(Type.Array(Type.String())),
|
|
706
|
+
channels: Type.Optional(Type.Unknown()),
|
|
707
|
+
patch: Type.Optional(jsonObject),
|
|
708
|
+
}, closed),
|
|
565
709
|
handler(args, ctx) {
|
|
566
710
|
const built = buildEditPipelineDraft(readDraftFromContext(ctx.getContext()), args);
|
|
567
711
|
if (!built.ok)
|
|
@@ -573,6 +717,18 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
573
717
|
const createStageTool = {
|
|
574
718
|
name: "create_stage",
|
|
575
719
|
description: "Add a file-backed stage to the draft (uses: ./id.yaml + stage body with io). Mutates immediately; Accept confirms, Reject soft-undos.",
|
|
720
|
+
parameters: Type.Object({
|
|
721
|
+
id: Type.Optional(Type.String()),
|
|
722
|
+
summary: Type.Optional(Type.String()),
|
|
723
|
+
label: Type.Optional(Type.String()),
|
|
724
|
+
uses: Type.Optional(Type.String()),
|
|
725
|
+
body: Type.Optional(jsonObject),
|
|
726
|
+
system_prompt: Type.Optional(Type.String()),
|
|
727
|
+
model: Type.Optional(Type.String()),
|
|
728
|
+
io: Type.Optional(jsonObject),
|
|
729
|
+
entry: Type.Optional(Type.Boolean()),
|
|
730
|
+
route: Type.Optional(Type.Array(Type.Unknown())),
|
|
731
|
+
}, closed),
|
|
576
732
|
handler(args, ctx) {
|
|
577
733
|
const built = buildCreateStageDraft(readDraftFromContext(ctx.getContext()), args);
|
|
578
734
|
if (!built.ok)
|
|
@@ -584,6 +740,18 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
584
740
|
const editStageTool = {
|
|
585
741
|
name: "edit_stage",
|
|
586
742
|
description: "Edit an existing draft stage by id (body fields and/or pipeline entry route/entry/uses). Mutates immediately.",
|
|
743
|
+
parameters: Type.Object({
|
|
744
|
+
id: Type.String({ minLength: 1 }),
|
|
745
|
+
patch: Type.Optional(jsonObject),
|
|
746
|
+
body: Type.Optional(jsonObject),
|
|
747
|
+
pipeline_entry: Type.Optional(jsonObject),
|
|
748
|
+
entry: Type.Optional(Type.Boolean()),
|
|
749
|
+
route: Type.Optional(Type.Array(Type.Unknown())),
|
|
750
|
+
uses: Type.Optional(Type.String()),
|
|
751
|
+
system_prompt: Type.Optional(Type.String()),
|
|
752
|
+
model: Type.Optional(Type.String()),
|
|
753
|
+
io: Type.Optional(jsonObject),
|
|
754
|
+
}, closed),
|
|
587
755
|
handler(args, ctx) {
|
|
588
756
|
const built = buildEditStageDraft(readDraftFromContext(ctx.getContext()), args);
|
|
589
757
|
if (!built.ok)
|
|
@@ -595,6 +763,13 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
595
763
|
const createTaskTool = {
|
|
596
764
|
name: "create_task",
|
|
597
765
|
description: "Create or replace the optional task (id + goal) on the draft. Mutates immediately.",
|
|
766
|
+
parameters: Type.Object({
|
|
767
|
+
id: Type.Optional(Type.String()),
|
|
768
|
+
goal: Type.Optional(Type.String()),
|
|
769
|
+
summary: Type.Optional(Type.String()),
|
|
770
|
+
filename: Type.Optional(Type.String()),
|
|
771
|
+
body: Type.Optional(jsonObject),
|
|
772
|
+
}, closed),
|
|
598
773
|
handler(args, ctx) {
|
|
599
774
|
const built = buildCreateTaskDraft(readDraftFromContext(ctx.getContext()), args);
|
|
600
775
|
if (!built.ok)
|
|
@@ -606,6 +781,13 @@ export function createWorkshopAuthorMutatingTools() {
|
|
|
606
781
|
const editTaskTool = {
|
|
607
782
|
name: "edit_task",
|
|
608
783
|
description: "Edit the draft task fields (id, goal, body). Mutates immediately.",
|
|
784
|
+
parameters: Type.Object({
|
|
785
|
+
id: Type.Optional(Type.String()),
|
|
786
|
+
goal: Type.Optional(Type.String()),
|
|
787
|
+
filename: Type.Optional(Type.String()),
|
|
788
|
+
patch: Type.Optional(jsonObject),
|
|
789
|
+
body: Type.Optional(jsonObject),
|
|
790
|
+
}, closed),
|
|
609
791
|
handler(args, ctx) {
|
|
610
792
|
const built = buildEditTaskDraft(readDraftFromContext(ctx.getContext()), args);
|
|
611
793
|
if (!built.ok)
|
|
@@ -627,6 +809,12 @@ export function createSaveTool(options = {}) {
|
|
|
627
809
|
return {
|
|
628
810
|
name: "save",
|
|
629
811
|
description: "Validate-then-write the draft via catalog facades (createDraftPackage / overwriteDraftPackage). When directory is omitted, writes under workshop/<pipeline-id> on registered catalogs (or <pipeline-id> on the workspace catalog). The host adds registered workshop paths to stageflow.yaml so Run can see them. Pass directory only when the operator names a folder. Soft undo does not reverse disk. Prefer mode auto; set allowInvalid only when the operator explicitly requests saving invalid YAML. Do not pass projectRoot — the host binds it.",
|
|
812
|
+
parameters: Type.Object({
|
|
813
|
+
directory: Type.Optional(Type.String()),
|
|
814
|
+
pipelineFilename: Type.Optional(Type.String()),
|
|
815
|
+
mode: Type.Optional(Type.Union([Type.Literal("auto"), Type.Literal("create"), Type.Literal("overwrite")])),
|
|
816
|
+
allowInvalid: Type.Optional(Type.Boolean()),
|
|
817
|
+
}, closed),
|
|
630
818
|
async handler(args, ctx) {
|
|
631
819
|
const writeTarget = await resolveSaveWriteTarget(ctx, options);
|
|
632
820
|
if (!writeTarget.ok) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { TSchema } from "typebox";
|
|
1
2
|
import type { DraftPackage } from "../config/draftPackage.js";
|
|
2
3
|
import type { ValidationResult } from "../config/validateCatalog.js";
|
|
3
4
|
import type { AcceptProposalResult, ProposalArtifactDiff, UndoMutationResult } from "./proposals.js";
|
|
@@ -10,6 +11,7 @@ export type OperatorAgentToolHandler = (args: Record<string, unknown>, ctx: Oper
|
|
|
10
11
|
export type OperatorAgentTool = {
|
|
11
12
|
name: string;
|
|
12
13
|
description: string;
|
|
14
|
+
parameters: TSchema;
|
|
13
15
|
handler: OperatorAgentToolHandler;
|
|
14
16
|
};
|
|
15
17
|
export type OperatorAgentToolContext = {
|
|
@@ -17,6 +19,14 @@ export type OperatorAgentToolContext = {
|
|
|
17
19
|
setContext(next: unknown): void;
|
|
18
20
|
/** Apply mutation immediately and record an undo receipt. */
|
|
19
21
|
emitProposal(proposal: OperatorAgentProposal): void;
|
|
22
|
+
/**
|
|
23
|
+
* Set only on an eval session. Returning a result skips the tool handler.
|
|
24
|
+
* Returning null lets the handler run. Absent on Workshop, author and Guide sessions.
|
|
25
|
+
*/
|
|
26
|
+
evalGate?: {
|
|
27
|
+
decide(name: string, args: Record<string, unknown>): OperatorAgentToolResult | null;
|
|
28
|
+
observe(name: string, result: OperatorAgentToolResult): void;
|
|
29
|
+
};
|
|
20
30
|
};
|
|
21
31
|
export type OperatorAgentProposal = {
|
|
22
32
|
/** Mutation id (Accept confirms; Reject / undoMutation soft-undos). */
|
|
@@ -72,6 +82,10 @@ export type WorkshopToolActivityUpdate = {
|
|
|
72
82
|
draft?: DraftPackage;
|
|
73
83
|
/** Build the turn is editing. Absent when the chat is unlinked. */
|
|
74
84
|
buildId?: string;
|
|
85
|
+
/** Tool arguments, on `running`. */
|
|
86
|
+
args?: Record<string, unknown>;
|
|
87
|
+
/** Tool result `content`, on `complete`. */
|
|
88
|
+
result?: unknown;
|
|
75
89
|
};
|
|
76
90
|
export type OperatorAgentSession = {
|
|
77
91
|
readonly profileId: string;
|
|
@@ -111,6 +125,15 @@ export type OperatorAgentHost = {
|
|
|
111
125
|
profileId: string;
|
|
112
126
|
context: unknown;
|
|
113
127
|
}): OperatorAgentSession;
|
|
128
|
+
/**
|
|
129
|
+
* A session whose tools pass through `gate` before they run. The gate is required:
|
|
130
|
+
* an eval session with no gate is refused.
|
|
131
|
+
*/
|
|
132
|
+
openEvalSession(input: {
|
|
133
|
+
profileId: string;
|
|
134
|
+
context: unknown;
|
|
135
|
+
gate: NonNullable<OperatorAgentToolContext["evalGate"]>;
|
|
136
|
+
}): OperatorAgentSession;
|
|
114
137
|
};
|
|
115
138
|
export type WorkshopDraftContext = {
|
|
116
139
|
draft: DraftPackage;
|
package/dist/package-meta.d.ts
CHANGED
package/dist/package-meta.js
CHANGED
package/dist/runstore/port.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { CompletionCheck } from "../types/completion.js";
|
|
|
9
9
|
import type { StageGateKind } from "../types/stage.js";
|
|
10
10
|
import type { StageUsage } from "../types/usage.js";
|
|
11
11
|
import type { OverviewRunRow } from "./overviewSummary.js";
|
|
12
|
-
import type { CreateEvalRunInput, EvalCaseInput, EvalCaseRow, EvalGraderVersionInput, EvalResultInput, EvalResultWithGrades, EvalReviewPatch, EvalReviewRow, EvalRunPage, EvalRunProgress, EvalRunRow, FinishEvalRunInput, ListEvalRunsQuery } from "../evals/storeTypes.js";
|
|
12
|
+
import type { CreateEvalRunInput, EvalCaseInput, EvalCaseRow, EvalGraderVersionInput, EvalResultInput, EvalResultWithGrades, EvalReviewPatch, EvalCalibrationInput, EvalCalibrationRow, EvalGraderLabelPatch, EvalGraderLabelRow, EvalReviewRow, EvalRunPage, EvalRunProgress, EvalRunRow, FinishEvalRunInput, ListEvalRunsQuery } from "../evals/storeTypes.js";
|
|
13
13
|
import type { SuggestionStatus } from "../evals/triage/constants.js";
|
|
14
14
|
import type { SuggestionInput, SuggestionRow } from "../evals/triage/types.js";
|
|
15
15
|
export type { ConfigOriginRecord };
|
|
@@ -491,6 +491,18 @@ export interface RunStore {
|
|
|
491
491
|
/** `tags` replaces the tag set and is accepted only for results with `passed = 0`. */
|
|
492
492
|
putEvalReview(evalRunId: string, caseId: string, repeatIndex: number, patch: EvalReviewPatch): Promise<EvalReviewRow>;
|
|
493
493
|
getEvalReviews(evalRunId: string): Promise<EvalReviewRow[]>;
|
|
494
|
+
/** `label: null` clears. Rejects a result that does not exist. */
|
|
495
|
+
putEvalGraderLabel(evalRunId: string, caseId: string, repeatIndex: number, graderId: string, patch: EvalGraderLabelPatch): Promise<EvalGraderLabelRow | null>;
|
|
496
|
+
listEvalGraderLabels(evalRunId: string): Promise<EvalGraderLabelRow[]>;
|
|
497
|
+
/** Which results a grader graded in a run, keys only. */
|
|
498
|
+
listGradedResultKeys(evalRunId: string, graderId: string): Promise<Array<{
|
|
499
|
+
caseId: string;
|
|
500
|
+
repeatIndex: number;
|
|
501
|
+
}>>;
|
|
502
|
+
/** Across all runs of the eval, newest label first. */
|
|
503
|
+
listEvalGraderLabelsForEval(projectRoot: string, evalId: string, graderId: string): Promise<EvalGraderLabelRow[]>;
|
|
504
|
+
insertEvalCalibration(input: EvalCalibrationInput): Promise<EvalCalibrationRow>;
|
|
505
|
+
listEvalCalibrations(projectRoot: string, evalId: string, graderId?: string, includeCandidates?: boolean, limit?: number): Promise<EvalCalibrationRow[]>;
|
|
494
506
|
/** The eval's failure-type vocabulary, most recently used first. */
|
|
495
507
|
listFailureTypes(projectRoot: string, evalId: string): Promise<string[]>;
|
|
496
508
|
/** Inserts unseen grader hashes with the next ordinal per grader id; returns grader id to ordinal. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RunMeta, RunStatus } from "./port.js";
|
|
2
|
+
import { type RunClockTerminalStatus } from "./runStatusClock.js";
|
|
2
3
|
export type RetentionDecision = "none" | "slim" | "purge";
|
|
3
4
|
export type StatusRetentionWindow = {
|
|
4
5
|
slimMs: number;
|
|
@@ -24,4 +25,4 @@ export declare function slimArtifactMaxBytesFromEnv(env?: NodeJS.ProcessEnv): nu
|
|
|
24
25
|
* Already-slimmed rows past SLIM but not PURGE return `"none"` (R18).
|
|
25
26
|
*/
|
|
26
27
|
export declare function retentionDecision(row: RetentionRow, now: Date, windows?: RetentionWindows): RetentionDecision;
|
|
27
|
-
export declare function isTerminalRunStatus(status: RunStatus | undefined): status is
|
|
28
|
+
export declare function isTerminalRunStatus(status: RunStatus | undefined): status is RunClockTerminalStatus;
|