# Network Tools

When you call `HubClient.register(agent, ...)` with the default `attach_plugin=True`, the framework attaches `NetworkPlugin` to your agent. The plugin does two things:

1. Adds an **assembly policy** that prefixes every LLM call with the agent's name and id.
2. Adds the **identity-level tools** to `agent.tools`: `delegate`, `peers`, `channels`, `tasks`, `context`. These are stable for the life of the registration and work in any channel context — discovery, channel lifecycle, task observation, and the one-shot `delegate` convenience.

The per-turn tool list an agent actually sees is the **union of two streams**:

| Stream            | Where it comes from                                                 | Examples                                                          |
|-------------------|--------------------------------------------------------------------|-------------------------------------------------------------------|
| **Identity-level** | `NetworkPlugin`, attached once at registration                      | `delegate`, `peers`, `channels`, `tasks`, `context`              |
| **Channel-level**  | `adapter.tools_for(...)`, resolved per turn by the default handler | `say` (text channels), user-authored `Handoff`-returning tools (workflow) |

So `say` is **not** on every agent's `agent.tools` — it's contributed by the adapter that owns the channel, only when that adapter accepts free-form text and only when it's this participant's turn. A workflow participant never sees `say`; it routes via handoff tools instead. See [Channel-level tools](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#channel-level-tools-adaptertools_for) below.

## `delegate` — the flat hot-path tool [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#delegate-the-flat-hot-path-tool "Permanent link")

| Tool      | Signature                                        | Purpose                                                                 |
|-----------|--------------------------------------------------|-------------------------------------------------------------------------|
| `delegate`| `delegate(target, prompt, capability?, timeout=300)` | One-shot consult: open a `consulting` channel with `target`, send `prompt`, await the single reply, return its text. |

`delegate` is the most common cross-cutting verb because "ask one specialist a question, take their answer" is the canonical multi-agent pattern — and unlike `say` it isn't tied to a channel the agent is already in, so it lives at the identity level.

|     |     |
|-----|-----|
| ```<br>1<br>2<br>``` | ```<br># The LLM emits, e.g.:<br>#   delegate(target="bob", prompt="What's the right way to model X?", capability="modeling")<br>``` |

The framework resolves `ChannelInject` (current channel) and `AgentClientInject` (calling agent's hub client) automatically inside the notify handler, so the LLM never sees those parameters.

## Four grouped action-dispatch tools [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#four-grouped-action-dispatch-tools "Permanent link")

Each grouped tool takes an `action` literal plus action-specific args, keeping the LLM's tool list short.

### `peers(action)` — discovery [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#peersaction-discovery "Permanent link")

| Action     | Args                                   | Returns                                                             |
|------------|----------------------------------------|---------------------------------------------------------------------|
| "find"    | `query?, capability?, sort_by?, limit=20`  | List of peer summaries (excludes the calling agent).               |
| "describe"| `name`                                 | One peer's full profile: `{passport, resume, skill_md}`. `skill_md` falls back to a rendered passport+resume when no `SKILL.md` is registered. |

### `channels(action)` — lifecycle [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#channelsaction-lifecycle "Permanent link")

| Action   | Args                                            | Returns                                                                 |
|----------|-------------------------------------------------|-------------------------------------------------------------------------|
| "list"  | `state="active"\|"all"`                    | Channels this agent participates in.                                   |
| "open"  | `type, target, knobs?, intent?, ttl?, message?` | Mirrors `AgentClient.open`. Returns `{channel_id, type, participants}` — plus `seed_envelope_id` when `message` was supplied. |
| "info"  | `channel_id`                                   | Full `ChannelMetadata` if the agent is a participant.                 |
| "close" | `channel_id?` (defaults to current)           | Closes the channel with reason "closed_by_agent".                   |

`"open"` accepts an optional `message`: when set, the tool opens the channel and — once it transitions to `OPENED` — posts that text as the first envelope on the initiator's behalf, in the same call. If the seed send fails, the just-opened channel is closed (`reason="seed_failed"`) so you never leave a dangling-open channel nobody ever sends into. Use it for short-lived channels where the agent wants "open and ask" to be one atomic step rather than two tool calls.

### `tasks(action)` — task lifecycle [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#tasksaction-task-lifecycle "Permanent link")

Two halves: **active actions** (the agent is inside its own `agent.task(...)` block) and **observation actions** (any task the hub has observed).

| Action    | Half       | Args                                         | Returns                                                             |
|-----------|------------|----------------------------------------------|---------------------------------------------------------------------|
| "progress" | active    | `payload`                                   | Emits `TaskProgress` on the active task.                            |
| "complete" | active    | `result?`                                   | Terminal — emits `TaskCompleted`.                                   |
| "list"    | observation| `scope="own"\|"all", state="active"\|"all", limit=20` | Task summaries.                                                    |
| "status"  | observation| `task_id`                                  | Refreshed `TaskMetadata`.                                          |
| "wait"    | observation| `task_id, timeout=300, poll_interval=0.1` | Blocks until the task reaches a terminal state.                    |
| "cancel"   | —        | —                                           | Not implemented; returns an error placeholder.                      |

`"start"` is intentionally **not** a tool — calling it from the LLM would bypass the `async with agent.task(...)` lifecycle that scopes `TaskInject` correctly. Owners start tasks in their own code; the LLM uses `"progress"`/`"complete"` once a task is active and `delegate` for one-shot remote work.

### `context(action)` — past content [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#contextaction-past-content "Permanent link")

| Action    | Args                                              | Returns                                                             |
|-----------|--------------------------------------------------|---------------------------------------------------------------------|
| "search" | `query, scope="channel"\|"knowledge", limit=10` | Excerpts of envelopes whose text matches `query` (case-insensitive substring). |
| "quote"  | `speaker, recent_n=1, channel_id?`              | The last `recent_n``EV_TEXT` envelopes from `speaker` in the current (or specified) channel. |

`scope="knowledge"` reaches into the calling agent's own `KnowledgeStore`. Substring search only — for vector / semantic search, the agent's own loop calls into framework-core `recall` directly.

## Channel-level tools — `adapter.tools_for` [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#channel-level-tools-adaptertools_for "Permanent link")

The tools above are _identity-level_ — the same on every turn. The tools an agent needs to actually **participate** in a given channel depend on the channel's protocol and on whose turn it is, so they come from the adapter, not the plugin:

```
def tools_for(
    self,
    client: AgentClient,
    metadata: ChannelMetadata,
    state: AdapterState,
    participant_id: str,
) -> list[Tool]: ...
```

The default handler calls `adapter.tools_for(...)` once per turn and merges the result into the per-call `agent.ask(tools=...)` override. The built-in adapters use it like this:

| Adapter        | `tools_for` returns                  | Gating                                                            |
|----------------|-------------------------------------|------------------------------------------------------------------|
| `conversation`  | `[say]`                            | Always — no turn order, both participants can post any time.     |
| `discussion`    | `[say]` on your round, else `[]`  | Round-robin: `say` only when `state.expected_next_speaker` is you. |
| `consulting`    | `[say]` to whoever holds the floor, else `[]` | Initiator until the prompt is sent; respondent after, until the one reply lands; then the channel auto-closes and nobody gets `say`. |
| `workflow`      | `[]`                                | Workflow agents route via user-authored `Handoff`-returning tools (already on `agent.tools`) — see [Workflow](https://docs.ag2.ai/0.13.1/docs/beta/network/workflow/#writing-a-handoff-tool). |

`say(content, audience?, channel_id?)` posts `EV_TEXT` into the active channel (`audience` is a list of peer **names**, resolved to ids; `None` broadcasts). Internally it builds the envelope via `adapter.build_text_envelope(...)` — the same Layer-2 helper a non-AG2 bridge would call — so per-adapter envelope shaping is honoured automatically. See [Adapters Overview → The Adapter Protocol](https://docs.ag2.ai/0.13.1/docs/beta/network/adapters_overview/#the-adapter-protocol) for the full three-layer picture.

Tool resolution is memoized per `client.agent_id` inside each adapter, so the `fast_depends` schema-build cost is paid once, not on every notify turn.

If you write a custom adapter, override `tools_for` to offer your channel's verbs (or leave the default, which returns `[]`).

## What gets injected, automatically [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#what-gets-injected-automatically "Permanent link")

Every grouped tool accepts `AgentClientInject`, `ChannelInject`, and (for `tasks`) `TaskInject` parameters that the framework resolves from `context.dependencies` when the tool runs inside a notify handler. Your code does not need to wire them up — the default handler stamps them via `stamp_dependencies` before invoking the agent's turn.

If you are testing a tool _outside_ the notify-handler context, pass them yourself:

|     |     |
|-----|-----|
| ```<br>1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>``` | ```<br>from autogen.beta import Context<br>from autogen.beta.network import AGENT_CLIENT_DEP, CHANNEL_DEP, Channel<br>ctx = Context(<br>    dependencies={<br>        AGENT_CLIENT_DEP: alice,<br>        CHANNEL_DEP: Channel(metadata=channel.metadata, client=alice),<br>    },<br>)<br>``` |

## Opting out [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#opting-out "Permanent link")

Pass `attach_plugin=False` to `HubClient.register` for a bare agent — useful for headless workers or gateways that handle envelopes entirely in your own code without needing the LLM-facing tool surface.

|     |     |
|-----|-----|
| ```<br>1<br>2<br>``` | ```<br>worker = await hc.register(agent, passport, resume, attach_plugin=False)<br>worker.on_envelope(my_custom_handler)<br>``` |

## See also [#](https://docs.ag2.ai/0.13.1/docs/beta/network/network_assigned_tools/#see-also "Permanent link")

- [Agent Clients and Handlers](https://docs.ag2.ai/0.13.1/docs/beta/network/agent_clients/) — what the default handler does and how to replace it.
- [Workflow](https://docs.ag2.ai/0.13.1/docs/beta/network/workflow/) — hand-written `Handoff`-returning tools complement `ToolCalled → AgentTarget` transitions for graph-driven routing.
