fix(squad): trim stall guidance prompts

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
J
2026-06-08 14:59:33 +08:00
parent 9cd17449cb
commit cd46429483
4 changed files with 16 additions and 23 deletions

View File

@@ -611,7 +611,7 @@ func buildMetaSkillContent(provider string, ctx TaskContextForEnv) string {
b.WriteString("7. **If you reply, post it as a comment — this step is mandatory when you reply.** Text in your terminal or run logs is NOT delivered to the user. ")
b.WriteString(BuildCommentReplyInstructions(provider, ctx.IssueID, ctx.TriggerCommentID))
b.WriteString("8. Before exiting: only if this run produced a fact that clears the high bar (important AND likely to be re-read by future runs on this same issue, e.g. a new PR URL or deploy URL), or you noticed a metadata key from entry that is now stale, pin or clear it via `multica issue metadata set`/`delete`. Most runs write nothing here — that is the expected outcome, not a gap. When in doubt, do not write. See the `## Issue Metadata` section above for the full bar.\n")
fmt.Fprintf(&b, "9. Do NOT change the issue status unless the comment explicitly asks for it — with one exception: if you did real work this turn and are stopping with the task NOT finished (you are blocked, waiting on someone, or only completed a partial/interim step and cannot continue right now), run `multica issue status %s blocked` and pin `blocked_reason` (and `waiting_on` when you are waiting on a specific person or event). Once your task ends nothing continues automatically, so an \"I'll continue later\" comment alone leaves the issue looking like it is still progressing when no session is running. Skip the status change only if your Agent Identity forbids issue status changes — then make the blocker explicit in your comment.\n\n", ctx.IssueID)
fmt.Fprintf(&b, "9. Do NOT change the issue status unless the comment explicitly asks for it — except when you did real work and must stop before the task is finished. In that case, run `multica issue status %s blocked`, pin `blocked_reason` and `waiting_on` when relevant, and explain the blocker in your reply. Skip this only if your Agent Identity forbids status changes.\n\n", ctx.IssueID)
} else {
// Assignment-triggered: defer to agent Skills for workflow specifics.
b.WriteString("You are responsible for managing the issue status throughout your work, unless your Agent Identity forbids issue status changes.\n\n")
@@ -627,7 +627,7 @@ func buildMetaSkillContent(provider string, ctx TaskContextForEnv) string {
}
b.WriteString("7. Before exiting: only if this run produced a fact that clears the high bar (important AND likely to be re-read by future runs on this same issue, e.g. a new PR URL or deploy URL), or you noticed a metadata key from entry that is now stale, pin or clear it via `multica issue metadata set`/`delete`. Most runs write nothing here — that is the expected outcome, not a gap. When in doubt, do not write. See the `## Issue Metadata` section above for the full bar.\n")
fmt.Fprintf(&b, "8. When done, run `multica issue status %s in_review` unless your Agent Identity forbids issue status changes; if it does, skip this step.\n", ctx.IssueID)
fmt.Fprintf(&b, "9. If blocked, run `multica issue status %s blocked` unless your Agent Identity forbids issue status changes. The same applies when you stop with the task unfinished and nothing will continue it automatically — you only finished an interim/partial step, or you are waiting on input: treat that as blocked, set the status, and pin `blocked_reason` (and `waiting_on` when you are waiting on a specific person or event). Leaving the issue in `in_progress`/`in_review` while no session is running makes it look like work is still happening when it has actually stopped. Post a comment explaining the blocker unless your Agent Identity forbids issue comments.\n\n", ctx.IssueID)
fmt.Fprintf(&b, "9. If blocked, or if you must stop with unfinished work and no automatic continuation, run `multica issue status %s blocked` unless your Agent Identity forbids status changes. Pin `blocked_reason` and `waiting_on` when relevant, and post a comment explaining the blocker unless issue comments are forbidden.\n\n", ctx.IssueID)
}
// Sub-issue creation semantics — the only piece of the old Parent /

View File

