Metadata-Version: 2.3
Name: entity-core
Version: 0.0.2
Summary: A flexible, plugin-based framework for building AI agents
License: MIT
Keywords: ai,agents,llm,framework,plugin,workflow,memory,rag,autonomous,assistant
Author: C. Thomas Brittain
Author-email: cthomasbrittain@hotmail.com
Requires-Python: >=3.11
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Classifier: Framework :: AsyncIO
Requires-Dist: aiobotocore (>=2.13.0,<3.0.0)
Requires-Dist: duckdb (>=1.3.1,<2.0.0)
Requires-Dist: grpcio (>=1.62.2,<2.0.0)
Requires-Dist: grpcio-tools (>=1.62.2,<2.0.0)
Requires-Dist: httpx (==0.27.*)
Requires-Dist: huggingface_hub (>=0.23,<0.24)
Requires-Dist: pydantic (>=2.0.0,<3.0.0)
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
Requires-Dist: rich (>=13.7,<14.0)
Requires-Dist: websockets (>=15.0,<16.0)
Project-URL: Bug Tracker, https://github.com/Ladvien/entity/issues
Project-URL: Discussions, https://github.com/Ladvien/entity/discussions
Project-URL: documentation, https://entity.readthedocs.io/en/latest/
Project-URL: homepage, https://github.com/Ladvien/entity
Project-URL: repository, https://github.com/Ladvien/entity
Description-Content-Type: text/markdown

# Entity Framework
Entity is a Python framework for building AI agents. It runs locally by default and sets up resources automatically.

## Examples
Run `python examples/default_agent.py` for a minimal CLI demo or
`python examples/kitchen_sink.py` for a full-featured vLLM example.
Resources are prepared automatically using ``load_defaults()`` so Docker is no
longer required for these examples.
The old `[examples]` extra has been removed.

### Workflow Templates

Parameterized workflow templates live in `entity.workflow.templates`.
Load them with custom values and visualize the result:

```python
from entity.workflow.templates import load_template
from entity.tools.workflow_viz import ascii_diagram

wf = load_template(
    "basic",
    think_plugin="entity.plugins.defaults.ThinkPlugin",
    output_plugin="entity.plugins.defaults.OutputPlugin",
)
print(ascii_diagram(wf))
```

## Persistent Memory

Entity uses a DuckDB database to store all remembered values. Keys are
namespaced by user ID to keep data isolated between users. The `Memory` API is
asynchronous and protected by an internal lock so concurrent workflows remain
thread safe.

## Stateless Scaling

Because all user data lives in the `Memory` resource, multiple workers can
share the same database file without keeping any local state. Start several
processes pointing at the same DuckDB path to horizontally scale:

```bash
ENTITY_DUCKDB_PATH=/data/agent.duckdb python -m entity.examples &
ENTITY_DUCKDB_PATH=/data/agent.duckdb python -m entity.examples &
```

Connection pooling in `DuckDBInfrastructure` allows many concurrent users to
read and write without exhausting file handles.

## Plugin Lifecycle

Plugins are validated before any workflow executes:

1. **Configuration validation** – each plugin defines a `ConfigModel` and the
   `validate_config` classmethod parses user options with Pydantic.
2. **Workflow validation** – `validate_workflow` is called when workflows are
   built to ensure a plugin supports its assigned stage.
3. **Execution** – once instantiated with resources, validated plugins run
   without further checks.

Entity stores all remembered values inside a DuckDB database. Keys are
automatically prefixed with the user ID so data never leaks across users. The
`Memory` API exposes asynchronous helpers that run queries in a background
thread while holding an internal `asyncio.Lock`.

```python
infra = DuckDBInfrastructure("agent.db")
memory = Memory(DatabaseResource(infra), VectorStoreResource(infra))
await memory.store("bob:greeting", "hello")
```

## Configuration via Environment Variables

`load_defaults()` reads a few environment variables when building default resources:

| Variable | Default |
| --- | --- |
| `ENTITY_DUCKDB_PATH` | `./agent_memory.duckdb` |
| `ENTITY_OLLAMA_URL` | `http://localhost:11434` |
| `ENTITY_OLLAMA_MODEL` | `llama3.2:3b` |
| `ENTITY_STORAGE_PATH` | `./agent_files` |
| `ENTITY_LOG_LEVEL` | `info` |
| `ENTITY_JSON_LOGS` | `0` |
| `ENTITY_LOG_FILE` | `./agent.log` |
| `ENTITY_AUTO_INSTALL_VLLM` | `true` |
| `ENTITY_VLLM_MODEL` | *(auto)* |

Set `ENTITY_JSON_LOGS=1` to write structured logs to ``ENTITY_LOG_FILE`` instead
of printing to the console.

Services are checked for availability when defaults are built. If a component is
unreachable, an in-memory or stub implementation is used so the framework still
starts:

```bash
ENTITY_DUCKDB_PATH=/data/db.duckdb \
ENTITY_OLLAMA_URL=http://ollama:11434 \
ENTITY_STORAGE_PATH=/data/files \
python -m entity.examples
```

### Environment Variable Substitution

Configuration files support `${VAR}` references. Values are resolved using the
current environment and variables defined in a local `.env` file if present.
Nested references are expanded recursively and circular references raise a
`ValueError`.

```yaml
resources:
  database:
    host: ${DB_HOST}
    password: ${DB_PASS}
```

You can resolve placeholders in Python using `substitute_variables`:

```python
from entity.config import substitute_variables

config = substitute_variables({"endpoint": "${DB_HOST}/api"})
```

## Observability

Logs are captured using `LoggingResource` which stores structured entries as
JSON dictionaries. Each entry contains a UTC timestamp, log level and any
additional fields supplied by the caller:

```python
{
    "level": "info",
    "message": "plugin_start",
    "timestamp": "2024-05-01T12:00:00Z",
    "fields": {"stage": "think", "plugin_name": "MyPlugin"}
}
```


## Tool Security

Registered tools run inside a small sandbox that limits CPU time and memory.
Inputs and outputs can be validated with Pydantic models when registering a
function. Use `SandboxedToolRunner` to adjust limits.

To list available tools:

```python
from entity.tools import generate_docs
print(generate_docs())
```

## Running Tests

Install dependencies with Poetry and run the full suite:

```bash
poetry install --with dev
poetry run poe test
```

Integration tests rely on the services defined in `docker-compose.yml`.
Run them with Docker installed:

```bash
poetry run poe test-with-docker
```
This task brings the containers up, runs all tests marked `integration` in
parallel, and then tears the services down so no state is shared between runs.

## Advanced Setup

Optional services are provided in `docker-compose.yml`. Use them when you need Postgres or Ollama:

```bash
docker compose build ollama
docker compose up -d
# run agents or tests here
docker compose down -v
```
See `install_docker.sh` for an automated install script on Ubuntu. Detailed deployment steps live in `docs/production_deployment.md`. For help migrating away from Docker, check `docs/migration_from_docker.md`.

### Ollama Setup

`ollama pull` requires an authentication key at `~/.ollama/id_ed25519`. Run `ollama login` once to generate this file before using `entity-cli`.
Automatic installation can be skipped by setting `ENTITY_AUTO_INSTALL_OLLAMA=false` when you prefer manual setup.

### vLLM Setup

The framework can start a vLLM server automatically. See [docs/vllm.md](docs/vllm.md) for configuration options and troubleshooting tips.

### Logging Workflows

Example workflow templates showing console and JSON logging live in [docs/logging_templates.md](docs/logging_templates.md).

