Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
integrations-ag2: ${{ steps.filter.outputs.integrations-ag2 }}
integrations-hermes: ${{ steps.filter.outputs.integrations-hermes }}
integrations-llamaindex: ${{ steps.filter.outputs.integrations-llamaindex }}
integrations-agentcore: ${{ steps.filter.outputs.integrations-agentcore }}
dev: ${{ steps.filter.outputs.dev }}
ci: ${{ steps.filter.outputs.ci }}
# Secrets are available for internal PRs, pull_request_review, and workflow_dispatch.
Expand Down Expand Up @@ -117,6 +118,8 @@ jobs:
- 'hindsight-integrations/hermes/**'
integrations-llamaindex:
- 'hindsight-integrations/llamaindex/**'
integrations-agentcore:
- 'hindsight-integrations/agentcore/**'
dev:
- 'hindsight-dev/**'
ci:
Expand Down Expand Up @@ -1829,6 +1832,43 @@ jobs:
working-directory: ./hindsight-integrations/llamaindex
run: uv run pytest tests -v

test-agentcore-integration:
needs: [detect-changes]
if: >-
github.event_name != 'pull_request_review' &&
(github.event_name == 'workflow_dispatch' ||
needs.detect-changes.outputs.integrations-agentcore == 'true' ||
needs.detect-changes.outputs.ci == 'true')
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha || '' }}

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
prune-cache: false

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version-file: ".python-version"

- name: Build agentcore integration
working-directory: ./hindsight-integrations/agentcore
run: uv build

- name: Install dependencies
working-directory: ./hindsight-integrations/agentcore
run: uv sync --frozen

- name: Run tests
working-directory: ./hindsight-integrations/agentcore
run: uv run pytest tests -v

test-pip-slim:
needs: [detect-changes]
if: >-
Expand Down Expand Up @@ -2448,6 +2488,7 @@ jobs:
- test-pydantic-ai-integration
- test-hermes-integration
- test-llamaindex-integration
- test-agentcore-integration
- test-pip-slim
- test-embed
- test-hindsight-all
Expand Down
209 changes: 209 additions & 0 deletions hindsight-docs/docs-integrations/agentcore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
---
sidebar_position: 14
title: "Amazon Bedrock AgentCore Persistent Memory with Hindsight | Integration"
description: "Add long-term memory to Amazon Bedrock AgentCore Runtime agents with Hindsight. Memory persists across sessions using stable user identity — not the ephemeral runtimeSessionId."
---

# Amazon Bedrock AgentCore Runtime

Persistent memory for [Amazon Bedrock AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-sessions.html) agents using Hindsight.

AgentCore Runtime sessions are explicitly ephemeral — they terminate on inactivity and reprovision fresh environments. `hindsight-agentcore` adds durable cross-session memory so agents remember users, decisions, and learned patterns across any number of Runtime sessions.

## How It Works

```
AgentCore Runtime invocation
before_turn() ← Recall relevant memories from Hindsight
Agent executes ← Prompt enriched with prior context
after_turn() ← Retain output to Hindsight (async)
```

Memory is keyed to stable user identity — **not** the `runtimeSessionId`. Banks survive session churn.

Default bank format:
```
tenant:{tenant_id}:user:{user_id}:agent:{agent_name}
```

## Installation

```bash
pip install hindsight-agentcore
```

## Quick Start

```python
import os
from hindsight_agentcore import HindsightRuntimeAdapter, TurnContext, configure

configure(
hindsight_api_url="https://api.hindsight.vectorize.io",
api_key=os.environ["HINDSIGHT_API_KEY"],
)

adapter = HindsightRuntimeAdapter(agent_name="support-agent")


# Your AgentCore Runtime handler
async def handler(event: dict) -> dict:
context = TurnContext(
runtime_session_id=event["sessionId"],
user_id=event["userId"], # from validated auth — never client-supplied
agent_name="support-agent",
tenant_id=event.get("tenantId"),
request_id=event.get("requestId"),
)

result = await adapter.run_turn(
context=context,
payload={"prompt": event["prompt"]},
agent_callable=run_my_agent,
)
return result


async def run_my_agent(payload: dict, memory_context: str) -> dict:
prompt = payload["prompt"]
if memory_context:
prompt = f"Past context:\n{memory_context}\n\nCurrent request: {prompt}"

output = await call_bedrock(prompt)
return {"output": output}
```

