glia-agents 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. glia_agents-0.1.0/.gitattributes +4 -0
  2. glia_agents-0.1.0/.github/workflows/ci.yml +40 -0
  3. glia_agents-0.1.0/.github/workflows/publish.yml +38 -0
  4. glia_agents-0.1.0/.gitignore +31 -0
  5. glia_agents-0.1.0/CHANGELOG.md +26 -0
  6. glia_agents-0.1.0/CONTRIBUTING.md +46 -0
  7. glia_agents-0.1.0/LICENSE +21 -0
  8. glia_agents-0.1.0/PKG-INFO +179 -0
  9. glia_agents-0.1.0/README.md +148 -0
  10. glia_agents-0.1.0/docs/ARCHITECTURE.md +78 -0
  11. glia_agents-0.1.0/docs/ROADMAP.md +42 -0
  12. glia_agents-0.1.0/docs/STRATEGY.md +136 -0
  13. glia_agents-0.1.0/examples/01_hello_agent.py +33 -0
  14. glia_agents-0.1.0/examples/02_tools.py +38 -0
  15. glia_agents-0.1.0/examples/03_structured_output.py +38 -0
  16. glia_agents-0.1.0/examples/04_subagents.py +43 -0
  17. glia_agents-0.1.0/examples/05_checkpoint_resume.py +37 -0
  18. glia_agents-0.1.0/examples/06_evals.py +39 -0
  19. glia_agents-0.1.0/examples/_common.py +26 -0
  20. glia_agents-0.1.0/glia/__init__.py +102 -0
  21. glia_agents-0.1.0/glia/agent.py +251 -0
  22. glia_agents-0.1.0/glia/checkpoint.py +59 -0
  23. glia_agents-0.1.0/glia/errors.py +49 -0
  24. glia_agents-0.1.0/glia/evals.py +141 -0
  25. glia_agents-0.1.0/glia/guardrails.py +77 -0
  26. glia_agents-0.1.0/glia/llm.py +71 -0
  27. glia_agents-0.1.0/glia/memory.py +140 -0
  28. glia_agents-0.1.0/glia/providers/__init__.py +25 -0
  29. glia_agents-0.1.0/glia/providers/anthropic.py +162 -0
  30. glia_agents-0.1.0/glia/providers/echo.py +98 -0
  31. glia_agents-0.1.0/glia/py.typed +0 -0
  32. glia_agents-0.1.0/glia/structured.py +101 -0
  33. glia_agents-0.1.0/glia/tools.py +232 -0
  34. glia_agents-0.1.0/glia/trajectory.py +245 -0
  35. glia_agents-0.1.0/glia/types.py +171 -0
  36. glia_agents-0.1.0/pyproject.toml +59 -0
  37. glia_agents-0.1.0/tests/conftest.py +18 -0
  38. glia_agents-0.1.0/tests/test_agent.py +82 -0
  39. glia_agents-0.1.0/tests/test_guardrails_memory.py +66 -0
  40. glia_agents-0.1.0/tests/test_structured_evals.py +69 -0
  41. glia_agents-0.1.0/tests/test_tools.py +81 -0
  42. glia_agents-0.1.0/tests/test_trajectory_checkpoint.py +68 -0
