Injeção
Decorators de parâmetro que dizem o que cada argumento deve receber. Como cada um se declara, a ordem não importa — e dois parâmetros do mesmo tipo deixam de ser ambíguos.
import { input, context, state, memory } from "@thenajs/core";| Decorator | Onde | O que entrega |
|---|---|---|
@input() | execute de tool | os argumentos, validados pelo schema |
@context() | execute de tool | o Context da execução |
@state() | construtor de agente, execute de tool | a instância de @Workflow({ state }) |
@memory(Store?) | construtor de agente | uma VectorMemory |
Em tools
@Tool({ name: "ler", description: "…", schema: z.object({ path: z.string() }) })
export class LerTool {
async execute(
@input() { path }: { path: string },
@context() ctx: Context,
@state() s: RevisaoState,
) {
s.arquivosLidos.push(path);
return readFile(path, "utf8", { signal: ctx.signal });
}
}Sem decorator nenhum, o execute recebe só os argumentos — o caso comum:
async execute({ path }: { path: string }) { … }Em agentes
@Agent({ provider: MeuProvider, prompt: "./a.agent.md" })
export class MeuAgente {
constructor(
@state() private readonly s: RevisaoState,
@memory(QdrantOpenAI) private readonly vetores: VectorMemory,
) {}
}@memory(Store) identifica a memória pela classe do store, removendo a dependência da ordem de ThenaConfig.stores. Sem argumento, entrega a primeira registrada.
Sem o decorator vale o contrato posicional — que é por que reordenar aquele array muda o comportamento em silêncio.
@context() não funciona em construtor
O agente é instanciado antes de a execução começar, então o contexto ainda não existe. O runtime falha com essa explicação em vez de injetar undefined. Use no execute de uma tool, ou receba o ctx como parâmetro do hook.
@tools() — as outras tools do agente
async execute(@input() args: Args, @tools() siblings: ToolType[]) {
const alvo = siblings.find((t) => t.name === "read_file");
return alvo?.execute({ path: "src/main.ts" });
}Dá a uma tool as outras tools registradas no mesmo agente, já embrulhadas na cadeia de middleware. O embrulho é o ponto: uma irmã chamada por aqui continua abrindo o próprio nó no report e passando pelos hooks do agente, pelos middlewares de app.use({ tool }), pela contagem de orçamento e pela política de erro. Uma lista entregue por fora perderia as cinco.
Valide os argumentos antes de despachar — o embrulho roda a cadeia, não o schema:
const args = alvo.schema.parse(bruto);
await alvo.execute(args);Só no execute
As tools são embrulhadas por invocação do passo, então no construtor a lista ainda não existe. Usar @tools() lá falha com essa explicação.
A ParallelTool é construída sobre isto.
context() como função
provider: () => new OpenAIProvider({ apiKey: chaveDe(context().data) });Mesmo objeto, momento diferente: dentro de um passo vem o ctx do passo, com state e turn; fora dele vem o da execução, e tocar em state lança com a explicação.
Construtores de tool
Tools são instanciadas pelo framework, então os construtores delas também recebem dependências — mais utilmente o WorkflowRuntime:
export class PesquisaTool {
constructor(private readonly runtime: WorkflowRuntime) {}
}Por que não por tipo
O reflect-metadata lê os tipos dos parâmetros e dispensaria estes decorators. Não é usado porque o esbuild — que o tsx usa em dev — não emite design:paramtypes: injeção por tipo compilaria e quebraria em silêncio no npm start.
As chamadas dos decorators são emitidas nos dois caminhos.
É também por isso que o experimentalDecorators é obrigatório, em vez da proposta Stage 3 — que não tem decorators de parâmetro.
Se você não declarar estado
| Situação | O que acontece |
|---|---|
| ninguém pede estado | funciona normal |
um agente pede com @state() | erro apontando a classe e o parâmetro |
uma tool pede com @state() | erro apontando o método e o parâmetro |
o until declara o 2º parâmetro | erro dizendo para acrescentar state |
O último é detectado antes de rodar, pela aridade do until. Sem essa checagem, o estado chegaria undefined e sairia como um TypeError na primeira leitura de campo, sem nunca dizer o que faltou.
Um until de um parâmetro só (untilAnswered, ou (ctx) => …) nunca dispara essa checagem.
Erros
[thena] @state() em RevisorAgent (parâmetro 0): nenhum estado declarado.
Acrescente `state: MinhaClasse` no @Workflow.
[thena] @memory(QdrantOpenAI) em MeuAgente: esse store não está registrado em
ThenaConfig.stores.Relacionado
- Injeção de dependência — o conceito
- Contexto
- Banco vetorial
