stageflow 0.36.0 → 0.40.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 +61 -26
- package/dist/agent/claudeAdapter.js +21 -1
- package/dist/agent/claudeTools.d.ts +13 -0
- package/dist/agent/claudeTools.js +98 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +59 -18
- package/dist/agent/piIsolatedMcp.js +14 -2
- package/dist/agent/piIsolatedMcpProbe.d.ts +5 -1
- package/dist/agent/piIsolatedMcpProbe.js +16 -30
- package/dist/agent/port.d.ts +5 -0
- package/dist/agent/sandboxPiTools.d.ts +99 -0
- package/dist/agent/sandboxPiTools.js +109 -0
- package/dist/agents/agentId.d.ts +8 -0
- package/dist/agents/agentId.js +27 -0
- package/dist/agents/approvalBroker.d.ts +16 -0
- package/dist/agents/approvalBroker.js +45 -0
- package/dist/agents/authorChat.d.ts +19 -0
- package/dist/agents/authorChat.js +63 -0
- package/dist/agents/chatTurn.d.ts +23 -0
- package/dist/agents/chatTurn.js +77 -0
- package/dist/agents/communications/agentmail.d.ts +19 -0
- package/dist/agents/communications/agentmail.js +46 -0
- package/dist/agents/communications/agentmailListener.d.ts +59 -0
- package/dist/agents/communications/agentmailListener.js +183 -0
- package/dist/agents/communications/allowlist.d.ts +10 -0
- package/dist/agents/communications/allowlist.js +36 -0
- package/dist/agents/communications/channelConnections.d.ts +3 -0
- package/dist/agents/communications/channelConnections.js +51 -0
- package/dist/agents/communications/delivery.d.ts +53 -0
- package/dist/agents/communications/delivery.js +142 -0
- package/dist/agents/communications/email.d.ts +26 -0
- package/dist/agents/communications/email.js +20 -0
- package/dist/agents/communications/identity.d.ts +13 -0
- package/dist/agents/communications/identity.js +18 -0
- package/dist/agents/communications/imessageListener.d.ts +41 -0
- package/dist/agents/communications/imessageListener.js +92 -0
- package/dist/agents/communications/inbound.d.ts +63 -0
- package/dist/agents/communications/inbound.js +143 -0
- package/dist/agents/communications/listener.d.ts +36 -0
- package/dist/agents/communications/listener.js +38 -0
- package/dist/agents/communications/photon.d.ts +19 -0
- package/dist/agents/communications/photon.js +38 -0
- package/dist/agents/communications/port.d.ts +27 -0
- package/dist/agents/communications/port.js +6 -0
- package/dist/agents/communications/slack.d.ts +28 -0
- package/dist/agents/communications/slack.js +65 -0
- package/dist/agents/communications/supervisor.d.ts +36 -0
- package/dist/agents/communications/supervisor.js +96 -0
- package/dist/agents/communications/telegram.d.ts +19 -0
- package/dist/agents/communications/telegram.js +52 -0
- package/dist/agents/definitionSummary.d.ts +13 -0
- package/dist/agents/definitionSummary.js +91 -0
- package/dist/agents/delegate.d.ts +3 -0
- package/dist/agents/delegate.js +8 -0
- package/dist/agents/errors.d.ts +10 -0
- package/dist/agents/errors.js +32 -0
- package/dist/agents/guardrails.d.ts +24 -0
- package/dist/agents/guardrails.js +39 -0
- package/dist/agents/historyFit.d.ts +10 -0
- package/dist/agents/historyFit.js +26 -0
- package/dist/agents/hostContext.d.ts +54 -0
- package/dist/agents/hostContext.js +156 -0
- package/dist/agents/ledgers.d.ts +29 -0
- package/dist/agents/ledgers.js +31 -0
- package/dist/agents/lineDiff.d.ts +12 -0
- package/dist/agents/lineDiff.js +46 -0
- package/dist/agents/ndjson.d.ts +9 -0
- package/dist/agents/ndjson.js +47 -0
- package/dist/agents/otlpExport.d.ts +9 -0
- package/dist/agents/otlpExport.js +58 -0
- package/dist/agents/otlpSink.d.ts +7 -0
- package/dist/agents/otlpSink.js +23 -0
- package/dist/agents/policy.d.ts +31 -0
- package/dist/agents/policy.js +84 -0
- package/dist/agents/projectRoot.d.ts +5 -0
- package/dist/agents/projectRoot.js +15 -0
- package/dist/agents/runtime/piRuntime.d.ts +52 -0
- package/dist/agents/runtime/piRuntime.js +474 -0
- package/dist/agents/runtime/types.d.ts +77 -0
- package/dist/agents/runtime/types.js +26 -0
- package/dist/agents/sandbox.d.ts +17 -0
- package/dist/agents/sandbox.js +10 -0
- package/dist/agents/scheduleSource.d.ts +32 -0
- package/dist/agents/scheduleSource.js +100 -0
- package/dist/agents/service.d.ts +298 -0
- package/dist/agents/service.js +1105 -0
- package/dist/agents/sessions.d.ts +38 -0
- package/dist/agents/sessions.js +321 -0
- package/dist/agents/store.d.ts +277 -0
- package/dist/agents/store.js +643 -0
- package/dist/agents/trace.d.ts +27 -0
- package/dist/agents/trace.js +29 -0
- package/dist/agents/turnLifecycle.d.ts +72 -0
- package/dist/agents/turnLifecycle.js +157 -0
- package/dist/agents/webChat/publicChat.d.ts +36 -0
- package/dist/agents/webChat/publicChat.js +290 -0
- package/dist/agents/webChat/rateLimit.d.ts +15 -0
- package/dist/agents/webChat/rateLimit.js +33 -0
- package/dist/agents/webChat/slug.d.ts +2 -0
- package/dist/agents/webChat/slug.js +9 -0
- package/dist/channels/providers/agentmail.js +14 -1
- package/dist/channels/providers/photonImessage.js +36 -0
- package/dist/channels/providers/slack.js +2 -1
- package/dist/channels/providers/telegram.js +2 -1
- package/dist/channels/types.d.ts +27 -0
- package/dist/cli/agentsCommand.d.ts +14 -0
- package/dist/cli/agentsCommand.js +291 -0
- package/dist/cli.js +9 -0
- package/dist/config/browseCatalog.js +4 -11
- package/dist/config/draftPackage.d.ts +1 -0
- package/dist/config/draftPackage.js +4 -0
- package/dist/config/hostConfig.js +9 -0
- package/dist/config/loadAgent.d.ts +266 -0
- package/dist/config/loadAgent.js +374 -0
- package/dist/config/loadPipeline.js +5 -2
- package/dist/config/loadTask.js +34 -1
- package/dist/config/mcpHostCatalog.d.ts +50 -0
- package/dist/config/mcpHostCatalog.js +405 -0
- package/dist/config/mcpOAuth.d.ts +37 -0
- package/dist/config/mcpOAuth.js +263 -0
- package/dist/config/mcpRedaction.d.ts +42 -0
- package/dist/config/mcpRedaction.js +314 -0
- package/dist/config/mcpToolCache.d.ts +20 -0
- package/dist/config/mcpToolCache.js +43 -0
- package/dist/config/mergePipelineIncludes.d.ts +2 -0
- package/dist/config/mergePipelineIncludes.js +25 -0
- package/dist/config/resolveStageMcpServers.d.ts +35 -3
- package/dist/config/resolveStageMcpServers.js +124 -9
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +22 -1
- package/dist/mcp/agentTools.d.ts +8 -0
- package/dist/mcp/agentTools.js +132 -0
- package/dist/mcp/catalogTools.js +17 -10
- package/dist/mcp/deps.d.ts +6 -0
- package/dist/mcp/pipelineAuthorSupport.d.ts +19 -0
- package/dist/mcp/pipelineAuthorSupport.js +10 -0
- package/dist/mcp/pipelineAuthorTools.d.ts +8 -0
- package/dist/mcp/pipelineAuthorTools.js +109 -0
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/mcp/triggerTools.js +32 -0
- package/dist/memory/access.d.ts +36 -0
- package/dist/memory/access.js +116 -0
- package/dist/memory/agentIssues.d.ts +3 -0
- package/dist/memory/agentIssues.js +23 -0
- package/dist/memory/bashDeny.d.ts +6 -0
- package/dist/memory/bashDeny.js +35 -0
- package/dist/memory/host.d.ts +51 -0
- package/dist/memory/host.js +394 -0
- package/dist/memory/ids.d.ts +15 -0
- package/dist/memory/ids.js +31 -0
- package/dist/memory/worker.d.ts +1 -0
- package/dist/memory/worker.js +84 -0
- package/dist/models/catalog.d.ts +113 -0
- package/dist/models/catalog.js +238 -0
- package/dist/models/response.d.ts +29 -0
- package/dist/models/response.js +25 -0
- package/dist/operatorAgent/agentAuthorContext.d.ts +17 -0
- package/dist/operatorAgent/agentAuthorContext.js +32 -0
- package/dist/operatorAgent/fakeHost.js +2 -0
- package/dist/operatorAgent/host.js +6 -3
- package/dist/operatorAgent/index.d.ts +4 -0
- package/dist/operatorAgent/index.js +4 -0
- package/dist/operatorAgent/piModel.js +2 -0
- package/dist/operatorAgent/profiles/agentAuthor.d.ts +11 -0
- package/dist/operatorAgent/profiles/agentAuthor.js +192 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +29 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +2 -2
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +3 -3
- package/dist/operatorAgent/proposals.d.ts +1 -0
- package/dist/operatorAgent/proposals.js +23 -2
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/preflight/pipelinePreflight.js +1 -0
- package/dist/runstore/createStore.d.ts +2 -0
- package/dist/runstore/createStore.js +8 -0
- package/dist/runstore/overviewSummary.d.ts +56 -0
- package/dist/runstore/overviewSummary.js +134 -0
- package/dist/runstore/port.d.ts +3 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +2 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +18 -0
- package/dist/runstore/sqlite/migrations/013-agents.d.ts +12 -0
- package/dist/runstore/sqlite/migrations/013-agents.js +156 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.js +32 -0
- package/dist/runstore/sqlite/migrations/index.js +4 -0
- package/dist/runtime/gitCheckoutCapability.d.ts +1 -0
- package/dist/runtime/gitCheckoutCapability.js +1 -1
- package/dist/runtime/gitWorktreeCheckout.d.ts +22 -0
- package/dist/runtime/gitWorktreeCheckout.js +120 -0
- package/dist/runtime/sandboxContainer.d.ts +62 -0
- package/dist/runtime/sandboxContainer.js +151 -0
- package/dist/runtime/sandboxDesk.d.ts +28 -0
- package/dist/runtime/sandboxDesk.js +242 -0
- package/dist/runtime/sandboxFiles.d.ts +20 -0
- package/dist/runtime/sandboxFiles.js +150 -0
- package/dist/runtime/stageAttemptBootstrap.js +15 -1
- package/dist/runtime/stageEnvironment.d.ts +2 -0
- package/dist/runtime/stageEnvironment.js +8 -1
- package/dist/runtime/stageProcessLauncher.js +23 -0
- package/dist/runtime/stageRoots.d.ts +9 -0
- package/dist/runtime/stageRoots.js +14 -0
- package/dist/runtime/stageRunner.d.ts +5 -0
- package/dist/runtime/stageRunner.js +38 -4
- package/dist/runtime/stageSandbox.d.ts +16 -0
- package/dist/runtime/stageSandbox.js +54 -0
- package/dist/runtime/stageSecrets.d.ts +6 -1
- package/dist/runtime/stageSecrets.js +34 -1
- package/dist/runtime/stageWorker.js +138 -105
- package/dist/runtime/workspaceBinding.d.ts +2 -1
- package/dist/runtime/workspaceBinding.js +20 -4
- package/dist/server/agentAuthorRoutes.d.ts +5 -0
- package/dist/server/agentAuthorRoutes.js +64 -0
- package/dist/server/agentRoutes.d.ts +5 -0
- package/dist/server/agentRoutes.js +323 -0
- package/dist/server/bootstrap.d.ts +8 -0
- package/dist/server/bootstrap.js +36 -10
- package/dist/server/controlToken.js +8 -0
- package/dist/server/http.d.ts +8 -1
- package/dist/server/http.js +172 -20
- package/dist/server/mcpHost.js +1 -0
- package/dist/server/memoryRoutes.d.ts +5 -0
- package/dist/server/memoryRoutes.js +146 -0
- package/dist/server/projectMcpRoutes.d.ts +1 -0
- package/dist/server/projectMcpRoutes.js +241 -3
- package/dist/toolkit/guard.d.ts +27 -0
- package/dist/toolkit/guard.js +98 -0
- package/dist/toolkit/index.d.ts +48 -0
- package/dist/toolkit/index.js +82 -0
- package/dist/toolkit/meta.d.ts +36 -0
- package/dist/toolkit/meta.js +117 -0
- package/dist/toolkit/profiles.d.ts +13 -0
- package/dist/toolkit/profiles.js +25 -0
- package/dist/toolkit/record.d.ts +15 -0
- package/dist/toolkit/record.js +17 -0
- package/dist/tools/memoryTools.d.ts +95 -0
- package/dist/tools/memoryTools.js +179 -0
- package/dist/types/pipeline.d.ts +3 -0
- package/dist/types/stage.d.ts +2 -0
- package/dist/types/task.d.ts +11 -1
- package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +9 -0
- package/dist/ui/assets/MarkdownText-D7tYaIFO.js +29 -0
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +6 -0
- package/dist/ui/assets/Tooltip-DrpoRRNi.js +1 -0
- package/dist/ui/assets/chat-BbLukq9W.js +5 -0
- package/dist/ui/assets/chat-zIZU_bP1.css +2 -0
- package/dist/ui/assets/jsx-runtime-iVoFAvQ_.js +1 -0
- package/dist/ui/assets/{index-Clv4sJpU.css → main-BFo79krC.css} +1 -1
- package/dist/ui/assets/main-CijYMeM0.js +259 -0
- package/dist/ui/chat.html +25 -0
- package/dist/ui/index.html +6 -2
- package/dist/workshop/modelSettings.d.ts +2 -2
- package/dist/workshop/modelSettings.js +5 -11
- package/examples/README.md +1 -0
- package/examples/channels-smoke/README.md +12 -1
- package/examples/github-release/README.md +1 -1
- package/examples/memory/README.md +101 -0
- package/examples/memory/desk-outage.task.yaml +15 -0
- package/examples/memory/desk-refund.task.yaml +15 -0
- package/examples/memory/desk-revisit-outage.task.yaml +11 -0
- package/examples/memory/desk-revisit.pipeline.yaml +123 -0
- package/examples/memory/desk.pipeline.yaml +192 -0
- package/examples/memory/file-card.pipeline.yaml +39 -0
- package/examples/memory/file-ledger.task.yaml +22 -0
- package/examples/memory/file-release.task.yaml +24 -0
- package/examples/memory/file-rich.pipeline.yaml +40 -0
- package/examples/memory/file-ticket.task.yaml +7 -0
- package/examples/memory/file-timeline.task.yaml +28 -0
- package/examples/memory/find-card.pipeline.yaml +46 -0
- package/examples/memory/find-ticket.task.yaml +7 -0
- package/examples/memory/missing.pipeline.yaml +16 -0
- package/examples/memory/probe-bash.task.yaml +3 -0
- package/examples/memory/recall.pipeline.yaml +24 -0
- package/examples/memory/recall.task.yaml +5 -0
- package/examples/memory/remember-ada.task.yaml +6 -0
- package/examples/memory/remember-grace.task.yaml +6 -0
- package/examples/memory/remember.pipeline.yaml +58 -0
- package/examples/memory/sandbox-memory-bash.pipeline.yaml +28 -0
- package/examples/memory/stageflow.yaml +12 -0
- package/examples/memory/update-card.pipeline.yaml +43 -0
- package/examples/memory/update-ledger.task.yaml +23 -0
- package/examples/memory/update-rich.pipeline.yaml +44 -0
- package/examples/memory/update-ticket.task.yaml +7 -0
- package/examples/ship-feature/README.md +15 -0
- package/examples/stage-mcp/README.md +1 -1
- package/package.json +2 -1
- package/dist/ui/assets/index-BOhqnPNg.js +0 -260
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { AGENT_ID_PATTERN } from "../agents/agentId.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Project agent definition (`agents/<id>.agent.yaml`), schema v2.
|
|
5
|
+
*
|
|
6
|
+
* The YAML file is the source of truth for new sessions. This module owns the
|
|
7
|
+
* shape, the field-level validation issues the editor maps onto controls, and
|
|
8
|
+
* the canonical YAML serialization used for saves, previews, and diffs.
|
|
9
|
+
*/
|
|
10
|
+
export { AGENT_ID_PATTERN };
|
|
11
|
+
/** Builtin tool groups an agent can be granted, and the Pi tools each unlocks. */
|
|
12
|
+
export declare const BUILTIN_TOOL_GROUPS: {
|
|
13
|
+
readonly read: readonly ["read", "grep", "find", "ls"];
|
|
14
|
+
readonly write: readonly ["write", "edit"];
|
|
15
|
+
readonly shell: readonly ["bash"];
|
|
16
|
+
};
|
|
17
|
+
export type BuiltinToolGroup = keyof typeof BUILTIN_TOOL_GROUPS;
|
|
18
|
+
/** Every individual builtin tool id (read, grep, find, ls, write, edit, bash), in group order. */
|
|
19
|
+
export declare const BUILTIN_TOOL_IDS: string[];
|
|
20
|
+
export declare const BUILTIN_TOOL_GROUP_IDS: BuiltinToolGroup[];
|
|
21
|
+
export type AgentCommunicationProvider = "agentmail" | "slack" | "telegram" | "photon" | "imessage" | "email";
|
|
22
|
+
export declare const WEB_CHAT_SLUG_PATTERN: RegExp;
|
|
23
|
+
declare const agentDefinitionObject: z.ZodObject<{
|
|
24
|
+
id: z.ZodString;
|
|
25
|
+
name: z.ZodString;
|
|
26
|
+
description: z.ZodOptional<z.ZodString>;
|
|
27
|
+
greeting: z.ZodOptional<z.ZodString>;
|
|
28
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
29
|
+
instructions: z.ZodString;
|
|
30
|
+
project_context: z.ZodDefault<z.ZodBoolean>;
|
|
31
|
+
execution: z.ZodDefault<z.ZodEnum<{
|
|
32
|
+
sandbox: "sandbox";
|
|
33
|
+
"trusted-local": "trusted-local";
|
|
34
|
+
}>>;
|
|
35
|
+
model: z.ZodPrefault<z.ZodObject<{
|
|
36
|
+
backend: z.ZodDefault<z.ZodEnum<{
|
|
37
|
+
claude: "claude";
|
|
38
|
+
pi: "pi";
|
|
39
|
+
}>>;
|
|
40
|
+
id: z.ZodOptional<z.ZodString>;
|
|
41
|
+
thinking: z.ZodDefault<z.ZodEnum<{
|
|
42
|
+
high: "high";
|
|
43
|
+
low: "low";
|
|
44
|
+
medium: "medium";
|
|
45
|
+
off: "off";
|
|
46
|
+
}>>;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
tools: z.ZodPrefault<z.ZodObject<{
|
|
49
|
+
builtin: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
50
|
+
read: "read";
|
|
51
|
+
shell: "shell";
|
|
52
|
+
write: "write";
|
|
53
|
+
}>>>;
|
|
54
|
+
builtin_tools: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
55
|
+
[x: string]: string;
|
|
56
|
+
}>>>;
|
|
57
|
+
mcp: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
58
|
+
skills: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
59
|
+
browser: z.ZodDefault<z.ZodBoolean>;
|
|
60
|
+
stageflow: z.ZodPrefault<z.ZodObject<{
|
|
61
|
+
groups: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
62
|
+
tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
63
|
+
}, z.core.$strict>>;
|
|
64
|
+
}, z.core.$strict>>;
|
|
65
|
+
approvals: z.ZodPrefault<z.ZodObject<{
|
|
66
|
+
ask_first: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
67
|
+
approvers: z.ZodPrefault<z.ZodObject<{
|
|
68
|
+
operators: z.ZodDefault<z.ZodBoolean>;
|
|
69
|
+
channel_ids: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
70
|
+
}, z.core.$strict>>;
|
|
71
|
+
timeout_minutes: z.ZodDefault<z.ZodNumber>;
|
|
72
|
+
on_timeout: z.ZodDefault<z.ZodEnum<{
|
|
73
|
+
deny: "deny";
|
|
74
|
+
skip: "skip";
|
|
75
|
+
}>>;
|
|
76
|
+
}, z.core.$strict>>;
|
|
77
|
+
sub_agents: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
78
|
+
sub_agent_depth: z.ZodDefault<z.ZodNumber>;
|
|
79
|
+
guardrails: z.ZodPrefault<z.ZodObject<{
|
|
80
|
+
block_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
81
|
+
}, z.core.$strict>>;
|
|
82
|
+
evals: z.ZodPrefault<z.ZodObject<{
|
|
83
|
+
groundedness: z.ZodDefault<z.ZodBoolean>;
|
|
84
|
+
}, z.core.$strict>>;
|
|
85
|
+
observability: z.ZodPrefault<z.ZodObject<{
|
|
86
|
+
capture: z.ZodDefault<z.ZodEnum<{
|
|
87
|
+
full: "full";
|
|
88
|
+
metadata: "metadata";
|
|
89
|
+
off: "off";
|
|
90
|
+
}>>;
|
|
91
|
+
otlp: z.ZodDefault<z.ZodBoolean>;
|
|
92
|
+
}, z.core.$strict>>;
|
|
93
|
+
channel: z.ZodOptional<z.ZodObject<{
|
|
94
|
+
connection_id: z.ZodString;
|
|
95
|
+
allow_from: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
96
|
+
}, z.core.$strict>>;
|
|
97
|
+
memories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
98
|
+
web_chat: z.ZodPrefault<z.ZodObject<{
|
|
99
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
100
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
101
|
+
rate_limit_per_minute: z.ZodDefault<z.ZodNumber>;
|
|
102
|
+
max_message_chars: z.ZodDefault<z.ZodNumber>;
|
|
103
|
+
}, z.core.$strict>>;
|
|
104
|
+
schedule: z.ZodOptional<z.ZodObject<{
|
|
105
|
+
cron: z.ZodString;
|
|
106
|
+
timezone: z.ZodOptional<z.ZodString>;
|
|
107
|
+
message: z.ZodOptional<z.ZodString>;
|
|
108
|
+
}, z.core.$strict>>;
|
|
109
|
+
limits: z.ZodPrefault<z.ZodObject<{
|
|
110
|
+
session_minutes: z.ZodDefault<z.ZodNumber>;
|
|
111
|
+
max_turns: z.ZodDefault<z.ZodNumber>;
|
|
112
|
+
cost_usd: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
113
|
+
long_context: z.ZodDefault<z.ZodEnum<{
|
|
114
|
+
summarize: "summarize";
|
|
115
|
+
truncate: "truncate";
|
|
116
|
+
}>>;
|
|
117
|
+
always_on: z.ZodDefault<z.ZodBoolean>;
|
|
118
|
+
}, z.core.$strict>>;
|
|
119
|
+
}, z.core.$strict>;
|
|
120
|
+
export declare const agentDefinitionSchema: z.ZodPreprocess<z.ZodObject<{
|
|
121
|
+
id: z.ZodString;
|
|
122
|
+
name: z.ZodString;
|
|
123
|
+
description: z.ZodOptional<z.ZodString>;
|
|
124
|
+
greeting: z.ZodOptional<z.ZodString>;
|
|
125
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
126
|
+
instructions: z.ZodString;
|
|
127
|
+
project_context: z.ZodDefault<z.ZodBoolean>;
|
|
128
|
+
execution: z.ZodDefault<z.ZodEnum<{
|
|
129
|
+
sandbox: "sandbox";
|
|
130
|
+
"trusted-local": "trusted-local";
|
|
131
|
+
}>>;
|
|
132
|
+
model: z.ZodPrefault<z.ZodObject<{
|
|
133
|
+
backend: z.ZodDefault<z.ZodEnum<{
|
|
134
|
+
claude: "claude";
|
|
135
|
+
pi: "pi";
|
|
136
|
+
}>>;
|
|
137
|
+
id: z.ZodOptional<z.ZodString>;
|
|
138
|
+
thinking: z.ZodDefault<z.ZodEnum<{
|
|
139
|
+
high: "high";
|
|
140
|
+
low: "low";
|
|
141
|
+
medium: "medium";
|
|
142
|
+
off: "off";
|
|
143
|
+
}>>;
|
|
144
|
+
}, z.core.$strict>>;
|
|
145
|
+
tools: z.ZodPrefault<z.ZodObject<{
|
|
146
|
+
builtin: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
147
|
+
read: "read";
|
|
148
|
+
shell: "shell";
|
|
149
|
+
write: "write";
|
|
150
|
+
}>>>;
|
|
151
|
+
builtin_tools: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
152
|
+
[x: string]: string;
|
|
153
|
+
}>>>;
|
|
154
|
+
mcp: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
155
|
+
skills: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
156
|
+
browser: z.ZodDefault<z.ZodBoolean>;
|
|
157
|
+
stageflow: z.ZodPrefault<z.ZodObject<{
|
|
158
|
+
groups: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
159
|
+
tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
160
|
+
}, z.core.$strict>>;
|
|
161
|
+
}, z.core.$strict>>;
|
|
162
|
+
approvals: z.ZodPrefault<z.ZodObject<{
|
|
163
|
+
ask_first: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
164
|
+
approvers: z.ZodPrefault<z.ZodObject<{
|
|
165
|
+
operators: z.ZodDefault<z.ZodBoolean>;
|
|
166
|
+
channel_ids: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
167
|
+
}, z.core.$strict>>;
|
|
168
|
+
timeout_minutes: z.ZodDefault<z.ZodNumber>;
|
|
169
|
+
on_timeout: z.ZodDefault<z.ZodEnum<{
|
|
170
|
+
deny: "deny";
|
|
171
|
+
skip: "skip";
|
|
172
|
+
}>>;
|
|
173
|
+
}, z.core.$strict>>;
|
|
174
|
+
sub_agents: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
175
|
+
sub_agent_depth: z.ZodDefault<z.ZodNumber>;
|
|
176
|
+
guardrails: z.ZodPrefault<z.ZodObject<{
|
|
177
|
+
block_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
178
|
+
}, z.core.$strict>>;
|
|
179
|
+
evals: z.ZodPrefault<z.ZodObject<{
|
|
180
|
+
groundedness: z.ZodDefault<z.ZodBoolean>;
|
|
181
|
+
}, z.core.$strict>>;
|
|
182
|
+
observability: z.ZodPrefault<z.ZodObject<{
|
|
183
|
+
capture: z.ZodDefault<z.ZodEnum<{
|
|
184
|
+
full: "full";
|
|
185
|
+
metadata: "metadata";
|
|
186
|
+
off: "off";
|
|
187
|
+
}>>;
|
|
188
|
+
otlp: z.ZodDefault<z.ZodBoolean>;
|
|
189
|
+
}, z.core.$strict>>;
|
|
190
|
+
channel: z.ZodOptional<z.ZodObject<{
|
|
191
|
+
connection_id: z.ZodString;
|
|
192
|
+
allow_from: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
193
|
+
}, z.core.$strict>>;
|
|
194
|
+
memories: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
195
|
+
web_chat: z.ZodPrefault<z.ZodObject<{
|
|
196
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
197
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
198
|
+
rate_limit_per_minute: z.ZodDefault<z.ZodNumber>;
|
|
199
|
+
max_message_chars: z.ZodDefault<z.ZodNumber>;
|
|
200
|
+
}, z.core.$strict>>;
|
|
201
|
+
schedule: z.ZodOptional<z.ZodObject<{
|
|
202
|
+
cron: z.ZodString;
|
|
203
|
+
timezone: z.ZodOptional<z.ZodString>;
|
|
204
|
+
message: z.ZodOptional<z.ZodString>;
|
|
205
|
+
}, z.core.$strict>>;
|
|
206
|
+
limits: z.ZodPrefault<z.ZodObject<{
|
|
207
|
+
session_minutes: z.ZodDefault<z.ZodNumber>;
|
|
208
|
+
max_turns: z.ZodDefault<z.ZodNumber>;
|
|
209
|
+
cost_usd: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
210
|
+
long_context: z.ZodDefault<z.ZodEnum<{
|
|
211
|
+
summarize: "summarize";
|
|
212
|
+
truncate: "truncate";
|
|
213
|
+
}>>;
|
|
214
|
+
always_on: z.ZodDefault<z.ZodBoolean>;
|
|
215
|
+
}, z.core.$strict>>;
|
|
216
|
+
}, z.core.$strict>, unknown>;
|
|
217
|
+
export type AgentDefinition = z.output<typeof agentDefinitionObject>;
|
|
218
|
+
/** What callers may send: every block optional, defaults filled on parse. */
|
|
219
|
+
export type AgentDefinitionInput = z.input<typeof agentDefinitionObject>;
|
|
220
|
+
export type AgentModelConfig = AgentDefinition["model"];
|
|
221
|
+
export type AgentTools = AgentDefinition["tools"];
|
|
222
|
+
export type AgentApprovals = AgentDefinition["approvals"];
|
|
223
|
+
export type AgentApprovers = AgentApprovals["approvers"];
|
|
224
|
+
export type AgentLimits = AgentDefinition["limits"];
|
|
225
|
+
export type AgentSchedule = NonNullable<AgentDefinition["schedule"]>;
|
|
226
|
+
export type AgentGuardrails = AgentDefinition["guardrails"];
|
|
227
|
+
export type AgentEvalsConfig = AgentDefinition["evals"];
|
|
228
|
+
export type AgentObservability = AgentDefinition["observability"];
|
|
229
|
+
export type AgentTraceCapture = AgentObservability["capture"];
|
|
230
|
+
export type AgentExecutionMode = AgentDefinition["execution"];
|
|
231
|
+
export type AgentWebChat = AgentDefinition["web_chat"];
|
|
232
|
+
export type AgentCommunicationBinding = NonNullable<AgentDefinition["channel"]>;
|
|
233
|
+
export type AgentIssue = {
|
|
234
|
+
/** Dotted field path, e.g. `tools.mcp.notion` or `instructions`. Empty for file-level problems. */
|
|
235
|
+
path: string;
|
|
236
|
+
code: string;
|
|
237
|
+
message: string;
|
|
238
|
+
line?: number;
|
|
239
|
+
column?: number;
|
|
240
|
+
};
|
|
241
|
+
export type AgentParseResult = {
|
|
242
|
+
ok: true;
|
|
243
|
+
value: AgentDefinition;
|
|
244
|
+
} | {
|
|
245
|
+
ok: false;
|
|
246
|
+
issues: AgentIssue[];
|
|
247
|
+
};
|
|
248
|
+
/** Parse an untrusted object (API body or parsed YAML) into a definition. */
|
|
249
|
+
export declare function parseAgentDefinition(raw: unknown): AgentParseResult;
|
|
250
|
+
export declare function parseAgentYaml(text: string): AgentParseResult;
|
|
251
|
+
/**
|
|
252
|
+
* Canonical YAML: fixed key order, defaults omitted, so diffs between
|
|
253
|
+
* revisions show only what an operator actually set.
|
|
254
|
+
*/
|
|
255
|
+
export declare function serializeAgentDefinition(definition: AgentDefinition): string;
|
|
256
|
+
/** Builtin tool ids granted by whole groups and by single tools, in group order. */
|
|
257
|
+
export declare function grantedBuiltinTools(definition: Pick<AgentDefinition, "tools">): string[];
|
|
258
|
+
/** Every tool id the definition grants: builtin tool names, `<server>.<tool>`, and `agent:<id>`. */
|
|
259
|
+
export declare function grantedToolIds(definition: Pick<AgentDefinition, "tools" | "sub_agents">): Set<string>;
|
|
260
|
+
/** A complete definition with every default applied, for a brand-new agent. */
|
|
261
|
+
export declare function newAgentDefinition(input: {
|
|
262
|
+
id: string;
|
|
263
|
+
name: string;
|
|
264
|
+
instructions: string;
|
|
265
|
+
description?: string;
|
|
266
|
+
}): AgentParseResult;
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { AGENT_ID_PATTERN, isReservedAgentId, RESERVED_AGENT_IDS } from "../agents/agentId.js";
|
|
2
|
+
import { normalizeEntry, SENDER_ENTRY } from "../agents/communications/allowlist.js";
|
|
3
|
+
import { grantedStageflowTools, isOperatorOnlyGroup, isOperatorOnlyTool, isToolGroupId, stageflowGrantId, TOOL_META } from "../toolkit/meta.js";
|
|
4
|
+
import { Cron } from "croner";
|
|
5
|
+
import { parse as parseYaml, stringify as stringifyYaml, YAMLParseError } from "yaml";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { yamlParsePosition } from "./yamlParsePosition.js";
|
|
8
|
+
import { MEMORY_ID_PATTERN } from "../memory/ids.js";
|
|
9
|
+
/**
|
|
10
|
+
* Project agent definition (`agents/<id>.agent.yaml`), schema v2.
|
|
11
|
+
*
|
|
12
|
+
* The YAML file is the source of truth for new sessions. This module owns the
|
|
13
|
+
* shape, the field-level validation issues the editor maps onto controls, and
|
|
14
|
+
* the canonical YAML serialization used for saves, previews, and diffs.
|
|
15
|
+
*/
|
|
16
|
+
export { AGENT_ID_PATTERN };
|
|
17
|
+
/** Builtin tool groups an agent can be granted, and the Pi tools each unlocks. */
|
|
18
|
+
export const BUILTIN_TOOL_GROUPS = {
|
|
19
|
+
read: ["read", "grep", "find", "ls"],
|
|
20
|
+
write: ["write", "edit"],
|
|
21
|
+
shell: ["bash"],
|
|
22
|
+
};
|
|
23
|
+
/** Every individual builtin tool id (read, grep, find, ls, write, edit, bash), in group order. */
|
|
24
|
+
export const BUILTIN_TOOL_IDS = Object.values(BUILTIN_TOOL_GROUPS).flat();
|
|
25
|
+
export const BUILTIN_TOOL_GROUP_IDS = Object.keys(BUILTIN_TOOL_GROUPS);
|
|
26
|
+
const MCP_NAME = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
27
|
+
const TOOL_ID = /^(agent:[a-z][a-z0-9_]{0,63}|[A-Za-z0-9_.-]{1,128})$/;
|
|
28
|
+
const nonEmpty = z.string().trim().min(1, "Required");
|
|
29
|
+
function isValidCron(expression) {
|
|
30
|
+
try {
|
|
31
|
+
new Cron(expression, { paused: true }).stop();
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isValidRegex(pattern) {
|
|
39
|
+
try {
|
|
40
|
+
void new RegExp(pattern);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const modelSchema = z
|
|
48
|
+
.strictObject({
|
|
49
|
+
backend: z.enum(["pi", "claude"]).default("pi"),
|
|
50
|
+
id: nonEmpty.optional(),
|
|
51
|
+
thinking: z.enum(["off", "low", "medium", "high"]).default("medium"),
|
|
52
|
+
})
|
|
53
|
+
.prefault({});
|
|
54
|
+
const toolsSchema = z
|
|
55
|
+
.strictObject({
|
|
56
|
+
builtin: z
|
|
57
|
+
.array(z.enum(BUILTIN_TOOL_GROUP_IDS))
|
|
58
|
+
.default([])
|
|
59
|
+
.refine((list) => new Set(list).size === list.length, "Duplicate tool group"),
|
|
60
|
+
/** Single builtin tools on top of the groups, e.g. `grep` without the rest of `read`. */
|
|
61
|
+
builtin_tools: z
|
|
62
|
+
.array(z.enum(BUILTIN_TOOL_IDS))
|
|
63
|
+
.default([])
|
|
64
|
+
.refine((list) => new Set(list).size === list.length, "Duplicate tool"),
|
|
65
|
+
mcp: z
|
|
66
|
+
.record(z.string().regex(MCP_NAME, "Invalid MCP server name"), z.array(nonEmpty).min(1, "Allow at least one tool, or remove the server"))
|
|
67
|
+
.default({}),
|
|
68
|
+
skills: z.array(nonEmpty).default([]),
|
|
69
|
+
browser: z.boolean().default(false),
|
|
70
|
+
stageflow: z
|
|
71
|
+
.strictObject({
|
|
72
|
+
groups: z.array(nonEmpty).default([]),
|
|
73
|
+
tools: z.array(nonEmpty).default([]),
|
|
74
|
+
})
|
|
75
|
+
.prefault({}),
|
|
76
|
+
})
|
|
77
|
+
.prefault({});
|
|
78
|
+
const approvalsSchema = z
|
|
79
|
+
.strictObject({
|
|
80
|
+
ask_first: z.array(z.string().regex(TOOL_ID, "Invalid tool id")).default([]),
|
|
81
|
+
approvers: z
|
|
82
|
+
.strictObject({
|
|
83
|
+
operators: z.boolean().default(true),
|
|
84
|
+
channel_ids: z.array(nonEmpty).default([]),
|
|
85
|
+
})
|
|
86
|
+
.prefault({}),
|
|
87
|
+
timeout_minutes: z.number().int().positive().max(10_080).default(30),
|
|
88
|
+
on_timeout: z.enum(["skip", "deny"]).default("skip"),
|
|
89
|
+
})
|
|
90
|
+
.prefault({})
|
|
91
|
+
.refine((value) => value.approvers.operators || value.approvers.channel_ids.length > 0, { message: "Someone must be able to approve", path: ["approvers"] });
|
|
92
|
+
const limitsSchema = z
|
|
93
|
+
.strictObject({
|
|
94
|
+
session_minutes: z.number().int().positive().max(1_440).default(10),
|
|
95
|
+
max_turns: z.number().int().positive().max(1_000).default(40),
|
|
96
|
+
cost_usd: z.number().positive().nullable().default(null),
|
|
97
|
+
long_context: z.enum(["summarize", "truncate"]).default("summarize"),
|
|
98
|
+
/** A session never ends by time or turn count (a cost cap still applies per day); it resumes after a failure. */
|
|
99
|
+
always_on: z.boolean().default(false),
|
|
100
|
+
})
|
|
101
|
+
.prefault({});
|
|
102
|
+
const scheduleSchema = z.strictObject({
|
|
103
|
+
cron: nonEmpty.refine(isValidCron, "Invalid cron expression"),
|
|
104
|
+
timezone: nonEmpty.optional(),
|
|
105
|
+
message: nonEmpty.optional(),
|
|
106
|
+
});
|
|
107
|
+
export const WEB_CHAT_SLUG_PATTERN = /^[a-z0-9]{16,32}$/;
|
|
108
|
+
const webChatSchema = z
|
|
109
|
+
.strictObject({
|
|
110
|
+
enabled: z.boolean().default(false),
|
|
111
|
+
slug: z.string().regex(WEB_CHAT_SLUG_PATTERN, "Use 16 to 32 lowercase letters or digits").optional(),
|
|
112
|
+
rate_limit_per_minute: z.number().int().min(1).max(120).default(10),
|
|
113
|
+
max_message_chars: z.number().int().min(1).max(20_000).default(4_000),
|
|
114
|
+
})
|
|
115
|
+
.prefault({});
|
|
116
|
+
const channelSchema = z.strictObject({
|
|
117
|
+
connection_id: nonEmpty,
|
|
118
|
+
/** Who may message the agent: emails, E.164 phones, `@domain`, Slack user ids, Telegram `@username`, or `*`. Empty lets nobody in. */
|
|
119
|
+
allow_from: z
|
|
120
|
+
.array(z.string().trim().regex(SENDER_ENTRY, "Use an email, a +phone number, @domain, a Slack user id, a Telegram @username or *"))
|
|
121
|
+
.default([])
|
|
122
|
+
.refine((list) => new Set(list.map(normalizeEntry)).size === list.length, "Duplicate sender"),
|
|
123
|
+
});
|
|
124
|
+
const agentDefinitionObject = z.strictObject({
|
|
125
|
+
id: z
|
|
126
|
+
.string()
|
|
127
|
+
.regex(AGENT_ID_PATTERN, "Use lowercase letters, digits and _, starting with a letter")
|
|
128
|
+
.refine((value) => !isReservedAgentId(value), `That id is reserved (${[...RESERVED_AGENT_IDS].join(", ")} are part of the agents URLs); choose another id`),
|
|
129
|
+
name: nonEmpty.max(120),
|
|
130
|
+
description: z.string().trim().max(500).optional(),
|
|
131
|
+
greeting: z.string().trim().max(500).optional(),
|
|
132
|
+
enabled: z.boolean().default(false),
|
|
133
|
+
instructions: nonEmpty,
|
|
134
|
+
project_context: z.boolean().default(false),
|
|
135
|
+
execution: z.enum(["trusted-local", "sandbox"]).default("trusted-local"),
|
|
136
|
+
model: modelSchema,
|
|
137
|
+
tools: toolsSchema,
|
|
138
|
+
approvals: approvalsSchema,
|
|
139
|
+
sub_agents: z
|
|
140
|
+
.array(z.string().regex(AGENT_ID_PATTERN, "Invalid agent id"))
|
|
141
|
+
.default([])
|
|
142
|
+
.refine((list) => new Set(list).size === list.length, "Duplicate sub-agent"),
|
|
143
|
+
sub_agent_depth: z.number().int().min(1).max(5).default(1),
|
|
144
|
+
guardrails: z
|
|
145
|
+
.strictObject({
|
|
146
|
+
block_patterns: z.array(nonEmpty.refine(isValidRegex, "Invalid regular expression")).default([]),
|
|
147
|
+
})
|
|
148
|
+
.prefault({}),
|
|
149
|
+
evals: z.strictObject({ groundedness: z.boolean().default(false) }).prefault({}),
|
|
150
|
+
observability: z
|
|
151
|
+
.strictObject({
|
|
152
|
+
capture: z.enum(["off", "metadata", "full"]).default("metadata"),
|
|
153
|
+
otlp: z.boolean().default(false),
|
|
154
|
+
})
|
|
155
|
+
.prefault({}),
|
|
156
|
+
/** The one connection (AgentMail inbox, iMessage line, ...) this agent answers on. */
|
|
157
|
+
channel: channelSchema.optional(),
|
|
158
|
+
memories: z
|
|
159
|
+
.array(z.string().regex(MEMORY_ID_PATTERN, "Invalid memory id"))
|
|
160
|
+
.optional()
|
|
161
|
+
.refine((list) => list === undefined || new Set(list).size === list.length, "Duplicate memory"),
|
|
162
|
+
web_chat: webChatSchema,
|
|
163
|
+
schedule: scheduleSchema.optional(),
|
|
164
|
+
limits: limitsSchema,
|
|
165
|
+
});
|
|
166
|
+
/** The earlier `channels: [{ connection_id }]` list becomes the single `channel`; more than one is an error. */
|
|
167
|
+
function migrateLegacyChannels(raw, ctx) {
|
|
168
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw) || !("channels" in raw))
|
|
169
|
+
return raw;
|
|
170
|
+
const { channels, ...rest } = raw;
|
|
171
|
+
if (!Array.isArray(channels))
|
|
172
|
+
return raw;
|
|
173
|
+
if (channels.length > 1) {
|
|
174
|
+
ctx.issues.push({ code: "custom", message: "An agent can have only one channel", input: raw, path: ["channels"] });
|
|
175
|
+
return rest;
|
|
176
|
+
}
|
|
177
|
+
if (channels.length === 1 && rest.channel === undefined)
|
|
178
|
+
return { ...rest, channel: channels[0] };
|
|
179
|
+
return rest;
|
|
180
|
+
}
|
|
181
|
+
export const agentDefinitionSchema = z.preprocess(migrateLegacyChannels, agentDefinitionObject);
|
|
182
|
+
function zodIssues(error) {
|
|
183
|
+
return error.issues.map((issue) => ({
|
|
184
|
+
path: issue.path.map(String).join("."),
|
|
185
|
+
code: issue.code === "unrecognized_keys"
|
|
186
|
+
? "agent.unknown_field"
|
|
187
|
+
: issue.code === "custom"
|
|
188
|
+
? "agent.invalid_value"
|
|
189
|
+
: issue.message === "Required"
|
|
190
|
+
? "agent.required"
|
|
191
|
+
: `agent.${issue.code}`,
|
|
192
|
+
message: issue.code === "unrecognized_keys"
|
|
193
|
+
? `Unknown field${issue.keys.length === 1 ? "" : "s"}: ${issue.keys.join(", ")}`
|
|
194
|
+
: issue.message,
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
/** Cross-field rules zod cannot express per-field. */
|
|
198
|
+
function semanticIssues(definition) {
|
|
199
|
+
const issues = [];
|
|
200
|
+
const granted = grantedToolIds(definition);
|
|
201
|
+
definition.approvals.ask_first.forEach((tool, index) => {
|
|
202
|
+
if (!granted.has(tool) && !isWildcardMcpTool(definition, tool)) {
|
|
203
|
+
issues.push({
|
|
204
|
+
path: `approvals.ask_first.${index}`,
|
|
205
|
+
code: "agent.ask_first_not_granted",
|
|
206
|
+
message: `${tool} is not a tool this agent is granted`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
definition.tools.stageflow.groups.forEach((group, index) => {
|
|
211
|
+
if (!isToolGroupId(group)) {
|
|
212
|
+
issues.push({ path: `tools.stageflow.groups.${index}`, code: "agent.stageflow_group_unknown", message: `${group} is not a Stageflow tool group` });
|
|
213
|
+
}
|
|
214
|
+
else if (isOperatorOnlyGroup(group)) {
|
|
215
|
+
issues.push({ path: `tools.stageflow.groups.${index}`, code: "agent.stageflow_operator_only", message: `${group} decides things a person must decide, so it cannot be granted to an agent` });
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
definition.tools.stageflow.tools.forEach((tool, index) => {
|
|
219
|
+
if (!(tool in TOOL_META)) {
|
|
220
|
+
issues.push({ path: `tools.stageflow.tools.${index}`, code: "agent.stageflow_tool_unknown", message: `${tool} is not a Stageflow tool` });
|
|
221
|
+
}
|
|
222
|
+
else if (isOperatorOnlyTool(tool)) {
|
|
223
|
+
issues.push({ path: `tools.stageflow.tools.${index}`, code: "agent.stageflow_operator_only", message: `${tool} is for operators only and cannot be granted to an agent` });
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
if ("stageflow" in definition.tools.mcp) {
|
|
227
|
+
issues.push({ path: "tools.mcp.stageflow", code: "agent.mcp_name_reserved", message: "stageflow is reserved for Stageflow's own tools; rename the MCP server" });
|
|
228
|
+
}
|
|
229
|
+
if (definition.sub_agents.includes(definition.id)) {
|
|
230
|
+
issues.push({
|
|
231
|
+
path: "sub_agents",
|
|
232
|
+
code: "agent.sub_agent_self",
|
|
233
|
+
message: "An agent cannot call itself",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
return issues;
|
|
237
|
+
}
|
|
238
|
+
/** Parse an untrusted object (API body or parsed YAML) into a definition. */
|
|
239
|
+
export function parseAgentDefinition(raw) {
|
|
240
|
+
const parsed = agentDefinitionSchema.safeParse(raw, {
|
|
241
|
+
error: (issue) => (issue.code === "invalid_type" && issue.input === undefined ? "Required" : undefined),
|
|
242
|
+
});
|
|
243
|
+
if (!parsed.success)
|
|
244
|
+
return { ok: false, issues: zodIssues(parsed.error) };
|
|
245
|
+
const issues = semanticIssues(parsed.data);
|
|
246
|
+
if (issues.length > 0)
|
|
247
|
+
return { ok: false, issues };
|
|
248
|
+
return { ok: true, value: parsed.data };
|
|
249
|
+
}
|
|
250
|
+
export function parseAgentYaml(text) {
|
|
251
|
+
let raw;
|
|
252
|
+
try {
|
|
253
|
+
raw = parseYaml(text);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
return {
|
|
257
|
+
ok: false,
|
|
258
|
+
issues: [
|
|
259
|
+
{
|
|
260
|
+
path: "",
|
|
261
|
+
code: "agent.yaml_syntax",
|
|
262
|
+
message: error instanceof YAMLParseError ? error.message.split("\n")[0] : "YAML could not be parsed",
|
|
263
|
+
...yamlParsePosition(error),
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
269
|
+
return { ok: false, issues: [{ path: "", code: "agent.invalid_shape", message: "Expected a YAML mapping" }] };
|
|
270
|
+
}
|
|
271
|
+
return parseAgentDefinition(raw);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Canonical YAML: fixed key order, defaults omitted, so diffs between
|
|
275
|
+
* revisions show only what an operator actually set.
|
|
276
|
+
*/
|
|
277
|
+
export function serializeAgentDefinition(definition) {
|
|
278
|
+
const defaults = agentDefinitionSchema.parse({ id: definition.id, name: "x", instructions: "x" });
|
|
279
|
+
const out = {
|
|
280
|
+
id: definition.id,
|
|
281
|
+
name: definition.name,
|
|
282
|
+
};
|
|
283
|
+
if (definition.description)
|
|
284
|
+
out.description = definition.description;
|
|
285
|
+
if (definition.greeting)
|
|
286
|
+
out.greeting = definition.greeting;
|
|
287
|
+
out.enabled = definition.enabled;
|
|
288
|
+
out.instructions = definition.instructions.endsWith("\n") ? definition.instructions : `${definition.instructions}\n`;
|
|
289
|
+
const keys = [
|
|
290
|
+
"project_context",
|
|
291
|
+
"execution",
|
|
292
|
+
"model",
|
|
293
|
+
"tools",
|
|
294
|
+
"approvals",
|
|
295
|
+
"sub_agents",
|
|
296
|
+
"sub_agent_depth",
|
|
297
|
+
"guardrails",
|
|
298
|
+
"evals",
|
|
299
|
+
"observability",
|
|
300
|
+
"channel",
|
|
301
|
+
"memories",
|
|
302
|
+
"web_chat",
|
|
303
|
+
"schedule",
|
|
304
|
+
"limits",
|
|
305
|
+
];
|
|
306
|
+
for (const key of keys) {
|
|
307
|
+
const value = definition[key];
|
|
308
|
+
if (value === undefined)
|
|
309
|
+
continue;
|
|
310
|
+
if (key === "memories" && Array.isArray(value) && value.length === 0)
|
|
311
|
+
continue;
|
|
312
|
+
const pruned = pruneDefaults(value, defaults[key]);
|
|
313
|
+
if (pruned !== undefined)
|
|
314
|
+
out[key] = pruned;
|
|
315
|
+
}
|
|
316
|
+
return stringifyYaml(out, { lineWidth: 0 });
|
|
317
|
+
}
|
|
318
|
+
function pruneDefaults(value, fallback) {
|
|
319
|
+
if (JSON.stringify(value) === JSON.stringify(fallback))
|
|
320
|
+
return undefined;
|
|
321
|
+
if (value !== null &&
|
|
322
|
+
typeof value === "object" &&
|
|
323
|
+
!Array.isArray(value) &&
|
|
324
|
+
fallback !== null &&
|
|
325
|
+
typeof fallback === "object" &&
|
|
326
|
+
!Array.isArray(fallback)) {
|
|
327
|
+
const result = {};
|
|
328
|
+
for (const [key, child] of Object.entries(value)) {
|
|
329
|
+
const pruned = pruneDefaults(child, fallback[key]);
|
|
330
|
+
if (pruned !== undefined)
|
|
331
|
+
result[key] = pruned;
|
|
332
|
+
}
|
|
333
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
334
|
+
}
|
|
335
|
+
return value;
|
|
336
|
+
}
|
|
337
|
+
/** Builtin tool ids granted by whole groups and by single tools, in group order. */
|
|
338
|
+
export function grantedBuiltinTools(definition) {
|
|
339
|
+
const granted = new Set(definition.tools.builtin_tools ?? []);
|
|
340
|
+
for (const group of definition.tools.builtin)
|
|
341
|
+
for (const tool of BUILTIN_TOOL_GROUPS[group])
|
|
342
|
+
granted.add(tool);
|
|
343
|
+
return BUILTIN_TOOL_IDS.filter((tool) => granted.has(tool));
|
|
344
|
+
}
|
|
345
|
+
/** Every tool id the definition grants: builtin tool names, `<server>.<tool>`, and `agent:<id>`. */
|
|
346
|
+
export function grantedToolIds(definition) {
|
|
347
|
+
const ids = new Set();
|
|
348
|
+
for (const tool of grantedBuiltinTools(definition))
|
|
349
|
+
ids.add(tool);
|
|
350
|
+
for (const [server, tools] of Object.entries(definition.tools.mcp)) {
|
|
351
|
+
for (const tool of tools)
|
|
352
|
+
ids.add(`${server}.${tool}`);
|
|
353
|
+
}
|
|
354
|
+
for (const tool of grantedStageflowTools(definition.tools.stageflow))
|
|
355
|
+
ids.add(stageflowGrantId(tool));
|
|
356
|
+
for (const agentId of definition.sub_agents)
|
|
357
|
+
ids.add(`agent:${agentId}`);
|
|
358
|
+
return ids;
|
|
359
|
+
}
|
|
360
|
+
function isWildcardMcpTool(definition, tool) {
|
|
361
|
+
const dot = tool.indexOf(".");
|
|
362
|
+
if (dot <= 0)
|
|
363
|
+
return false;
|
|
364
|
+
return definition.tools.mcp[tool.slice(0, dot)]?.includes("*") ?? false;
|
|
365
|
+
}
|
|
366
|
+
/** A complete definition with every default applied, for a brand-new agent. */
|
|
367
|
+
export function newAgentDefinition(input) {
|
|
368
|
+
return parseAgentDefinition({
|
|
369
|
+
id: input.id,
|
|
370
|
+
name: input.name,
|
|
371
|
+
instructions: input.instructions,
|
|
372
|
+
...(input.description ? { description: input.description } : {}),
|
|
373
|
+
});
|
|
374
|
+
}
|
|
@@ -147,7 +147,7 @@ function applyPipelineChannels(stage, defaults, pipelineId) {
|
|
|
147
147
|
}
|
|
148
148
|
async function buildLoadedPipelineFromMerge(merge, options) {
|
|
149
149
|
const { projectRoot, requireIo, pipelinePath } = options;
|
|
150
|
-
const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, requires: pipelineRequires, channels: pipelineChannels, warnings: mergeWarnings, } = merge;
|
|
150
|
+
const { entries: rawEntries, pipelineId, agent: pipelineAgent, model: pipelineModel, schemas: pipelineSchemas, requires: pipelineRequires, channels: pipelineChannels, memories: pipelineMemories, warnings: mergeWarnings, } = merge;
|
|
151
151
|
const ctx = { pipelineId, path: pipelinePath };
|
|
152
152
|
const warnings = [...mergeWarnings];
|
|
153
153
|
const normalizeOutcome = normalizePipelineStageEntries(rawEntries, ctx);
|
|
@@ -330,7 +330,9 @@ async function buildLoadedPipelineFromMerge(merge, options) {
|
|
|
330
330
|
if (!materializeOutcome.ok) {
|
|
331
331
|
return loadFailure(materializeOutcome.issues);
|
|
332
332
|
}
|
|
333
|
-
const loadedStages =
|
|
333
|
+
const loadedStages = pipelineMemories?.length
|
|
334
|
+
? materializeOutcome.value.map((stage) => ({ ...stage, memories: pipelineMemories }))
|
|
335
|
+
: materializeOutcome.value;
|
|
334
336
|
const pipeline = {
|
|
335
337
|
id: pipelineId,
|
|
336
338
|
stages: stageIds,
|
|
@@ -339,6 +341,7 @@ async function buildLoadedPipelineFromMerge(merge, options) {
|
|
|
339
341
|
...(pipelineSchemas !== undefined ? { schemas: pipelineSchemas } : {}),
|
|
340
342
|
...(pipelineRequires !== undefined ? { requires: pipelineRequires } : {}),
|
|
341
343
|
...(pipelineChannels !== undefined ? { channels: pipelineChannels } : {}),
|
|
344
|
+
...(pipelineMemories !== undefined ? { memories: pipelineMemories } : {}),
|
|
342
345
|
};
|
|
343
346
|
const effectiveRequires = mergeToolRequires([pipelineRequires, ...loadedStages.map((s) => s.requires)], { pipelineId });
|
|
344
347
|
if (!effectiveRequires.ok)
|