@@ -0,0 +1,4 @@
1
+ # Normalise line endings across platforms.
2
+ * text=auto eol=lf
3
+ *.png binary
4
+ *.jpg binary
@@ -0,0 +1,40 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python ${{ matrix.python-version }}
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install (dev extras)
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -e ".[dev]"
28
+
29
+ - name: Lint (ruff)
30
+ run: python -m ruff check .
31
+
32
+ - name: Tests (pytest, fully offline)
33
+ run: python -m pytest -q
34
+
35
+ - name: Examples run offline
36
+ run: |
37
+ for f in examples/0*.py; do
38
+ echo "--- $f ---"
39
+ python "$f"
40
+ done
@@ -0,0 +1,38 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes to PyPI via Trusted Publishing (OIDC) — no API token needed.
4
+ # Configure the trusted publisher once on PyPI:
5
+ # https://pypi.org/manage/account/publishing/
6
+ # Project: glia-agents | Owner: DenisDrobyshev | Repo: glia | Workflow: publish.yml
7
+ # Then publishing runs automatically whenever a GitHub Release is published
8
+ # (or manually via the "Run workflow" button / workflow_dispatch).
9
+
10
+ on:
11
+ release:
12
+ types: [published]
13
+ workflow_dispatch:
14
+
15
+ jobs:
16
+ publish:
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ id-token: write # required for Trusted Publishing (OIDC)
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: "3.12"
26
+
27
+ - name: Build sdist and wheel
28
+ run: |
29
+ python -m pip install --upgrade build
30
+ python -m build
31
+
32
+ - name: Check metadata
33
+ run: |
34
+ python -m pip install --upgrade twine
35
+ python -m twine check dist/*
36
+
37
+ - name: Publish to PyPI
38
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ *.egg
9
+
10
+ # Virtual envs
11
+ .venv/
12
+ venv/
13
+ env/
14
+
15
+ # Tooling caches
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
19
+ .coverage
20
+ htmlcov/
21
+
22
+ # Editors / OS
23
+ .vscode/
24
+ .idea/
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # Local secrets / scratch
29
+ .env
30
+ *.local
31
+ glia_run.json
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to glia are documented here. Format loosely follows
4
+ [Keep a Changelog](https://keepachangelog.com/); this project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.1.0] — 2026-07-22
8
+
9
+ Initial release. Proves the glass-box thesis end-to-end.
10
+
11
+ ### Added
12
+ - Transparent agent loop: `Agent.run()` and `Agent.run_events()` with a full
13
+ event stream (`RunStarted`, `ModelCall`, `ModelResponse`, `ToolCalled`,
14
+ `ToolReturned`, `Compacted`, `RunFinished`).
15
+ - `@tool` decorator deriving JSON schemas from type hints (scalars, `Literal`,
16
+ `Optional`/PEP 604 unions, `list`/`dict`, `Annotated` descriptions).
17
+ - `LLM` provider protocol with two adapters: `ClaudeLLM` (Anthropic SDK,
18
+ optional dependency) and `EchoLLM` (deterministic, offline, for tests/CI).
19
+ - Serialisable `Trajectory` with checkpoint/resume (`glia.checkpoint`).
20
+ - Context engineering: `SummarizingCompactor` and `TrimmingCompactor`.
21
+ - Input/output guardrails (`glia.guardrails`).
22
+ - Provider-agnostic structured outputs (`generate_structured`).
23
+ - Subagents via `Agent.as_tool(...)`.
24
+ - Evals-as-tests harness (`glia.evals`).
25
+ - Zero-dependency core, `py.typed`, six runnable offline examples, 26 tests,
26
+ green CI.
@@ -0,0 +1,46 @@
1
+ # Contributing to glia
2
+
3
+ Thanks for your interest. glia has one guiding principle, and contributions are
4
+ judged against it:
5
+
6
+ > **No hidden control flow.** A new feature must be inspectable — if you can't
7
+ > see it happen in the event stream or read it in one file, it doesn't fit.
8
+
9
+ ## Setup
10
+
11
+ ```bash
12
+ git clone https://github.com/DenisDrobyshev/glia
13
+ cd glia
14
+ pip install -e ".[anthropic,dev]"
15
+ ```
16
+
17
+ ## Checks (all must pass)
18
+
19
+ ```bash
20
+ python -m pytest # tests — run fully offline, no API key
21
+ python -m ruff check . # lint
22
+ python -m mypy glia # types (best-effort)
23
+ ```
24
+
25
+ The whole test suite runs against the offline `EchoLLM`, so it's fast and
26
+ deterministic. New behaviour should come with a test that uses `EchoLLM` — if a
27
+ feature can't be tested offline, that's usually a design smell worth discussing
28
+ first.
29
+
30
+ ## Guidelines
31
+
32
+ - **Keep the core dependency-free.** New runtime deps go behind an optional
33
+ extra (like `[anthropic]`), imported lazily.
34
+ - **Prefer a primitive over a feature.** A small composable piece (a new
35
+ `Compactor`, a new guardrail, a new provider) beats a bespoke flag on `Agent`.
36
+ - **Match the surrounding style.** Readable code with comments that explain
37
+ _why_, not _what_. The codebase is meant to be read.
38
+ - **New provider?** Implement the `LLM` protocol in ~40 lines; see
39
+ `glia/providers/echo.py` for the minimal shape.
40
+
41
+ ## Opening a PR
42
+
43
+ 1. Branch from `master`.
44
+ 2. Add/adjust tests.
45
+ 3. Make sure `pytest` and `ruff` are green.
46
+ 4. Describe the change and how it stays inside the glass box.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Denis Drobyshev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: glia-agents
3
+ Version: 0.1.0
4
+ Summary: A glass-box, minimal library for building LLM agents — modern techniques as opt-in primitives, no hidden control flow.
5
+ Project-URL: Homepage, https://github.com/DenisDrobyshev/glia
6
+ Project-URL: Repository, https://github.com/DenisDrobyshev/glia
7
+ Project-URL: Issues, https://github.com/DenisDrobyshev/glia/issues
8
+ Author: Denis Drobyshev
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent-framework,agents,ai,anthropic,claude,evals,llm,tools
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Provides-Extra: anthropic
23
+ Requires-Dist: anthropic>=0.40; extra == 'anthropic'
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.8; extra == 'dev'
26
+ Requires-Dist: pytest>=7; extra == 'dev'
27
+ Requires-Dist: ruff>=0.5; extra == 'dev'
28
+ Provides-Extra: pydantic
29
+ Requires-Dist: pydantic>=2; extra == 'pydantic'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # glia
33
+
34
+ **A glass-box, minimal library for building LLM agents.** Every model call, tool
35
+ call, and state transition is a plain object you can log, snapshot, and replay.
36
+ No hidden control flow. The whole loop fits in one file you can read in an
37
+ afternoon.
38
+
39
+ > _glia_ (n.): the cells that support and connect neurons. This is the connective
40
+ > tissue for LLM agents — not a framework you submit to, a small library you
41
+ > build on.
42
+
43
+ [![CI](https://github.com/DenisDrobyshev/glia/actions/workflows/ci.yml/badge.svg)](https://github.com/DenisDrobyshev/glia/actions/workflows/ci.yml)
44
+  Python 3.10+  ·  MIT  ·  zero required dependencies  ·  typed
45
+
46
+ ---
47
+
48
+ ## Why another agent library?
49
+
50
+ The 2026 agent-framework field is crowded, and the loudest, most consistent
51
+ complaint about the incumbents is the same: **too much abstraction, hidden
52
+ control flow, painful to debug.** Developers keep stripping the framework out to
53
+ call the model API directly, just to see what's happening.
54
+
55
+ glia is the opposite bet. It ships the modern techniques — tools, structured
56
+ outputs, context compaction, durable checkpoints, guardrails, subagents,
57
+ evals-as-tests — as **opt-in primitives you can read**, not a monolith you must
58
+ trust. The design goal is understandability and control, not feature count.
59
+
60
+ If you want a graph engine, use [LangGraph](https://github.com/langchain-ai/langgraph).
61
+ If you want role-play crews, use [CrewAI](https://github.com/crewAIInc/crewAI).
62
+ If you want a small, transparent loop you fully understand — glia.
63
+
64
+ See [docs/STRATEGY.md](docs/STRATEGY.md) for the full market analysis.
65
+
66
+ ## Install
67
+
68
+ ```bash
69
+ pip install glia-agents # core — no dependencies
70
+ pip install "glia-agents[anthropic]" # + the Claude provider
71
+ ```
72
+
73
+ > The distribution is `glia-agents` (the bare name `glia` was taken on PyPI);
74
+ > the import stays `import glia`. For development: `git clone` then
75
+ > `pip install -e ".[anthropic,dev]"`.
76
+
77
+ ## 30-second tour
78
+
79
+ ```python
80
+ import asyncio
81
+ from glia import Agent, tool
82
+ from glia.providers import ClaudeLLM
83
+
84
+ @tool
85
+ async def get_weather(city: str) -> str:
86
+ """Get the current weather for a city."""
87
+ return {"Paris": "18°C, cloudy"}.get(city, "unknown")
88
+
89
+ async def main():
90
+ agent = Agent(ClaudeLLM(), tools=[get_weather], system="Be concise.")
91
+ result = await agent.run("What's the weather in Paris?")
92
+ print(result.output) # the answer
93
+ print(result.usage) # what it cost
94
+
95
+ asyncio.run(main())
96
+ ```
97
+
98
+ No API key handy? Every example runs offline with the deterministic `EchoLLM`
99
+ provider — same code, no network:
100
+
101
+ ```python
102
+ from glia.providers import EchoLLM, call
103
+ llm = EchoLLM([call("get_weather", {"city": "Paris"}), "It's 18°C and cloudy."])
104
+ ```
105
+
106
+ ## See the whole glass box
107
+
108
+ Because the loop emits an event for everything it does, you can watch it work:
109
+
110
+ ```python
111
+ async for event in agent.run_events("What's the weather in Paris?"):
112
+ print(event.kind)
113
+ # run_started → model_call → model_response → tool_called → tool_returned → model_call → ... → run_finished
114
+ ```
115
+
116
+ And the entire run state is one serialisable object:
117
+
118
+ ```python
119
+ from glia.checkpoint import save, load
120
+ save(result.trajectory, "run.json") # durable execution: it's just JSON
121
+ resumed = load("run.json")
122
+ await agent.run("follow-up question", trajectory=resumed) # pick up where you left off
123
+ ```
124
+
125
+ ## What's in the box
126
+
127
+ | Primitive | What it gives you |
128
+ |---|---|
129
+ | **Transparent loop** | `agent.run()` / `agent.run_events()` — no hidden control flow |
130
+ | **Typed tools** | `@tool` on a plain function; JSON schema derived from type hints |
131
+ | **Provider boundary** | one ~40-line `LLM` protocol; Claude + offline adapters |
132
+ | **Trajectory** | the full, JSON-serialisable run state and event log |
133
+ | **Structured output** | `generate_structured(...)` → a dataclass / Pydantic model / dict |
134
+ | **Context engineering** | `SummarizingCompactor`, `TrimmingCompactor` |
135
+ | **Durable execution** | checkpoint & resume — a run is a JSON file |
136
+ | **Guardrails** | `(text) -> None` validators for input and output |
137
+ | **Subagents** | `agent.as_tool(...)` — any agent becomes a tool |
138
+ | **Evals-as-tests** | a pytest-style regression harness for agent behaviour |
139
+
140
+ ## Examples
141
+
142
+ Runnable, offline, no API key needed:
143
+
144
+ ```bash
145
+ python examples/01_hello_agent.py # basic agent + event stream
146
+ python examples/02_tools.py # tools
147
+ python examples/03_structured_output.py # typed output
148
+ python examples/04_subagents.py # subagent as a tool
149
+ python examples/05_checkpoint_resume.py # durable execution
150
+ python examples/06_evals.py # eval suite
151
+ ```
152
+
153
+ ## Design in one picture
154
+
155
+ ```
156
+ Agent.run() → [ call model → (tools? run them, loop) : done ]
157
+ │ │
158
+ every step emits an Event you can see, log, and replay
159
+
160
+ all state lives in one serialisable Trajectory
161
+ ```
162
+
163
+ Full details in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
164
+
165
+ ## Project docs
166
+
167
+ - [Strategy & market analysis](docs/STRATEGY.md) — why glia, and who it competes with
168
+ - [Architecture](docs/ARCHITECTURE.md) — how the whole thing works
169
+ - [Roadmap](docs/ROADMAP.md) — where it's going
170
+ - [Contributing](CONTRIBUTING.md)
171
+
172
+ ## Status
173
+
174
+ **v0.1 — alpha.** The core thesis is proven end-to-end with a full test suite and
175
+ green CI. APIs may still change before 1.0. Feedback and issues welcome.
176
+
177
+ ## License
178
+
179
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,148 @@
1
+ # glia
2
+
3
+ **A glass-box, minimal library for building LLM agents.** Every model call, tool
4
+ call, and state transition is a plain object you can log, snapshot, and replay.
5
+ No hidden control flow. The whole loop fits in one file you can read in an
6
+ afternoon.
7
+
8
+ > _glia_ (n.): the cells that support and connect neurons. This is the connective
9
+ > tissue for LLM agents — not a framework you submit to, a small library you
10
+ > build on.
11
+
12
+ [![CI](https://github.com/DenisDrobyshev/glia/actions/workflows/ci.yml/badge.svg)](https://github.com/DenisDrobyshev/glia/actions/workflows/ci.yml)
13
+  Python 3.10+  ·  MIT  ·  zero required dependencies  ·  typed
14
+
15
+ ---
16
+
17
+ ## Why another agent library?
18
+
19
+ The 2026 agent-framework field is crowded, and the loudest, most consistent
20
+ complaint about the incumbents is the same: **too much abstraction, hidden
21
+ control flow, painful to debug.** Developers keep stripping the framework out to
22
+ call the model API directly, just to see what's happening.
23
+
24
+ glia is the opposite bet. It ships the modern techniques — tools, structured
25
+ outputs, context compaction, durable checkpoints, guardrails, subagents,
26
+ evals-as-tests — as **opt-in primitives you can read**, not a monolith you must
27
+ trust. The design goal is understandability and control, not feature count.
28
+
29
+ If you want a graph engine, use [LangGraph](https://github.com/langchain-ai/langgraph).
30
+ If you want role-play crews, use [CrewAI](https://github.com/crewAIInc/crewAI).
31
+ If you want a small, transparent loop you fully understand — glia.
32
+
33
+ See [docs/STRATEGY.md](docs/STRATEGY.md) for the full market analysis.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install glia-agents # core — no dependencies
39
+ pip install "glia-agents[anthropic]" # + the Claude provider
40
+ ```
41
+
42
+ > The distribution is `glia-agents` (the bare name `glia` was taken on PyPI);
43
+ > the import stays `import glia`. For development: `git clone` then
44
+ > `pip install -e ".[anthropic,dev]"`.
45
+
46
+ ## 30-second tour
47
+
48
+ ```python
49
+ import asyncio
50
+ from glia import Agent, tool
51
+ from glia.providers import ClaudeLLM
52
+
53
+ @tool
54
+ async def get_weather(city: str) -> str:
55
+ """Get the current weather for a city."""
56
+ return {"Paris": "18°C, cloudy"}.get(city, "unknown")
57
+
58
+ async def main():
59
+ agent = Agent(ClaudeLLM(), tools=[get_weather], system="Be concise.")
60
+ result = await agent.run("What's the weather in Paris?")
61
+ print(result.output) # the answer
62
+ print(result.usage) # what it cost
63
+
64
+ asyncio.run(main())
65
+ ```
66
+
67
+ No API key handy? Every example runs offline with the deterministic `EchoLLM`
68
+ provider — same code, no network:
69
+
70
+ ```python
71
+ from glia.providers import EchoLLM, call
72
+ llm = EchoLLM([call("get_weather", {"city": "Paris"}), "It's 18°C and cloudy."])
73
+ ```
74
+
75
+ ## See the whole glass box
76
+
77
+ Because the loop emits an event for everything it does, you can watch it work:
78
+
79
+ ```python
80
+ async for event in agent.run_events("What's the weather in Paris?"):
81
+ print(event.kind)
82
+ # run_started → model_call → model_response → tool_called → tool_returned → model_call → ... → run_finished
83
+ ```
84
+
85
+ And the entire run state is one serialisable object:
86
+
87
+ ```python
88
+ from glia.checkpoint import save, load
89
+ save(result.trajectory, "run.json") # durable execution: it's just JSON
90
+ resumed = load("run.json")
91
+ await agent.run("follow-up question", trajectory=resumed) # pick up where you left off
92
+ ```
93
+
94
+ ## What's in the box
95
+
96
+ | Primitive | What it gives you |
97
+ |---|---|
98
+ | **Transparent loop** | `agent.run()` / `agent.run_events()` — no hidden control flow |
99
+ | **Typed tools** | `@tool` on a plain function; JSON schema derived from type hints |
100
+ | **Provider boundary** | one ~40-line `LLM` protocol; Claude + offline adapters |
101
+ | **Trajectory** | the full, JSON-serialisable run state and event log |
102
+ | **Structured output** | `generate_structured(...)` → a dataclass / Pydantic model / dict |
103
+ | **Context engineering** | `SummarizingCompactor`, `TrimmingCompactor` |
104
+ | **Durable execution** | checkpoint & resume — a run is a JSON file |
105
+ | **Guardrails** | `(text) -> None` validators for input and output |
106
+ | **Subagents** | `agent.as_tool(...)` — any agent becomes a tool |
107
+ | **Evals-as-tests** | a pytest-style regression harness for agent behaviour |
108
+
109
+ ## Examples
110
+
111
+ Runnable, offline, no API key needed:
112
+
113
+ ```bash
114
+ python examples/01_hello_agent.py # basic agent + event stream
115
+ python examples/02_tools.py # tools
116
+ python examples/03_structured_output.py # typed output
117
+ python examples/04_subagents.py # subagent as a tool
118
+ python examples/05_checkpoint_resume.py # durable execution
119
+ python examples/06_evals.py # eval suite
120
+ ```
121
+
122
+ ## Design in one picture
123
+
124
+ ```
125
+ Agent.run() → [ call model → (tools? run them, loop) : done ]
126
+ │ │
127
+ every step emits an Event you can see, log, and replay
128
+
129
+ all state lives in one serialisable Trajectory
130
+ ```
131
+
132
+ Full details in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
133
+
134
+ ## Project docs
135
+
136
+ - [Strategy & market analysis](docs/STRATEGY.md) — why glia, and who it competes with
137
+ - [Architecture](docs/ARCHITECTURE.md) — how the whole thing works
138
+ - [Roadmap](docs/ROADMAP.md) — where it's going
139
+ - [Contributing](CONTRIBUTING.md)
140
+
141
+ ## Status
142
+
143
+ **v0.1 — alpha.** The core thesis is proven end-to-end with a full test suite and
144
+ green CI. APIs may still change before 1.0. Feedback and issues welcome.
145
+
146
+ ## License
147
+
148
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,78 @@
1
+ # Architecture
2
+
3
+ glia has one rule: **no hidden control flow**. If you want to know what the agent
4
+ does, you read `agent.py`. If you want to know what state it holds, you read
5
+ `trajectory.py`. That's the whole system.
6
+
7
+ ## The pieces
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────┐
11
+ │ Agent │
12
+ │ the loop: call model → run tools → repeat │
13
+ └───────┬───────────────┬──────────────┬───────┘
14
+ │ │ │
15
+ ┌───────▼──────┐ ┌──────▼──────┐ ┌─────▼───────┐
16
+ │ LLM │ │ ToolRegistry│ │ Trajectory │
17
+ │ (protocol) │ │ (@tool fns)│ │ state+events│
18
+ └───────┬──────┘ └─────────────┘ └─────────────┘
19
+
20
+ ┌─────────┴─────────┐
21
+ ┌────▼─────┐ ┌─────▼──────┐
22
+ │ ClaudeLLM│ │ EchoLLM │
23
+ │ (Anthropic) │(offline/CI)│
24
+ └──────────┘ └────────────┘
25
+ ```
26
+
27
+ | Module | Responsibility | Lines you'd read to understand it |
28
+ |---|---|---|
29
+ | `types.py` | Content blocks, `Message`, `Usage`. Immutable, JSON-serialisable. | ~170 |
30
+ | `llm.py` | The provider boundary: `LLMRequest`, `LLMResponse`, and the `LLM` protocol. | ~90 |
31
+ | `tools.py` | `@tool` decorator (schema from type hints), `ToolRegistry`. | ~230 |
32
+ | `trajectory.py` | The run state + the `Event` types. The glass box itself. | ~250 |
33
+ | `agent.py` | The loop. `run()` and `run_events()`. | ~230 |
34
+ | `memory.py` | Context engineering: compactors. | ~140 |
35
+ | `guardrails.py` | Input/output validators. | ~90 |
36
+ | `structured.py` | Structured output via a forced tool call. | ~110 |
37
+ | `checkpoint.py` | Save/load a trajectory; a checkpointer hook. | ~70 |
38
+ | `evals.py` | Evals-as-tests harness. | ~140 |
39
+ | `providers/` | `EchoLLM` (offline) and `ClaudeLLM` (Anthropic). | ~120 each |
40
+
41
+ ## The loop, precisely
42
+
43
+ `Agent.run_events()` is the single source of behaviour. Each iteration:
44
+
45
+ 1. **(optional) compact** — if a `Compactor` says the trajectory is too big,
46
+ shrink it first, emitting a `Compacted` event.
47
+ 2. **build an `LLMRequest`** from the current trajectory + tool schemas.
48
+ 3. **call the provider** (`ModelCall` → `ModelResponse` events), appending the
49
+ assistant message and its `Usage` to the trajectory.
50
+ 4. **if the model asked for tools:** run each (`ToolCalled` → `ToolReturned`),
51
+ append all results as one user turn, and loop.
52
+ 5. **otherwise:** run output guardrails and finish (`RunFinished`).
53
+
54
+ `run()` is just `run_events()` drained to completion. That's the whole thing.
55
+
56
+ ## Why these choices
57
+
58
+ - **Blocks are a closed union, not a class hierarchy.** You `isinstance`/match on
59
+ four types; there are no subclasses to discover or plugins to register.
60
+ - **Tool results are a `user` turn.** That's the Anthropic convention, and it
61
+ keeps our message model and the wire format aligned with no translation debt.
62
+ - **Events are records, not commands.** Hooks observe; they never mutate the
63
+ loop. This keeps behaviour readable and hooks safe.
64
+ - **The provider boundary is tiny on purpose.** Adapting to a new model or an
65
+ API change touches one file. Vendor churn can't ripple through the codebase.
66
+ - **`EchoLLM` is a first-class citizen.** Deterministic, offline testing of the
67
+ entire loop is a design goal, not an afterthought.
68
+
69
+ ## Extending it
70
+
71
+ - **New provider:** implement `async def generate(request) -> LLMResponse`. ~40
72
+ lines. See `providers/echo.py` for the simplest possible example.
73
+ - **New context strategy:** implement the `Compactor` protocol
74
+ (`should_compact` + `compact`). See `memory.py`.
75
+ - **New guardrail:** write a `(text) -> None` function that raises
76
+ `GuardrailTripped`. That's the whole interface.
77
+ - **Observability:** add a hook. Every event flows through it; export to logs,
78
+ a tracer, or a UI.
@@ -0,0 +1,42 @@
1
+ # Roadmap
2
+
3
+ glia follows one principle when adding features: **a new primitive must not add
4
+ hidden control flow.** If a feature can't be made inspectable, it doesn't ship.
5
+
6
+ ## v0.1 — thesis proven (this release)
7
+ - Transparent agent loop (`run` / `run_events`) with a full event stream
8
+ - Tools from typed functions (`@tool`) + `ToolRegistry`
9
+ - Provider boundary + `ClaudeLLM` (Anthropic) and `EchoLLM` (offline)
10
+ - Serialisable `Trajectory`; checkpoint/resume (durable execution)
11
+ - Context engineering: `SummarizingCompactor`, `TrimmingCompactor`
12
+ - Guardrails (input/output validators)
13
+ - Structured outputs (provider-agnostic, via forced tool call)
14
+ - Subagents (any agent → a tool)
15
+ - Evals-as-tests harness
16
+ - Zero-dependency core, `py.typed`, green CI, runnable offline examples
17
+
18
+ ## v0.2 — ergonomics & throughput
19
+ - [ ] Parallel tool execution (`asyncio.gather`) with preserved event ordering
20
+ - [ ] Streaming token output through the event stream (`ModelDelta` events)
21
+ - [ ] Retry/backoff policy as an explicit, inspectable wrapper (not hidden magic)
22
+ - [ ] `RunResult` niceties: per-tool timings, cost summary helpers
23
+
24
+ ## v0.3 — interop
25
+ - [ ] MCP tool bridge: expose MCP servers as glia tools, and glia tools as MCP
26
+ - [ ] OpenTelemetry span exporter driven off the event stream
27
+ - [ ] Prompt-caching hints on the Claude adapter (stable-prefix breakpoints)
28
+
29
+ ## v0.4 — reliability
30
+ - [ ] Pluggable persistence backends for checkpoints (file, sqlite, redis)
31
+ - [ ] Deterministic replay: re-run a saved trajectory against a recorded provider
32
+ - [ ] Human-in-the-loop tool approval as a first-class, inspectable gate
33
+
34
+ ## Later
35
+ - [ ] TypeScript port once the Python core stabilises (same glass-box contract)
36
+ - [ ] A tiny local trace viewer that renders a `Trajectory` as a timeline
37
+
38
+ ## Non-goals (on purpose)
39
+ - A graph/DSL orchestration engine — use LangGraph.
40
+ - A hosted runtime/sandbox — use the Claude Agent SDK / Managed Agents.
41
+ - A role-play "crew" abstraction — use CrewAI.
42
+ - Anything that requires the core to grow a heavy dependency.