stageflow 0.42.0 → 0.44.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/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/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.js +21 -3
- 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 +43 -2
- 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/constants.d.ts +3 -1
- package/dist/evals/constants.js +3 -1
- package/dist/evals/engine/FakeEngine.d.ts +1 -1
- package/dist/evals/engine/FakeEngine.js +2 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
- package/dist/evals/engine/promptfoo/PromptfooEngine.js +2 -1
- package/dist/evals/engine/promptfoo/generate.d.ts +1 -1
- package/dist/evals/engine/promptfoo/generate.js +11 -8
- package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +1 -1
- package/dist/evals/engine/promptfoo/rubricPrompt.js +5 -3
- package/dist/evals/manager.d.ts +13 -0
- package/dist/evals/manager.js +10 -2
- package/dist/evals/plan.d.ts +8 -1
- package/dist/evals/plan.js +28 -9
- package/dist/evals/planInternalAgent.d.ts +19 -0
- package/dist/evals/planInternalAgent.js +205 -0
- package/dist/evals/read/api.d.ts +12 -0
- package/dist/evals/read/api.js +5 -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/types.d.ts +12 -2
- package/dist/evals/types.js +4 -1
- 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 +684 -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 +132 -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/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 +1 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +45 -45
- 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 +38 -9
- 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 +39 -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-S5C_vemc.js} +2 -2
- package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
- package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
- package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
- package/dist/ui/assets/{main-CHlmTNJe.css → main-Del1GeLf.css} +1 -1
- package/dist/ui/assets/main-_yXVqcW9.js +277 -0
- 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/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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contracts for Stageflow's built-in compaction (docs/plans/compaction-strategy.md).
|
|
3
|
+
* Pure data types only: the layers (mask, pin, state, summary, guards) import from here.
|
|
4
|
+
*/
|
|
5
|
+
export type PinnedFactKind = "id" | "number" | "timestamp" | "url" | "path" | "error" | "other";
|
|
6
|
+
/** A value copied verbatim out of a message so a summary cannot lose or reword it. */
|
|
7
|
+
export type PinnedFact = {
|
|
8
|
+
kind: PinnedFactKind;
|
|
9
|
+
/** The exact text, e.g. "INC-4471", "48211", "2026-03-14T05:52:03Z". */
|
|
10
|
+
value: string;
|
|
11
|
+
/** A short verbatim snippet around the value (single line, capped), for orientation. */
|
|
12
|
+
context: string;
|
|
13
|
+
/** Position in the message list the facts were extracted from, and the tool when from a tool result. */
|
|
14
|
+
source: {
|
|
15
|
+
messageIndex: number;
|
|
16
|
+
toolName?: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
/** A tool result replaced by a placeholder in the model's context. */
|
|
20
|
+
export type ClearedResult = {
|
|
21
|
+
toolName: string;
|
|
22
|
+
toolCallId: string;
|
|
23
|
+
/** Where the full output can be read again (a file path or a tool + args hint). */
|
|
24
|
+
recoverHint: string;
|
|
25
|
+
bytes: number;
|
|
26
|
+
/** One line describing what the result was, for the recovery index. */
|
|
27
|
+
descriptor: string;
|
|
28
|
+
};
|
|
29
|
+
export type WorkingStateKind = "fact" | "decision" | "progress" | "todo" | "blocker";
|
|
30
|
+
/** One keyed entry in the model's working state (the `working_state` tool). */
|
|
31
|
+
export type WorkingStateEntry = {
|
|
32
|
+
key: string;
|
|
33
|
+
kind: WorkingStateKind;
|
|
34
|
+
value: string;
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
};
|
|
37
|
+
export declare const WORKING_STATE_TOOL_NAME = "working_state";
|
|
38
|
+
/** Everything the compaction summary is built from, besides the model-written part. */
|
|
39
|
+
export type CompactionSections = {
|
|
40
|
+
pinned: readonly PinnedFact[];
|
|
41
|
+
cleared: readonly ClearedResult[];
|
|
42
|
+
state: readonly WorkingStateEntry[];
|
|
43
|
+
};
|
|
44
|
+
/** Bumped whenever the focus prompt or section layout changes (like RUBRIC_PROMPT_VERSION). */
|
|
45
|
+
export declare const COMPACTION_PROMPT_VERSION = 1;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared contracts for Stageflow's built-in compaction (docs/plans/compaction-strategy.md).
|
|
3
|
+
* Pure data types only: the layers (mask, pin, state, summary, guards) import from here.
|
|
4
|
+
*/
|
|
5
|
+
export const WORKING_STATE_TOOL_NAME = "working_state";
|
|
6
|
+
/** Bumped whenever the focus prompt or section layout changes (like RUBRIC_PROMPT_VERSION). */
|
|
7
|
+
export const COMPACTION_PROMPT_VERSION = 1;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { WorkingStateEntry, WorkingStateKind } from "./types.js";
|
|
2
|
+
export declare const WORKING_STATE_CUSTOM_TYPE = "stageflow.working_state";
|
|
3
|
+
export declare const WORKING_STATE_KINDS: readonly WorkingStateKind[];
|
|
4
|
+
export declare const WORKING_STATE_MAX_KEY = 80;
|
|
5
|
+
export declare const WORKING_STATE_MAX_VALUE = 600;
|
|
6
|
+
export declare const WORKING_STATE_MAX_ENTRIES = 60;
|
|
7
|
+
export declare const WORKING_STATE_DEFAULT_RENDER_CHARS = 6000;
|
|
8
|
+
export declare const WORKING_STATE_GUIDANCE = "Older messages and tool results are trimmed automatically as the conversation grows, so keep your own working state with the working_state tool. As soon as you learn or decide something you will need later, record it: exact values and identifiers (fact), choices and their reasons (decision), what is done (progress), what remains (todo) and what is stuck (blocker). Keep each entry to one or two short lines, update an existing key instead of adding a duplicate, and delete entries that no longer matter. Never store secrets or credentials in it.";
|
|
9
|
+
export type WorkingStateEvent = {
|
|
10
|
+
op: "set";
|
|
11
|
+
key: string;
|
|
12
|
+
kind: WorkingStateKind;
|
|
13
|
+
value: string;
|
|
14
|
+
at: string;
|
|
15
|
+
} | {
|
|
16
|
+
op: "delete";
|
|
17
|
+
key: string;
|
|
18
|
+
at: string;
|
|
19
|
+
};
|
|
20
|
+
export type WorkingStateSetResult = {
|
|
21
|
+
ok: true;
|
|
22
|
+
dropped: string[];
|
|
23
|
+
replaced: boolean;
|
|
24
|
+
redacted: boolean;
|
|
25
|
+
entry: WorkingStateEntry;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
error: string;
|
|
29
|
+
};
|
|
30
|
+
export type WorkingStateInput = {
|
|
31
|
+
key: string;
|
|
32
|
+
kind: WorkingStateKind;
|
|
33
|
+
value: string;
|
|
34
|
+
updatedAt?: string;
|
|
35
|
+
};
|
|
36
|
+
export declare class WorkingStateStore {
|
|
37
|
+
private readonly entries;
|
|
38
|
+
get size(): number;
|
|
39
|
+
set(input: WorkingStateInput): WorkingStateSetResult;
|
|
40
|
+
delete(key: string): boolean;
|
|
41
|
+
list(): WorkingStateEntry[];
|
|
42
|
+
apply(event: WorkingStateEvent): void;
|
|
43
|
+
load(events: readonly WorkingStateEvent[]): void;
|
|
44
|
+
render(maxChars?: number): string;
|
|
45
|
+
private oldestOfKind;
|
|
46
|
+
}
|
|
47
|
+
export declare function reduceWorkingState(events: readonly WorkingStateEvent[]): WorkingStateStore;
|
|
48
|
+
type SessionEntryLike = {
|
|
49
|
+
type?: unknown;
|
|
50
|
+
customType?: unknown;
|
|
51
|
+
data?: unknown;
|
|
52
|
+
};
|
|
53
|
+
export declare function workingStateEventsFromEntries(entries: readonly SessionEntryLike[]): WorkingStateEvent[];
|
|
54
|
+
export declare function restoreWorkingState(entries: readonly SessionEntryLike[]): WorkingStateStore;
|
|
55
|
+
export declare function getWorkingStateSections(entries: readonly SessionEntryLike[]): WorkingStateEntry[];
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { scrubSecrets } from "./scrub.js";
|
|
2
|
+
export const WORKING_STATE_CUSTOM_TYPE = "stageflow.working_state";
|
|
3
|
+
export const WORKING_STATE_KINDS = [
|
|
4
|
+
"fact",
|
|
5
|
+
"decision",
|
|
6
|
+
"progress",
|
|
7
|
+
"todo",
|
|
8
|
+
"blocker",
|
|
9
|
+
];
|
|
10
|
+
export const WORKING_STATE_MAX_KEY = 80;
|
|
11
|
+
export const WORKING_STATE_MAX_VALUE = 600;
|
|
12
|
+
export const WORKING_STATE_MAX_ENTRIES = 60;
|
|
13
|
+
export const WORKING_STATE_DEFAULT_RENDER_CHARS = 6000;
|
|
14
|
+
export const WORKING_STATE_GUIDANCE = "Older messages and tool results are trimmed automatically as the conversation grows, so keep your own working state with the working_state tool. As soon as you learn or decide something you will need later, record it: exact values and identifiers (fact), choices and their reasons (decision), what is done (progress), what remains (todo) and what is stuck (blocker). Keep each entry to one or two short lines, update an existing key instead of adding a duplicate, and delete entries that no longer matter. Never store secrets or credentials in it.";
|
|
15
|
+
const RENDER_ORDER = [
|
|
16
|
+
"blocker",
|
|
17
|
+
"todo",
|
|
18
|
+
"decision",
|
|
19
|
+
"fact",
|
|
20
|
+
"progress",
|
|
21
|
+
];
|
|
22
|
+
const EVICTION_ORDER = [
|
|
23
|
+
"progress",
|
|
24
|
+
"fact",
|
|
25
|
+
"decision",
|
|
26
|
+
"todo",
|
|
27
|
+
"blocker",
|
|
28
|
+
];
|
|
29
|
+
const HEADINGS = {
|
|
30
|
+
blocker: "Blockers",
|
|
31
|
+
todo: "Todo",
|
|
32
|
+
decision: "Decisions",
|
|
33
|
+
fact: "Facts",
|
|
34
|
+
progress: "Progress",
|
|
35
|
+
};
|
|
36
|
+
function isKind(value) {
|
|
37
|
+
return (typeof value === "string" &&
|
|
38
|
+
WORKING_STATE_KINDS.includes(value));
|
|
39
|
+
}
|
|
40
|
+
function oneLine(text) {
|
|
41
|
+
return text.replace(/\s+/g, " ").trim();
|
|
42
|
+
}
|
|
43
|
+
export class WorkingStateStore {
|
|
44
|
+
entries = new Map();
|
|
45
|
+
get size() {
|
|
46
|
+
return this.entries.size;
|
|
47
|
+
}
|
|
48
|
+
set(input) {
|
|
49
|
+
if (!isKind(input.kind)) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
error: `kind must be one of ${WORKING_STATE_KINDS.join(", ")}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const rawKey = oneLine(String(input.key ?? ""));
|
|
56
|
+
const rawValue = oneLine(String(input.value ?? ""));
|
|
57
|
+
const key = oneLine(scrubSecrets(rawKey));
|
|
58
|
+
const value = oneLine(scrubSecrets(rawValue));
|
|
59
|
+
const redacted = key !== rawKey || value !== rawValue;
|
|
60
|
+
if (key.length === 0)
|
|
61
|
+
return { ok: false, error: "key is required" };
|
|
62
|
+
if (key.length > WORKING_STATE_MAX_KEY) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
error: `key is ${key.length} chars; max ${WORKING_STATE_MAX_KEY}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (value.length === 0)
|
|
69
|
+
return { ok: false, error: "value is required" };
|
|
70
|
+
if (value.length > WORKING_STATE_MAX_VALUE) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
error: `value is ${value.length} chars; max ${WORKING_STATE_MAX_VALUE}. Shorten it.`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const replaced = this.entries.delete(key);
|
|
77
|
+
const dropped = [];
|
|
78
|
+
while (this.entries.size >= WORKING_STATE_MAX_ENTRIES) {
|
|
79
|
+
const victim = this.oldestOfKind("progress");
|
|
80
|
+
if (victim === undefined) {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
error: `working state is full (${WORKING_STATE_MAX_ENTRIES} entries, none are progress). Delete entries first.`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
this.entries.delete(victim);
|
|
87
|
+
dropped.push(victim);
|
|
88
|
+
}
|
|
89
|
+
const entry = {
|
|
90
|
+
key,
|
|
91
|
+
kind: input.kind,
|
|
92
|
+
value,
|
|
93
|
+
updatedAt: input.updatedAt ?? new Date().toISOString(),
|
|
94
|
+
};
|
|
95
|
+
this.entries.set(key, entry);
|
|
96
|
+
return { ok: true, dropped, replaced, redacted, entry };
|
|
97
|
+
}
|
|
98
|
+
delete(key) {
|
|
99
|
+
const raw = oneLine(String(key ?? ""));
|
|
100
|
+
return this.entries.delete(raw) || this.entries.delete(oneLine(scrubSecrets(raw)));
|
|
101
|
+
}
|
|
102
|
+
list() {
|
|
103
|
+
return [...this.entries.values()];
|
|
104
|
+
}
|
|
105
|
+
apply(event) {
|
|
106
|
+
if (event.op === "set") {
|
|
107
|
+
this.set({
|
|
108
|
+
key: event.key,
|
|
109
|
+
kind: event.kind,
|
|
110
|
+
value: event.value,
|
|
111
|
+
updatedAt: event.at,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else if (event.op === "delete") {
|
|
115
|
+
this.delete(event.key);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
load(events) {
|
|
119
|
+
this.entries.clear();
|
|
120
|
+
for (const event of events)
|
|
121
|
+
this.apply(event);
|
|
122
|
+
}
|
|
123
|
+
render(maxChars = WORKING_STATE_DEFAULT_RENDER_CHARS) {
|
|
124
|
+
const all = this.list();
|
|
125
|
+
if (all.length === 0)
|
|
126
|
+
return "";
|
|
127
|
+
const keep = new Set(all);
|
|
128
|
+
let omitted = 0;
|
|
129
|
+
const build = () => {
|
|
130
|
+
const lines = ["## Working state"];
|
|
131
|
+
for (const kind of RENDER_ORDER) {
|
|
132
|
+
const group = all.filter((e) => keep.has(e) && e.kind === kind);
|
|
133
|
+
if (group.length === 0)
|
|
134
|
+
continue;
|
|
135
|
+
lines.push("", `### ${HEADINGS[kind]}`);
|
|
136
|
+
for (const e of group)
|
|
137
|
+
lines.push(`- ${e.key}: ${e.value}`);
|
|
138
|
+
}
|
|
139
|
+
if (omitted > 0) {
|
|
140
|
+
lines.push("", `(${omitted} older entries omitted for space)`);
|
|
141
|
+
}
|
|
142
|
+
return lines.join("\n");
|
|
143
|
+
};
|
|
144
|
+
let text = build();
|
|
145
|
+
for (const kind of EVICTION_ORDER) {
|
|
146
|
+
for (const e of all) {
|
|
147
|
+
if (text.length <= maxChars)
|
|
148
|
+
return text;
|
|
149
|
+
if (e.kind !== kind)
|
|
150
|
+
continue;
|
|
151
|
+
keep.delete(e);
|
|
152
|
+
omitted += 1;
|
|
153
|
+
text = build();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return text.length <= maxChars ? text : text.slice(0, Math.max(0, maxChars));
|
|
157
|
+
}
|
|
158
|
+
oldestOfKind(kind) {
|
|
159
|
+
for (const e of this.entries.values()) {
|
|
160
|
+
if (e.kind === kind)
|
|
161
|
+
return e.key;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export function reduceWorkingState(events) {
|
|
167
|
+
const store = new WorkingStateStore();
|
|
168
|
+
for (const event of events)
|
|
169
|
+
store.apply(event);
|
|
170
|
+
return store;
|
|
171
|
+
}
|
|
172
|
+
function isEvent(data) {
|
|
173
|
+
if (data === null || typeof data !== "object")
|
|
174
|
+
return false;
|
|
175
|
+
const d = data;
|
|
176
|
+
if (typeof d.key !== "string")
|
|
177
|
+
return false;
|
|
178
|
+
if (d.op === "delete")
|
|
179
|
+
return true;
|
|
180
|
+
return d.op === "set" && isKind(d.kind) && typeof d.value === "string";
|
|
181
|
+
}
|
|
182
|
+
export function workingStateEventsFromEntries(entries) {
|
|
183
|
+
const events = [];
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
if (entry.type === "custom" &&
|
|
186
|
+
entry.customType === WORKING_STATE_CUSTOM_TYPE &&
|
|
187
|
+
isEvent(entry.data)) {
|
|
188
|
+
events.push(entry.data);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return events;
|
|
192
|
+
}
|
|
193
|
+
export function restoreWorkingState(entries) {
|
|
194
|
+
return reduceWorkingState(workingStateEventsFromEntries(entries));
|
|
195
|
+
}
|
|
196
|
+
export function getWorkingStateSections(entries) {
|
|
197
|
+
return restoreWorkingState(entries).list();
|
|
198
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { access, mkdir, readdir, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { ensureCatalogScanRoot } from "./ensureCatalogScanRoot.js";
|
|
3
4
|
import { invertPredecessorEdgesToRoute, invertRouteToPredecessorEdges, parsePipelineNeeds, toPipelineNeeds, } from "./pipelineNeeds.js";
|
|
4
5
|
import { STAGE_ID_PATTERN } from "./createStage.js";
|
|
5
6
|
import { inferIdFromUsesPath, normalizePipelineStageEntries, toWiringRefs, } from "./normalizePipelineStageEntry.js";
|
|
@@ -548,6 +549,7 @@ export async function createPipeline(projectRoot, input) {
|
|
|
548
549
|
error: errorFinding?.message ?? "Pipeline validation failed",
|
|
549
550
|
};
|
|
550
551
|
}
|
|
552
|
+
await ensureCatalogScanRoot(projectRoot, path.relative(projectRoot, pipelineDirectory));
|
|
551
553
|
const loadOutcome = await loadPipelineOutcome(relPath, { cwd: projectRoot });
|
|
552
554
|
if (!loadOutcome.ok) {
|
|
553
555
|
await unlink(filePath).catch(() => { });
|
|
@@ -6,6 +6,7 @@ import { STAGE_ID_PATTERN } from "./createStage.js";
|
|
|
6
6
|
import { getCatalogScanPaths } from "./browseCatalog.js";
|
|
7
7
|
import { catalogContextFromStageflow } from "./resolveCatalogContext.js";
|
|
8
8
|
import { resolveStageflowContext } from "../project/resolveStageflowContext.js";
|
|
9
|
+
import { githubMatchActionError } from "./githubTriggerAction.js";
|
|
9
10
|
import { loadTriggerOutcome } from "./loadTrigger.js";
|
|
10
11
|
import { collectPipelineIdsFromPaths, collectTaskIdsFromPaths } from "./validateCatalog.js";
|
|
11
12
|
import { findCatalogPathById } from "../runtime/triggerCatalog.js";
|
|
@@ -56,11 +57,16 @@ export function parseEventField(raw) {
|
|
|
56
57
|
if (raw.config !== undefined && !isPlainObject(raw.config)) {
|
|
57
58
|
return { ok: false, message: "event.config must be an object" };
|
|
58
59
|
}
|
|
60
|
+
const match = isPlainObject(raw.match) ? raw.match : undefined;
|
|
61
|
+
const actionError = githubMatchActionError(raw.source, match);
|
|
62
|
+
if (actionError !== undefined) {
|
|
63
|
+
return { ok: false, message: actionError };
|
|
64
|
+
}
|
|
59
65
|
return {
|
|
60
66
|
ok: true,
|
|
61
67
|
value: {
|
|
62
68
|
source: raw.source,
|
|
63
|
-
...(
|
|
69
|
+
...(match !== undefined ? { match } : {}),
|
|
64
70
|
...(isPlainObject(raw.config) ? { config: raw.config } : {}),
|
|
65
71
|
},
|
|
66
72
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CatalogRootKind } from "./resolveCatalogRoots.js";
|
|
2
2
|
/** Directory scanned for workshop-authored pipelines and tasks. */
|
|
3
3
|
export declare const WORKSHOP_PACKAGE_ROOT = "workshop";
|
|
4
|
+
/** Directory the Guide always uses for pipeline packages and their stage files. */
|
|
5
|
+
export declare const GUIDE_PIPELINES_ROOT = "pipelines";
|
|
4
6
|
export declare function normalizeCatalogDir(directory: string): string;
|
|
5
7
|
/** Untitled workshop saves land here so Run can see them without a new catalog edit. */
|
|
6
8
|
export declare function defaultWorkshopPackageDirectory(pipelineId: string | undefined, catalogRootKind?: CatalogRootKind): string;
|
|
@@ -3,6 +3,8 @@ import { isSeq, parseDocument } from "yaml";
|
|
|
3
3
|
import { manifestPathForProject } from "./loadStageflowManifest.js";
|
|
4
4
|
/** Directory scanned for workshop-authored pipelines and tasks. */
|
|
5
5
|
export const WORKSHOP_PACKAGE_ROOT = "workshop";
|
|
6
|
+
/** Directory the Guide always uses for pipeline packages and their stage files. */
|
|
7
|
+
export const GUIDE_PIPELINES_ROOT = "pipelines";
|
|
6
8
|
export function normalizeCatalogDir(directory) {
|
|
7
9
|
return directory.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/\/+$/, "");
|
|
8
10
|
}
|
|
@@ -30,6 +32,10 @@ export function catalogScanRootForDirectory(directory) {
|
|
|
30
32
|
normalized.startsWith(`${WORKSHOP_PACKAGE_ROOT}/`)) {
|
|
31
33
|
return WORKSHOP_PACKAGE_ROOT;
|
|
32
34
|
}
|
|
35
|
+
if (normalized === GUIDE_PIPELINES_ROOT ||
|
|
36
|
+
normalized.startsWith(`${GUIDE_PIPELINES_ROOT}/`)) {
|
|
37
|
+
return GUIDE_PIPELINES_ROOT;
|
|
38
|
+
}
|
|
33
39
|
return normalized;
|
|
34
40
|
}
|
|
35
41
|
function isCovered(entries, root) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { stat } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { isInsideProjectRoot } from "./catalogRelativePath.js";
|
|
3
4
|
import { getModelCatalog } from "../models/catalog.js";
|
|
4
5
|
import { loadDatasetFile } from "./loadDataset.js";
|
|
5
6
|
import { loadEvalOutcome, resolveEvalPaths } from "./loadEval.js";
|
|
@@ -15,8 +16,35 @@ async function listFiles(manifest, kind) {
|
|
|
15
16
|
export function listEvalFiles(manifest) {
|
|
16
17
|
return listFiles(manifest, "eval");
|
|
17
18
|
}
|
|
18
|
-
export function listDatasetFiles(manifest) {
|
|
19
|
-
|
|
19
|
+
export async function listDatasetFiles(manifest) {
|
|
20
|
+
const scanned = await listFiles(manifest, "dataset");
|
|
21
|
+
const referenced = await datasetsReferencedByEvals(manifest, scanned);
|
|
22
|
+
return [...scanned, ...referenced].sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0));
|
|
23
|
+
}
|
|
24
|
+
async function datasetsReferencedByEvals(manifest, scanned) {
|
|
25
|
+
const seen = new Set(scanned.map((ref) => path.resolve(ref.absPath)));
|
|
26
|
+
const extra = [];
|
|
27
|
+
for (const ref of await listFiles(manifest, "eval")) {
|
|
28
|
+
const outcome = await loadEvalOutcome(ref.absPath, manifest.projectRoot);
|
|
29
|
+
if (!outcome.ok)
|
|
30
|
+
continue;
|
|
31
|
+
const abs = path.resolve(resolveEvalPaths(outcome.value.file, outcome.value.path).datasetPath);
|
|
32
|
+
if (seen.has(abs) || !isInsideProjectRoot(manifest.projectRoot, abs))
|
|
33
|
+
continue;
|
|
34
|
+
try {
|
|
35
|
+
if (!(await stat(abs)).isFile())
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
seen.add(abs);
|
|
42
|
+
extra.push({
|
|
43
|
+
absPath: abs,
|
|
44
|
+
relPath: path.relative(manifest.projectRoot, abs).split(path.sep).join("/"),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return extra;
|
|
20
48
|
}
|
|
21
49
|
export async function loadEvalCatalog(manifest, options = {}) {
|
|
22
50
|
const refs = await listEvalFiles(manifest);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const GITHUB_TRIGGER_ACTIONS: readonly ["opened", "synchronize", "updated", "merged", "closed"];
|
|
2
|
+
export type GithubTriggerAction = (typeof GITHUB_TRIGGER_ACTIONS)[number];
|
|
3
|
+
export declare function isGithubTriggerAction(value: unknown): value is GithubTriggerAction;
|
|
4
|
+
/**
|
|
5
|
+
* For `event.source` values starting with `github.`, `match.action` must be set
|
|
6
|
+
* to one of the five PR poll actions. Returns an error message or undefined.
|
|
7
|
+
*/
|
|
8
|
+
export declare function githubMatchActionError(source: string, match: Record<string, unknown> | undefined): string | undefined;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const GITHUB_TRIGGER_ACTIONS = [
|
|
2
|
+
"opened",
|
|
3
|
+
"synchronize",
|
|
4
|
+
"updated",
|
|
5
|
+
"merged",
|
|
6
|
+
"closed",
|
|
7
|
+
];
|
|
8
|
+
const ACTION_SET = new Set(GITHUB_TRIGGER_ACTIONS);
|
|
9
|
+
export function isGithubTriggerAction(value) {
|
|
10
|
+
return typeof value === "string" && ACTION_SET.has(value);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* For `event.source` values starting with `github.`, `match.action` must be set
|
|
14
|
+
* to one of the five PR poll actions. Returns an error message or undefined.
|
|
15
|
+
*/
|
|
16
|
+
export function githubMatchActionError(source, match) {
|
|
17
|
+
if (!source.startsWith("github."))
|
|
18
|
+
return undefined;
|
|
19
|
+
const action = match?.action;
|
|
20
|
+
if (action === undefined) {
|
|
21
|
+
return ("event.match.action is required for github.* sources " +
|
|
22
|
+
`(one of: ${GITHUB_TRIGGER_ACTIONS.join(", ")})`);
|
|
23
|
+
}
|
|
24
|
+
if (!isGithubTriggerAction(action)) {
|
|
25
|
+
return (`event.match.action must be one of: ${GITHUB_TRIGGER_ACTIONS.join(", ")} ` +
|
|
26
|
+
`(got ${JSON.stringify(action)})`);
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
@@ -28,6 +28,7 @@ export const KNOWN_STAGEFLOW_ENV_KEYS = new Set([
|
|
|
28
28
|
"STAGEFLOW_READ_TOKEN_FILE",
|
|
29
29
|
"STAGEFLOW_ALLOW_UNKNOWN_CONFIG",
|
|
30
30
|
"STAGEFLOW_EVALS_KEEP_WORKDIR",
|
|
31
|
+
"STAGEFLOW_SHOW_INTERNAL_AGENTS",
|
|
31
32
|
"STAGEFLOW_MAX_CONCURRENT_RUNS",
|
|
32
33
|
"STAGEFLOW_MAX_CONCURRENT_RUNS_PER_PROJECT",
|
|
33
34
|
"STAGEFLOW_MAX_QUEUED",
|
|
@@ -59,6 +60,7 @@ export const KNOWN_STAGEFLOW_ENV_KEYS = new Set([
|
|
|
59
60
|
"STAGEFLOW_STAGE_EXECUTION",
|
|
60
61
|
"STAGEFLOW_STAGE_CONTAINER_IMAGE",
|
|
61
62
|
"STAGEFLOW_STAGE_CONTAINER_DOCKER_BIN",
|
|
63
|
+
"STAGEFLOW_STAGE_READONLY_DIR",
|
|
62
64
|
"STAGEFLOW_STAGE_ENV_ALLOW",
|
|
63
65
|
"STAGEFLOW_STAGE_ENV_PASSTHROUGH",
|
|
64
66
|
"STAGEFLOW_GC_INTERVAL_MS",
|
package/dist/config/loadEval.js
CHANGED
|
@@ -74,6 +74,7 @@ const TOP_KEYS = [
|
|
|
74
74
|
];
|
|
75
75
|
const TARGET_KEYS = ["kind", "pipeline", "stage", "file"];
|
|
76
76
|
const AGENT_TARGET_KEYS = ["kind", "agent"];
|
|
77
|
+
const INTERNAL_AGENT_TARGET_KEYS = ["kind", "profile"];
|
|
77
78
|
const CONVERSATION_KEYS = [
|
|
78
79
|
"mode",
|
|
79
80
|
"max_turns",
|
|
@@ -188,13 +189,15 @@ function parseTarget(c, raw) {
|
|
|
188
189
|
return undefined;
|
|
189
190
|
}
|
|
190
191
|
if (raw.kind === undefined) {
|
|
191
|
-
c.add("eval.invalid_field", `target "kind" is required ("stage" or "
|
|
192
|
+
c.add("eval.invalid_field", `target "kind" is required ("stage", "agent" or "internal_agent")`);
|
|
192
193
|
return undefined;
|
|
193
194
|
}
|
|
194
195
|
if (raw.kind === "agent")
|
|
195
196
|
return parseAgentTarget(c, raw);
|
|
197
|
+
if (raw.kind === "internal_agent")
|
|
198
|
+
return parseInternalAgentTarget(c, raw);
|
|
196
199
|
if (raw.kind !== "stage") {
|
|
197
|
-
c.add("eval.target_kind_unsupported", `target kind ${JSON.stringify(raw.kind)} is not supported (only "stage" and "
|
|
200
|
+
c.add("eval.target_kind_unsupported", `target kind ${JSON.stringify(raw.kind)} is not supported (only "stage", "agent" and "internal_agent")`);
|
|
198
201
|
return undefined;
|
|
199
202
|
}
|
|
200
203
|
if (raw.agent !== undefined) {
|
|
@@ -251,6 +254,21 @@ function parseAgentTarget(c, raw) {
|
|
|
251
254
|
}
|
|
252
255
|
return { kind: "agent", agent };
|
|
253
256
|
}
|
|
257
|
+
function parseInternalAgentTarget(c, raw) {
|
|
258
|
+
for (const key of ["agent", "pipeline", "stage", "file"]) {
|
|
259
|
+
if (raw[key] !== undefined) {
|
|
260
|
+
c.add("eval.target_invalid", `target "${key}" is not valid with kind: internal_agent; use "profile"`);
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
c.unknownKeys(raw, INTERNAL_AGENT_TARGET_KEYS, "target");
|
|
265
|
+
const profile = raw.profile;
|
|
266
|
+
if (typeof profile !== "string" || !/^[a-z][a-z0-9-]{0,63}$/.test(profile)) {
|
|
267
|
+
c.add("eval.target_invalid", `target "profile" must be an internal agent id such as stageflow-guide`);
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
return { kind: "internal_agent", profile };
|
|
271
|
+
}
|
|
254
272
|
function parseTask(c, raw) {
|
|
255
273
|
if (raw === undefined)
|
|
256
274
|
return undefined;
|
|
@@ -669,7 +687,7 @@ function parseGrader(c, raw, index, defaultJudge, kind) {
|
|
|
669
687
|
c.add("eval.grader_invalid", `${label} "mode" must be "each_mentioned" or "equals"`);
|
|
670
688
|
ok = false;
|
|
671
689
|
}
|
|
672
|
-
let pathValue = kind === "agent" ? "final_reply" : "payload";
|
|
690
|
+
let pathValue = kind === "agent" || kind === "internal_agent" ? "final_reply" : "payload";
|
|
673
691
|
if (raw.path !== undefined) {
|
|
674
692
|
if (typeof raw.path === "string" && FIELD_PATH_PATTERN.test(raw.path))
|
|
675
693
|
pathValue = raw.path;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { NeedTerminalState, PipelineNeedEdge, PipelineNeedItem, PipelineNeeds, PipelineRoute, PipelineRouteForwardEntry, ResolvedPipelineStageNode } from "../types/pipeline.js";
|
|
2
2
|
export declare const NEED_TERMINAL_STATES: readonly NeedTerminalState[];
|
|
3
3
|
export declare function isNeedTerminalState(value: unknown): value is NeedTerminalState;
|
|
4
|
+
/** Map known aliases; return undefined if not a terminal state or known alias. */
|
|
5
|
+
export declare function canonicalizeNeedTerminalState(value: unknown): NeedTerminalState | undefined;
|
|
4
6
|
export declare function parsePipelineNeeds(raw: unknown, stageId: string): {
|
|
5
7
|
ok: true;
|
|
6
8
|
value: PipelineNeeds;
|
|
@@ -5,9 +5,21 @@ export const NEED_TERMINAL_STATES = [
|
|
|
5
5
|
"skipped",
|
|
6
6
|
];
|
|
7
7
|
const NEED_TERMINAL_STATE_SET = new Set(NEED_TERMINAL_STATES);
|
|
8
|
+
const NEED_TERMINAL_ALIASES = {
|
|
9
|
+
success: "succeeded",
|
|
10
|
+
failure: "failed",
|
|
11
|
+
};
|
|
8
12
|
export function isNeedTerminalState(value) {
|
|
9
13
|
return typeof value === "string" && NEED_TERMINAL_STATE_SET.has(value);
|
|
10
14
|
}
|
|
15
|
+
/** Map known aliases; return undefined if not a terminal state or known alias. */
|
|
16
|
+
export function canonicalizeNeedTerminalState(value) {
|
|
17
|
+
if (typeof value !== "string")
|
|
18
|
+
return undefined;
|
|
19
|
+
if (isNeedTerminalState(value))
|
|
20
|
+
return value;
|
|
21
|
+
return NEED_TERMINAL_ALIASES[value];
|
|
22
|
+
}
|
|
11
23
|
function isPlainObject(value) {
|
|
12
24
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
25
|
}
|
|
@@ -21,14 +33,15 @@ function parseNeedOn(raw, stageId, parentId) {
|
|
|
21
33
|
const seen = new Set();
|
|
22
34
|
const on = [];
|
|
23
35
|
for (const item of raw) {
|
|
24
|
-
|
|
36
|
+
const canonical = canonicalizeNeedTerminalState(item);
|
|
37
|
+
if (canonical === undefined || seen.has(canonical)) {
|
|
25
38
|
return {
|
|
26
39
|
ok: false,
|
|
27
40
|
message: `stage "${stageId}": needs "${parentId}": on must be a non-empty unique subset of succeeded, failed, skipped`,
|
|
28
41
|
};
|
|
29
42
|
}
|
|
30
|
-
seen.add(
|
|
31
|
-
on.push(
|
|
43
|
+
seen.add(canonical);
|
|
44
|
+
on.push(canonical);
|
|
32
45
|
}
|
|
33
46
|
return { ok: true, value: on };
|
|
34
47
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { canonicalizeNeedTerminalState } from "./pipelineNeeds.js";
|
|
2
2
|
import { parseRouteIf } from "./routeIf.js";
|
|
3
3
|
function isPlainObject(value) {
|
|
4
4
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -81,14 +81,15 @@ function parseRouteOn(raw, stageId, targetId) {
|
|
|
81
81
|
const seen = new Set();
|
|
82
82
|
const on = [];
|
|
83
83
|
for (const item of items) {
|
|
84
|
-
|
|
84
|
+
const canonical = canonicalizeNeedTerminalState(item);
|
|
85
|
+
if (canonical === undefined || seen.has(canonical)) {
|
|
85
86
|
return {
|
|
86
87
|
ok: false,
|
|
87
88
|
message: `stage "${stageId}": route "${targetId}": on must be a non-empty unique subset of succeeded, failed, skipped`,
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
|
-
seen.add(
|
|
91
|
-
on.push(
|
|
91
|
+
seen.add(canonical);
|
|
92
|
+
on.push(canonical);
|
|
92
93
|
}
|
|
93
94
|
return { ok: true, value: on };
|
|
94
95
|
}
|
|
@@ -4,7 +4,7 @@ import type { LoadIssue } from "./loadOutcome.js";
|
|
|
4
4
|
import type { AnyChannelProvider } from "../channels/types.js";
|
|
5
5
|
export type ValidationSeverity = "error" | "warning";
|
|
6
6
|
export type ValidationCategory = "pipeline" | "stage" | "catalog" | "task" | "trigger" | "eval" | "dataset";
|
|
7
|
-
export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "pipeline.string_stage_ref" | "pipeline.stage_uses_inline_conflict" | "pipeline.stage_missing_body" | "pipeline.stage_id_mismatch" | "pipeline.stage_wrapper_skill_rejected" | "pipeline.invalid_completion" | "catalog.path_case_mismatch" | "pipeline.invalid_recovery" | "pipeline.include_cycle" | "pipeline.include_invalid" | "pipeline.include_duplicate_stage" | "pipeline.invalid_agent" | "pipeline.invalid_model" | "pipeline.invalid_verify" | "pipeline.io_incompatible" | "pipeline.model_applies" | "pipeline.route_if_invalid" | "pipeline.route_all_gated" | "pipeline.invalid_requires" | "pipeline.requires_conflict" | "pipeline.invalid_channels" | "pipeline.invalid_memories" | "pipeline.memory_unavailable" | "stage.invalid_shape" | "stage.invalid_model" | "stage.missing_model" | "stage.invalid_payload_schema" | "stage.invalid_clone_input_schema" | "stage.unresolved_schema_ref" | "stage.invalid_clone_actions" | "stage.invalid_gate_kinds" | "stage.invalid_pre_emit_checks" | "stage.invalid_timeout_ms" | "stage.invalid_skill" | "stage.invalid_mcp" | "stage.invalid_channels" | "stage.channel_unavailable" | "stage.invalid_browser" | "stage.invalid_secrets" | "stage.unknown_secret" | "stage.denied_secret" | "stage.invalid_requires" | "stage.invalid_agent" | "stage.invalid_io" | "stage.load_error" | "stage.id_filename_mismatch" | "task.invalid_shape" | "task.load_error" | "task.entry_input_unmet" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid" | "trigger.invalid_shape" | "trigger.load_error" | "trigger.unknown_pipeline" | "trigger.unknown_task" | "catalog.duplicate_pipeline_id" | "catalog.manifest_missing" | "catalog.manifest_invalid" | "catalog.empty_catalog" | "catalog.manifest_load_error" | "catalog.invalid_mcp" | "catalog.mcp_command_missing" | "catalog.mixed_yaml_dialect" | "catalog.legacy_yaml" | "catalog.stageflow_home_absolute_path";
|
|
7
|
+
export type ValidationFindingCode = "pipeline.invalid_shape" | "pipeline.dag_error" | "pipeline.missing_stage" | "pipeline.load_error" | "pipeline.string_stage_ref" | "pipeline.stage_uses_inline_conflict" | "pipeline.stage_missing_body" | "pipeline.stage_id_mismatch" | "pipeline.stage_wrapper_skill_rejected" | "pipeline.invalid_completion" | "catalog.path_case_mismatch" | "pipeline.invalid_recovery" | "pipeline.include_cycle" | "pipeline.include_invalid" | "pipeline.include_duplicate_stage" | "pipeline.invalid_agent" | "pipeline.invalid_model" | "pipeline.invalid_verify" | "pipeline.io_incompatible" | "pipeline.model_applies" | "pipeline.route_if_invalid" | "pipeline.route_all_gated" | "pipeline.invalid_requires" | "pipeline.requires_conflict" | "pipeline.invalid_channels" | "pipeline.invalid_memories" | "pipeline.memory_unavailable" | "stage.invalid_shape" | "stage.invalid_model" | "stage.missing_model" | "stage.invalid_payload_schema" | "stage.invalid_clone_input_schema" | "stage.unresolved_schema_ref" | "stage.invalid_clone_actions" | "stage.invalid_gate_kinds" | "stage.invalid_pre_emit_checks" | "stage.invalid_timeout_ms" | "stage.invalid_skill" | "stage.invalid_mcp" | "stage.invalid_channels" | "stage.channel_unavailable" | "stage.invalid_browser" | "stage.invalid_secrets" | "stage.unknown_secret" | "stage.denied_secret" | "stage.invalid_requires" | "stage.invalid_agent" | "stage.invalid_io" | "stage.load_error" | "stage.id_filename_mismatch" | "task.invalid_shape" | "task.load_error" | "task.entry_input_unmet" | "task.binding_conflict" | "task.repository_ref_required" | "task.ref_without_repository" | "task.repository_invalid" | "trigger.invalid_shape" | "trigger.load_error" | "trigger.unknown_pipeline" | "trigger.unknown_task" | "trigger.github_action_required" | "trigger.invalid_github_action" | "catalog.duplicate_pipeline_id" | "catalog.manifest_missing" | "catalog.manifest_invalid" | "catalog.empty_catalog" | "catalog.manifest_load_error" | "catalog.invalid_mcp" | "catalog.mcp_command_missing" | "catalog.mixed_yaml_dialect" | "catalog.legacy_yaml" | "catalog.stageflow_home_absolute_path";
|
|
8
8
|
export type ValidationFinding = {
|
|
9
9
|
severity: ValidationSeverity;
|
|
10
10
|
code: ValidationFindingCode | string;
|
|
@@ -6,6 +6,7 @@ import { INLINE_PIPELINE_PATH, loadPipelineFromObjectOutcome, loadPipelineOutcom
|
|
|
6
6
|
import { loadStageOutcome } from "./loadStage.js";
|
|
7
7
|
import { loadTaskOutcome } from "./loadTask.js";
|
|
8
8
|
import { loadTriggerOutcome } from "./loadTrigger.js";
|
|
9
|
+
import { githubMatchActionError, isGithubTriggerAction } from "./githubTriggerAction.js";
|
|
9
10
|
import { loadEvalCatalog } from "./evalCatalog.js";
|
|
10
11
|
import { evalFindingsFromIssues } from "./validateEval.js";
|
|
11
12
|
import { readYamlObject } from "./readYamlObject.js";
|
|
@@ -666,6 +667,17 @@ export function findingsForTriggerRefs(cwd, absPath, trigger, refs) {
|
|
|
666
667
|
if (trigger.task !== undefined && !refs.taskIds.has(trigger.task)) {
|
|
667
668
|
findings.push(findingTriggerError(cwd, absPath, `Trigger "${trigger.id}" references unknown task "${trigger.task}"`, "trigger.unknown_task"));
|
|
668
669
|
}
|
|
670
|
+
const source = trigger.event?.source;
|
|
671
|
+
if (typeof source === "string" && source.startsWith("github.")) {
|
|
672
|
+
const action = trigger.event?.match?.action;
|
|
673
|
+
if (action === undefined) {
|
|
674
|
+
findings.push(findingTriggerError(cwd, absPath, `Trigger "${trigger.id}" requires event.match.action for github.* sources`, "trigger.github_action_required"));
|
|
675
|
+
}
|
|
676
|
+
else if (!isGithubTriggerAction(action)) {
|
|
677
|
+
findings.push(findingTriggerError(cwd, absPath, githubMatchActionError(source, trigger.event?.match) ??
|
|
678
|
+
`Trigger "${trigger.id}" has an invalid event.match.action`, "trigger.invalid_github_action"));
|
|
679
|
+
}
|
|
680
|
+
}
|
|
669
681
|
return findings;
|
|
670
682
|
}
|
|
671
683
|
async function validateSingleTask(invocationCwd, taskArg) {
|