Run tool-started workflows with the script copy for that call

Why: A conversation run has no launch of its own, so a script step looked up an empty copy and refused to run.
Evidence: go test ./internal/runtime/ -run TestRegisteredWorkflowUsesItsOwnScriptCopy passed. The body is taken from the launch passed into the runner.
Impact: Intent-started runs still use the copy made at start.
Refs: feature/agent-harness-p4
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-01 16:36:54 +00:00
co-authored by Cursor
parent 7112ace34f
commit 4b4be2be25
3 changed files with 26 additions and 9 deletions
+5 -5
View File
@@ -177,7 +177,7 @@ func (w WorkflowRunner) run(rc RunCtx, launch workflow.Launch) (workflowOutcome,
if err != nil {
return outcome(def, statuses, arts, drops, err.Error()), err
}
output, stepArts, reason, err := w.runStepWithCritic(rc, def, rendered, vars, prev, &wholeLeft, &drops)
output, stepArts, reason, err := w.runStepWithCritic(rc, def, rendered, vars, prev, launch.Scripts, &wholeLeft, &drops)
arts = append(arts, stepArts...)
if err != nil {
statuses[i] = "failed"
@@ -198,7 +198,7 @@ func (w WorkflowRunner) run(rc RunCtx, launch workflow.Launch) (workflowOutcome,
return res, nil
}
func (w WorkflowRunner) runStepWithCritic(rc RunCtx, def core.WorkflowDef, step core.WorkflowStep, vars workflow.Vars, prev string, wholeLeft *int, drops *[]string) (string, []*core.ArtifactRef, string, error) {
func (w WorkflowRunner) runStepWithCritic(rc RunCtx, def core.WorkflowDef, step core.WorkflowStep, vars workflow.Vars, prev string, scripts map[string]string, wholeLeft *int, drops *[]string) (string, []*core.ArtifactRef, string, error) {
stepRetries := 1
if step.Critic != nil && step.Critic.MaxRetries > 0 {
stepRetries = step.Critic.MaxRetries
@@ -216,7 +216,7 @@ func (w WorkflowRunner) runStepWithCritic(rc RunCtx, def core.WorkflowDef, step
} else if note != "" {
current.Prompt = "未通过验收:" + note
}
output, got, err := w.runWorkflowStep(rc, current, vars, prev)
output, got, err := w.runWorkflowStep(rc, current, vars, prev, scripts)
arts = append(arts, got...)
if err != nil {
return output, arts, err.Error(), err
@@ -242,7 +242,7 @@ func (w WorkflowRunner) runStepWithCritic(rc RunCtx, def core.WorkflowDef, step
}
}
func (w WorkflowRunner) runWorkflowStep(rc RunCtx, step core.WorkflowStep, vars workflow.Vars, prev string) (string, []*core.ArtifactRef, error) {
func (w WorkflowRunner) runWorkflowStep(rc RunCtx, step core.WorkflowStep, vars workflow.Vars, prev string, scripts map[string]string) (string, []*core.ArtifactRef, error) {
switch step.Kind {
case "prompt":
return runPromptStep(rc, step)
@@ -302,7 +302,7 @@ func (w WorkflowRunner) runWorkflowStep(rc RunCtx, step core.WorkflowStep, vars
}
return string(created.ID), nil, nil
case "script":
return executeScriptStep(rc, w, step)
return executeScriptStep(rc, w, step, scripts)
default:
return "", nil, fmt.Errorf("workflow: 未知步骤类型 %s", step.Kind)
}
+8 -4
View File
@@ -63,10 +63,14 @@ func scriptSandbox(rc RunCtx) (string, error) {
return sandbox, nil
}
func executeScriptStep(rc RunCtx, runner WorkflowRunner, step core.WorkflowStep) (string, []*core.ArtifactRef, error) {
body, err := scriptBody(rc, step.Script)
if err != nil {
return "", nil, err
func executeScriptStep(rc RunCtx, runner WorkflowRunner, step core.WorkflowStep, scripts map[string]string) (string, []*core.ArtifactRef, error) {
body := scripts[step.Script]
if strings.TrimSpace(body) == "" {
var err error
body, err = scriptBody(rc, step.Script)
if err != nil {
return "", nil, err
}
}
sandbox, err := scriptSandbox(rc)
if err != nil {
+13
View File
@@ -209,6 +209,19 @@ f.flush()
}
}
func TestRegisteredWorkflowUsesItsOwnScriptCopy(t *testing.T) {
f := &wfFake{sandbox: t.TempDir(), settings: scriptSettings()}
res, err := (WorkflowRunner{}).run(f, workflow.Launch{
Def: core.WorkflowDef{ID: "demo.script", Title: "脚本", Steps: []core.WorkflowStep{{
ID: "run", Title: "跑", Kind: "script", Script: "workflows/scripts/demo.py",
}}},
Scripts: map[string]string{"workflows/scripts/demo.py": "print('from-launch')\n"},
})
if err != nil || !strings.Contains(res.Summary, "完成") {
t.Fatalf("err %v summary %s", err, res.Summary)
}
}
func TestModelScriptNeedsSwitchAndConfirm(t *testing.T) {
f := &wfFake{sandbox: t.TempDir()}
out := (&directRun{rc: f}).runRegisteredWorkflow(`{"script":"print('pong')"}`)