@@ -172,7 +172,7 @@ func TestBriefCarriesBlockedOnStallGuidance(t *testing.T) {
})
for _, want := range []string{
"Do NOT change the issue status unless the comment explicitly asks for it",
"stopping with the task NOT finished",
"must stop before the task is finished",
"multica issue status " + issueID + " blocked",
"blocked_reason",
} {
@@ -185,8 +185,8 @@ func TestBriefCarriesBlockedOnStallGuidance(t *testing.T) {
// task unfinished and nothing continuing automatically.
assignment := buildMetaSkillContent("claude", TaskContextForEnv{IssueID: issueID})
for _, want := range []string{
"If blocked, run `multica issue status " + issueID + " blocked`",
"The same applies when you stop with the task unfinished",
"run `multica issue status " + issueID + " blocked`",
"must stop with unfinished work",
"blocked_reason",
} {
if !strings.Contains(assignment, want) {
@@ -314,7 +314,8 @@ func TestAssignmentTriggeredProtocolHonorsAgentIdentity(t *testing.T) {
"Complete the task within your Agent Identity boundaries.",
"Do not investigate, implement, create issues, update issues, or delegate if your Agent Identity forbids that action",
"When done, run `multica issue status " + issueID + " in_review` unless your Agent Identity forbids issue status changes; if it does, skip this step.",
"If blocked, run `multica issue status " + issueID + " blocked` unless your Agent Identity forbids issue status changes.",
"If blocked, or if you must stop with unfinished work and no automatic continuation",
"run `multica issue status " + issueID + " blocked` unless your Agent Identity forbids status changes.",
} {
if !strings.Contains(out, want) {
t.Errorf("assignment-triggered brief missing identity-bound workflow text %q\n---\n%s", want, out)

View File

@@ -55,18 +55,11 @@ Your responsibilities, in order:
- a delegated member posts an update or asks you a question;
- a delegated member finishes and the issue moves forward;
- someone @mentions you again on this issue.
5. **Re-evaluate on each trigger.** When you wake up again, read the new
activity and decide whether to delegate the next step, escalate to
the human reporter, or close the loop. Before you settle on
` + "`" + `no_action` + "`" + `, consult the **Current Execution State** snapshot
below: a delegated agent's task ends the moment it stops producing
output, so an interim "I'll continue later" report does NOT mean a
session is still running. If no worker session is active and the issue
is not actually done, the work has stalled — delegate the next step,
mark the issue ` + "`" + `blocked` + "`" + `, or escalate to a human rather than
silently recording ` + "`" + `no_action` + "`" + `. Record ` + "`" + `no_action` + "`" + ` and exit
silently only when no action genuinely is needed (e.g. a worker is
still running, or a member posted an update that requires no response).
5. **Re-evaluate on each trigger.** Read the new activity and the
**Current Execution State** snapshot. If no worker task is active and
the issue is not done, delegate the next step, mark ` + "`" + `blocked` + "`" + `, or
escalate; do not silently record ` + "`" + `no_action` + "`" + `. Use ` + "`" + `no_action` + "`" + `
only when no follow-up is needed.
Hard rules:
- EVERY delegation MUST use the full mention markdown syntax
@@ -170,12 +163,11 @@ func buildSquadExecutionState(ctx context.Context, q *db.Queries, issueID pgtype
if len(workers) == 0 {
sb.WriteString("**No worker task is currently active on this issue.** ")
sb.WriteString("No delegated agent has an active queued, waiting, or running task right now. A worker's task ends the moment it stops producing output, so a recent comment that reads like work is still in progress (\"I'll continue later\", \"still verifying\", a partial/interim report) does NOT mean anything is active — nothing resumes automatically. ")
sb.WriteString("Before you record `no_action`, confirm the issue is genuinely done or genuinely waiting on a human. If work remains, delegate the next step, or mark the issue `blocked` and escalate. An interim report with no active session is a stalled issue, not a progressing one.\n")
sb.WriteString("Nothing will continue automatically unless you delegate a new step. Before `no_action`, confirm the issue is done or waiting on a human; otherwise delegate, mark `blocked`, or escalate.\n")
return sb.String()
}
fmt.Fprintf(&sb, "**%d worker task(s) currently active on this issue.** A delegated agent has queued, waiting, or running work:\n", len(workers))
fmt.Fprintf(&sb, "**%d worker task(s) currently active on this issue:**\n", len(workers))
for _, t := range workers {
name := "a squad member"
if ag, err := q.GetAgent(ctx, t.AgentID); err == nil {
@@ -183,7 +175,7 @@ func buildSquadExecutionState(ctx context.Context, q *db.Queries, issueID pgtype
}
fmt.Fprintf(&sb, "- %s — status `%s`\n", name, t.Status)
}
sb.WriteString("\nYou usually do NOT need to delegate the same work again while a worker task is in flight — recording `no_action` and waiting for it to finish is appropriate. Re-delegate only if the active work is clearly wrong or stuck, or hand off a genuinely independent next step.\n")
sb.WriteString("\nUsually wait for active worker tasks to finish. Re-delegate only if the active work is wrong/stuck or you have an independent next step.\n")
return sb.String()
}

View File

@@ -431,7 +431,7 @@ func TestBuildSquadLeaderBriefing_ExecutionState(t *testing.T) {
insertActiveTask(t, worker, issueID, false)
out = buildSquadLeaderBriefing(ctx, testHandler.Queries, squad, issueID)
for _, want := range []string{
"worker task(s) currently active on this issue.",
"worker task(s) currently active on this issue:",
"Exec Worker",
"status `running`",
} {