384a206737
- Changed `AgentOutputManager` to use requested names verbatim, adding `-2`/`-3` suffixes only on repeats (e.g. `Anna`, `Anna-2`). - Renamed main agent id from `0-Main` to `Main`; nested ids now use dot notation without numeric prefix (e.g. `Parent.Child`). - Updated task widget to render dotted hierarchy as `Parent>Child` breadcrumb without leading index. - Resume scan now tracks seen names instead of a counter to avoid clobbering prior outputs.
120 lines
8.8 KiB
Markdown
120 lines
8.8 KiB
Markdown
# irc
|
|
|
|
> Send short prose messages to other live agents in the current process.
|
|
|
|
## Source
|
|
- Entry: `packages/coding-agent/src/tools/irc.ts`
|
|
- Model-facing prompt: `packages/coding-agent/src/prompts/tools/irc.md`
|
|
- Key collaborators:
|
|
- `packages/coding-agent/src/registry/agent-registry.ts` — process-global live agent directory.
|
|
- `packages/coding-agent/src/session/agent-session.ts` — side-channel reply generation and history injection.
|
|
- `packages/coding-agent/src/prompts/system/irc-incoming.md` — no-tools auto-reply prompt.
|
|
- `packages/coding-agent/src/tools/index.ts` — tool availability gating.
|
|
- `packages/coding-agent/src/config/settings-schema.ts` — `irc.enabled` default.
|
|
- `packages/coding-agent/src/modes/controllers/event-controller.ts` — renders IRC events into chat UI.
|
|
- `packages/coding-agent/src/modes/utils/ui-helpers.ts` — formats `[IRC]` transcript lines.
|
|
- `packages/coding-agent/src/task/executor.ts` — carries `irc.enabled` into subagents.
|
|
|
|
## Inputs
|
|
|
|
### `op: "list"`
|
|
|
|
| Field | Type | Required | Description |
|
|
| --- | --- | --- | --- |
|
|
| `op` | `"list"` | Yes | Lists peers visible to the caller. |
|
|
|
|
### `op: "send"`
|
|
|
|
| Field | Type | Required | Description |
|
|
| --- | --- | --- | --- |
|
|
| `op` | `"send"` | Yes | Sends one message to one peer or to `"all"`. |
|
|
| `to` | `string` | Yes | Peer id such as `Main`, or `"all"` for broadcast. Whitespace is trimmed. |
|
|
| `message` | `string` | Yes | Message body. Whitespace is trimmed; empty-after-trim is rejected. |
|
|
| `awaitReply` | `boolean` | No | Wait for prose replies. Defaults to `true` for direct messages and `false` for `to: "all"`. |
|
|
|
|
## Outputs
|
|
- Single-shot `AgentToolResult`; no streaming updates.
|
|
- `content` is one text block.
|
|
- `list` returns either `No other live agents.` or a bullet list headed by `<n> peer(s):`.
|
|
- `send` returns delivery summary text, then optional `## Replies`, `## Failed`, and `Unknown / unavailable peers:` sections.
|
|
- `details` is structured metadata:
|
|
- `list`: `{ op, from, peers, channels }`
|
|
- `send`: `{ op, from, to, delivered, replies?, failed?, notFound? }`
|
|
- The tool does not return raw IRC frames, message ids, or a transcript object.
|
|
|
|
## Flow
|
|
1. `IrcTool.createIf` only constructs the tool when `irc.enabled` is on and the session has both an `AgentRegistry` and `getAgentId` (`packages/coding-agent/src/tools/irc.ts`).
|
|
2. Tool discovery adds another gate in `packages/coding-agent/src/tools/index.ts`: if the caller is `Main` and `async.enabled` is off, `irc` is hidden because the main agent cannot talk to concurrent peers in sync mode.
|
|
3. `execute` resolves the process-global registry and sender id. Missing either returns a text error result instead of throwing.
|
|
4. `op: "list"` calls `registry.listVisibleTo(senderId)`, which exposes every other agent in flat namespace whose status is `running` or `idle` (`packages/coding-agent/src/registry/agent-registry.ts`).
|
|
5. `list` formats human-readable lines and returns `channels` as `['all', ...peerIds]`. These are logical targets only; there is no channel join state.
|
|
6. `op: "send"` trims `to` and `message`; missing values produce text errors.
|
|
7. `send` resolves targets:
|
|
- `to === "all"`: all visible peers.
|
|
- otherwise: one exact registry id, excluding self and excluding peers not in `running`/`idle`.
|
|
8. `send` chooses `awaitReply = params.awaitReply ?? !isBroadcast`.
|
|
9. Each target is dispatched in parallel via `target.session.respondAsBackground(...)`. One slow or failing peer does not block dispatch to the others.
|
|
10. `respondAsBackground` emits an `irc_message` session event, forwards a display-only relay to the main session UI, and either:
|
|
- queues just the incoming message for later history injection when `awaitReply === false`, or
|
|
- renders `packages/coding-agent/src/prompts/system/irc-incoming.md`, runs `runEphemeralTurn` with `toolChoice: "none"`, emits an auto-reply event, then queues both incoming and reply messages for history injection.
|
|
11. Deferred injection waits until the recipient is no longer streaming; `#flushPendingBackgroundExchanges` appends the custom messages through normal `message_start`/`message_end` external events so persistence and listeners see them.
|
|
12. Dispatch waits are bounded by `irc.timeoutMs` (default `120_000` ms). A value of `0` disables the local timeout; parent aborts still abort the dispatch.
|
|
13. `send` aggregates `delivered`, `replies`, `failed`, and `notFound`, then returns one text summary plus matching `details`.
|
|
|
|
## Modes / Variants
|
|
- `list`: enumerate visible peers and logical channels.
|
|
- `send` direct message: one exact peer id, default synchronous auto-reply.
|
|
- `send` broadcast: `to: "all"`, default fire-and-forget (`awaitReply: false`) to every visible peer.
|
|
- `send` with `awaitReply: false`: recipient records the incoming message but does not generate a reply.
|
|
- `send` with `awaitReply: true`: recipient performs a no-tools ephemeral LLM turn and returns prose.
|
|
|
|
## Side Effects
|
|
- Session state
|
|
- Reads from the process-global `AgentRegistry`.
|
|
- Emits `irc_message` session events on recipient sessions.
|
|
- Queues IRC custom messages into recipient persisted history after the current stream finishes.
|
|
- For non-main recipients, forwards display-only relay observations into the main session UI; these relays are not persisted to the main agent history.
|
|
- Subagents inherit `irc.enabled` from task executor settings.
|
|
- User-visible prompts / interactive UI
|
|
- IRC events render as `[IRC]` transcript lines in the TUI.
|
|
- Auto-replies are generated from `packages/coding-agent/src/prompts/system/irc-incoming.md` and explicitly forbid tool use.
|
|
- Background work / cancellation
|
|
- `send` starts one background `respondAsBackground` call per target.
|
|
- The caller's `AbortSignal` is forwarded into each background reply turn. `irc.timeoutMs` creates a per-recipient `AbortController` and reports timeout failures per target.
|
|
- Network
|
|
- No IRC server connection.
|
|
- When `awaitReply: true`, the recipient may make model-provider API calls through `runEphemeralTurn`.
|
|
- Filesystem
|
|
- No direct filesystem writes in the tool itself.
|
|
|
|
## Limits & Caps
|
|
- Availability gates:
|
|
- `irc.enabled` defaults to `true` in `packages/coding-agent/src/config/settings-schema.ts`.
|
|
- Main agent tool discovery suppresses `irc` when `async.enabled` is off (`packages/coding-agent/src/tools/index.ts`).
|
|
- Visibility scope: only peers in status `running` or `idle` are addressable via `listVisibleTo`.
|
|
- Reply execution:
|
|
- No tools are available in auto-reply turns (`toolChoice: "none"` in `runEphemeralTurn`).
|
|
- `irc.timeoutMs` defaults to `120_000`; `0` disables the timeout, non-finite values fall back to the default, and positive values are truncated and clamped to at least `1` ms.
|
|
- No retry, backoff, rate limit, or reply length cap is defined in `irc.ts`; behavior otherwise relies on the underlying model stream and any upstream API limits.
|
|
- Flush scheduling: deferred history injection polls every `50` ms while the recipient is still streaming (`#scheduleBackgroundExchangeFlush` in `packages/coding-agent/src/session/agent-session.ts`).
|
|
|
|
## Errors
|
|
- The tool returns text errors, not thrown exceptions, for:
|
|
- missing registry: `IRC is unavailable in this session.`
|
|
- missing sender id: `IRC is unavailable: caller has no agent id.`
|
|
- missing `to`: `` `to` is required for op="send". ``
|
|
- missing `message`: `` `message` is required for op="send". ``
|
|
- unknown op: `Unknown irc op.`
|
|
- Unknown, self-addressed, non-running, and non-idle direct targets are reported under `details.notFound` and in the text footer `Unknown / unavailable peers:`.
|
|
- If a target has no attached session, it is treated as not found.
|
|
- Exceptions thrown by `respondAsBackground`, `runEphemeralTurn`, abort handling, or timeout handling are caught per-target and surfaced under `details.failed` as `{ id, error }`; other recipients still complete.
|
|
- If no target succeeds, `send` still returns normally with `No recipients received the message.` and optional `failed`/`notFound` metadata.
|
|
|
|
## Notes
|
|
- This is IRC-like naming only. There are no servers, sockets, nick registration, auth handshakes, channels beyond `all`, or commands such as join/part/topic.
|
|
- Addressing is by exact agent id from the registry; there is no fuzzy lookup or aliasing.
|
|
- `channels` in `list` is synthetic output: `all` plus visible peer ids. Nothing is persisted across calls as channel membership.
|
|
- Persistence is per recipient history, not per sender history. The sender gets the tool result; the recipient later sees injected custom messages on its next turn.
|
|
- The main UI may show IRC relays for conversations it was not part of, but those relay records are explicitly display-only.
|
|
- Because reply generation snapshots in-flight assistant text, a recipient can answer based on partially streamed context.
|
|
- Direct self-messaging is rejected by resolving the target as unavailable. |