Sub-agente isolado
Às vezes uma subtarefa é ruidosa: dez voltas de tentativa e erro para chegar a uma resposta de uma linha. Se isso acontece no mesmo histórico, o agente principal carrega todo o ruído — e com modelo pequeno, isso degrada as decisões dele.
A saída é rodar a subtarefa num workflow próprio, disparado por uma tool:
agente pai (histórico enxuto)
└─ tool ──▶ workflow isolado (estado próprio)
├─ 10 voltas de tentativa e erro
└─ devolve UMA string ao paiComo se escreve
O construtor da tool recebe o WorkflowRuntime injetado:
import { Tool, WorkflowRuntime } from "@thenajs/core";
import { z } from "zod";
import { DeployWorkflow } from "../workflows/deploy.workflow.js";
@Tool({
name: "deploy",
description: "Executa o processo de deploy e devolve o resultado.",
schema: z.object({ repositorio: z.string() }),
})
export class DeployTool {
constructor(private readonly runtime: WorkflowRuntime) {}
async execute(@input() args: { repositorio: string }) {
return this.runtime.run(DeployWorkflow, {
input: { message: `Faça o deploy de ${input.repositorio}` },
memory: { ambiente: "staging" }, // contexto explícito para o filho
});
}
}O filho começa com estado novo: só recebe o que você passou em input e memory.
Isso é bom — o ruído dele não polui o pai — e tem um custo: ele começa sem saber o que foi pedido. Se precisar repassar algo da conversa do pai, peça o contexto:
import { Tool, WorkflowRuntime, input, context } from "@thenajs/core";
export class DeployTool {
constructor(private readonly runtime: WorkflowRuntime) {}
async execute(
@input() { repositorio }: { repositorio: string },
@context() ctx: AgentContext,
) {
const pedido = ctx.state.history.find((m) => m.role === "user")?.content;
return this.runtime.run(DeployWorkflow, {
input: { message: `Faça o deploy de ${repositorio}` },
memory: { pedidoOriginal: pedido },
});
}
}É o caso de uso central do @context(): você escolhe o que atravessa o isolamento, em vez de tudo ou nada.
Step ou tool? O guia de decisão
É a escolha arquitetural central de um workflow, e as duas formas parecem equivalentes até a primeira vez que a diferença morde.
| sub-agente como step | sub-agente como tool | |
|---|---|---|
| Histórico | compartilhado com o pai | próprio, isolado |
| A saída vira | mensagem assistant | observação de ferramenta |
| Quem decide se roda | você, na ordem dos steps | o modelo, chamando a tool |
| Custo de contexto no pai | todos os turnos do filho | uma string |
| Use quando | é uma conversa só e o pai precisa ver o caminho | a subtarefa é ruidosa, ou só o resultado importa |
A visibilidade não se perde
O report aninha a execução do filho dentro do nó da tool:
workflow WorkflowPai
agent AgentePai
chat
tool deploy
workflow DeployWorkflow ← o filho aparece aqui
agent DeployAgent
chatVocê abriu mão do contexto compartilhado, não da observabilidade.
O orçamento não atravessa
Cada run tem contador próprio. Um budget no pai não soma o consumo dos filhos. Se o subworkflow é caro, passe um budget no runtime.run dele também.