## Lower-Level Hooks

For direct control over the recall → execute → retain cycle:

```python
memory_context = await adapter.before_turn(context, query=user_message)

result = await run_my_agent(payload, memory_context=memory_context)

await adapter.after_turn(context, result=result["output"], query=user_message)
```

## Retrieval Modes

### Recall (default)

Fast multi-strategy retrieval (semantic + keyword + graph + temporal):

```python
from hindsight_agentcore import RecallPolicy

adapter = HindsightRuntimeAdapter(
recall_policy=RecallPolicy(mode="recall", budget="mid", max_tokens=1500)
)
```

### Reflect

LLM-synthesized context for complex reasoning tasks:

```python
adapter = HindsightRuntimeAdapter(
recall_policy=RecallPolicy(mode="reflect")
)
```

Use `reflect` selectively — it's slower. Reserve it for explicit planning steps or routing decisions.

## Async Retention

By default, `after_turn()` fires retention as a background task — the user turn is never delayed:

```python
configure(retain_async=True) # default
configure(retain_async=False) # await retention before returning
```

## Long-Running Workflows

For jobs spanning multiple Runtime sessions, retain at start and completion:

```python
# Task start
await adapter.after_turn(
context,
result="Started QBR analysis for Acme Corp",
query=task_description,
)

# ... long-running work across potentially multiple sessions ...

# Task completion
await adapter.after_turn(
context,
result=f"Completed QBR analysis. Finding: {summary}",
query=task_description,
)
```

## Identity and Auth

**Never use `runtimeSessionId` as the bank ID.** Sessions expire. Memory must survive session churn.

Preferred identity sources (in order):
1. Validated user ID from AgentCore JWT/OAuth context
2. `X-Amzn-Bedrock-AgentCore-Runtime-User-Id` header
3. Application-supplied user ID in trusted server-side deployments

```python
context = TurnContext(
runtime_session_id=event["sessionId"],
user_id=jwt_claims["sub"], # stable identity from validated token
agent_name="support-agent",
tenant_id=jwt_claims.get("tenant"),
)
```

## Custom Bank Resolution

Override the default `tenant:user:agent` format:

```python
from hindsight_agentcore import TurnContext

def my_resolver(context: TurnContext) -> str:
return f"acme:{context.user_id}:{context.agent_name}"

adapter = HindsightRuntimeAdapter(bank_resolver=my_resolver)
```

**Security rule:** The resolver must fail closed (`BankResolutionError`) rather than leak memory across users when identity is missing.

## Configuration Reference

| Option | Env Variable | Default | Description |
|---|---|---|---|
| `hindsight_api_url` | `HINDSIGHT_API_URL` | Hindsight Cloud | Hindsight server URL |
| `api_key` | `HINDSIGHT_API_KEY` | — | API key for Hindsight Cloud |
| `recall_budget` | — | `"mid"` | Search depth: `low`, `mid`, `high` |
| `recall_max_tokens` | — | `1500` | Max tokens recalled |
| `retain_async` | — | `True` | Non-blocking retention |
| `timeout` | — | `15.0` | HTTP timeout in seconds |
| `tags` | — | `[]` | Tags applied to all retained memories |
| `verbose` | — | `False` | Log memory operations |

## Failure Modes

| Failure | Behavior |
|---|---|
| Hindsight unavailable | `before_turn()` returns `""`, agent continues |
| Recall timeout | Returns `""`, agent continues |
| Retain failure | Logged as warning, user turn unaffected |
| Bad bank resolution | Fails closed — no cross-user memory leakage |

## Requirements

- Python 3.10+
- `hindsight-client>=0.4.0`
6 changes: 6 additions & 0 deletions hindsight-docs/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ const sidebars: SidebarsConfig = {
label: 'Strands Agents',
customProps: { icon: '/img/icons/strands.png' },
},
{
type: 'link',
href: '/sdks/integrations/agentcore',
label: 'AgentCore Runtime',
customProps: { icon: '/img/icons/agentcore.png' },
},
{
type: 'link',
href: '/sdks/integrations/ag2',
Expand Down
Binary file added hindsight-docs/static/img/icons/agentcore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading