Metadata-Version: 2.5
Name: agentino-framework
Version: 1.1.1
Summary: Lightweight Python agent framework. Config → agents → run.
Project-URL: Homepage, https://github.com/islavutin-oss/agentino
Project-URL: Documentation, https://github.com/islavutin-oss/agentino
Project-URL: Repository, https://github.com/islavutin-oss/agentino
Author: Iliya Slavutin
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: agent,ai,anthropic,llm,openai,tools
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: croniter>=2.0
Requires-Dist: httpx>=0.27
Requires-Dist: pyyaml>=6.0
Provides-Extra: all
Requires-Dist: aiogram>=3.10; extra == 'all'
Requires-Dist: aiohttp>=3.9; extra == 'all'
Requires-Dist: beautifulsoup4>=4.12; extra == 'all'
Requires-Dist: fastapi>=0.109; extra == 'all'
Requires-Dist: feedparser>=6.0; extra == 'all'
Requires-Dist: markdown>=3.5; extra == 'all'
Requires-Dist: numpy>=1.26; extra == 'all'
Requires-Dist: openpyxl>=3.1; extra == 'all'
Requires-Dist: python-docx>=1.0; extra == 'all'
Requires-Dist: python-pptx>=0.6; extra == 'all'
Requires-Dist: reportlab>=4.0; extra == 'all'
Requires-Dist: slack-bolt>=1.18; extra == 'all'
Requires-Dist: starlette>=0.38; extra == 'all'
Requires-Dist: uvicorn>=0.30; extra == 'all'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
Provides-Extra: docgen
Requires-Dist: markdown>=3.5; extra == 'docgen'
Requires-Dist: openpyxl>=3.1; extra == 'docgen'
Requires-Dist: python-docx>=1.0; extra == 'docgen'
Requires-Dist: python-pptx>=0.6; extra == 'docgen'
Requires-Dist: reportlab>=4.0; extra == 'docgen'
Provides-Extra: memory
Requires-Dist: numpy>=1.26; extra == 'memory'
Provides-Extra: serve
Requires-Dist: fastapi>=0.109; extra == 'serve'
Requires-Dist: starlette>=0.38; extra == 'serve'
Requires-Dist: uvicorn>=0.30; extra == 'serve'
Provides-Extra: slack
Requires-Dist: aiohttp>=3.9; extra == 'slack'
Requires-Dist: slack-bolt>=1.18; extra == 'slack'
Provides-Extra: stdtools
Requires-Dist: beautifulsoup4>=4.12; extra == 'stdtools'
Requires-Dist: feedparser>=6.0; extra == 'stdtools'
Requires-Dist: markdown>=3.5; extra == 'stdtools'
Requires-Dist: numpy>=1.26; extra == 'stdtools'
Requires-Dist: openpyxl>=3.1; extra == 'stdtools'
Requires-Dist: python-docx>=1.0; extra == 'stdtools'
Requires-Dist: python-pptx>=0.6; extra == 'stdtools'
Requires-Dist: reportlab>=4.0; extra == 'stdtools'
Provides-Extra: telegram
Requires-Dist: aiogram>=3.10; extra == 'telegram'
Provides-Extra: transports
Requires-Dist: aiogram>=3.10; extra == 'transports'
Requires-Dist: aiohttp>=3.9; extra == 'transports'
Requires-Dist: fastapi>=0.109; extra == 'transports'
Requires-Dist: slack-bolt>=1.18; extra == 'transports'
Requires-Dist: starlette>=0.38; extra == 'transports'
Requires-Dist: uvicorn>=0.30; extra == 'transports'
Provides-Extra: web
Requires-Dist: beautifulsoup4>=4.12; extra == 'web'
Requires-Dist: feedparser>=6.0; extra == 'web'
Provides-Extra: websocket
Requires-Dist: aiohttp>=3.9; extra == 'websocket'
Description-Content-Type: text/markdown

# Agentino

A lightweight Python agent framework. **YAML config → tool-calling loop → output.** No graphs, no DSLs, no DAG editors — just functions you decorate and a runtime that knows how to call them.

```bash
pip install agentino-framework
```

The distribution is `agentino-framework` because the `agentino` name on PyPI
belongs to an unrelated project. It imports as `agentino` regardless:

```python
from agentino import Agent, tool
```

---

## Hello agent in 8 lines

