{"_id":"@cosmixclub/parsero","_rev":"4-9fbbbbabd8e399eab0b2c854dbcbb036","name":"@cosmixclub/parsero","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0":{"name":"@cosmixclub/parsero","version":"1.0.0","keywords":["crewai","langchain","langgraph"],"author":{"name":"Gepetojj","email":"contato.gepetojj@gmail.com"},"license":"MIT","_id":"@cosmixclub/parsero@1.0.0","maintainers":[{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"}],"homepage":"https://github.com/cosmixclub/parsero","bugs":{"url":"https://github.com/cosmixclub/parsero/issues"},"dist":{"shasum":"6af519da23bc145e82dd10a0a7960e32a31f1e06","tarball":"https://registry.npmjs.org/@cosmixclub/parsero/-/parsero-1.0.0.tgz","fileCount":7,"integrity":"sha512-/PugnpnBzJdDAnXaH3IEf43Oj0gHVZBp1mwrlL9RlCz89Yq0kDr86i/vBXyGZdLi86DwDccmORH19kiQPFwRwQ==","signatures":[{"sig":"MEQCID6JuWZIsXpvMWZBkUcrSQHyasSayeBIs5sjmHsrc67XAiA/WtMx7D0N6cvuWu+nO5SB2ubNonuaGdpNNAb9qT2+qA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":61983},"main":"dist/index.js","type":"module","_from":"file:cosmixclub-parsero-1.0.0.tgz","types":"./dist/index.d.ts","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"exports":{".":{"import":"./dist/index.js","default":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"ci":"pnpm build && pnpm check-format && pnpm check-exports","lint":"eslint --fix .","build":"tsup","commit":"git cz","format":"prettier --write .","check-format":"prettier --check .","check-exports":"attw --pack .","local-release":"changeset version && changeset publish"},"_npmUser":{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},"_resolved":"/tmp/2d9e6173497161e883b3f992d20f2c0a/cosmixclub-parsero-1.0.0.tgz","_integrity":"sha512-/PugnpnBzJdDAnXaH3IEf43Oj0gHVZBp1mwrlL9RlCz89Yq0kDr86i/vBXyGZdLi86DwDccmORH19kiQPFwRwQ==","repository":{"url":"git+https://github.com/cosmixclub/parsero.git","type":"git"},"_npmVersion":"10.8.1","description":"Construtor de agentes de IA de maneira simplificada.","directories":{},"_nodeVersion":"20.16.0","dependencies":{"zod":"^3.24.1","@langchain/core":"0.3.26","@langchain/langgraph":"^0.2.36"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.3.5","dotenv":"^16.4.7","eslint":"8.57.1","prettier":"^3.4.2","commitizen":"^4.3.1","typescript":"^5.7.2","@types/node":"^22.10.2","@changesets/cli":"^2.27.11","@langchain/openai":"^0.3.16","@vercel/style-guide":"^6.0.0","@langchain/community":"^0.3.20","@arethetypeswrong/cli":"^0.17.2","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.1","@typescript-eslint/parser":"^8.18.2","cz-conventional-changelog":"^3.3.0","eslint-plugin-perfectionist":"^4.4.0","@typescript-eslint/eslint-plugin":"^8.18.2","@trivago/prettier-plugin-sort-imports":"^5.2.0"},"_npmOperationalInternal":{"tmp":"tmp/parsero_1.0.0_1735488478551_0.372843921996423","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@cosmixclub/parsero","version":"1.1.2","keywords":["crewai","langchain","langgraph"],"author":{"name":"Gepetojj","email":"contato.gepetojj@gmail.com"},"license":"MIT","_id":"@cosmixclub/parsero@1.1.2","maintainers":[{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},{"name":"alex-custodio","email":"alex.scustod@gmail.com"}],"homepage":"https://github.com/cosmixclub/parsero","bugs":{"url":"https://github.com/cosmixclub/parsero/issues"},"dist":{"shasum":"0e5c829c844817661b1827c9a9dd8527ccb2f589","tarball":"https://registry.npmjs.org/@cosmixclub/parsero/-/parsero-1.1.2.tgz","fileCount":7,"integrity":"sha512-chrA/IJNYeNtUOkSP9rrdD08LEzeybN34N5DTGdswg9JuszYShiBKgAY3rh3NPB7k1Tk1H3MTJ3pvzWSBSKzRA==","signatures":[{"sig":"MEQCIGpfuavdwFrKGBAGDMYGlLLwmC1YqFCDuJuWreuHTPlKAiA83FuNqNqcveGnlPaGKYPM4rEpbQZoi16L4/04GkpsmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":69772},"main":"dist/index.js","type":"module","_from":"file:cosmixclub-parsero-1.1.2.tgz","types":"./dist/index.d.ts","config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"exports":{".":{"import":"./dist/index.js","default":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"ci":"pnpm build && pnpm check-format && pnpm check-exports && pnpm test","lint":"eslint --fix .","test":"vitest run","build":"tsup","commit":"git cz","format":"prettier --write .","test:ui":"vitest --ui","test:watch":"vitest","check-format":"prettier --check .","check-exports":"attw --pack .","local-release":"changeset version && changeset publish","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},"_resolved":"/tmp/2ab3c099aa03c5df848c1f441cd279da/cosmixclub-parsero-1.1.2.tgz","_integrity":"sha512-chrA/IJNYeNtUOkSP9rrdD08LEzeybN34N5DTGdswg9JuszYShiBKgAY3rh3NPB7k1Tk1H3MTJ3pvzWSBSKzRA==","repository":{"url":"git+https://github.com/cosmixclub/parsero.git","type":"git"},"_npmVersion":"10.5.0","description":"Construtor de agentes de IA de maneira simplificada.","directories":{},"_nodeVersion":"21.7.3","_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.3","zod":"^3.24.2","tsup":"^8.4.0","dotenv":"^16.5.0","eslint":"8.57.1","vitest":"^3.1.1","prettier":"^3.5.3","@vitest/ui":"^3.1.1","commitizen":"^4.3.1","typescript":"^5.8.3","@types/node":"^22.14.1","@changesets/cli":"^2.28.1","@langchain/core":"0.3.44","@langchain/openai":"^0.5.5","@vercel/style-guide":"^6.0.0","@vitest/coverage-v8":"^3.1.1","@langchain/community":"^0.3.40","@langchain/langgraph":"^0.2.63","@arethetypeswrong/cli":"^0.17.4","eslint-config-prettier":"^9.1.0","eslint-plugin-prettier":"^5.2.6","@typescript-eslint/parser":"^8.29.1","cz-conventional-changelog":"^3.3.0","eslint-plugin-perfectionist":"^4.11.0","@typescript-eslint/eslint-plugin":"^8.29.1","@trivago/prettier-plugin-sort-imports":"^5.2.2"},"peerDependencies":{"zod":"^3.20.0","@langchain/core":">=0.3.0 <0.4.0","@langchain/langgraph":"^0.2.10"},"_npmOperationalInternal":{"tmp":"tmp/parsero_1.1.2_1744509558222_0.6288441014353483","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@cosmixclub/parsero","version":"1.2.0","description":"Construtor de agentes de IA de maneira simplificada.","author":{"name":"Gepetojj","email":"contato.gepetojj@gmail.com"},"license":"MIT","main":"dist/index.js","keywords":["crewai","langchain","langgraph"],"homepage":"https://github.com/cosmixclub/parsero","bugs":{"url":"https://github.com/cosmixclub/parsero/issues"},"repository":{"type":"git","url":"git+https://github.com/cosmixclub/parsero.git"},"type":"module","types":"./dist/index.d.ts","exports":{"./package.json":"./package.json",".":{"import":"./dist/index.js","default":"./dist/index.cjs"}},"dependencies":{"langsmith":"^0.3.16"},"peerDependencies":{"@langchain/core":">=0.3.0 <0.4.0","@langchain/langgraph":"^0.2.10","zod":"^3.20.0"},"devDependencies":{"@arethetypeswrong/cli":"^0.17.4","@changesets/cli":"^2.29.1","@langchain/community":"^0.3.40","@langchain/core":"0.3.44","@langchain/langgraph":"^0.2.64","@langchain/openai":"^0.5.5","@trivago/prettier-plugin-sort-imports":"^5.2.2","@types/node":"^22.14.1","@typescript-eslint/eslint-plugin":"^8.29.1","@typescript-eslint/parser":"^8.29.1","@vercel/style-guide":"^6.0.0","@vitest/coverage-v8":"^3.1.1","@vitest/ui":"^3.1.1","commitizen":"^4.3.1","cz-conventional-changelog":"^3.3.0","dotenv":"^16.5.0","eslint":"8.57.1","eslint-config-prettier":"^9.1.0","eslint-plugin-perfectionist":"^4.11.0","eslint-plugin-prettier":"^5.2.6","prettier":"^3.5.3","tsup":"^8.4.0","tsx":"^4.19.3","typescript":"^5.8.3","vitest":"^3.1.1","zod":"^3.24.2"},"config":{"commitizen":{"path":"./node_modules/cz-conventional-changelog"}},"scripts":{"ci":"pnpm build && pnpm check-format && pnpm check-exports && pnpm test","build":"tsup","lint":"eslint --fix .","format":"prettier --write .","check-format":"prettier --check .","commit":"git cz","check-exports":"attw --pack .","local-release":"changeset version && changeset publish","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","test:ui":"vitest --ui"},"_id":"@cosmixclub/parsero@1.2.0","_integrity":"sha512-IWtt12j/Givm0rONcU8Nb7E/cbu8KzZgtKcQr4KkvAYUw4BirNyHHpCEIBkIxFGFjOIW1U084F2EafLOATZ4Gw==","_resolved":"/tmp/a6c843632feddf524e10590d042dbeb5/cosmixclub-parsero-1.2.0.tgz","_from":"file:cosmixclub-parsero-1.2.0.tgz","_nodeVersion":"21.7.3","_npmVersion":"10.5.0","dist":{"integrity":"sha512-IWtt12j/Givm0rONcU8Nb7E/cbu8KzZgtKcQr4KkvAYUw4BirNyHHpCEIBkIxFGFjOIW1U084F2EafLOATZ4Gw==","shasum":"db567843fa30c76e64423ff467836bf4045e1ece","tarball":"https://registry.npmjs.org/@cosmixclub/parsero/-/parsero-1.2.0.tgz","fileCount":7,"unpackedSize":75305,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC+cU2N4O6YClEwgWZmo93O5BjUDDclDQMubC4WJpuHxQIhAKwon7+lrgcIAIY0O91YuvfqF+3BBrcSyVuZhY/yCnm/"}]},"_npmUser":{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},"directories":{},"maintainers":[{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},{"name":"alex-custodio","email":"alex.scustod@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/parsero_1.2.0_1744741958779_0.03180064067018762"},"_hasShrinkwrap":false}},"time":{"created":"2024-12-29T16:07:58.446Z","modified":"2025-04-15T18:32:39.181Z","1.0.0":"2024-12-29T16:07:58.757Z","1.1.2":"2025-04-13T01:59:18.416Z","1.2.0":"2025-04-15T18:32:38.968Z"},"bugs":{"url":"https://github.com/cosmixclub/parsero/issues"},"author":{"name":"Gepetojj","email":"contato.gepetojj@gmail.com"},"license":"MIT","homepage":"https://github.com/cosmixclub/parsero","keywords":["crewai","langchain","langgraph"],"repository":{"type":"git","url":"git+https://github.com/cosmixclub/parsero.git"},"description":"Construtor de agentes de IA de maneira simplificada.","maintainers":[{"name":"gepetojj","email":"nmjoaopedro22@gmail.com"},{"name":"alex-custodio","email":"alex.scustod@gmail.com"}],"readme":"# Parsero\r\n\r\n> Uma biblioteca **simples** e **fortemente tipada** para criar agentes de IA com [LangChain](https://js.langchain.com/docs/) e [LangGraph](https://langchain-ai.github.io/langgraphjs/).  \r\n> Inspirada no [CrewAI](https://docs.crewai.com/introduction) e criada para ser mais **descritiva** e **direta**, com padrões bem-definidos para a criação de agentes reutilizáveis.\r\n\r\n## Sumário\r\n\r\n- [Parsero](#parsero)\r\n    - [Sumário](#sumário)\r\n    - [Objetivo](#objetivo)\r\n    - [Características Principais](#características-principais)\r\n    - [Compatibilidade](#compatibilidade)\r\n    - [Casos de Uso](#casos-de-uso)\r\n    - [Utilizando Múltiplos LLMs](#utilizando-múltiplos-llms)\r\n        - [Como Funciona](#como-funciona)\r\n        - [Integração com LangGraph](#integração-com-langgraph)\r\n        - [Tipagem para Múltiplos LLMs](#tipagem-para-múltiplos-llms)\r\n    - [Reutilizando Procedures com InferState](#reutilizando-procedures-com-inferstate)\r\n        - [Como Funciona](#como-funciona-1)\r\n        - [Por que Usar](#por-que-usar)\r\n        - [Exemplo Completo](#exemplo-completo)\r\n    - [Exemplos](#exemplos)\r\n        - [Exemplo 1: CheckProcedure customizando a ordem de execução](#exemplo-1-checkprocedure-customizando-a-ordem-de-execução)\r\n        - [Exemplo 2: Fluxo sequencial **sem** `CheckProcedure` e **sem** `nextProcedure`](#exemplo-2-fluxo-sequencial-sem-checkprocedure-e-sem-nextprocedure)\r\n        - [Exemplo 3: Fluxo personalizado com `nextProcedure`](#exemplo-3-fluxo-personalizado-com-nextprocedure)\r\n        - [Exemplo 4: Utilizando múltiplos modelos para tarefas especializadas](#exemplo-4-utilizando-múltiplos-modelos-para-tarefas-especializadas)\r\n        - [Exemplo 5: Combinando diferentes famílias de modelos](#exemplo-5-combinando-diferentes-famílias-de-modelos)\r\n    - [Observabilidade e Integração com LangSmith](#observabilidade-e-integração-com-langsmith)\r\n        - [Como funciona](#como-funciona-2)\r\n        - [Exemplo de uso com observabilidade](#exemplo-de-uso-com-observabilidade)\r\n\r\n---\r\n\r\n## Objetivo\r\n\r\nO **Parsero** foi desenvolvido para **simplificar** a criação de agentes de IA utilizando [LangChain](https://js.langchain.com/docs/) e [LangGraph](https://langchain-ai.github.io/langgraphjs/). Ele oferece uma interface mais **intuitiva**, **fortemente tipada** e com **padrões claros**, permitindo:\r\n\r\n- Facilitar a orquestração de **procedimentos** (Procedures) em agentes de IA.\r\n- Reduzir a complexidade de criação de fluxos e decisões (grafos).\r\n- Reaproveitar a lógica de agentes em diferentes projetos, graças às definições claras de entrada/saída.\r\n\r\n---\r\n\r\n## Características Principais\r\n\r\n- **Forte Tipagem**: Usa [Zod](https://zod.dev/) para schemas de entrada/saída, garantindo segurança de tipos.\r\n- **Simplicidade**: Os superpoderes do LangGraph mas com interface mais direta, seguindo padrões definidos (Procedures do tipo `action` e `check`).\r\n- **Extensibilidade**: Compatível nativamente com LangChain e LangGraph, para que você possa aproveitar o ecossistema existente.\r\n- **Orquestração por Procedimentos**: Define _procedures_ que podem modificar o estado (`action`) ou indicar o próximo passo (`check`).\r\n- **Múltiplos LLMs**: Suporte para utilizar diferentes modelos de linguagem em diferentes procedures, otimizando custo e desempenho.\r\n- **Organização Modular**: Permite definir procedures fora dos agentes com a utilidade `InferState`, facilitando a organização e reuso do código.\r\n\r\n---\r\n\r\n## Compatibilidade\r\n\r\n- **LangChain**: Pode ser usado junto com qualquer [ChatModel](https://js.langchain.com/docs/modules/models/chat) disponível (por exemplo, `ChatOpenAI`, `ChatGoogleGenerativeAI`, etc.).\r\n- **LangGraph**: Totalmente integrável ao LangGraph, para que você possa desenhar fluxos de conversação e lógicas mais complexas de maneira visual e tipada. A classe `Agent` fornece acesso ao seu equivalente em grafo.\r\n\r\n---\r\n\r\n## Casos de Uso\r\n\r\n1. **Criação de Agentes de IA Customizados**\r\n\r\n    - Defina **procedures** específicas para o seu caso.\r\n    - **Aplique** validação de entrada e saída para garantir conformidade dos dados.\r\n\r\n2. **Fluxos de Decisão com IA**\r\n\r\n    - Utilize **CheckProcedure** para direcionar o fluxo conforme o conteúdo do estado.\r\n\r\n3. **Aplicações com Entrada e Saída Bem Definidas**\r\n\r\n    - Perfeito para pipelines de dados, chatbots especializados, ou qualquer agente que precise controlar o estado de forma clara.\r\n\r\n4. **Orquestração de Múltiplos LLMs**\r\n    - Cada **procedure** pode acessar diferentes instâncias de LLM, permitindo combinar modelos especializados.\r\n    - Use modelos mais econômicos para tarefas simples e modelos avançados apenas para tarefas complexas.\r\n    - Combine diferentes famílias de modelos (OpenAI, Anthropic, Google, etc.) no mesmo agente.\r\n\r\n---\r\n\r\n## Utilizando Múltiplos LLMs\r\n\r\nO Parsero permite que você use diferentes modelos de linguagem para diferentes partes do seu agente, otimizando tanto o desempenho quanto os custos.\r\n\r\n### Como Funciona\r\n\r\nAo criar seu agente, você pode fornecer um mapa de modelos em vez de um único modelo:\r\n\r\n```ts\r\nimport { Agent, State } from \"@cosmixclub/parsero\";\r\nimport { ChatAnthropic } from \"@langchain/anthropic\";\r\nimport { ChatGoogleGenerativeAI } from \"@langchain/google-genai\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\nconst agent = new Agent({\r\n\t// Outros parâmetros...\r\n\tllm: {\r\n\t\tdefault: new ChatOpenAI({ model: \"gpt-4o\" }), // Modelo principal\r\n\t\tsummarize: new ChatGoogleGenerativeAI({ model: \"gemini-pro\" }), // Para resumos\r\n\t\tclassify: new ChatOpenAI({ model: \"gpt-4o-mini\", temperature: 0 }), // Para classificações\r\n\t\tcreative: new ChatAnthropic({ model: \"claude-3-opus-20240229\" }), // Para geração criativa\r\n\t},\r\n\t// ...\r\n});\r\n```\r\n\r\nDentro de suas procedures, você pode acessar o modelo específico que deseja utilizar:\r\n\r\n```ts\r\n// Em uma ActionProcedure\r\nasync run(state, llms) {\r\n  // Use o modelo específico para tarefas de classificação\r\n  const result = await llms.classify.invoke(\"Classifique este texto...\");\r\n\r\n  // Use o modelo específico para resumos\r\n  const summary = await llms.summarize.invoke(\"Resuma este conteúdo...\");\r\n\r\n  // Use o modelo padrão\r\n  const response = await llms.default.invoke(\"Responda esta pergunta...\");\r\n\r\n  // Continue seu código...\r\n  return state;\r\n}\r\n```\r\n\r\n### Integração com LangGraph\r\n\r\nAo utilizar `agent.graph` para acessar o grafo LangGraph equivalente, a biblioteca automaticamente:\r\n\r\n1. **Usará o modelo \"default\"** se estiver disponível no objeto de LLMs\r\n2. **Usará o primeiro modelo** do objeto se não houver um modelo chamado \"default\"\r\n\r\nEsta abordagem garante compatibilidade com o LangGraph que atualmente espera um único modelo, mas ainda permite que você utilize múltiplos modelos dentro do seu agente Parsero.\r\n\r\n```ts\r\nconst agent = new Agent({\r\n\tllm: {\r\n\t\tdefault: new ChatOpenAI(), // Este será usado no LangGraph\r\n\t\tspecialTask: new ChatAnthropic(),\r\n\t},\r\n\t// ...\r\n});\r\n\r\n// O grafo usará o modelo \"default\" internamente\r\nconst graph = agent.graph;\r\n\r\n// Execute o grafo\r\nawait graph.invoke({ input: \"exemplo\" });\r\n```\r\n\r\n### Tipagem para Múltiplos LLMs\r\n\r\nSe você estiver usando TypeScript, pode tirar vantagem do sistema de tipos para garantir que suas procedures acessem apenas LLMs que realmente existem:\r\n\r\n```ts\r\n// Defina o tipo do seu mapa de LLMs\r\ntype MyLLMs = {\r\n\tdefault: ChatOpenAI;\r\n\tsummarize: ChatGoogleGenerativeAI;\r\n\tclassify: ChatOpenAI;\r\n};\r\n\r\n// Use o tipo genérico na sua procedure\r\nconst classifyProcedure: ActionProcedure<any, MyLLMs> = {\r\n\tname: \"classify\",\r\n\ttype: \"action\",\r\n\tasync run(state, llms) {\r\n\t\t// TypeScript sabe que llms.classify existe e é do tipo ChatOpenAI\r\n\t\tconst result = await llms.classify.invoke(\"...\");\r\n\t\t// ...\r\n\t},\r\n};\r\n```\r\n\r\n---\r\n\r\n## Reutilizando Procedures com InferState\r\n\r\nO Parsero fornece a utilidade `InferState<>` que permite definir procedures de forma independente e reutilizável, separadas da definição do agente. Isso traz várias vantagens para a organização do código:\r\n\r\n### Como Funciona\r\n\r\n`InferState<>` é um tipo utilitário que extrai os tipos de entrada e saída de um `State`, facilitando a definição de procedures fora do contexto do agente:\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, InferState, Procedure, State } from \"@cosmixclub/parsero\";\r\nimport { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\r\n\r\n// 1. Defina seu State\r\nconst state = new State({\r\n\tinputSchema: z.object({\r\n\t\tquery: z.string(),\r\n\t}),\r\n\toutputSchema: z.object({\r\n\t\tresult: z.string(),\r\n\t}),\r\n});\r\n\r\n// 2. Crie procedures reutilizáveis com tipagem correta\r\nconst analyzeQuery: Procedure<InferState<typeof state>, BaseChatModel> = {\r\n\tname: \"analyzeQuery\",\r\n\tnextProcedure: \"generateResponse\",\r\n\ttype: \"action\",\r\n\tasync run(state, llm) {\r\n\t\t// Seu código aqui...\r\n\t\treturn state;\r\n\t},\r\n};\r\n\r\nconst generateResponse: Procedure<InferState<typeof state>, BaseChatModel> = {\r\n\tname: \"generateResponse\",\r\n\ttype: \"action\",\r\n\tnextProcedure: END,\r\n\tasync run(state, llm) {\r\n\t\t// Seu código aqui...\r\n\t\treturn state;\r\n\t},\r\n};\r\n\r\n// 3. Use as procedures no agente\r\nconst agent = new Agent({\r\n\tstate,\r\n\tllm: new ChatOpenAI(),\r\n\tprocedures: [\r\n\t\tanalyzeQuery,\r\n\t\tgenerateResponse,\r\n\t\t// Outras procedures...\r\n\t],\r\n});\r\n```\r\n\r\n### Por que Usar\r\n\r\n- **Organização de Código**: Separe a lógica em arquivos distintos para melhor manutenção.\r\n- **Reusabilidade**: Reutilize procedures em diferentes agentes.\r\n- **Testabilidade**: Teste procedures individualmente, facilitando os testes unitários.\r\n- **Colaboração**: Permite que diferentes membros da equipe trabalhem em diferentes procedures.\r\n\r\n### Exemplo Completo\r\n\r\nVeja como organizar seu código com procedures em arquivos separados:\r\n\r\n```ts\r\n// state.ts\r\nimport { z } from \"zod\";\r\nimport { State } from \"@cosmixclub/parsero\";\r\n\r\nexport const numberClassifierState = new State({\r\n    inputSchema: z.object({\r\n        number: z.number(),\r\n    }),\r\n    outputSchema: z.object({\r\n        class: z.enum([\"odd\", \"even\"]),\r\n        explanation: z.string(),\r\n    }),\r\n});\r\n\r\n// procedures/classify.ts\r\nimport { Procedure } from \"@cosmixclub/parsero\";\r\nimport { InferState } from \"@cosmixclub/parsero\";\r\nimport { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\r\nimport { z } from \"zod\";\r\nimport { numberClassifierState } from \"../state\";\r\n\r\nexport const whatNumberIs: Procedure<InferState<typeof numberClassifierState>, BaseChatModel> = {\r\n    name: \"whatNumberIs\",\r\n    nextProcedure: \"router\",\r\n    async run(state, llm) {\r\n        const chain = llm.withStructuredOutput(\r\n            z.object({\r\n                class: z.enum([\"odd\", \"even\"]).describe(\"Se o número é par ou ímpar\"),\r\n            }),\r\n        );\r\n        const output = await chain.invoke(`Determine se o número a seguir é par ou ímpar: ${state.input.number}`);\r\n        state.output.class = output.class;\r\n        return state;\r\n    },\r\n    type: \"action\",\r\n};\r\n\r\n// procedures/router.ts\r\nimport { Procedure } from \"@cosmixclub/parsero\";\r\nimport { InferState } from \"@cosmixclub/parsero\";\r\nimport { numberClassifierState } from \"../state\";\r\n\r\nexport const router: Procedure<InferState<typeof numberClassifierState>, any> = {\r\n    name: \"router\",\r\n    async run(state) {\r\n        const numberClass = state.output.class;\r\n        if (numberClass === \"odd\") return \"isOdd\";\r\n        return \"isEven\";\r\n    },\r\n    type: \"check\",\r\n};\r\n\r\n// agent.ts\r\nimport { Agent, END } from \"@cosmixclub/parsero\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\nimport { StringOutputParser } from \"@langchain/core/output_parsers\";\r\nimport { numberClassifierState } from \"./state\";\r\nimport { whatNumberIs } from \"./procedures/classify\";\r\nimport { router } from \"./procedures/router\";\r\n\r\nconst agent = new Agent({\r\n    state: numberClassifierState,\r\n    llm: new ChatOpenAI(),\r\n    procedures: [\r\n        whatNumberIs,\r\n        router,\r\n        {\r\n            name: \"isOdd\",\r\n            nextProcedure: END,\r\n            async run(state, llm) {\r\n                const chain = llm.pipe(new StringOutputParser());\r\n                const output = await chain.invoke(\r\n                    `Gere uma explicação do motivo de '${state.input.number}' ser ímpar.`,\r\n                );\r\n                state.output.explanation = output;\r\n                return state;\r\n            },\r\n            type: \"action\",\r\n        },\r\n        {\r\n            name: \"isEven\",\r\n            nextProcedure: END,\r\n            async run(state, llm) {\r\n                const chain = llm.pipe(new StringOutputParser());\r\n                const output = await chain.invoke(`Gere uma explicação do motivo de '${state.input.number}' ser par.`);\r\n                state.output.explanation = output;\r\n                return state;\r\n            },\r\n            type: \"action\",\r\n        },\r\n    ],\r\n});\r\n```\r\n\r\nUsando essa abordagem, seu código fica mais organizado, modular e fácil de manter, especialmente em projetos maiores com múltiplos agentes e procedures complexas.\r\n\r\n---\r\n\r\n## Exemplos\r\n\r\n### Exemplo 1: CheckProcedure customizando a ordem de execução\r\n\r\nNo exemplo abaixo, o agente:\r\n\r\n1. **Descobre** se o número é par ou ímpar (action).\r\n2. **Verifica** o resultado e **decide** qual próximo passo a seguir (check).\r\n3. **Executa** a procedure correspondente a par ou ímpar (action).\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, END, State } from \"@cosmixclub/parsero\";\r\nimport { StringOutputParser } from \"@langchain/core/output_parsers\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\n// exemplificando, pois depende do seu setup\r\n\r\nconst agent = new Agent({\r\n\tstate: new State({\r\n\t\tinputSchema: z.object({\r\n\t\t\tnumber: z.number(),\r\n\t\t}),\r\n\t\toutputSchema: z.object({\r\n\t\t\tclass: z.enum([\"odd\", \"even\"]),\r\n\t\t\texplanation: z.string(),\r\n\t\t}),\r\n\t}),\r\n\tllm: new ChatOpenAI({\r\n\t\tmodel: \"gpt-4o-mini\",\r\n\t\ttemperature: 0.1,\r\n\t\tmaxTokens: 500,\r\n\t\tstreaming: true,\r\n\t\tcache: true,\r\n\t\tapiKey: process.env.OPENAI_API_KEY,\r\n\t}),\r\n\toptions: {\r\n\t\tverbose: true,\r\n\t},\r\n\tprocedures: [\r\n\t\t{\r\n\t\t\t// 1. Procedure que classifica o número como par ou ímpar.\r\n\t\t\tname: \"whatNumberIs\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: \"router\",\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\tconst chain = llm.withStructuredOutput(\r\n\t\t\t\t\tz.object({\r\n\t\t\t\t\t\tclass: z.enum([\"odd\", \"even\"]).describe(\"Se o número é par ou ímpar\"),\r\n\t\t\t\t\t}),\r\n\t\t\t\t);\r\n\t\t\t\tconst output = await chain.invoke(\r\n\t\t\t\t\t`Determine se o número a seguir é par ou ímpar: ${state.input.number}`,\r\n\t\t\t\t);\r\n\t\t\t\tstate.output.class = output.class;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\t// 2. Procedure do tipo 'check' que decide qual caminho seguir\r\n\t\t\tname: \"router\",\r\n\t\t\ttype: \"check\",\r\n\t\t\tasync run(state) {\r\n\t\t\t\tconst numberClass = state.output.class;\r\n\t\t\t\tif (numberClass === \"odd\") return \"isOdd\";\r\n\t\t\t\treturn \"isEven\";\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\t// 3a. Se for ímpar, chama esta procedure.\r\n\t\t\tname: \"isOdd\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\tconst chain = llm.pipe(new StringOutputParser());\r\n\t\t\t\tconst output = await chain.invoke(\r\n\t\t\t\t\t`Gere uma explicação do motivo de '${state.input.number}' ser ímpar.`,\r\n\t\t\t\t);\r\n\t\t\t\tstate.output.explanation = output;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\t// 3b. Se for par, chama esta procedure.\r\n\t\t\tname: \"isEven\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\tconst chain = llm.pipe(new StringOutputParser());\r\n\t\t\t\tconst output = await chain.invoke(`Gere uma explicação do motivo de '${state.input.number}' ser par.`);\r\n\t\t\t\tstate.output.explanation = output;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t],\r\n});\r\n\r\n// Execução:\r\nconst output = await agent.run({ number: 11 });\r\nconsole.log(output);\r\n// => { class: \"odd\", explanation: \"Explicação sobre por que 11 é ímpar...\" }\r\n```\r\n\r\n> Observe que uma `CheckProcedure` **não altera** o estado. Ela apenas **retorna** o nome da próxima procedure a ser executada.\r\n\r\n---\r\n\r\n### Exemplo 2: Fluxo sequencial **sem** `CheckProcedure` e **sem** `nextProcedure`\r\n\r\nO exemplo abaixo mostra um fluxo **estritamente sequencial**, onde cada procedure de tipo `action` é executada na **ordem** em que foi definida. Assim que uma procedure termina, o agente avança para a próxima.\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, State } from \"@cosmixclub/parsero\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\nconst agent = new Agent({\r\n\tstate: new State({\r\n\t\tinputSchema: z.object({\r\n\t\t\ttext: z.string(),\r\n\t\t}),\r\n\t\toutputSchema: z.object({\r\n\t\t\tuppercase: z.string(),\r\n\t\t\treversed: z.string(),\r\n\t\t}),\r\n\t}),\r\n\tllm: new ChatOpenAI({ model: \"gpt-4\", apiKey: \"...\" }),\r\n\tprocedures: [\r\n\t\t{\r\n\t\t\t// 1. Procedure que converte o texto para maiúsculas.\r\n\t\t\tname: \"toUpperCase\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tasync run(state) {\r\n\t\t\t\tstate.output.uppercase = state.input.text.toUpperCase();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\t// 2. Procedure que reverte o texto já convertido.\r\n\t\t\tname: \"reverseText\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tasync run(state) {\r\n\t\t\t\tstate.output.reversed = state.output.uppercase.split(\"\").reverse().join(\"\");\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t],\r\n});\r\n\r\n// Ao chamar `agent.run`, ele executa `toUpperCase` e depois `reverseText`.\r\nconst output = await agent.run({ text: \"parsero\" });\r\nconsole.log(output);\r\n// => { uppercase: \"PARSERO\", reversed: \"ORESRAP\" }\r\n```\r\n\r\n> Como não há `CheckProcedure` ou `nextProcedure`, o fluxo é linear, executando cada procedure na ordem em que foi definida na lista.\r\n\r\n---\r\n\r\n### Exemplo 3: Fluxo personalizado com `nextProcedure`\r\n\r\nCaso você queira **controlar a ordem** entre procedures de modo mais explícito (sem `check`), basta utilizar a propriedade `nextProcedure` em uma `ActionProcedure`.\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, END, State } from \"@cosmixclub/parsero\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\nconst agent = new Agent({\r\n\tstate: new State({\r\n\t\tinputSchema: z.object({\r\n\t\t\ttext: z.string(),\r\n\t\t}),\r\n\t\toutputSchema: z.object({\r\n\t\t\tprocessed: z.string(),\r\n\t\t\tsummary: z.string(),\r\n\t\t}),\r\n\t}),\r\n\tllm: new ChatOpenAI({ model: \"gpt-4\", apiKey: \"...\" }),\r\n\tprocedures: [\r\n\t\t{\r\n\t\t\t// 1. Lê e processa a entrada, definindo `processed`.\r\n\t\t\tname: \"processInput\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: \"generateSummary\",\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\t// Suponha que faça algum processamento local:\r\n\t\t\t\tstate.output.processed = `Processed: ${state.input.text}`;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\t// 2. Gera um resumo do texto processado, definindo `summary`.\r\n\t\t\tname: \"generateSummary\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\tconst response = await llm.invoke(`Resuma o seguinte texto: \"${state.output.processed}\"`);\r\n\t\t\t\tstate.output.summary = response;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t],\r\n});\r\n\r\nconst output = await agent.run({ text: \"Esta é uma frase de teste\" });\r\nconsole.log(output);\r\n// => { processed: \"Processed: Esta é uma frase de teste\", summary: \"...\" }\r\n```\r\n\r\n> A execução passa **explicitamente** de `\"processInput\"` para `\"generateSummary\"`. Em seguida, `\"generateSummary\"` define `nextProcedure: END` para indicar o fim.\r\n\r\n---\r\n\r\n### Exemplo 4: Utilizando múltiplos modelos para tarefas especializadas\r\n\r\nEste exemplo mostra como utilizar diferentes modelos para diferentes partes do fluxo, otimizando o custo e especialização:\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, END, State } from \"@cosmixclub/parsero\";\r\nimport { ChatGoogleGenerativeAI } from \"@langchain/google-genai\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\nconst agent = new Agent({\r\n\tstate: new State({\r\n\t\tinputSchema: z.object({\r\n\t\t\ttext: z.string(),\r\n\t\t}),\r\n\t\toutputSchema: z.object({\r\n\t\t\tclassification: z.string(),\r\n\t\t\tsummary: z.string(),\r\n\t\t\tresponse: z.string(),\r\n\t\t}),\r\n\t}),\r\n\t// Configuração de múltiplos modelos para diferentes funções\r\n\tllm: {\r\n\t\t// Modelo padrão para casos gerais\r\n\t\tdefault: new ChatOpenAI({ model: \"gpt-4o\" }),\r\n\r\n\t\t// Modelo especializado e econômico para classificação\r\n\t\tclassify: new ChatOpenAI({\r\n\t\t\tmodel: \"gpt-4o-mini\",\r\n\t\t\ttemperature: 0, // Temperatura baixa para classificação precisa\r\n\t\t}),\r\n\r\n\t\t// Modelo especializado em resumos\r\n\t\tsummarize: new ChatGoogleGenerativeAI({\r\n\t\t\tmodel: \"gemini-pro\",\r\n\t\t\ttemperature: 0.2,\r\n\t\t}),\r\n\t},\r\n\tprocedures: [\r\n\t\t{\r\n\t\t\tname: \"classifyContent\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: \"summarizeContent\",\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\t// Usa o modelo econômico e especializado para classificação\r\n\t\t\t\tconst response = await llms.classify.invoke(\r\n\t\t\t\t\t`Classifique o seguinte texto em uma categoria: \"${state.input.text}\"`,\r\n\t\t\t\t);\r\n\t\t\t\tstate.output.classification = response.toString().trim();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tname: \"summarizeContent\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: \"generateFullResponse\",\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\t// Usa o modelo especializado em resumos\r\n\t\t\t\tconst response = await llms.summarize.invoke(\r\n\t\t\t\t\t`Resuma o seguinte texto de maneira concisa: \"${state.input.text}\"`,\r\n\t\t\t\t);\r\n\t\t\t\tstate.output.summary = response.toString().trim();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t{\r\n\t\t\tname: \"generateFullResponse\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\t// Usa o modelo principal (mais poderoso) para a resposta final\r\n\t\t\t\tconst response = await llms.default.invoke(`\r\n\t\t\t\t\tCrie uma resposta detalhada para o texto a seguir, considerando que:\r\n\t\t\t\t\t- Ele foi classificado como: ${state.output.classification}\r\n\t\t\t\t\t- Um resumo conciso seria: ${state.output.summary}\r\n\t\t\t\t\t\r\n\t\t\t\t\tTexto original: \"${state.input.text}\"\r\n\t\t\t\t\t\r\n\t\t\t\t\tSua resposta deve ser completa e considerar tanto a classificação quanto o resumo.\r\n\t\t\t\t`);\r\n\t\t\t\tstate.output.response = response.toString().trim();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t],\r\n});\r\n\r\nconst output = await agent.run({ text: \"Um texto longo para análise...\" });\r\nconsole.log(output);\r\n// => {\r\n//      classification: \"Artigo científico\",\r\n//      summary: \"Este texto aborda...\",\r\n//      response: \"Análise detalhada considerando a classificação e o resumo...\"\r\n//    }\r\n```\r\n\r\n> Neste exemplo, cada procedure usa um modelo diferente otimizado para sua tarefa específica: classificação, resumo e geração de resposta completa.\r\n\r\n---\r\n\r\n### Exemplo 5: Combinando diferentes famílias de modelos\r\n\r\nEste exemplo demonstra como combinar diferentes famílias de modelos de linguagem para aproveitar as vantagens de cada uma:\r\n\r\n```ts\r\nimport { z } from \"zod\";\r\n\r\nimport { Agent, END, State } from \"@cosmixclub/parsero\";\r\nimport { ChatAnthropic } from \"@langchain/anthropic\";\r\nimport { ChatGoogleGenerativeAI } from \"@langchain/google-genai\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\n\r\nconst agent = new Agent({\r\n\tstate: new State({\r\n\t\tinputSchema: z.object({\r\n\t\t\tquery: z.string(),\r\n\t\t\tcontext: z.string().optional(),\r\n\t\t}),\r\n\t\toutputSchema: z.object({\r\n\t\t\tqueryType: z.enum([\"factual\", \"creative\", \"technical\"]),\r\n\t\t\tresponse: z.string(),\r\n\t\t\tsources: z.array(z.string()).optional(),\r\n\t\t}),\r\n\t}),\r\n\tllm: {\r\n\t\t// GPT-4o como modelo padrão\r\n\t\tdefault: new ChatOpenAI({\r\n\t\t\tmodel: \"gpt-4o\",\r\n\t\t\ttemperature: 0.7,\r\n\t\t}),\r\n\r\n\t\t// Claude para consultas factuais e precisas\r\n\t\tfactual: new ChatAnthropic({\r\n\t\t\tmodel: \"claude-3-opus-20240229\",\r\n\t\t\ttemperature: 0.1,\r\n\t\t}),\r\n\r\n\t\t// Gemini para geração de conteúdo criativo\r\n\t\tcreative: new ChatGoogleGenerativeAI({\r\n\t\t\tmodel: \"gemini-pro\",\r\n\t\t\ttemperature: 1.0,\r\n\t\t}),\r\n\r\n\t\t// Modelo econômico para roteamento\r\n\t\trouter: new ChatOpenAI({\r\n\t\t\tmodel: \"gpt-4o-mini\",\r\n\t\t\ttemperature: 0,\r\n\t\t}),\r\n\t},\r\n\tprocedures: [\r\n\t\t// Primeiro determina o tipo de consulta\r\n\t\t{\r\n\t\t\tname: \"analyzeQuery\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: \"routeQuery\",\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\t// Usa o modelo mais econômico para classificação\r\n\t\t\t\tconst result = await llms.router.withStructuredOutput(\r\n\t\t\t\t\tz.object({\r\n\t\t\t\t\t\tqueryType: z\r\n\t\t\t\t\t\t\t.enum([\"factual\", \"creative\", \"technical\"])\r\n\t\t\t\t\t\t\t.describe(\"O tipo de consulta baseado na natureza da pergunta\"),\r\n\t\t\t\t\t\texplanation: z.string().describe(\"Explicação rápida sobre porque essa categoria foi escolhida\"),\r\n\t\t\t\t\t}),\r\n\t\t\t\t).invoke(`\r\n          Classifique a seguinte consulta em uma das categorias:\r\n          - factual: Busca por informações factuais, precisas e verificáveis\r\n          - creative: Busca por conteúdo criativo, ideias, ou explorações conceituais\r\n          - technical: Busca por explicações técnicas ou soluções para problemas\r\n\r\n          Consulta: \"${state.input.query}\"\r\n        `);\r\n\r\n\t\t\t\tstate.output.queryType = result.queryType;\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\r\n\t\t// Router decide qual modelo usar com base no tipo de consulta\r\n\t\t{\r\n\t\t\tname: \"routeQuery\",\r\n\t\t\ttype: \"check\",\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\t// Lógica de roteamento baseada no tipo de consulta\r\n\t\t\t\tswitch (state.output.queryType) {\r\n\t\t\t\t\tcase \"factual\":\r\n\t\t\t\t\t\treturn \"processFact\";\r\n\t\t\t\t\tcase \"creative\":\r\n\t\t\t\t\t\treturn \"generateCreative\";\r\n\t\t\t\t\tcase \"technical\":\r\n\t\t\t\t\tdefault:\r\n\t\t\t\t\t\treturn \"handleTechnical\";\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t},\r\n\r\n\t\t// Processa consultas factuais com Claude (alta precisão)\r\n\t\t{\r\n\t\t\tname: \"processFact\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\tconst response = await llms.factual.invoke(`\r\n          Responda a seguinte consulta factual com alta precisão.\r\n          Forneça fontes ou referências quando possível.\r\n          \r\n          Consulta: ${state.input.query}\r\n          ${state.input.context ? `Contexto adicional: ${state.input.context}` : \"\"}\r\n        `);\r\n\r\n\t\t\t\tstate.output.response = response.toString();\r\n\t\t\t\t// Em um caso real, você poderia extrair fontes usando structured output\r\n\t\t\t\tstate.output.sources = [\"Conhecimento integrado do Claude\"];\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\r\n\t\t// Gera conteúdo criativo com Gemini\r\n\t\t{\r\n\t\t\tname: \"generateCreative\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\tconst response = await llms.creative.invoke(`\r\n          Crie uma resposta criativa e inspiradora para:\r\n          \r\n          ${state.input.query}\r\n          ${state.input.context ? `Considerando este contexto: ${state.input.context}` : \"\"}\r\n          \r\n          Seja original, imaginativo e expressivo em sua resposta.\r\n        `);\r\n\r\n\t\t\t\tstate.output.response = response.toString();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\r\n\t\t// Processa consultas técnicas com o modelo padrão (GPT-4o)\r\n\t\t{\r\n\t\t\tname: \"handleTechnical\",\r\n\t\t\ttype: \"action\",\r\n\t\t\tnextProcedure: END,\r\n\t\t\tasync run(state, llms) {\r\n\t\t\t\tconst response = await llms.default.invoke(`\r\n          Forneça uma resposta técnica detalhada e precisa para:\r\n          \r\n          ${state.input.query}\r\n          ${state.input.context ? `Contexto adicional: ${state.input.context}` : \"\"}\r\n          \r\n          Inclua exemplos práticos quando relevante.\r\n        `);\r\n\r\n\t\t\t\tstate.output.response = response.toString();\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t],\r\n});\r\n\r\n// Teste com diferentes tipos de consultas\r\nconst factualResult = await agent.run({\r\n\tquery: \"Qual é a distância média da Terra ao Sol?\",\r\n});\r\n// Usará o Claude para esta consulta factual\r\n\r\nconst creativeResult = await agent.run({\r\n\tquery: \"Escreva um poema sobre inteligência artificial e a natureza humana.\",\r\n});\r\n// Usará o Gemini para esta consulta criativa\r\n\r\nconst technicalResult = await agent.run({\r\n\tquery: \"Como implementar uma árvore binária de busca em JavaScript?\",\r\n});\r\n// Usará o GPT-4o para esta consulta técnica\r\n```\r\n\r\n> Este exemplo mostra um agente sofisticado que roteia consultas para diferentes modelos com base no tipo de pergunta, utilizando os pontos fortes de cada modelo.\r\n\r\n---\r\n\r\n## Observabilidade e Integração com LangSmith\r\n\r\nO Parsero possui integração nativa com o [LangSmith](https://docs.smith.langchain.com/observability), a plataforma de observabilidade da LangChain. Isso permite rastrear, inspecionar e depurar a execução dos agentes, procedures e fluxos de decisão de forma detalhada.\r\n\r\n### Como funciona\r\n\r\n- Toda execução do agente (`agent.run(...)`) é automaticamente rastreada pelo LangSmith, incluindo cada procedure executada, entradas, saídas, erros e metadados.\r\n- Você pode customizar o rastreamento de cada procedure usando a propriedade `tracing`:\r\n    - `label`: nome amigável para exibição na interface do LangSmith.\r\n    - `runType`: tipo da execução (ex: \"llm\", \"parser\", \"tool\", etc).\r\n    - `metadata`: metadados extras para facilitar a análise.\r\n- O agente também aceita metadados globais via `options.metadata`.\r\n- Para visualizar os rastreamentos, basta configurar as variáveis de ambiente do LangSmith (ex: `LANGCHAIN_API_KEY`, `LANGCHAIN_PROJECT`, etc).\r\n\r\n### Exemplo de uso com observabilidade\r\n\r\n```ts\r\nconst agent = new Agent({\r\n\t// ...outros parâmetros...\r\n\tprocedures: [\r\n\t\t{\r\n\t\t\tname: \"classify\",\r\n\t\t\ttype: \"action\",\r\n\t\t\ttracing: {\r\n\t\t\t\tlabel: \"Classificação do texto\",\r\n\t\t\t\trunType: \"llm\",\r\n\t\t\t\tmetadata: { etapa: \"classificação\" },\r\n\t\t\t},\r\n\t\t\tasync run(state, llm) {\r\n\t\t\t\t// ...\r\n\t\t\t\treturn state;\r\n\t\t\t},\r\n\t\t},\r\n\t\t// ...outras procedures...\r\n\t],\r\n\toptions: {\r\n\t\tmetadata: { projeto: \"meu-agente\" },\r\n\t\tname: \"Agente de exemplo\",\r\n\t},\r\n});\r\n\r\nawait agent.run({ text: \"Exemplo\" });\r\n// A execução será rastreada e poderá ser inspecionada no painel do LangSmith\r\n```\r\n\r\n> Para detalhes sobre configuração, variáveis de ambiente e análise dos rastreamentos, consulte a [documentação oficial do LangSmith](https://docs.smith.langchain.com/observability).\r\n\r\n---\r\n\r\n**Happy Coding!**\r\n\r\n> **Nota**: Exemplos e instruções podem variar de acordo com a versão utilizada do Parsero, LangChain e LangGraph. Consulte sempre a documentação oficial para detalhes de configuração e versões compatíveis.\r\n","readmeFilename":"README.md"}