---
title: strands-execution-adapter-research
type: note
permalink: main/convergence-hub/agents-platform/projects/agent-squad-substrate/strands-execution-adapter-research
---

# Strands Agents como Execution Adapter dentro de Amazon Bedrock AgentCore Runtime

Fecha de investigacion: 2026-07-09. Alcance: fuentes oficiales de Strands Agents, GitHub/PyPI/npm cuando fue accesible, y documentacion oficial de Amazon Bedrock AgentCore.

## 1. ESTADO ACTUAL (jul-2026)

### Versiones y madurez

| SDK | Estado observado | Version / release observado | Madurez |
|---|---|---:|---|
| Python `strands-agents` | SDK principal, paquete PyPI verificado por PyPI, autor AWS. Requiere Python `>=3.10`. | `1.46.0`, publicado el 2026-07-08 en PyPI. | PyPI clasifica `Development Status :: 5 - Production/Stable`. La documentacion de Strands lo describe como "production-ready". |
| TypeScript `@strands-agents/sdk` | Existe SDK TypeScript y documentacion oficial. El repo historico `strands-agents/sdk-typescript` aparece archivado el 2026-06-03; el repo activo es el monorepo `strands-agents/harness-sdk`, que contiene `strands-ts/`. | GitHub monorepo muestra release latest `typescript/v1.8.0`, 2026-07-08. No pude confirmar directamente el registry npm con la herramienta disponible; no invento el numero npm si difiere del release oficial del monorepo. | Funcional, pero no paritario con Python: la doc dice que Session Management y Structured Output "not supported in TypeScript", aunque la API TypeScript lista `structuredOutputSchema?: z.ZodSchema`. Tratar esas capacidades TS como "verificar antes de produccion". |

### Relacion oficial con Amazon Bedrock AgentCore Runtime

Strands tiene integracion first-class en su documentacion de despliegue a Amazon Bedrock AgentCore Runtime, con guias separadas para Python y TypeScript. Pero AgentCore Runtime no es exclusivo de Strands: la doc de Strands dice que AgentCore Runtime permite usar "any open-source framework including Strands Agents, LangChain, LangGraph and CrewAI" y soporta varios protocolos/modelos. Por tanto:

- Strands es un framework oficial y AWS-backed, con guia de despliegue especifica a AgentCore.
- AgentCore Runtime es framework-agnostic; Strands no debe considerarse el orquestador de referencia obligatorio.
- Para Python, el helper oficial de runtime es `bedrock_agentcore.runtime.BedrockAgentCoreApp` con `@app.entrypoint` y `app.run()`. Ese helper viene del paquete `bedrock-agentcore`, no de `strands-agents`.
- Para TypeScript no encontre helper equivalente a `BedrockAgentCoreApp` en la doc de Strands; la guia oficial usa Express, Docker, `@aws-sdk/client-bedrock-agentcore`, y endpoints HTTP.

Confidence: Alta para Python/version/madurez/AgentCore; Media para la version npm exacta por falta de confirmacion directa del registry.

## 2. INVENTARIO DE CAPACIDADES SEGUN CRITERIO RECTOR

