Salta ai contenuti

Implementare e configurare l'agente Story

Lo Story Agent è un agente Strands generato con --protocol=AG-UI nel Modulo 1, in modo che l’interfaccia utente possa ricevere lo streaming da esso tramite il protocollo Agent-User Interaction via CopilotKit. Utilizza il server MCP dell’inventario per gestire gli oggetti del giocatore e l’S3SessionManager integrato di Strands per persistere la cronologia delle conversazioni nel bucket delle sessioni che abbiamo fornito nel Modulo 2.

Aggiorna i seguenti file in packages/story/dungeon_adventure_story/agent:

import logging
import os
from functools import cache
from typing import Any, cast
from ag_ui.core import RunAgentInput
from ag_ui_strands import StrandsAgent, StrandsAgentConfig, create_strands_app
from aws_lambda_powertools.utilities import parameters
from strands.session import FileSessionManager, S3SessionManager, SessionManager
from .agent import get_agent
logging.basicConfig(level=logging.INFO)
@cache
def _resolve_sessions_bucket() -> str:
"""Read the conversation-history bucket name from runtime config.
Resolved lazily (and memoised) so `fastapi dev` can import this module
before ``RUNTIME_CONFIG_APP_ID`` is in the environment.
"""
application = os.environ.get("RUNTIME_CONFIG_APP_ID")
if not application:
raise RuntimeError("RUNTIME_CONFIG_APP_ID is not set — cannot resolve the StorySessions bucket.")
provider = parameters.AppConfigProvider(environment="default", application=application)
buckets = cast(dict[str, Any], provider.get("buckets", transform="json"))
return buckets["StorySessions"]["bucketName"]
def _session_manager_provider(input_data: RunAgentInput) -> SessionManager:
"""Create a session manager keyed by the AG-UI thread_id.
- In AgentCore (and `agent-serve`), persist to the shared ``StorySessions``
S3 bucket — the same bucket the Game API reads from to rebuild
conversation history on revisit.
- In `agent-serve-local` (`SERVE_LOCAL=true`), persist to a temp
directory so the agent can run fully offline against the local MCP
server without any AWS calls.
"""
session_id = input_data.thread_id or "default"
if os.environ.get("SERVE_LOCAL") == "true":
return FileSessionManager(session_id=session_id, storage_dir="/tmp/strands-sessions")
return S3SessionManager(session_id=session_id, bucket=_resolve_sessions_bucket())
# The template Agent is cloned per thread_id by ``StrandsAgent`` — we plug in
# a ``session_manager_provider`` so each thread gets its own session manager
# and conversation history is replayed on subsequent turns and survives agent
# restarts.
_agent_ctx = get_agent()
_agent = _agent_ctx.__enter__()
agui_agent = StrandsAgent(
agent=_agent,
name="StoryAgent",
description="A Strands Agent exposed via the AG-UI protocol.",
config=StrandsAgentConfig(session_manager_provider=_session_manager_provider),
)
app = create_strands_app(agui_agent, path="/invocations")

Le modifiche sono:

  • main.py aggiunge un session_manager_provider che crea un S3SessionManager per ogni thread_id quando deployato, e ricade su un FileSessionManager su disco sotto /tmp/strands-sessions quando eseguito con agent-serve-local (SERVE_LOCAL=true). In deployment, il bucket S3 è lo stesso da cui legge il queryActions della Game API, così il browser può ricostruire le trascrizioni alla rivisitazione; localmente l’agente funziona completamente offline contro il server MCP locale senza chiamate AWS.
  • agent.py rimuove lo strumento di esempio subtract e sostituisce il prompt di sistema con uno da dungeon-master che invita il primo messaggio dell’utente a dichiarare il nome del giocatore e il genere, e utilizza gli strumenti del server MCP dell’inventario.

Per compilare il codice:

Terminal window
pnpm build

Per effettuare il deploy dell’applicazione, esegui il seguente comando:

Terminal window
pnpm nx deploy infra "dungeon-adventure-infra-sandbox/*"

Il deployment richiederà circa 2 minuti per completarsi.

Una volta completato il deployment, vedrai output simili ai seguenti (alcuni valori sono stati oscurati):

Terminal window
dungeon-adventure-infra-sandbox-Application
dungeon-adventure-infra-sandbox-Application: deploying... [2/2]
dungeon-adventure-infra-sandbox-Application
Deployment time: 354s
Outputs:
dungeon-adventure-infra-sandbox-Application.ElectroDbTableTableNameXXX = dungeon-adventure-infra-sandbox-Application-ElectroDbTableXXX-YYY
dungeon-adventure-infra-sandbox-Application.GameApiEndpointXXX = https://xxx.execute-api.region.amazonaws.com/prod/
dungeon-adventure-infra-sandbox-Application.GameUIDistributionDomainNameXXX = xxx.cloudfront.net
dungeon-adventure-infra-sandbox-Application.InventoryMcpArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventureventoryMcpServerXXXX-YYYY
dungeon-adventure-infra-sandbox-Application.RuntimeConfigApplicationId = xxxx
dungeon-adventure-infra-sandbox-Application.StoryAgentArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventurecationStoryAgentXXXX-YYYY
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityIdentityPoolIdXXX = region:xxx
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityUserPoolIdXXX = region_xxx

Puoi testare il tuo Agent in due modi:

  • Avviando un’istanza locale del server Agent e chattando con esso tramite il target generato agent-chat, oppure
  • Chiamando l’API deployata usando curl con un token JWT.

Apri un REPL interattivo contro una copia dell’agente AG-UI servita localmente utilizzando il target generato agent-chat:

Terminal window
pnpm nx agent-chat story

agent-chat ha dependsOn: ['agent-serve-local'], quindi non è necessario avviare il server dell’agente separatamente — Nx avvierà agent-serve-local (che a sua volta avvia il server MCP dell’inventario localmente), quindi lancerà il REPL AG-UI agent-chat-cli contro http://localhost:8081/invocations. Il tuo primo messaggio dovrebbe dire all’agente il nome del tuo eroe e il genere (per esempio: My name is Alice. Start my zombie adventure.) e la storia verrà trasmessa in streaming.

Se il comando viene eseguito con successo, dovresti iniziare a vedere la storia trasmessa in streaming come un flusso di eventi AG-UI (Server-Sent Events) — i chunk RUN_STARTED / TEXT_MESSAGE_START / TEXT_MESSAGE_CONTENT avvolgono i token effettivi della storia:

data: {"type":"RUN_STARTED","threadId":"Alice-zombie00000000000000000000000",...}
data: {"type":"TEXT_MESSAGE_START","messageId":"...","role":"assistant"}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":"Greetings, Alice. "}
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"...","delta":"The moans grow louder beyond the barricaded door..."}

Complimenti. Hai creato e deployato il tuo primo Strands Agent su Bedrock AgentCore Runtime! 🎉🎉🎉