```python
from agentino import Agent, tool

@tool
async def get_weather(city: str) -> str:
    """Look up current weather for a city."""
    return f"It's 22°C in {city}."

agent = Agent(instructions="You're a helpful assistant.", tools=[get_weather])
print(await agent.run("What's the weather in Lisbon?"))
# → "It's 22°C in Lisbon. Want a forecast?"
```

That's the whole API: define tools as plain async functions, hand them to an `Agent`, call `.run()`. The framework handles the LLM round-trip, tool dispatch, retries, and the final-text extraction.

---

## What's in the box

```
src/agentino/
├── core/              Agent, Runner, LLM, Tool, Message, Context, State, Session
├── config/            YAML loaders for agents, pipelines, tools
├── pipeline/          Pipeline, StagedPipeline (multi-stage flows with verdicts)
├── safety/            GateManager, HookManager, security, sanitizers
├── reliability/       resilience (retry/backoff), compaction, error taxonomy
├── extras/            knowledge (TF-IDF + embeddings), memory, audio, skills
├── providers/         Codex, Anthropic — pluggable LLM backends
├── scheduler/         CronScheduler + JobStore protocol (file/sqlite/in-memory)
├── tools/std/         Built-in tools: files, shell, grep, web search and fetch,
│                      weather, document generation (pdf/docx/xlsx/pptx/csv),
│                      agent memory. `BUILTIN_TOOLS` is the ten a coding-style
│                      agent gets by default; the rest are opt-in.
├── transport/         Outbound channel adapters (Telegram, Slack, WhatsApp, WebSocket)
├── workers/           fork_agent, make_spawn_tool — multi-agent spawning
└── cli/               REPL renderer
```

Top-level `from agentino import …` exports the curated public API. Deeper paths
like `from agentino.safety.gates import GateManager` are how internal packages
talk to each other.

---

## Configure agents from YAML

```yaml
# agents.yml
agents:
  reviewer:
    model: gpt-5.4-codex
    instructions_file: prompts/reviewer.md
    tools: [read_file, grep, shell]            # auto-discovered from tools/
    knowledge:
      dir: ./knowledge                          # TF-IDF + dense embeddings
```

```bash
agentino run agents.yml                  # one-shot REPL
agentino run agents.yml --agent reviewer # specific agent
agentino run agents.yml --serve 8080     # HTTP server
agentino run agents.yml -m "Review PR #42"
agentino run agents.yml -m "Review PR #42" --mode json   # machine-readable (one envelope)
agentino run agents.yml -m "Review PR #42" --mode jsonl  # streaming events + final envelope
```

### Headless / foreign-harness mode

`--mode json|jsonl` makes `agentino run --message …` emit a structured contract
on stdout instead of ANSI-prettified markdown — the same shape `pi --print`,
`codex exec --json`, and `claude -p --output-format stream-json` provide. Lets
non-Python harnesses (IDE extensions, polyglot stacks)
shell out to agentino and parse the result programmatically.

```bash
$ agentino run agents.yml -m "List open invoices" --mode json
{"type":"final","text":"…","tools_used":["list_invoices"],
 "tool_outputs":["…"],"usage":{"prompt_tokens":1200,"completion_tokens":85},
 "model":"gpt-5.4-codex","elapsed_ms":2254}
```

---

## What you can do beyond a single tool call

### Pipelines

`StagedPipeline` runs multi-stage flows where each stage produces a verdict
the next stage can read. A benchmark harness can use it for *security check → execute →
report*; the security stage rejects unsafe inputs before the execute stage
ever runs.

```python
from agentino import StagedPipeline, StageDef
pipeline = StagedPipeline(stages=[
    StageDef(name="security", agent=security_agent, verdict_required=True),
    StageDef(name="execute", agent=worker_agent, on_reject="report_threat"),
])
```

### Gates — declarative tool preconditions

`GateManager` rejects tool calls whose preconditions haven't been met.
Useful when you want guarantees beyond the LLM following its instructions.

```python
from agentino.safety.gates import GateRule, GateManager
rules = [GateRule(
    gate="invoice_listed",
    tools=["set_invoice_status"],
    message="Run list_invoices first so you've actually seen the IDs.",
)]
```

When the agent loop encounters `set_invoice_status` and `invoice_listed`
isn't marked, the tool returns the rejection message instead of running.

### Hooks — observe + block tool calls without touching the tool

Two flavours of [`HookManager`](docs/cookbook/hooks.md): Python callbacks
(in-process, fast — for audit logs, history mirroring, metric emission)
and shell commands (subprocess — for ops integrations, external validators).

```python
from agentino.safety.hooks import HookManager
hooks = HookManager()
hooks.register("PostToolUse", matcher={"tool_name": "chat"},
               callback=lambda ctx: audit_db.insert(ctx))
```

### Scheduler — cron-style routine execution

```python
from agentino.scheduler import CronScheduler, FileJobStore
scheduler = CronScheduler(store=FileJobStore("data/jobs.json"))
await scheduler.start()
```

`JobStore` is a protocol — ship `InMemoryJobStore`, `SqliteJobStore`,
`FileJobStore`, or write your own (e.g. file-as-truth tenant routines, see
`runspace`'s tenant routine store).

### Knowledge base

Hybrid TF-IDF + dense-embedding retrieval with one tool: `search_knowledge`.
Drop markdown files in a directory, point an agent at it, the LLM gets a
search tool and reaches into the corpus when it needs to.

### Multi-channel gateway

```bash
agentino run agents.yml --gateway
```

Maps Slack, Telegram, WhatsApp, and WebSocket transports onto the same agent
config. One agent serves users from any channel without changing its code.

---

## Pointing it at a model

```bash
export AGENTINO_BASE_URL=https://api.openai.com/v1   # or vLLM, Ollama, OpenRouter…
export AGENTINO_API_KEY=sk-…
```

The wire protocol is inferred from the URL: Anthropic for an Anthropic
endpoint, Codex for `chatgpt.com/backend-api` or a `/codex` path, and plain
OpenAI-compatible `/chat/completions` for everything else — which is what vLLM,
Ollama, LM Studio, OpenRouter and api.openai.com all speak.

Set `AGENTINO_PROVIDER` to `openai`, `openai-codex` or `anthropic` to override
the guess. A `sk-ant-` key implies Anthropic, and a ChatGPT subscription token
implies Codex, whatever the URL says.

## Why a new framework

Agentino was built around a few opinions other frameworks make hard:

- **Functions, not classes**: tools are `@tool`-decorated `async def`. No
  `BaseTool.execute()` ceremony.
- **YAML for shape, code for behaviour**: agent identity (model, prompt,
  available tools) is config. Logic stays in Python.
- **No graph editor**: complex flows are just `Pipeline` / `StagedPipeline`
  composed in code. If you can read a function call, you can read your flow.
- **Async-first, batteries included**: retry-with-backoff, context
  compaction, tool-output truncation, error taxonomy — all built in.
- **Provider-agnostic**: Codex, OpenAI, Anthropic, anything OpenAI-compatible.

If you've fought a framework's abstractions to get a simple agent working,
agentino is the one with the smallest surface that still grows with you.

---

## Cookbook

Concrete recipes for the patterns above:

- [`docs/cookbook/hooks.md`](docs/cookbook/hooks.md) — Python callbacks +
  shell hooks; `PostToolUse` audit trails; `PreToolUse` blockers
- ADRs in [`docs/architecture/`](docs/architecture/) — design rationale for
  the agent loop, tool chain, async-first core, JSONL sessions
- [`docs/integration-guide.md`](docs/integration-guide.md) — wiring agentino
  into an existing FastAPI app

---

## Used by

Agentino powers:

- **[Runspace](https://github.com/islavutin-oss/runspace)** — a multi-agent
  workspace: channels, @mention routing, scheduled routines and a protocol
  layer (Store, Vision, Transport, FileStorage, Embeddings). Agentino is one
  of the runtimes it drives.
- **Multi-agent back offices** — agents grouped by role (booking, finance,
  inventory, analytics), reached by @mention in a shared channel
- **Single-pane chat shells** — the same gateway configured down to one agent
- **Agentic benchmarks** — staged pipelines with security/execute/report
  stages and an LLM-gate pattern (the gates cookbook is built from it)

---

## Stability

- Public API at `from agentino import …` is stable as of v1.0
- Internal layout (subpackages) was reshaped in v1.0 — deep imports like
  `agentino.context` moved to `agentino.core.context`
- Async-first throughout. There is no synchronous wrapper: call it with
  `asyncio.run(agent.run(...))` from sync code

---

## License

Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