| Criterio | Item / API exacta | Estado recomendado y como se desactiva u omite |
|---|---|---|
| NUCLEO DE EJECUCION | Python `strands.Agent` | Usar como loop efimero por request. Constructor relevante: `Agent(model=..., messages=..., tools=..., system_prompt=..., conversation_manager=..., session_manager=..., callback_handler=..., retry_strategy=..., load_tools_from_directory=...)`. |
| NUCLEO DE EJECUCION | TS `new Agent(config?: AgentConfig)` | Usar solo si se necesita TS. `AgentConfig` documentado: `model?`, `messages?`, `tools?`, `systemPrompt?`, `state?`, `printer?`, `conversationManager?`, `hooks?`, `structuredOutputSchema?`. |
| NUCLEO DE EJECUCION | Modelo por invocacion: Python `model` o string model-id; TS `model?: Model | string` | Pasarlo siempre desde el payload curado por Substrate. No usar default: Python crea `BedrockModel()` si `model=None`; la guia quickstart indica default Bedrock + Claude Sonnet 4 por region. |
| NUCLEO DE EJECUCION | Herramientas Python `tools=[...]`; TS `tools?: ToolList`; decorator Python `@strands.tool`; TS `tool(...)` | Pasar una lista explicita y ya autorizada por Substrate. En Python, la doc de `Agent` dice: si `tools` se provee, solo esas estan disponibles; si `tools=None`, "all tools will be available". Para nuestro caso, pasar `tools=[]` o lista explicita. |
| NUCLEO DE EJECUCION | Ejecucion de tools: Python `tool_executor`, default `ConcurrentToolExecutor()`, alternativa `SequentialToolExecutor`; TS tool callbacks | Usar solo para ejecutar tools ya curadas. Si el orden importa o se quiere reducir no determinismo operacional, usar `SequentialToolExecutor` en Python. Si no se especifica, Python usa concurrencia. |
| NUCLEO DE EJECUCION | Streaming Python `agent.stream_async(prompt)`; TS `agent.stream(args, options?)` | Permitido como transporte de eventos. Debe devolverse al caller como stream/SSE del Runtime, sin persistir contexto local. |
| NUCLEO DE EJECUCION | Respuesta no streaming Python `agent(prompt)`; TS `agent.invoke(args, options?)` | Permitido. Python devuelve `AgentResult` con `message` y `structured_output` cuando aplica; TS devuelve `AgentResult` con `lastMessage`/`stopReason` segun ejemplo oficial. |
| NUCLEO DE EJECUCION | Structured output Python `structured_output_model=...`, constructor `structured_output_model`, `structured_output_prompt`; resultado `AgentResult.structured_output` | Permitido si Substrate selecciona un schema/modelo local permitido. Es opt-in: default `None`, sin structured output. No aceptar clases/esquemas arbitrarios desde payload sin mapeo interno. |
| NUCLEO DE EJECUCION | Structured output TS `structuredOutputSchema?: z.ZodSchema` | La API TypeScript lo lista, pero la guia de usuario dice "not supported in TypeScript". Marcar como no confirmado para produccion; no depender de ello sin prueba directa. |
| NUCLEO DE EJECUCION | Hooks Python `hooks: list[HookProvider]`, `HookRegistry`, `agent.add_hook(...)`; eventos como `BeforeInvocationEvent`, `AfterInvocationEvent`, `BeforeModelCallEvent`, `AfterModelCallEvent`, `BeforeToolCallEvent`, `AfterToolCallEvent` | Usar solo hooks propios de observabilidad/policy auditables. No usar hooks que modifiquen prompt/tools/model salvo que Substrate los controle. |
| NUCLEO DE EJECUCION | Observabilidad OTel / Strands telemetry; AgentCore observability via `aws-opentelemetry-distro` y `opentelemetry-instrument` | Permitido. Cuidado: trazas pueden incluir system prompt, parametros, mensajes input/output y tool input/output. Exportar solo a destinos aprobados. |
| NUCLEO DE EJECUCION | AgentCore Python `BedrockAgentCoreApp`, `@app.entrypoint`, `app.run()` | Usar como lifecycle HTTP del Runtime si se acepta el wrapper. Alternativa: FastAPI custom. |
| NUCLEO DE EJECUCION | AgentCore HTTP contract `/invocations` POST, `/ping` GET, `/ws` opcional | Implementar estrictamente. Requisitos: host `0.0.0.0`, puerto `8080`, contenedor ARM64. `/invocations` acepta JSON y responde JSON o SSE; `/ping` responde status de salud. |
| A DESACTIVAR / NO USAR | Multi-agent Python `strands.multiagent.Graph`, `Swarm`, `Workflow`; TS multi-agent patterns | No instanciar. Son opt-in. No pasar `session_manager` a orquestadores. Mantener Strands como single-agent loop por step. |
| A DESACTIVAR / NO USAR | Agent2Agent / A2A: Python docs listan `A2AAgent`, API `strands.multiagent.a2a.*`; user guide `Agent2Agent (A2A)` | No instalar extras `a2a`, no importar, no exponer endpoints A2A. Opt-in. |
| A DESACTIVAR / NO USAR | Agents-as-Tools | No envolver agentes como herramientas. Opt-in por patron de multi-agent. |
| A DESACTIVAR / NO USAR | MCP clients/tools: Python/TS `McpClient`, MCP tool provider APIs | No usar salvo que Substrate lo encapsule como tool ya autorizada. MCP amplia superficie dinamica de tools; para soberania, resolver y congelar tools fuera de Strands. |
| A DESACTIVAR / NO USAR | Semantic/autonomous tool selection amplio | Strands es model-driven: el modelo decide si usa tools en el loop. No hay switch global documentado para "force only this one tool" en `Agent`. Neutralizar reduciendo `tools` a la lista minima por request y usando instrucciones del step; si se requiere determinismo absoluto, ejecutar la tool fuera del agent loop. |
| A DESACTIVAR / NO USAR | Planners/razonamiento autonomo multi-paso fuera del step | No encontre API de planner separada en el constructor actual. El loop en si es multi-iteracion hasta stop reason. Limitar por contrato externo: timeout, presupuesto de tokens, lista de tools minima, y hooks de auditoria. |
| A DESACTIVAR / NO USAR | Plugins `plugins: list[Plugin]` | No pasar `plugins`. Son opt-in y pueden registrar hooks/tools o modificar atributos del agent. |
| A DESACTIVAR / NO USAR | Carga automatica de tools `load_tools_from_directory` | Mantener `False` (default). Nunca usar `./tools/` como discovery dinamico en el runtime. |
| A AISLAR | Python `session_manager: SessionManager | None` | No pasar `session_manager` en el adapter. Es opt-in; si se provee, habilita persistencia y estado de sesion. |
| A AISLAR | `FileSessionManager(session_id, storage_dir=...)` | No usar directamente. Persiste a filesystem `session_<session_id>/...`. Si algun producto lo necesita, envolverlo detras de interfaz del Substrate y con ownership claro. |
| A AISLAR | `S3SessionManager(session_id, bucket, prefix=..., boto_session=..., region_name=...)` | No usar directamente. Persiste mensajes/estado a S3 y requiere permisos `s3:PutObject`, `GetObject`, `DeleteObject`, `ListBucket`. |
| A AISLAR | `RepositorySessionManager`, `SessionRepository`, `SessionManager` | Solo detras de interfaz propia. Son la abstraccion de persistencia del SDK. |
| A AISLAR | AgentCore Memory session manager | La nav oficial lista "Amazon AgentCore Memory" como community session manager, pero no confirme el nombre exacto de clase/API en esta investigacion. No usar hasta verificar clase exacta y semantica. |
| A AISLAR | Conversation managers: `ConversationManager`, `NullConversationManager`, `SlidingWindowConversationManager`, `SummarizingConversationManager` | Para adapter puro, usar `NullConversationManager()` o agente efimero con `messages` curados. El default es `SlidingWindowConversationManager()`, que modifica/trunca historia. `SummarizingConversationManager` es opt-in y debe quedar fuera. |
| A AISLAR | `state` / `AgentState` | No reutilizar entre requests. Si Substrate envia estado del step, pasarlo como copia local y devolver delta explicito; no dejarlo vivir en un agente global. |

