Add script steps and critic fields to workflow definitions
Why: The workflow executor needs a shared contract for subagent profiles, plugin scripts, and per-step plus whole-run retry caps. Evidence: go test ./... passed, including the new workflow_def golden. Impact: New fields are omitempty, so existing workflow JSON still decodes. Kind script is additive. Refs: feature/agent-harness-p4 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -207,6 +207,26 @@ func TestGoldenIngest(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoldenWorkflowDef(t *testing.T) {
|
||||
golden(t, "workflow_def", WorkflowDef{
|
||||
ID: "demo.brief", Title: "简报", Description: "按主题写一份简报",
|
||||
IntentID: "demo.brief", MaxRetries: 6,
|
||||
Steps: []WorkflowStep{
|
||||
{ID: "length", Title: "篇幅", Kind: "hitl", Hitl: &HITLCardTemplate{
|
||||
Question: "篇幅?", Kind: HITLKindChoice, AllowFreeInput: false,
|
||||
Choices: []HITLChoice{{ID: "short", Label: "短", Description: "一页", Impact: "更快"}},
|
||||
}},
|
||||
{ID: "draft", Title: "起草", Kind: "prompt", Agent: "research",
|
||||
Prompt: "写一份关于 {{slots.topic}} 的简报。用户说:{{input}}。上一步:{{steps.length.output}}",
|
||||
Critic: &StepCritic{Criteria: "必须点明主题", MaxRetries: 1}},
|
||||
{ID: "lookup", Title: "查时间", Kind: "tool", Tool: "time_now", Args: json.RawMessage(`{"tz":"UTC"}`)},
|
||||
{ID: "save", Title: "存稿", Kind: "artifact", Artifact: "brief.md", Prompt: "{{steps.draft.output}}"},
|
||||
{ID: "note", Title: "通知", Kind: "card", Card: &ActivityCardTemplate{Kind: CardKindResult, Title: "简报已写好"}},
|
||||
{ID: "run", Title: "脚本", Kind: "script", Script: "scripts/demo.py"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestGoldenPlugin(t *testing.T) {
|
||||
golden(t, "plugin_manifest", PluginManifest{
|
||||
ID: "example", Name: "示例插件", Version: "0.1.0", APIVersion: PluginAPIVersion,
|
||||
|
||||
@@ -52,24 +52,35 @@ type PluginPanel struct {
|
||||
}
|
||||
|
||||
// WorkflowDef:工作流即数据(4.6)。Step 可产 HITL 卡片、调工具、产出工件。
|
||||
// 模板占位符:{{input}}、{{slots.<key>}}、{{steps.<id>.output}}。
|
||||
type WorkflowDef struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description,omitempty"`
|
||||
IntentID string `json:"intentId,omitempty"` // 绑定意图(命中即启动)
|
||||
MaxRetries int `json:"maxRetries,omitempty"` // 整条工作流的 critic 重试上限
|
||||
Steps []WorkflowStep `json:"steps"`
|
||||
}
|
||||
|
||||
// StepCritic:单步验收。无法解析的判定按不通过处理。
|
||||
type StepCritic struct {
|
||||
Criteria string `json:"criteria"`
|
||||
MaxRetries int `json:"maxRetries,omitempty"` // 本步重试上限;0 表示缺省 1 次
|
||||
}
|
||||
|
||||
type WorkflowStep struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Kind string `json:"kind"` // prompt | tool | hitl | artifact | card
|
||||
Kind string `json:"kind"` // prompt | tool | hitl | artifact | card | script
|
||||
Prompt string `json:"prompt,omitempty"` // prompt: 发给模型的指令模板
|
||||
Agent string `json:"agent,omitempty"` // prompt: 子代理 profile,缺省 general
|
||||
Tool string `json:"tool,omitempty"` // tool: 工具名
|
||||
Args json.RawMessage `json:"args,omitempty"` // tool: 参数模板
|
||||
Hitl *HITLCardTemplate `json:"hitl,omitempty"` // hitl: 卡片模板
|
||||
Artifact string `json:"artifact,omitempty"` // artifact: 产出工件名模板
|
||||
Card *ActivityCardTemplate `json:"card,omitempty"` // card: 产收件箱任务卡
|
||||
Script string `json:"script,omitempty"` // script: 插件目录内的相对路径
|
||||
Critic *StepCritic `json:"critic,omitempty"`
|
||||
}
|
||||
|
||||
// ActivityCardTemplate:工作流步骤产卡模板(kind=card)——步骤执行时生成
|
||||
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"id": "demo.brief",
|
||||
"title": "简报",
|
||||
"description": "按主题写一份简报",
|
||||
"intentId": "demo.brief",
|
||||
"maxRetries": 6,
|
||||
"steps": [
|
||||
{
|
||||
"id": "length",
|
||||
"title": "篇幅",
|
||||
"kind": "hitl",
|
||||
"hitl": {
|
||||
"question": "篇幅?",
|
||||
"kind": "choice",
|
||||
"choices": [
|
||||
{
|
||||
"id": "short",
|
||||
"label": "短",
|
||||
"description": "一页",
|
||||
"impact": "更快"
|
||||
}
|
||||
],
|
||||
"allowFreeInput": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "draft",
|
||||
"title": "起草",
|
||||
"kind": "prompt",
|
||||
"prompt": "写一份关于 {{slots.topic}} 的简报。用户说:{{input}}。上一步:{{steps.length.output}}",
|
||||
"agent": "research",
|
||||
"critic": {
|
||||
"criteria": "必须点明主题",
|
||||
"maxRetries": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lookup",
|
||||
"title": "查时间",
|
||||
"kind": "tool",
|
||||
"tool": "time_now",
|
||||
"args": {
|
||||
"tz": "UTC"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save",
|
||||
"title": "存稿",
|
||||
"kind": "artifact",
|
||||
"prompt": "{{steps.draft.output}}",
|
||||
"artifact": "brief.md"
|
||||
},
|
||||
{
|
||||
"id": "note",
|
||||
"title": "通知",
|
||||
"kind": "card",
|
||||
"card": {
|
||||
"kind": "result",
|
||||
"title": "简报已写好"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "run",
|
||||
"title": "脚本",
|
||||
"kind": "script",
|
||||
"script": "scripts/demo.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
+30
@@ -261,6 +261,36 @@ export interface PluginPanel {
|
||||
id: string; title: string; icon?: string; body: UINode[]; refreshTool?: string;
|
||||
}
|
||||
|
||||
/** 模板占位符:{{input}}、{{slots.<key>}}、{{steps.<id>.output}}。 */
|
||||
export interface WorkflowDef {
|
||||
id: string; title: string; description?: string; intentId?: string;
|
||||
/** 整条工作流的 critic 重试上限。 */
|
||||
maxRetries?: number;
|
||||
steps: WorkflowStep[];
|
||||
}
|
||||
|
||||
export interface StepCritic {
|
||||
criteria: string;
|
||||
/** 本步重试上限;缺省 1 次。 */
|
||||
maxRetries?: number;
|
||||
}
|
||||
|
||||
export interface WorkflowStep {
|
||||
id: string; title: string;
|
||||
kind: 'prompt' | 'tool' | 'hitl' | 'artifact' | 'card' | 'script';
|
||||
prompt?: string;
|
||||
/** prompt 步骤的子代理 profile,缺省 general。 */
|
||||
agent?: string;
|
||||
tool?: string;
|
||||
args?: unknown;
|
||||
hitl?: { question: string; kind: HITLKind; choices?: HITLChoice[]; allowFreeInput: boolean; freeInputHint?: string };
|
||||
artifact?: string;
|
||||
card?: { kind: CardKind; title: string; tone?: string; body?: UINode[]; actions?: { id: string; label: string; style?: 'primary' | 'default' | 'danger'; command?: string }[] };
|
||||
/** script 步骤在插件目录内的相对路径。 */
|
||||
script?: string;
|
||||
critic?: StepCritic;
|
||||
}
|
||||
|
||||
export interface PluginWorkspace {
|
||||
id: string; title: string; icon?: string; shortcut?: string;
|
||||
badgeTool?: string; body: UINode[]; refreshTool?: string;
|
||||
|
||||
Reference in New Issue
Block a user