diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index e4a78d177..f44cda3a7 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -122,6 +122,7 @@ - Added an optional `role` field to `task` spawns that gives each subagent a tailored specialist identity: the role is injected as a system-prompt specialization preamble and becomes the subagent's display name and telemetry identity in the registry, IRC roster, and Agent Hub, so delegated trees are no longer clones of one generic worker ([#2467](https://github.com/can1357/oh-my-pi/issues/2467)) - Added a non-blocking specialization advisory to the `task` tool: when a spawner with remaining depth capacity spawns generic role-less workers (a `task`/`quick_task` spawn without a `role`, or the same agent cloned ≥2× all without roles), the result steers it toward tailored specialists. Gated so a leaf at max recursion depth is never nudged; the task-tool depth gate is extracted into a shared `canSpawnAtDepth` helper ([#2469](https://github.com/can1357/oh-my-pi/issues/2469)) - Added a work-aware IRC roster: `irc list` and the subagent peer roster now show each peer's current activity (a short gist of its latest intent/tool) alongside its role-derived display name, so a tree of tailored specialists is legible enough to coordinate. Backed by a new display-only `activity` field on the agent registry ([#2470](https://github.com/can1357/oh-my-pi/issues/2470)) +- Added proactive IRC coordination: when one `task` call spawns ≥2 live siblings with spawn capacity remaining, the result suggests coordinating overlapping work via `irc` (composed onto the specialization advisory), and the subagent COOP/`irc` prompts now actively steer discovery (`list`), coordination (message before overlapping edits), and follow-up (`replyTo`/`await`) instead of only assuming agents resolve collisions on their own ([#2471](https://github.com/can1357/oh-my-pi/issues/2471)) ### Changed diff --git a/packages/coding-agent/src/prompts/system/subagent-system-prompt.md b/packages/coding-agent/src/prompts/system/subagent-system-prompt.md index 59337b45c..f38f2cf45 100644 --- a/packages/coding-agent/src/prompts/system/subagent-system-prompt.md +++ b/packages/coding-agent/src/prompts/system/subagent-system-prompt.md @@ -41,7 +41,10 @@ You NEVER modify files outside this tree or in the original repository. You can reach other live agents via the `irc` tool. Your id is `{{ircSelfId}}`. Currently visible peers: {{ircPeers}} -Use `irc` only when you need a quick answer from a peer; NEVER use it for long-form content. Address peers by id or use `"all"` to broadcast. +Use `irc` only for quick coordination, never long-form content. Address peers by id or use `"all"` to broadcast. +- Discovery: the roster above shows each peer's role and what it is doing now; `irc` op:"list" refreshes it. +- Coordination: before you edit a file or start work a sibling may already own, message that peer first — overlapping edits collide. +- Follow-up: answer a peer's question with a short reply (set `replyTo`); use `await` only when you genuinely cannot proceed without the answer. {{/if}} COMPLETION diff --git a/packages/coding-agent/src/prompts/tools/irc.md b/packages/coding-agent/src/prompts/tools/irc.md index b202daed9..74f819846 100644 --- a/packages/coding-agent/src/prompts/tools/irc.md +++ b/packages/coding-agent/src/prompts/tools/irc.md @@ -17,7 +17,7 @@ Reach for `irc` proactively when continuing alone is wasteful or wrong; when in - **Unexpected state** — missing file, config contradicting the assignment, API/tool behaving differently than told. DM `Main` (or your spawner) instead of guessing. - **Blocked by another agent** — a peer holds the file/branch/resource or decision you need, or started the change you're about to make. DM them (or broadcast to discover who) before duplicating work. - **Decision outside your scope** — a genuine fork the assignment didn't pre-decide. Ask the requester rather than picking unilaterally. -- **Coordination** — a peer's in-flight work would benefit from yours, or vice-versa. +- **Coordination** — a peer's in-flight work overlaps yours (the roster shows each peer's role and current activity); message before editing a shared file or duplicating a sibling's change. NEVER for: routine progress updates, things a tool call can verify, questions your assignment/repo/docs already answer. diff --git a/packages/coding-agent/src/task/index.ts b/packages/coding-agent/src/task/index.ts index a846f69fb..e9ad724a7 100644 --- a/packages/coding-agent/src/task/index.ts +++ b/packages/coding-agent/src/task/index.ts @@ -366,6 +366,49 @@ export function buildSpecializationAdvisory( ); } +/** + * Suggestion — never a rejection — nudging the spawner to coordinate via `irc` + * when one call creates ≥2 live siblings and it still holds spawn capacity. + * Returns undefined when there is nothing to coordinate or IRC is unavailable. + */ +export function buildCoordinationAdvisory( + items: TaskItem[], + depthCapacity: boolean, + ircEnabled: boolean, +): string | undefined { + if (!depthCapacity || !ircEnabled || items.length < 2) return undefined; + return ( + `Coordinate: ${items.length} siblings are running together. If their work overlaps, have them ` + + `message each other via \`irc\` (by id, or "all" to broadcast) before editing shared files — ` + + `live coordination beats a serial handoff. Check \`irc\` op:"list" to see who is doing what.` + ); +} + +/** + * Compose the non-blocking advisory appended to a `task` result: the + * specialization nudge, plus — only when the siblings keep running after this + * call (`willRunAsync`) — the coordination suggestion. Coordination is gated on + * async because a sync fanout's siblings have already finished, so a + * "coordinate while they run" hint would misfire. Returns undefined when + * neither applies. + */ +export function composeSpawnAdvisory(args: { + agentName: string | undefined; + items: TaskItem[]; + depthCapacity: boolean; + ircEnabled: boolean; + willRunAsync: boolean; +}): string | undefined { + return ( + [ + buildSpecializationAdvisory(args.agentName, args.items, args.depthCapacity), + args.willRunAsync ? buildCoordinationAdvisory(args.items, args.depthCapacity, args.ircEnabled) : undefined, + ] + .filter(Boolean) + .join("\n\n") || undefined + ); +} + /** Sentinel for async jobs whose subagent finished with a failing result; progress is already updated. */ class TaskJobError extends Error {} @@ -539,16 +582,35 @@ export class TaskTool implements AgentTool