## 3. PUNTOS DE FUGA DE SOBERANIA

1. Agente global en ejemplos oficiales.
   - Ejemplo de la guia AgentCore Python crea `agent = Agent()` a nivel modulo y lo reutiliza en `@app.entrypoint`.
   - Fuga: `agent.messages` acumula conversacion en memoria del proceso; dentro de un Runtime/session puede mezclar estado no gobernado por Substrate.
   - Neutralizacion: crear `Agent(...)` dentro del handler por cada request; pasar `messages` desde payload o `[]`; no mantener `Agent` global.

2. Modelo default.
   - Python `Agent` crea `BedrockModel()` si `model=None`; la guia dice default Bedrock + Claude Sonnet 4 por region/credenciales.
   - Fuga: el Runtime decide modelo si el caller no lo fija.
   - Neutralizacion: requerir `payload.model_id` o `payload.model` validado por Substrate; rechazar requests sin modelo.

3. Tools por defecto / discovery.
   - Python doc: si `tools` se provee, solo esas estan disponibles; si `tools=None`, todas las tools estaran disponibles. `load_tools_from_directory=True` activa carga/reload desde `./tools/`.
   - Fuga: tool surface no curada.
   - Neutralizacion: siempre pasar `tools=[]` o lista explicita resuelta por allowlist; mantener `load_tools_from_directory=False`; no montar tool directories mutables.

