Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
AG-UI define eventos de estado e campos de pedido para partilhar o estado da aplicação entre um cliente e um endpoint agente. A implementação e os padrões de estado suportados variam consoante o SDK MAF.
Pré-requisitos
Antes de começar, certifique-se de que compreende:
O que é a Gestão do Estado?
AG-UI estado pode fornecer:
- Estado compartilhado: o cliente e o servidor mantêm uma exibição sincronizada do estado do aplicativo
- Atualizações do cliente e servidor: As aplicações podem enviar pedidos de estado e emitir eventos de estado
- Atualizações em tempo real: as alterações são transmitidas imediatamente usando eventos de estado
- Atualizações Preditivas: Um SDK pode mapear o progresso das chamadas de ferramentas para o estado otimista da interface de utilizador
- Dados estruturados: o estado segue um esquema JSON para validação
Casos de uso
A gestão do Estado é valiosa para:
- Interface do usuário generativa: crie componentes da interface do usuário com base no estado controlado pelo agente
- Criação de formulários: o agente preenche campos de formulário à medida que reúne informações
- Acompanhamento do progresso: mostre o progresso em tempo real das operações em várias etapas
- Painéis interativos: exibem dados que são atualizados à medida que o agente os processa
- Edição colaborativa: vários usuários veem atualizações de estado consistentes
O estado AG-UI é JSON visível para o cliente, associado a uma execução. No .NET, a integração fornece dois mecanismos explícitos:
- Leia o estado fornecido pelo cliente a partir do original
RunAgentInput. - Mapear chamadas ou resultados de ferramentas selecionadas para eventos de estado da AG-UI com
AGUIStreamOptions.
O mapeamento de estados é opcional. Resultados arbitrários de ferramentas não se tornam automaticamente estado partilhado.
Leia o estado do cliente
MapAGUIServer armazena a origem RunAgentInput em ChatOptions. Um agente de delegação ou middleware de cliente de chat pode recuperá-lo com TryGetRunAgentInput:
using System.Text.Json;
using AGUI.Abstractions;
using AGUI.Server;
using Microsoft.Extensions.AI;
static bool TryGetClientState(ChatOptions options, out JsonElement state)
{
if (options.TryGetRunAgentInput(out RunAgentInput? input) &&
input.State is { ValueKind: not JsonValueKind.Undefined } value)
{
state = value;
return true;
}
state = default;
return false;
}
O estado do cliente é entrada do pedido. Valide a sua forma e valores antes de o usar em prompts, encaminhamentos ou operações privilegiadas.
Emitir um instantâneo de estado
Mapeie um resultado da ferramenta para STATE_SNAPSHOT quando a ferramenta retorna o estado completo:
using AGUI.Server;
AGUIStreamOptions streamOptions = new AGUIStreamOptions()
.MapResultAsStateSnapshot("generate_recipe");
app.MapAGUIServer("/", agent).WithMetadata(streamOptions);
MapResultAsStateSnapshot requer que o FunctionResultContent.Result valor seja um JsonElement. Serialize um POCO, dicionário ou coleção na JsonElement ferramenta antes de o devolver. O resultado de generate_recipe torna-se então o snapshot e substitui o estado partilhado atual do cliente.
Para outros tipos de resultados, use MapResult com um mapeador personalizado que construa o StateSnapshotEvent.
Deltas do estado de emissão
Associe o resultado de uma ferramenta a STATE_DELTA quando esta devolve um JSON Patch RFC 6902:
AGUIStreamOptions streamOptions = new AGUIStreamOptions()
.MapResultAsStateSnapshot("create_plan")
.MapResultAsStateDelta("update_plan_step");
app.MapAGUIServer("/", agent).WithMetadata(streamOptions);
Use um snapshot para inicializar ou substituir estados e deltas para alterações incrementais.
MapResultAsStateDelta também requer um resultado JsonElement. O elemento deve conter um array de RFC 6902 JSON Patch. Use MapResult com um mapeador personalizado se a ferramenta devolver outra representação.
Chamadas de ferramenta de mapas para o estado
AGUIStreamOptions.MapCall mapeia um FunctionCallContent selecionado para eventos adicionais de AG-UI emitidos após os eventos normais de chamada da ferramenta. Use-o quando o estado deriva dos argumentos da ferramenta em vez do resultado da ferramenta:
AGUIStreamOptions streamOptions = new AGUIStreamOptions()
.MapCall("write_document", call =>
{
if (call.Arguments?.TryGetValue("document", out object? document) is not true)
{
return [];
}
JsonElement snapshot = JsonSerializer.SerializeToElement(new { document });
return [new StateSnapshotEvent { Snapshot = snapshot }];
});
app.MapAGUIServer("/", agent).WithMetadata(streamOptions);
A aplicação detém o mapeamento e a forma do estado.
MapCall não infere estado a partir de argumentos arbitrários de ferramentas nem suprime a execução normal da ferramenta. As atualizações incrementais exigem que o cliente do modelo subjacente exponha argumentos de chamada de ferramenta transmitidos e que a aplicação configure a extração correspondente de argumentos.
Estado de receção num cliente .NET
O cliente AG-UI .NET expõe eventos do protocolo de estado através de ChatResponseUpdate.RawRepresentation:
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages, session))
{
if (update.AsChatResponseUpdate().RawRepresentation is StateSnapshotEvent snapshot)
{
JsonElement state = snapshot.Snapshot;
}
else if (update.AsChatResponseUpdate().RawRepresentation is StateDeltaEvent delta)
{
JsonElement changes = delta.Delta;
}
}
O cliente é responsável por reter e aplicar o estado partilhado, enviando depois o estado atual em pedidos posteriores quando a aplicação assim o exigir.
Passos seguintes
Modelos de Estados
Primeiro, defina modelos pidânticos para a sua estrutura de estado. Isso garante a segurança do tipo e a validação:
from enum import Enum
from pydantic import BaseModel, Field
class SkillLevel(str, Enum):
"""The skill level required for the recipe."""
BEGINNER = "Beginner"
INTERMEDIATE = "Intermediate"
ADVANCED = "Advanced"
class CookingTime(str, Enum):
"""The cooking time of the recipe."""
FIVE_MIN = "5 min"
FIFTEEN_MIN = "15 min"
THIRTY_MIN = "30 min"
FORTY_FIVE_MIN = "45 min"
SIXTY_PLUS_MIN = "60+ min"
class Ingredient(BaseModel):
"""An ingredient with its details."""
icon: str = Field(..., description="Emoji icon representing the ingredient (e.g., 🥕)")
name: str = Field(..., description="Name of the ingredient")
amount: str = Field(..., description="Amount or quantity of the ingredient")
class Recipe(BaseModel):
"""A complete recipe."""
title: str = Field(..., description="The title of the recipe")
skill_level: SkillLevel = Field(..., description="The skill level required")
special_preferences: list[str] = Field(
default_factory=list, description="Dietary preferences (e.g., Vegetarian, Gluten-free)"
)
cooking_time: CookingTime = Field(..., description="The estimated cooking time")
ingredients: list[Ingredient] = Field(..., description="Complete list of ingredients")
instructions: list[str] = Field(..., description="Step-by-step cooking instructions")
Esquema de estado
Defina um esquema de estado para especificar a estrutura e os tipos do seu estado:
state_schema = {
"recipe": {"type": "object", "description": "The current recipe"},
}
Observação
O esquema de estado usa um formato simples com type e opcional description. A estrutura real é definida pelos seus modelos Pydantic.
Atualizações de estado preditivas
As atualizações de estado preditivo transmitem argumentos da ferramenta para o estado à medida que o LLM os gera, permitindo atualizações otimistas da interface do usuário:
predict_state_config = {
"recipe": {"tool": "update_recipe", "tool_argument": "recipe"},
}
Esta configuração mapeia o recipe campo de estado para o recipe argumento da update_recipe ferramenta. Quando o agente chama a ferramenta, os argumentos são transmitidos para o estado em tempo real à medida que o modelo de linguagem de máquina os gera.
Definir ferramenta de atualização de estado
Crie uma função de ferramenta que aceite o seu modelo Pydantic:
from agent_framework import tool
@tool
def update_recipe(recipe: Recipe) -> str:
"""Update the recipe with new or modified content.
You MUST write the complete recipe with ALL fields, even when changing only a few items.
When modifying an existing recipe, include ALL existing ingredients and instructions plus your changes.
NEVER delete existing data - only add or modify.
Args:
recipe: The complete recipe object with all details
Returns:
Confirmation that the recipe was updated
"""
return "Recipe updated."
Importante
O nome do parâmetro da função de ferramenta (recipe) deve corresponder ao tool_argument no seu predict_state_config.
Criar agente com gestão de estado
Aqui está uma implementação completa do servidor com gerenciamento de estado:
"""AG-UI server with state management."""
from agent_framework import Agent
from agent_framework.openai import OpenAIChatCompletionClient
from agent_framework_ag_ui import (
AgentFrameworkAgent,
add_agent_framework_fastapi_endpoint,
)
from azure.identity import AzureCliCredential
from fastapi import FastAPI
# Create the chat agent with tools
agent = Agent(
name="recipe_agent",
instructions="""You are a helpful recipe assistant that creates and modifies recipes.
CRITICAL RULES:
1. You will receive the current recipe state in the system context
2. To update the recipe, you MUST use the update_recipe tool
3. When modifying a recipe, ALWAYS include ALL existing data plus your changes in the tool call
4. NEVER delete existing ingredients or instructions - only add or modify
5. After calling the tool, provide a brief conversational message (1-2 sentences)
When creating a NEW recipe:
- Provide all required fields: title, skill_level, cooking_time, ingredients, instructions
- Use actual emojis for ingredient icons (🥕 🧄 🧅 🍅 🌿 🍗 🥩 🧀)
- Leave special_preferences empty unless specified
- Message: "Here's your recipe!" or similar
When MODIFYING or IMPROVING an existing recipe:
- Include ALL existing ingredients + any new ones
- Include ALL existing instructions + any new/modified ones
- Update other fields as needed
- Message: Explain what you improved (e.g., "I upgraded the ingredients to premium quality")
- When asked to "improve", enhance with:
* Better ingredients (upgrade quality, add complementary flavors)
* More detailed instructions
* Professional techniques
* Adjust skill_level if complexity changes
* Add relevant special_preferences
Example improvements:
- Upgrade "chicken" → "organic free-range chicken breast"
- Add herbs: basil, oregano, thyme
- Add aromatics: garlic, shallots
- Add finishing touches: lemon zest, fresh parsley
- Make instructions more detailed and professional
""",
client=OpenAIChatCompletionClient(
model=deployment_name,
azure_endpoint=endpoint,
api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
credential=AzureCliCredential(),
),
tools=[update_recipe],
)
# Wrap agent with state management
recipe_agent = AgentFrameworkAgent(
agent=agent,
name="RecipeAgent",
description="Creates and modifies recipes with streaming state updates",
state_schema={
"recipe": {"type": "object", "description": "The current recipe"},
},
predict_state_config={
"recipe": {"tool": "update_recipe", "tool_argument": "recipe"},
},
)
# Create FastAPI app
app = FastAPI(title="AG-UI Recipe Assistant")
add_agent_framework_fastapi_endpoint(app, recipe_agent, "/")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8888)
Conceitos-chave
- Modelos Pydantic: Definir estado estruturado com segurança de tipo e validação
- Esquema de estado: formato simples especificando tipos de campo de estado
- Configuração de estado preditivo: mapeia campos de estado para argumentos de ferramenta para atualizações de streaming
- Injeção de estado: O estado atual é injetado automaticamente como mensagens do sistema para fornecer contexto
- Atualizações completas: as ferramentas devem gravar o estado completo, não apenas deltas
- Estratégia de confirmação: Personalize as mensagens de aprovação para o seu domínio (receita, documento, planeamento de tarefas, etc.)
Noções básicas sobre eventos de estado
Evento de instantâneo de estado
Um instantâneo completo do estado atual, emitido quando a ferramenta é finalizada:
{
"type": "STATE_SNAPSHOT",
"snapshot": {
"recipe": {
"title": "Classic Pasta Carbonara",
"skill_level": "Intermediate",
"special_preferences": ["Authentic Italian"],
"cooking_time": "30 min",
"ingredients": [
{"icon": "🍝", "name": "Spaghetti", "amount": "400g"},
{"icon": "🥓", "name": "Guanciale or bacon", "amount": "200g"},
{"icon": "🥚", "name": "Egg yolks", "amount": "4"},
{"icon": "🧀", "name": "Pecorino Romano", "amount": "100g grated"},
{"icon": "🧂", "name": "Black pepper", "amount": "To taste"}
],
"instructions": [
"Bring a large pot of salted water to boil",
"Cut guanciale into small strips and fry until crispy",
"Beat egg yolks with grated Pecorino and black pepper",
"Cook spaghetti until al dente",
"Reserve 1 cup pasta water, then drain pasta",
"Remove pan from heat, add hot pasta to guanciale",
"Quickly stir in egg mixture, adding pasta water to create creamy sauce",
"Serve immediately with extra Pecorino and black pepper"
]
}
}
}
Evento Delta do Estado
Atualizações de estado incrementais usando o formato JSON Patch, emitidas como os argumentos da ferramenta LLM streams:
{
"type": "STATE_DELTA",
"delta": [
{
"op": "replace",
"path": "/recipe",
"value": {
"title": "Classic Pasta Carbonara",
"skill_level": "Intermediate",
"cooking_time": "30 min",
"ingredients": [
{"icon": "🍝", "name": "Spaghetti", "amount": "400g"}
],
"instructions": ["Bring a large pot of salted water to boil"]
}
}
]
}
Observação
Os eventos delta de estado são transmitidos em tempo real à medida que o LLM gera os argumentos da ferramenta, fornecendo atualizações otimistas da interface do usuário. O instantâneo de estado final é emitido quando a ferramenta conclui a execução.
Implementação do Cliente
O agent_framework_ag_ui pacote fornece AGUIChatClient a conexão com servidores AG-UI, trazendo a experiência do cliente Python para a paridade com o .NET:
"""AG-UI client with state management."""
import asyncio
import json
import os
from typing import Any
from agent_framework import Agent, Message, Role
from agent_framework_ag_ui import AGUIChatClient
async def main():
"""Example client with state tracking."""
server_url = os.environ.get("AGUI_SERVER_URL", "http://127.0.0.1:8888/")
print(f"Connecting to AG-UI server at: {server_url}\n")
# Create AG-UI chat client
chat_client = AGUIChatClient(endpoint=server_url)
# Wrap with Agent for convenient API
agent = Agent(
name="ClientAgent",
client=chat_client,
instructions="You are a helpful assistant.",
)
# Get a thread for conversation continuity
thread = agent.create_session()
# Track state locally
state: dict[str, Any] = {}
try:
while True:
message = input("\nUser (:q to quit, :state to show state): ")
if not message.strip():
continue
if message.lower() in (":q", "quit"):
break
if message.lower() == ":state":
print(f"\nCurrent state: {json.dumps(state, indent=2)}")
continue
print()
# Stream the agent response with state
async for update in agent.run(message, session=thread, stream=True):
# Handle text content
if update.text:
print(update.text, end="", flush=True)
# Handle state updates surfaced through AG-UI events.
for content in update.contents:
if content.type == "data" and getattr(content, "media_type", None) == "application/json":
print("\n[JSON state payload received]")
print(f"\n\nCurrent state: {json.dumps(state, indent=2)}")
print()
except KeyboardInterrupt:
print("\n\nExiting...")
if __name__ == "__main__":
# Install dependencies: pip install agent-framework-ag-ui --pre
asyncio.run(main())
Principais Benefícios
O AGUIChatClient dispõe:
- Conexão simplificada: manipulação automática de comunicação HTTP/SSE
- Gerenciamento de threads: rastreamento de ID de thread integrado para continuidade de conversa
-
Integração de agentes: funciona perfeitamente com
Agentuma API familiar - State Handling: Análise automática de eventos de estado do servidor
- Paridade com .NET: experiência consistente entre idiomas
Tip
Use AGUIChatClient com Agent para obter todos os benefícios dos recursos da estrutura do agente, como histórico de conversas, execução de ferramentas e suporte a middleware.
Confirmação do estado previsto
Defina require_confirmation=True em AgentFrameworkAgent quando as mudanças de estado previstas tiverem de aguardar a confirmação do cliente antes de serem aplicadas:
recipe_agent = AgentFrameworkAgent(
agent=agent,
state_schema={"recipe": {"type": "object", "description": "The current recipe"}},
predict_state_config={"recipe": {"tool": "update_recipe", "tool_argument": "recipe"}},
require_confirmation=True,
)
Personaliza a cópia de confirmação na interface do cliente AG-UI ao renderizar o evento de confirmação.
Exemplo de interação
Com o servidor e o cliente em execução:
User (:q to quit, :state to show state): I want to make a classic Italian pasta carbonara
[Run Started]
[Calling Tool: update_recipe]
[State Updated]
[State Updated]
[State Updated]
[Tool Result: Recipe updated.]
Here's your recipe!
[Run Finished]
============================================================
CURRENT STATE
============================================================
recipe:
title: Classic Pasta Carbonara
skill_level: Intermediate
special_preferences: ['Authentic Italian']
cooking_time: 30 min
ingredients:
- 🍝 Spaghetti: 400g
- 🥓 Guanciale or bacon: 200g
- 🥚 Egg yolks: 4
- 🧀 Pecorino Romano: 100g grated
- 🧂 Black pepper: To taste
instructions:
1. Bring a large pot of salted water to boil
2. Cut guanciale into small strips and fry until crispy
3. Beat egg yolks with grated Pecorino and black pepper
4. Cook spaghetti until al dente
5. Reserve 1 cup pasta water, then drain pasta
6. Remove pan from heat, add hot pasta to guanciale
7. Quickly stir in egg mixture, adding pasta water to create creamy sauce
8. Serve immediately with extra Pecorino and black pepper
============================================================
Tip
Use o :state comando para exibir o estado atual a qualquer momento durante a conversa.
Atualizações de estado preditivas em ação
Ao usar atualizações de estado preditivas com predict_state_config, o cliente recebe STATE_DELTA eventos à medida que o LLM gera argumentos da ferramenta em tempo real, antes da execução da ferramenta.
// Agent starts generating tool call for update_recipe
// Client receives STATE_DELTA events as the recipe argument streams:
// First delta - partial recipe with title
{
"type": "STATE_DELTA",
"delta": [{"op": "replace", "path": "/recipe", "value": {"title": "Classic Pasta"}}]
}
// Second delta - title complete with more fields
{
"type": "STATE_DELTA",
"delta": [{"op": "replace", "path": "/recipe", "value": {
"title": "Classic Pasta Carbonara",
"skill_level": "Intermediate"
}}]
}
// Third delta - ingredients starting to appear
{
"type": "STATE_DELTA",
"delta": [{"op": "replace", "path": "/recipe", "value": {
"title": "Classic Pasta Carbonara",
"skill_level": "Intermediate",
"cooking_time": "30 min",
"ingredients": [
{"icon": "🍝", "name": "Spaghetti", "amount": "400g"}
]
}}]
}
// ... more deltas as the LLM generates the complete recipe
Isso permite que o cliente mostre atualizações otimistas da interface do usuário em tempo real conforme o agente está pensando, fornecendo feedback imediato aos usuários.
Estado com Human-in-the-Loop
Você pode combinar o gerenciamento de estado com fluxos de trabalho de aprovação definindo require_confirmation=True:
recipe_agent = AgentFrameworkAgent(
agent=agent,
state_schema={"recipe": {"type": "object", "description": "The current recipe"}},
predict_state_config={"recipe": {"tool": "update_recipe", "tool_argument": "recipe"}},
require_confirmation=True, # Require approval for state changes
)
Quando ativado:
- Fluxo de atualizações de estado à medida que o agente gera argumentos de ferramenta (atualizações preditivas por meio de
STATE_DELTAeventos) - O agente faz uma pausa antes de executar a ferramenta com uma interrupção
tool_callemRUN_FINISHED.outcome.interrupts - Se aprovada, a ferramenta é executada e o estado final é emitido (via
STATE_SNAPSHOTevento) - Se rejeitadas, as alterações de estado preditivo são descartadas
Padrões de estado avançados
Estado complexo com vários campos
Você pode gerenciar vários campos de estado com diferentes ferramentas:
from pydantic import BaseModel
class TaskStep(BaseModel):
"""A single task step."""
description: str
status: str = "pending"
estimated_duration: str = "5 min"
@tool
def generate_task_steps(steps: list[TaskStep]) -> str:
"""Generate task steps for a given task."""
return f"Generated {len(steps)} steps."
@tool
def update_preferences(preferences: dict[str, Any]) -> str:
"""Update user preferences."""
return "Preferences updated."
# Configure with multiple state fields
agent_with_multiple_state = AgentFrameworkAgent(
agent=agent,
state_schema={
"steps": {"type": "array", "description": "List of task steps"},
"preferences": {"type": "object", "description": "User preferences"},
},
predict_state_config={
"steps": {"tool": "generate_task_steps", "tool_argument": "steps"},
"preferences": {"tool": "update_preferences", "tool_argument": "preferences"},
},
)
Usando argumentos da ferramenta curinga
Quando uma ferramenta retorna dados aninhados complexos, use "*" para mapear todos os argumentos da ferramenta para afirmar:
@tool
def create_document(title: str, content: str, metadata: dict[str, Any]) -> str:
"""Create a document with title, content, and metadata."""
return "Document created."
# Map all tool arguments to document state
predict_state_config = {
"document": {"tool": "create_document", "tool_argument": "*"}
}
Isso mapeia toda a chamada de ferramenta (todos os argumentos) para o document campo de estado.
Melhores práticas
Usar modelos pidânticos
Definir modelos estruturados para segurança de tipo:
class Recipe(BaseModel):
"""Use Pydantic models for structured, validated state."""
title: str
skill_level: SkillLevel
ingredients: list[Ingredient]
instructions: list[str]
Benefícios:
- Segurança do tipo: Validação automática de tipos de dados
- Documentação: As descrições dos campos servem como documentação
- Suporte IDE: Preenchimento automático e verificação de tipo
- Serialização: conversão automática de JSON
Atualizações de estado completas
Escreva sempre o estado completo, não apenas deltas:
@tool
def update_recipe(recipe: Recipe) -> str:
"""
You MUST write the complete recipe with ALL fields.
When modifying a recipe, include ALL existing ingredients and
instructions plus your changes. NEVER delete existing data.
"""
return "Recipe updated."
Isso garante a consistência do estado e atualizações preditivas adequadas.
Corresponder nomes de parâmetros
Verifique se os nomes dos parâmetros da ferramenta correspondem à tool_argument configuração:
# Tool parameter name
def update_recipe(recipe: Recipe) -> str: # Parameter name: 'recipe'
...
# Must match in predict_state_config
predict_state_config = {
"recipe": {"tool": "update_recipe", "tool_argument": "recipe"} # Same name
}
Fornecer contexto nas instruções
Inclua instruções claras sobre a gestão do estado:
agent = Agent(
instructions="""
CRITICAL RULES:
1. You will receive the current recipe state in the system context
2. To update the recipe, you MUST use the update_recipe tool
3. When modifying a recipe, ALWAYS include ALL existing data plus your changes
4. NEVER delete existing ingredients or instructions - only add or modify
""",
...
)
Personalizar interface de confirmação
Personalize mensagens de aprovação e confirmação de estado no seu cliente AG-UI ao apresentar eventos de confirmação a partir do servidor.
Próximas Etapas
Agora você aprendeu todos os principais recursos AG-UI! Em seguida, você pode:
- Explore a documentação do Agent Framework
- Crie um aplicativo completo combinando todos os recursos AG-UI
- Implante seu serviço de AG-UI na produção
Recursos adicionais
No Go AG-UI, a gestão do estado pode ser implementada com middleware que emite atualizações estruturadas de message.DataContent a par das atualizações normais de texto.
stateSnapshotMiddleware := agent.MiddlewareFunc(func(next agent.RunFunc, ctx context.Context, messages []*message.Message, opts ...agent.Option) iter.Seq2[*agent.ResponseUpdate, error] {
return func(yield func(*agent.ResponseUpdate, error) bool) {
for update, err := range next(ctx, messages, opts...) {
if err != nil {
yield(nil, err)
return
}
if update != nil {
// Inspect update contents and yield DataContent snapshots as needed.
}
if !yield(update, nil) {
return
}
}
}
})
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Config: agent.Config{
Middlewares: []agent.Middleware{stateSnapshotMiddleware},
},
})
Tip
Consulte o exemplo de gestão de estadoAG-UI para um exemplo completo executável.