Agent as Tool
Last updated:
Agent-as-tool lets one agent call another exposed agent as a specialized helper. The caller receives a normal AI function. Invoking that function starts a separate run of the called agent.

Note
Agent as tool means exposing a specialist agent so another agent can call it like a tool for focused work.
Definition and discovery contract
Two definition properties control delegation:
AgentDefinition.IsExposedAsToolmakes a custom agent eligible to be called.AgentDefinition.AgentToolIdslists the exposed agent IDs a caller may use.
Both conditions are required. AgentOrchestrator resolves IDs only from the definitions visible to the current user and builds a reference only when the target still has IsExposedAsTool enabled. A missing, hidden, or no-longer-exposed target is omitted, and a stale cached instance is removed.
The build walk starts with the requested agent ID in a HashSet<string>. Repeated IDs, self-references, and cycles therefore stop at their first visit instead of expanding indefinitely. There is no separate numeric delegation-depth setting: the finite definition graph and this build guard bound construction.
Important
AgentAsToolProvider itself preserves the supplied ID order and does not remove duplicate IDs. Host editors should persist unique selections, and callers that construct the public provider directly should deduplicate their input.
Callable name and function contract
AgentAsToolProvider creates an AI function for each resolved ChatClientAgent. Oscova sets the function name by normalizing the agent display name: each run of characters outside ASCII letters and digits becomes _. The agent description remains the function description.
Agent saves reject normalized-name collisions between non-main agents whose user audiences overlap. This prevents two visible agents such as Release Notes and Release-Notes from both becoming Release_Notes.
The resulting function contract is:
- Input: one required
querystring and one optionalconversationstring. - Output: the called agent's final
AgentResponse.Text. - Cancellation: the function passes its cancellation token through to the called run.
- Failure: child-run exceptions are not converted into a success string. They propagate through the caller's function-invocation pipeline.
- Session: a repeated conversation name resumes that child conversation inside the same parent session. A missing or blank name uses the default conversation for that child.
Framework run-option AdditionalProperties from the current function-invocation context are copied into the child run. This lets host run metadata continue across the delegation boundary.
Conversation lifecycle
Each parent session stores one child session for every called agent and conversation name. The child agent ID is the stable identity. Conversation names are trimmed and compared without case sensitivity, so Research and research continue the same line of work.
The child session is saved only after a successful call. A failed or cancelled call leaves the last successful snapshot unchanged. If a framework caller invokes the provider without a parent session, every delegated call remains stateless and starts with a fresh child session.
The child keeps its configured compaction behavior. When compaction reduces its history, the reduced conversation is the history that remains available. Function invocation for this provider must stay serial because two calls must not mutate the same child session concurrently.
The Host presents stored child messages as read-only chat tabs after the parent run finishes. The tab shows user and assistant text, not the child's tool activity or private reasoning. Incognito parent chats keep the same continuity in memory, but their parent and child sessions are not written to disk.
Runtime flow
The host prepares an AgentBuildRequest with the requested definition, definitions visible to the user, model-client and context-provider factories, workspace resolution, and optional run middleware. AgentOrchestrator.GetOrCreateAgentAsync() then:
- Walks
AgentToolIdsand builds nested exposed dependencies before their parents. - Builds every exposed agent from that agent's definition.
- Adds built exposed agents to
AIAgentCollection. - Builds the requested agent.
- Lets
AgentAsToolProvidercapture the already-built child instances and expose them as functions.
That last step is a snapshot. A provider does not perform a new collection lookup on every request. This is also important for public use: populate AIAgentCollection before constructing AgentAsToolProvider.
Called-agent runtime shape
The called agent does not inherit the caller's entire context. Oscova deliberately rebuilds a restricted sub-agent shape:
| Concern | Delegated behavior |
|---|---|
| Model and model options | Uses the called definition's default model provider, or the app default, plus that provider's chat options. |
| Standing instruction | Uses the called definition's system instruction and its resolved variables. |
| Ordinary tools | Uses the called definition's allowlist and tool policies. |
| Nested agent tools | Uses the called definition's AgentToolIds, subject to the same exposure and cycle rules. |
| Workspaces | Resolves the called definition's own allowed directories. |
| Compaction | Uses the called definition's compaction setting and reducer. |
| Local-only posture | Inherits the initiating run's air gap and can tighten it with the called definition's IsLocalOnly. It cannot loosen the caller's posture. |
| Memory and skills | Not attached to delegated sub-agent builds, even when enabled or assigned on the called definition. |
| Private notes, Library, task list, and extra request providers | Attached only to the active requested agent, not the delegated build. |
Calling that same definition directly makes it the active requested agent, so its enabled memory, assigned skills, and other active-agent providers apply normally.
When to use it
- A support agent delegates billing lookup to a billing specialist.
- A writing assistant asks a research agent to gather source notes.
- A project coordinator asks a scheduler agent to prepare task instructions.
Caution
Avoid circular delegation patterns. The builder guard prevents infinite construction, but there is no global runtime delegation-depth counter. Each nested agent run receives its own function-loop limits, so do not use the construction guard as a runtime recursion policy.
Governance and failure limits
The caller's permission to use an agent tool is not permission to bypass the called agent's policies. AgentToolProvider or tool search resolves the called definition's ordinary tools independently:
Denytools are omitted.RequireApprovaltools are also omitted for delegated runs becauseAsAIFunction()has no route to the interactive approval loop.- Air-gapped runs omit tools classified as network egress.
- Default and auto-approved tools remain available when otherwise allowed.
When the host supplies agent-specific runtime middleware, it is installed on every built agent. Tool hooks, quotas, workspace validation, repeated-call refusal, and accounting therefore record the called agent's identity rather than treating its work as a tool call by the parent.
Every built agent also has the framework function loop capped at 40 iterations per request and three consecutive tool errors, with detailed exception text excluded from model-visible tool results. A nested child invocation is its own request and receives the same per-agent caps.
Caching and lifetimes
Exposed agents normally live in AgentOrchestrator.AIAgents and are reused across builds. The requested agent is cached only when it is not itself exposed, has no request customizers, and the request does not bypass the cache.
Run-specific general builder and options customizers apply only to the requested agent. The per-agent builder customizer applies to exposed agents as well. When present, exposed dependencies are rebuilt and replace their collection entries so host middleware matches the current run. Providers that already captured an earlier child keep that captured instance for their run.
Evict the affected agent or invalidate the agent cache after changing an exposed definition, provider, tools, context, or execution policy. Host save and settings flows perform the relevant invalidation. Integrations that use the public runtime types directly must do so themselves.