4. Seleccion autonoma de tools.
   - El agent loop "invoke model -> check tool use -> execute -> invoke again" deja al modelo decidir usar tools y cuando terminar.
   - Fuga: decision local no planificada por Substrate.
   - Neutralizacion: cada request representa un unico step ya planificado; exponer solo tools permitidas para ese step; prompt de sistema imperativo; timeout/presupuesto externo; hooks para auditar `BeforeToolCallEvent`/`AfterToolCallEvent`. Si el step exige llamada determinista, no usar loop de agente: ejecutar la tool fuera de Strands.

5. Conversation manager default.
   - Python default `SlidingWindowConversationManager()`; TS default `SlidingWindowConversationManager` con `windowSize` 40. Puede truncar resultados/mensajes y pedir retry ante context overflow.
   - Fuga: Strands decide que contexto conservar.
   - Neutralizacion: `conversation_manager=NullConversationManager()` en Python; `conversationManager: new NullConversationManager()` en TS. Mejor aun: agente efimero por request y contexto ya recortado por Substrate.

6. Persistencia de sesion.
   - `session_manager` es opt-in, pero si se provee persiste automaticamente en inicializacion, adicion de mensajes, post-invocacion y redaccion.
   - Fuga: historia/estado fuera del Substrate.
   - Neutralizacion: `session_manager=None`; no importar `FileSessionManager`/`S3SessionManager`; no usar AgentCore Memory directo.

7. Retry strategy.
   - Python default `ModelRetryStrategy(max_attempts=6, initial_delay=4s, max_delay=240s)` para throttling/transient errors; `retry_strategy=None` desactiva retries (`max_attempts=1`).
   - Fuga: reintentos y latencia/coste no decididos por Substrate.
   - Neutralizacion: pasar `retry_strategy=None` si Substrate gobierna retries; o pasar estrategia propia solo si forma parte del contrato.

8. Tool error recovery.
   - La doc del loop dice que fallos de tools se devuelven al modelo como tool result de error, dandole oportunidad de recuperarse o probar alternativas.
   - Fuga: el modelo puede intentar rutas alternativas dentro del mismo step.
   - Neutralizacion: lista minima de tools; validar tool args antes de ejecutar; hook de veto antes de tool call; timeout maximo; no incluir tools alternativas no autorizadas.

9. Callback/console output.
   - Python default crea `PrintingCallbackHandler()`; TS `printer` default `true`.
   - Fuga: prompts, razonamiento o tool usage pueden salir por stdout/logs.
   - Neutralizacion: Python `callback_handler=None` o handler propio redactor; TS `printer: false`; logging estructurado y redactado.

10. Observability demasiado rica.
    - La doc de observabilidad indica spans con system prompt, parametros, input/output messages, token usage, tool input/output.
    - Fuga: trazas contienen datos gobernados por Substrate.
    - Neutralizacion: exportadores OTel aprobados; redaccion; atributos minimos; no loggear payload completo salvo politica explicita.

11. AgentCore session lifecycle.
    - AgentCore usa `runtimeSessionId`, aislamiento por microVM y persistencia de sesion del runtime.
    - Fuga: confundir session lifecycle con memoria conversacional.
    - Neutralizacion: tratar `runtimeSessionId` solo como lifecycle/routing/observability; memoria y politicas siguen en Substrate.

## 4. CONTRATO RECOMENDADO: STRANDS COMO EXECUTION ADAPTER PURO

