# Here I Strand

Library that provides a [Strands](https://github.com/strands-agents) agent for AWS Bedrock Agent Core with DynamoDB status tracking, S3 session persistence, and a concurrent tool executor with per-tool timeouts (HIS: *here-i-strand*).

**Repository:** [github.com/tisaarus/here-i-strand](https://github.com/tisaarus/here-i-strand)

## Installation

```bash
pip install here-i-strand
# or with uv
uv add here-i-strand
```

## Quick start

You define how to load configuration (environment variables, your own settings module, etc.) and pass the values to `HISAgent`:

```python
import os
from his import HISAgent

agent = HISAgent(
    bucket_name=os.environ["BUCKET_NAME"],
    status_dynamo_table_name=os.environ["STATUS_DYNAMO_TABLE_NAME"],
    session_id="my-session-id",
    name=os.environ.get("AGENT_NAME", "my-agent"),
    agent_id=os.environ.get("AGENT_ID"),  # Optional: unique identifier for the agent instance
    tools=[...],
)
```

## Configuration

The library does not provide a settings layer. Pass `bucket_name`, `status_dynamo_table_name`, `session_id`, and optionally `name`, `agent_id` (and any other `HISAgent` arguments) from your own config:

- Environment variables
- A `.env` file loaded by your app (e.g. `python-dotenv`, `pydantic-settings`)
- Any other configuration source you use

## Project structure (development)

```
here-i-strand/
├── README.md
├── pyproject.toml
├── .env.example             # Example env vars (for your app)
│
├── his/                      # Main package
│   ├── __init__.py           # HISAgent, TimeoutConcurrentToolExecutor, event_loop_tracker, ping_status_task, write_dynamo
│   ├── his.py                # HISAgent, TimeoutConcurrentToolExecutor, ping, event_loop_tracker, write_dynamo
│   └── logging/
│       └── logging.py
│
└── tests/
    ├── conftest.py
    └── test_his.py
```

## Main components

- **`HISAgent`**: Strands agent with a DynamoDB ping thread and S3 sessions. You pass `status_dynamo_table_name`, `bucket_name`, `session_id`, and optionally `name` and `agent_id` so the ping and tracker use your table and bucket. Includes a default system prompt that enforces DynamoDB status reporting at key milestones. The `write_dynamo` tool is automatically added to the agent's tools.
- **`TimeoutConcurrentToolExecutor`**: Tool executor with a per-invocation timeout (default: 300s); if a tool exceeds the limit, an error is returned and execution continues with the rest.
- **`event_loop_tracker`**: Callback that writes event-loop milestones (init, start, message, result, force_stop) to DynamoDB along with `agent_id` and stops the ping when done.
- **`write_dynamo`**: Strands tool for writing custom event records to DynamoDB for agent tracking and observability. Automatically included in `HISAgent`.
- **`DEFAULT_DYNAMODB_REPORTING_PROMPT_TEMPLATE`**: Template for the default system prompt that instructs the agent to report status updates to DynamoDB at key milestones (start, tooling, completion, error). The template is populated with the actual `table_name`, `session_id`, and `agent_id` values when the agent is created.

## Default behavior

When you create an `HISAgent`, the following happens automatically:

1. **System prompt**: The `DEFAULT_DYNAMODB_REPORTING_PROMPT` is prepended to any custom system prompt you provide, instructing the agent to report status at key milestones.
2. **Tools**: The `write_dynamo` tool is automatically added to your tools list, enabling the agent to write status updates to DynamoDB.
3. **Ping thread**: A daemon thread starts that pings DynamoDB every 20 seconds with a "running" status until the agent completes.
4. **Event tracking**: The `event_loop_tracker` callback records event-loop milestones to DynamoDB.

## Tests

```bash
uv sync --all-groups
uv run pytest tests/ -v
```

## Authors

- [Lorenzo Pizarro Martin](mailto:lorenzo.pizarro.martin@gmail.com)
- [Antonio Calavia Robert](mailto:calavia88@gmail.com)
- [Manuel Sierra Lavado](mailto:yosierr@gmail.com)

## License

MIT. See [LICENSE](LICENSE).
