Merge pull request #4381 from code-yeongyu/fix/team-mode-closure-prompts

fix(team-mode): make lead close teams on its own initiative
This commit is contained in:
YeonGyu-Kim
2026-05-24 15:37:28 +09:00
committed by GitHub
7 changed files with 35 additions and 106 deletions
@@ -91,7 +91,7 @@ Do not use \`oracle\`, \`prometheus\`, or other non-eligible agents here. For th
## Lifecycle
Teams are **ephemeral**: one team per phase of work. The moment a phase ends, or the team's shape no longer fits the next problem, **call \`team_delete\` immediately and spawn a fresh team for the next phase**. There is no in-place reshape; restructuring is delete-then-create. Lingering teams burn sessions, mailbox quota, and member-turn budget.
Teams are **ephemeral**. There is no in-place reshape restructuring is delete-then-create. Lingering teams burn sessions, mailbox quota, and member-turn budget every idle minute.
One cycle:
@@ -99,8 +99,28 @@ One cycle:
2. Lead assigns work with \`team_send_message\` or \`team_task_create\`.
3. Members report progress with \`team_send_message\` plus \`team_task_update\`.
4. Lead and members track progress with \`team_task_list\`, \`team_task_get\`, and \`team_status\`.
5. A member that finishes early asks to leave with \`team_shutdown_request\`; the lead handles \`team_approve_shutdown\` or \`team_reject_shutdown\`.
6. **Phase done or shape outgrown? Call \`team_delete\` now; no idle members "just in case." Loop to step 1 for the next phase.**
5. When the **Closure Contract** below holds, the lead runs the **Closure Sequence** in the same turn. Loop to step 1 for the next phase.
### Closure Contract
A team is **closable** when ALL of the following hold, as observed by \`team_task_list({ teamRunId })\` and \`team_status({ teamRunId })\`:
- Every task is in a terminal state: \`completed\` or \`failed\`. (No \`pending\`, no \`claimed\`, no \`in_progress\`.)
- No outstanding \`team_shutdown_request\` is still awaiting approval.
- The user has not asked you to keep the team open for follow-up.
Closure is **the lead's responsibility**, not the user's. Do not wait to be told. The check runs after every \`team_task_update\` that completes or fails a task — if the contract holds, close in the same turn. Closure now is cheaper than closure after the next user message, because by then the model has paged out the context.
### Closure Sequence
Run in order:
1. For each active member \`M\` returned by \`team_status\`:
- \`team_shutdown_request({ teamRunId, memberName: M })\`
- \`team_approve_shutdown({ teamRunId, memberName: M })\`
2. \`team_delete({ teamRunId })\`
If step 2 errors because a member is still active, re-run \`team_status\`. Use \`team_delete({ teamRunId, force: true })\` **only** after confirming the remaining member is not mid-write — for example, after an unrecoverable error path where graceful shutdown is impossible. Do not use \`force: true\` to skip step 1.
## Task ownership
+4 -4
View File
@@ -38,9 +38,9 @@ Going idle after sending a message is the expected flow — it does NOT mean you
## Wrap-up
When you finish your assigned work, ALWAYS:
1. Send your results to the lead via \`team_send_message\`.
2. Mark your task as completed via \`team_task_update\`.
3. Send a completion message to the lead so the lead can decide whether to request shutdown.
When you finish your assigned work, ALWAYS, in this order:
1. Mark your task \`status: "completed"\` (or \`"failed"\` with a reason) via \`team_task_update\` — the lead's closure check reads \`team_task_list\`, so the task update must land before any completion message.
2. Re-check \`team_task_list\` for newly unblocked work. If there is any, claim it and continue — do not idle.
3. If \`team_task_list\` shows nothing left for you, send the lead a single short \`team_send_message\` with your results and the phrase \`closure-ready\` so the lead knows you have no more work in flight. Then go idle.
`
}
@@ -224,7 +224,7 @@ describe("createTeamRun", () => {
expect(firstPrompt).toContain("Include `summary` and `references`")
expect(firstPrompt).toContain("Move to `status: \"in_progress\"` when you start working")
expect(firstPrompt).toContain("Do NOT call this from inside team members")
expect(firstPrompt).toContain("lead can decide whether to request shutdown")
expect(firstPrompt).toContain("closure-ready")
expect(firstPrompt).toContain("user interacts primarily with the team lead")
expect(firstPrompt).toContain("Idle is normal")
expect(firstPrompt).toContain("structured JSON status messages")