### Contrato de entrada

El payload hacia `/invocations` debe ser un "ExecutionStep" ya decidido por Substrate:

```json
{
  "step_id": "uuid",
  "model_id": "us.anthropic.claude-sonnet-4-20250514-v1:0",
  "system_prompt": "Instrucciones cerradas del step...",
  "messages": [],
  "prompt": "Tarea puntual del step",
  "tool_names": ["lookup_customer", "calculate_total"],
  "structured_output_schema_id": "optional-known-schema",
  "trace": {
    "tenant_id": "t-123",
    "substrate_run_id": "r-456"
  }
}
```

Reglas:

- El adapter rechaza payload sin `model_id`.
- El adapter resuelve `tool_names` contra una allowlist local provisionada por Substrate.
- No acepta imports, paths, MCP servers, prompts de tool ni schemas arbitrarios desde el request.
- El adapter devuelve solo resultado, stop reason y telemetria minima; no persiste mensajes.

### Python con `BedrockAgentCoreApp`

Snippet basado en APIs documentadas actuales: `BedrockAgentCoreApp`, `Agent`, `NullConversationManager`, `retry_strategy=None`, `callback_handler=None`, `session_manager=None`.

```python
from __future__ import annotations

from typing import Any

from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent
from strands.agent.conversation_manager import NullConversationManager

from substrate_tools import resolve_tools
from substrate_schemas import resolve_pydantic_model

app = BedrockAgentCoreApp()


@app.entrypoint
def invoke(payload: dict[str, Any]) -> dict[str, Any]:
    model_id = payload["model_id"]
    tools = resolve_tools(payload.get("tool_names", []))
    output_model = resolve_pydantic_model(payload.get("structured_output_schema_id"))

    agent = Agent(
        model=model_id,
        messages=payload.get("messages", []),
        tools=tools,
        system_prompt=payload.get("system_prompt"),
        conversation_manager=NullConversationManager(),
        session_manager=None,
        callback_handler=None,
        retry_strategy=None,
        load_tools_from_directory=False,
        state={},
        trace_attributes={
            "substrate.step_id": payload.get("step_id", ""),
            "substrate.run_id": payload.get("trace", {}).get("substrate_run_id", ""),
        },
    )

    result = agent(
        payload.get("prompt"),
        invocation_state={
            "step_id": payload.get("step_id"),
            "substrate_trace": payload.get("trace", {}),
        },
        structured_output_model=output_model,
    )

    response: dict[str, Any] = {
        "step_id": payload.get("step_id"),
        "message": result.message,
        "structured_output": (
            result.structured_output.model_dump()
            if getattr(result, "structured_output", None) is not None
            else None
        ),
        "telemetry": {
            "model_id": model_id,
            "tool_names": [getattr(tool, "__name__", str(tool)) for tool in tools],
        },
    }
    agent.cleanup()
    return response


if __name__ == "__main__":
    app.run()
```

Notas de implementacion:

- `resolve_tools` debe devolver funciones/decorated tools ya importadas y autorizadas, nunca paths recibidos del request.
- `resolve_pydantic_model` debe mapear `schema_id` a clases Pydantic locales; si no hay schema, devuelve `None`.
- `callback_handler=None` evita `PrintingCallbackHandler`.
- `NullConversationManager()` evita trimming/summarization local; aun asi `agent.messages` existe, pero muere al terminar el request.
- `retry_strategy=None` evita retries internos del modelo; si se quiere retry, hacerlo desde Substrate.
- Para streaming, cambiar el handler a `async def` y usar `agent.stream_async(...)`, yield de eventos filtrados/redactados al SSE de AgentCore.

### TypeScript / Express

No encontre helper TS equivalente a `BedrockAgentCoreApp`; la guia oficial usa Express y endpoints obligatorios. Adaptacion efimera por request:

```ts
import express from 'express'
import { Agent, BedrockModel, NullConversationManager } from '@strands-agents/sdk'
import { resolveTools } from './substrate-tools.js'

const app = express()
app.get('/ping', (_, res) => res.json({ status: 'Healthy' }))

app.post('/invocations', express.raw({ type: '*/*' }), async (req, res) => {
  const payload = JSON.parse(new TextDecoder().decode(req.body))
  const tools = resolveTools(payload.tool_names ?? [])

  const agent = new Agent({
    model: new BedrockModel({ modelId: payload.model_id }),
    messages: payload.messages ?? [],
    tools,
    systemPrompt: payload.system_prompt,
    conversationManager: new NullConversationManager(),
    printer: false,
    state: {},
  })

  const result = await agent.invoke(payload.prompt)
  return res.json({
    step_id: payload.step_id,
    response: result,
    telemetry: {
      model_id: payload.model_id,
      tool_names: payload.tool_names ?? [],
    },
  })
})

app.listen(8080, '0.0.0.0')
```

TS caveats:

- Session Management no esta soportado oficialmente en TS segun la guia actual; esto ayuda al caso stateless.
- Structured output TS aparece en API como `structuredOutputSchema?: z.ZodSchema`, pero la guia de usuario dice no soportado. No lo uses como contrato de produccion sin prueba directa.

Confidence: Alta para Python; Media para TS por inconsistencias documentales.

## 5. FUENTES

Consultadas el 2026-07-09.

1. Strands Agents docs - Welcome / Quickstart / features: https://strandsagents.com/latest/documentation/docs/
2. Strands Agents GitHub monorepo `strands-agents/harness-sdk`: https://github.com/strands-agents/harness-sdk
3. PyPI `strands-agents` 1.46.0: https://pypi.org/project/strands-agents/
4. GitHub archived TS repo `strands-agents/sdk-typescript`: https://github.com/strands-agents/sdk-typescript
5. TypeScript API reference: https://strandsagents.com/latest/documentation/docs/api-reference/typescript/
6. TypeScript `Agent` API: https://strandsagents.com/latest/documentation/docs/api-reference/typescript/classes/Agent.html
7. TypeScript `AgentConfig` API: https://strandsagents.com/latest/documentation/docs/api-reference/typescript/types/AgentConfig.html
8. Python `Agent` API: https://strandsagents.com/latest/documentation/docs/api-reference/python/agent/agent/
9. Agent Loop: https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/agent-loop/
10. Conversation Management: https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/conversation-management/
11. Session Management: https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/session-management/
12. Structured Output: https://strandsagents.com/latest/documentation/docs/user-guide/concepts/agents/structured-output/
13. Observability: https://strandsagents.com/latest/documentation/docs/user-guide/observability-evaluation/observability/
14. Deploying Strands Agents to Amazon Bedrock AgentCore Runtime: https://strandsagents.com/latest/documentation/docs/user-guide/deploy/deploy_to_bedrock_agentcore/
15. Python deployment to AgentCore Runtime: https://strandsagents.com/latest/documentation/docs/user-guide/deploy/deploy_to_bedrock_agentcore/python/
16. TypeScript deployment to AgentCore Runtime: https://strandsagents.com/latest/documentation/docs/user-guide/deploy/deploy_to_bedrock_agentcore/typescript/
17. Amazon Bedrock AgentCore HTTP protocol contract: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-http-protocol-contract.html
18. Amazon Bedrock AgentCore observability: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-configure.html

### Confidence por seccion

| Seccion | Confidence | Motivo |
|---|---|---|
| 1. Estado actual | Alta para Python y relacion AgentCore; Media para npm exacto TS | PyPI/GitHub/docs oficiales claros; npm registry no fue confirmado directamente. |
| 2. Inventario | Alta para Python core/session/conversation/AgentCore; Media para TS structured output | APIs Python y docs AgentCore claras; TS tiene discrepancia entre API y guia. |
| 3. Fugas de soberania | Alta | Basado en defaults documentados y codigo/API source renderizado en docs. |
| 4. Contrato recomendado | Alta para patron Python; Media para TS | Python usa APIs documentadas; TS Express es la ruta oficial pero algunas capacidades no son paritarias. |
| 5. Fuentes | Alta | URLs oficiales, consultadas en la fecha indicada. |