weakincentives 0.1.0__tar.gz → 0.2.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.
Potentially problematic release.
This version of weakincentives might be problematic. Click here for more details.
- {weakincentives-0.1.0 → weakincentives-0.2.0}/.github/workflows/release.yml +4 -1
- weakincentives-0.2.0/AGENTS.md +95 -0
- weakincentives-0.2.0/CHANGELOG.md +29 -0
- weakincentives-0.2.0/Makefile +58 -0
- weakincentives-0.2.0/PKG-INFO +173 -0
- weakincentives-0.2.0/README.md +146 -0
- weakincentives-0.2.0/ROADMAP.md +64 -0
- weakincentives-0.2.0/WARP.md +3 -0
- weakincentives-0.2.0/concat_all.py +63 -0
- weakincentives-0.2.0/openai_example.py +278 -0
- weakincentives-0.2.0/pyproject.toml +102 -0
- weakincentives-0.2.0/specs/ADAPTERS.md +168 -0
- weakincentives-0.2.0/specs/DATACLASS_SERDE.md +159 -0
- weakincentives-0.2.0/specs/PROMPTS.md +158 -0
- weakincentives-0.2.0/specs/STRUCTURED_OUTPUT.md +222 -0
- weakincentives-0.2.0/specs/TOOLS.md +166 -0
- weakincentives-0.2.0/src/weakincentives/__init__.py +15 -0
- weakincentives-0.2.0/src/weakincentives/adapters/__init__.py +30 -0
- weakincentives-0.2.0/src/weakincentives/adapters/core.py +85 -0
- weakincentives-0.2.0/src/weakincentives/adapters/openai.py +361 -0
- weakincentives-0.2.0/src/weakincentives/prompts/__init__.py +45 -0
- weakincentives-0.2.0/src/weakincentives/prompts/_types.py +27 -0
- weakincentives-0.2.0/src/weakincentives/prompts/errors.py +57 -0
- weakincentives-0.2.0/src/weakincentives/prompts/prompt.py +440 -0
- weakincentives-0.2.0/src/weakincentives/prompts/response_format.py +54 -0
- weakincentives-0.2.0/src/weakincentives/prompts/section.py +120 -0
- weakincentives-0.2.0/src/weakincentives/prompts/structured.py +140 -0
- weakincentives-0.2.0/src/weakincentives/prompts/text.py +89 -0
- weakincentives-0.2.0/src/weakincentives/prompts/tool.py +236 -0
- weakincentives-0.2.0/src/weakincentives/serde/__init__.py +31 -0
- weakincentives-0.2.0/src/weakincentives/serde/dataclass_serde.py +1016 -0
- weakincentives-0.2.0/tests/adapters/test_openai_adapter.py +717 -0
- weakincentives-0.2.0/tests/prompts/test_exceptions.py +52 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_edge_cases.py +244 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_init.py +163 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_integration.py +126 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_render.py +239 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_tools.py +214 -0
- weakincentives-0.2.0/tests/prompts/test_prompt_tools_integration.py +89 -0
- weakincentives-0.2.0/tests/prompts/test_section_base.py +73 -0
- weakincentives-0.2.0/tests/prompts/test_section_tools.py +87 -0
- weakincentives-0.2.0/tests/prompts/test_structured_output.py +276 -0
- weakincentives-0.2.0/tests/prompts/test_text_section.py +83 -0
- weakincentives-0.2.0/tests/prompts/test_tool_dataclass.py +314 -0
- weakincentives-0.2.0/tests/prompts/test_typing_specializations.py +92 -0
- weakincentives-0.2.0/tests/serde/test_dataclass_serde.py +1318 -0
- weakincentives-0.2.0/tests/test_example.py +17 -0
- weakincentives-0.2.0/tests/test_openai_example.py +158 -0
- weakincentives-0.2.0/uv.lock +865 -0
- weakincentives-0.1.0/Makefile +0 -37
- weakincentives-0.1.0/PKG-INFO +0 -21
- weakincentives-0.1.0/README.md +0 -12
- weakincentives-0.1.0/WARP.md +0 -104
- weakincentives-0.1.0/pyproject.toml +0 -33
- weakincentives-0.1.0/src/weakincentives/__init__.py +0 -2
- weakincentives-0.1.0/tests/test_example.py +0 -11
- weakincentives-0.1.0/uv.lock +0 -186
- {weakincentives-0.1.0 → weakincentives-0.2.0}/.github/workflows/ci.yml +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/.gitignore +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/.python-version +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/LICENSE +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/hooks/pre-commit +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/install-hooks.sh +0 -0
- {weakincentives-0.1.0 → weakincentives-0.2.0}/src/weakincentives/py.typed +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This handbook is the primary source of truth for autonomous or assisted agents working in the `weakincentives` repository. WARP and other entrypoints should defer to this document.
|
|
4
|
+
|
|
5
|
+
## Project Snapshot
|
|
6
|
+
|
|
7
|
+
- **Goal**: Build tooling for "side effect free" background agents; current codebase is intentionally minimal and pre-alpha.
|
|
8
|
+
- **Language**: Python 3.14 (see `.python-version`).
|
|
9
|
+
- **Package manager**: [`uv`](https://github.com/astral-sh/uv) orchestrates dependency management and task execution.
|
|
10
|
+
- **Build backend**: `hatchling` (configured in `pyproject.toml`).
|
|
11
|
+
|
|
12
|
+
## Repository Tour
|
|
13
|
+
|
|
14
|
+
- `src/weakincentives/`: Library source. Currently contains the prompt scaffolding and supporting modules.
|
|
15
|
+
- `tests/`: Pytest suite. `tests/test_example.py` demonstrates the expected structure and ensures the package imports.
|
|
16
|
+
- `specs/`: Design docs and product specifications. `PROMPTS.md` defines the prompt abstraction requirements—read this before adding prompt-related code.
|
|
17
|
+
- `Makefile`: Canonical task surface (formatting, linting, typing, tests, aggregate checks, clean-up).
|
|
18
|
+
- `uv.lock`: Dependency lockfile maintained by `uv`.
|
|
19
|
+
- `hooks/` & `install-hooks.sh`: Symlink-based Git hook installer. Hooks expect `make check` to pass before commits land.
|
|
20
|
+
- Version tags (`vX.Y.Z`, the `v` prefix is required) in git control the published package version; cut them manually when releasing.
|
|
21
|
+
|
|
22
|
+
## Environment & Setup
|
|
23
|
+
|
|
24
|
+
1. Install Python 3.14 (pyenv users can run `pyenv install 3.14.0` if needed).
|
|
25
|
+
1. Install `uv` locally.
|
|
26
|
+
1. Sync dependencies and development tooling:
|
|
27
|
+
```bash
|
|
28
|
+
uv sync
|
|
29
|
+
./install-hooks.sh
|
|
30
|
+
```
|
|
31
|
+
The hook installer wires every script in `hooks/` into `.git/hooks/` via symlinks.
|
|
32
|
+
|
|
33
|
+
## Day-to-Day Commands
|
|
34
|
+
|
|
35
|
+
All commands are defined in `Makefile` and should be executed with `uv` to ensure a consistent virtualenv. The targets are configured to run in quiet mode—by default they suppress success chatter and surface only warnings or errors. Mirror this style when invoking tools manually so downstream agents process as few tokens as possible.
|
|
36
|
+
|
|
37
|
+
- `make format`: Auto-format via `ruff format -q`.
|
|
38
|
+
- `make format-check`: Formatting audit without changes (`ruff format -q --check`).
|
|
39
|
+
- `make lint` / `make lint-fix`: Static analysis with Ruff in quiet mode (`ruff check --preview -q`; add `--fix` when autofixing).
|
|
40
|
+
- `make bandit`: Security linting via `build/run_bandit.py`, which patches Python 3.14 AST regressions before invoking Bandit.
|
|
41
|
+
- `make deptry`: Dependency graph audit on `src/weakincentives` that surfaces unused or missing requirements while staying quiet on success.
|
|
42
|
+
- `make pip-audit`: Dependency vulnerability audit that stays silent on success via `build/run_pip_audit.py`.
|
|
43
|
+
- `make markdown-check`: Runs `mdformat --check` through `build/run_mdformat.py` to ensure Markdown stays consistently formatted. This command now runs inside `make check`.
|
|
44
|
+
- `make typecheck`: Runs `ty check -qq --error-on-warning` for silent success.
|
|
45
|
+
- `make test`: Executes pytest through `build/run_pytest.py`, only emitting failures or warnings while enforcing coverage (`--cov-fail-under=80`).
|
|
46
|
+
- `make check`: Aggregates format-check, lint, typecheck, Bandit, deptry, pip-audit, markdown-check, and tests with minimal output.
|
|
47
|
+
- `make all`: Runs format, lint-fix, Bandit, pip-audit, typecheck, and tests while staying quiet on success.
|
|
48
|
+
- `make clean`: Purges caches (`__pycache__`, `.pytest_cache`, `.ruff_cache`, `*.pyc`).
|
|
49
|
+
|
|
50
|
+
Prefer `make check` before every commit; git hooks will call the same pipeline.
|
|
51
|
+
|
|
52
|
+
**You MUST run `make check` before committing any changes.**
|
|
53
|
+
|
|
54
|
+
## Optional Dependencies
|
|
55
|
+
|
|
56
|
+
- `openai` is exposed as an extra. Install it with `uv sync --extra openai` during development or `pip install weakincentives[openai]` for consumers. Adapter modules guard imports and raise clear guidance when the extra is missing, so the core package stays lean.
|
|
57
|
+
- `make test` (and thus `make check` / `make all`) automatically run with all extras enabled via `uv run --all-extras`, ensuring adapter integrations stay validated.
|
|
58
|
+
|
|
59
|
+
## Testing & Quality Expectations
|
|
60
|
+
|
|
61
|
+
- Pytest is configured in `pyproject.toml` to collect coverage on `src/weakincentives` and fail if coverage dips below 80%.
|
|
62
|
+
- Type hints are part of the public contract (`py.typed`). Keep new code fully typed and run `make typecheck` when touching typing-sensitive areas.
|
|
63
|
+
- Ruff is both the formatter and the linter. Obey the default line length of 88 and the Python target version `py314`.
|
|
64
|
+
- Lint runs enable `I`, `UP`, `B`, `SIM`, `C4`, `ANN`, `RET`, `RSE`, `PTH`, and `ISC` rule families; fix or explicitly justify any violations when contributing.
|
|
65
|
+
|
|
66
|
+
## TDD Workflow Recipe
|
|
67
|
+
|
|
68
|
+
- Read the relevant spec in `specs/` and any prior plans to anchor scope, capture target module paths, and list the concrete behaviors you will validate.
|
|
69
|
+
- Break the work into thin iterations that each pair a specific test module or case (for example `tests/prompts/test_text_section.py`) with the minimal production changes required in `src/weakincentives/`.
|
|
70
|
+
- For every iteration, author the failing test first, run it directly with `uv run pytest tests/path_to_test.py -k target_case`, and confirm it asserts the desired API, errors, and context payloads.
|
|
71
|
+
- Implement only the code needed to satisfy the new test (including exports and defaults), then rerun the targeted test and expand to `make test` once the local loop is green.
|
|
72
|
+
- Refactor immediately after the test passes: deduplicate helpers, thread depth or placeholder metadata, and update docs so the next iteration starts from a clean slate.
|
|
73
|
+
- Repeat the loop until the feature-level acceptance scenario is covered, finish with `make check`, and capture the final iteration summary in the commit message or handoff notes.
|
|
74
|
+
|
|
75
|
+
## Release & Versioning Notes
|
|
76
|
+
|
|
77
|
+
- Package releases read their version from the latest git tag (`vX.Y.Z`, must include the `v`). Use `git tag vX.Y.Z` followed by `git push origin vX.Y.Z` when you’re ready to release.
|
|
78
|
+
- No publishing automation exists yet—coordinate manual releases outside this repository.
|
|
79
|
+
|
|
80
|
+
## Adding Features
|
|
81
|
+
|
|
82
|
+
- Mirror the structure in `tests/` when adding new modules—write tests alongside new code and keep them deterministic.
|
|
83
|
+
- Follow test-driven development best practices while iterating; commit to the red→green→refactor loop so features stay focused and covered.
|
|
84
|
+
- Reference `specs/PROMPTS.md` before modifying or introducing prompt-related functionality.
|
|
85
|
+
- Write commit messages with useful descriptions that summarize the change set; avoid placeholder or empty messages.
|
|
86
|
+
- Keep the `README.md` concise; extended onboarding belongs here in `AGENTS.md`.
|
|
87
|
+
- When introducing new tooling, extend the `Makefile` so agents can discover it without hunting through scripts.
|
|
88
|
+
|
|
89
|
+
## Quick Facts
|
|
90
|
+
|
|
91
|
+
- `README.md` offers a public-facing overview; this document captures agent-facing operational details.
|
|
92
|
+
- The codebase is intentionally small; expect to create new modules under `src/weakincentives/` rather than modifying many existing files.
|
|
93
|
+
- All documentation should be ASCII unless the surrounding file already uses other characters.
|
|
94
|
+
|
|
95
|
+
Use this document as the authoritative onboarding and execution guide for automated agents. Update it whenever workflows or tooling change.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Release highlights for weakincentives.
|
|
4
|
+
|
|
5
|
+
## v0.2.0 - 2025-10-29
|
|
6
|
+
|
|
7
|
+
### Highlights
|
|
8
|
+
|
|
9
|
+
- Launched the prompt composition system with typed `Prompt`, `Section`, and `TextSection` building blocks, structured rendering, and placeholder validation backed by comprehensive tests.
|
|
10
|
+
- Added tool orchestration primitives including the `Tool` dataclass, shared dataclass handling, duplicate detection, and prompt-level aggregation utilities.
|
|
11
|
+
- Delivered stdlib-only dataclass serde helpers (`parse`, `dump`, `clone`, `schema`) for lightweight validation and JSON serialization.
|
|
12
|
+
|
|
13
|
+
### Integrations
|
|
14
|
+
|
|
15
|
+
- Introduced an optional OpenAI adapter behind the `openai` extra that builds configured clients and provides friendly guidance when the dependency is missing.
|
|
16
|
+
|
|
17
|
+
### Developer Experience
|
|
18
|
+
|
|
19
|
+
- Tightened the quality gate with quiet wrappers for Ruff, Ty, pytest (100% coverage), Bandit, Deptry, and pip-audit, all wired through `make check`.
|
|
20
|
+
- Adopted Hatch VCS versioning, refreshed `pyproject.toml` metadata, and standardized automation scripts for releases.
|
|
21
|
+
|
|
22
|
+
### Documentation
|
|
23
|
+
|
|
24
|
+
- Replaced `WARP.md` with a comprehensive `AGENTS.md` handbook describing workflows, TDD guidance, and integration expectations.
|
|
25
|
+
- Added prompt and tool specifications under `specs/` and refreshed the README to highlight the new primitives and developer tooling.
|
|
26
|
+
|
|
27
|
+
## v0.1.0 - 2025-10-22
|
|
28
|
+
|
|
29
|
+
Initial repository bootstrap with the package scaffold, testing and linting toolchain, CI configuration, and contributor documentation.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
.PHONY: format check test lint typecheck bandit deptry pip-audit markdown-check all clean
|
|
2
|
+
|
|
3
|
+
# Format code with ruff
|
|
4
|
+
format:
|
|
5
|
+
@uv run ruff format -q .
|
|
6
|
+
|
|
7
|
+
# Check formatting without making changes
|
|
8
|
+
format-check:
|
|
9
|
+
@uv run ruff format -q --check .
|
|
10
|
+
|
|
11
|
+
# Run ruff linter
|
|
12
|
+
lint:
|
|
13
|
+
@uv run ruff check --preview -q .
|
|
14
|
+
|
|
15
|
+
# Run ruff linter with fixes
|
|
16
|
+
lint-fix:
|
|
17
|
+
@uv run ruff check --fix -q .
|
|
18
|
+
|
|
19
|
+
# Run Bandit security scanner
|
|
20
|
+
bandit:
|
|
21
|
+
@uv run python build/run_bandit.py -q -r src/weakincentives
|
|
22
|
+
|
|
23
|
+
# Check for unused or missing dependencies with deptry
|
|
24
|
+
deptry:
|
|
25
|
+
@uv run python build/run_deptry.py
|
|
26
|
+
|
|
27
|
+
# Run pip-audit for dependency vulnerabilities
|
|
28
|
+
pip-audit:
|
|
29
|
+
@uv run python build/run_pip_audit.py
|
|
30
|
+
|
|
31
|
+
# Validate Markdown formatting
|
|
32
|
+
markdown-check:
|
|
33
|
+
@uv run python build/run_mdformat.py
|
|
34
|
+
|
|
35
|
+
# Run type checkers
|
|
36
|
+
typecheck:
|
|
37
|
+
@uv run --all-extras ty check --error-on-warning -qq . || \
|
|
38
|
+
(echo "ty check failed; rerunning with verbose output..." >&2; \
|
|
39
|
+
uv run --all-extras ty check --error-on-warning .)
|
|
40
|
+
@uv run --all-extras pyright --project pyproject.toml || \
|
|
41
|
+
(echo "pyright failed; rerunning with verbose output..." >&2; \
|
|
42
|
+
uv run --all-extras pyright --project pyproject.toml --verbose)
|
|
43
|
+
|
|
44
|
+
# Run tests with coverage (100% minimum)
|
|
45
|
+
test:
|
|
46
|
+
@uv run --all-extras python build/run_pytest.py --strict-config --strict-markers --maxfail=1 --cov-fail-under=100 -q --no-header --no-summary --cov-report=
|
|
47
|
+
|
|
48
|
+
# Run all checks (format check, lint, typecheck, bandit, deptry, pip-audit, markdown, test)
|
|
49
|
+
check: format-check lint typecheck bandit deptry pip-audit markdown-check test
|
|
50
|
+
|
|
51
|
+
# Run all checks and fixes
|
|
52
|
+
all: format lint-fix bandit deptry pip-audit typecheck test
|
|
53
|
+
|
|
54
|
+
# Clean cache files
|
|
55
|
+
clean:
|
|
56
|
+
rm -rf .pytest_cache .ruff_cache __pycache__
|
|
57
|
+
find . -type d -name "__pycache__" -exec rm -rf {} +
|
|
58
|
+
find . -type f -name "*.pyc" -delete
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: weakincentives
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Tools for developing and optimizing side effect free background agents
|
|
5
|
+
Project-URL: Homepage, https://weakincentives.com/
|
|
6
|
+
Project-URL: Documentation, https://github.com/weakincentives/weakincentives#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/weakincentives/weakincentives
|
|
8
|
+
Project-URL: Issue Tracker, https://github.com/weakincentives/weakincentives/issues
|
|
9
|
+
Author-email: Andrei Savu <andrei@weakincentives.com>
|
|
10
|
+
License: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agents,ai,background-agents,optimization,side-effect-free,weak-incentives
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.14
|
|
24
|
+
Provides-Extra: openai
|
|
25
|
+
Requires-Dist: openai>=2.6.1; extra == 'openai'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Weak Incentives
|
|
29
|
+
|
|
30
|
+
Tools for developing and optimizing side effect free background agents. The library ships prompt composition primitives, structured tool metadata, and optional provider adapters so you can scaffold deterministic automation flows quickly. All commands below assume Astral's `uv` CLI.
|
|
31
|
+
|
|
32
|
+
## For Library Users
|
|
33
|
+
|
|
34
|
+
### Installation
|
|
35
|
+
|
|
36
|
+
- `uv add weakincentives`
|
|
37
|
+
- Add `uv add "weakincentives[openai]"` (or `uv sync --extra openai` when cloning the repo) to enable the OpenAI adapter helpers.
|
|
38
|
+
|
|
39
|
+
### Key Features
|
|
40
|
+
|
|
41
|
+
- Fully typed prompt composition primitives (`Prompt`, `Section`, `TextSection`, `Tool`, `ToolResult`) for assembling deterministic Markdown prompts with attached tool metadata.
|
|
42
|
+
- Stdlib-only dataclass serde utilities (`parse`, `dump`, `clone`, `schema`) for Pydantic-like ergonomics without third-party dependencies.
|
|
43
|
+
- Optional OpenAI adapter that gates imports behind a friendly error and returns the SDK client when the extra is present.
|
|
44
|
+
- Quiet-by-default package with minimal runtime dependencies so background agents stay lean and predictable.
|
|
45
|
+
|
|
46
|
+
### Quickstart
|
|
47
|
+
|
|
48
|
+
````python
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
|
|
51
|
+
from weakincentives.prompts import (
|
|
52
|
+
Prompt,
|
|
53
|
+
TextSection,
|
|
54
|
+
Tool,
|
|
55
|
+
ToolResult,
|
|
56
|
+
parse_output,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class ResearchGuidance:
|
|
62
|
+
topic: str
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class SourceLookup:
|
|
67
|
+
source_id: str
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class SourceDetails:
|
|
72
|
+
source_id: str
|
|
73
|
+
title: str
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@dataclass
|
|
77
|
+
class ResearchSummary:
|
|
78
|
+
summary: str
|
|
79
|
+
citations: list[str]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def lookup_source(params: SourceLookup) -> ToolResult[SourceDetails]:
|
|
83
|
+
details = SourceDetails(source_id=params.source_id, title="Ada Lovelace Archive")
|
|
84
|
+
return ToolResult(message=f"Loaded {details.title}", payload=details)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
catalog_tool = Tool[SourceLookup, SourceDetails](
|
|
88
|
+
name="catalog_lookup",
|
|
89
|
+
description="Look up a primary source identifier and return structured details.",
|
|
90
|
+
handler=lookup_source,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
research_section = TextSection[ResearchGuidance](
|
|
94
|
+
title="Task",
|
|
95
|
+
body=(
|
|
96
|
+
"Research ${topic}. Use the `catalog_lookup` tool for citations and return"
|
|
97
|
+
" a JSON summary with citations."
|
|
98
|
+
),
|
|
99
|
+
tools=[catalog_tool],
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
prompt = Prompt[ResearchSummary](
|
|
103
|
+
name="research_run",
|
|
104
|
+
sections=[research_section],
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
rendered = prompt.render(ResearchGuidance(topic="Ada Lovelace"))
|
|
108
|
+
print(rendered.text)
|
|
109
|
+
print([tool.name for tool in rendered.tools])
|
|
110
|
+
|
|
111
|
+
reply = """```json
|
|
112
|
+
{
|
|
113
|
+
"summary": "Ada Lovelace pioneered computing...",
|
|
114
|
+
"citations": ["catalog_lookup:ada-archive"]
|
|
115
|
+
}
|
|
116
|
+
```"""
|
|
117
|
+
|
|
118
|
+
parsed = parse_output(reply, rendered)
|
|
119
|
+
print(parsed.summary)
|
|
120
|
+
print(parsed.citations)
|
|
121
|
+
````
|
|
122
|
+
|
|
123
|
+
### Optional Extras
|
|
124
|
+
|
|
125
|
+
Use the OpenAI helpers once the extra is installed:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from weakincentives.adapters import OpenAIAdapter
|
|
129
|
+
|
|
130
|
+
adapter = OpenAIAdapter(model="gpt-4o-mini", client_kwargs={"api_key": "sk-..."})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If the dependency is missing, the adapter raises a runtime error with installation guidance.
|
|
134
|
+
|
|
135
|
+
## For Library Developers
|
|
136
|
+
|
|
137
|
+
### Environment Setup
|
|
138
|
+
|
|
139
|
+
1. Install Python 3.14 (pyenv users can run `pyenv install 3.14.0`).
|
|
140
|
+
1. Install [`uv`](https://github.com/astral-sh/uv).
|
|
141
|
+
1. Sync the virtualenv and optional git hooks:
|
|
142
|
+
```bash
|
|
143
|
+
uv sync
|
|
144
|
+
./install-hooks.sh # optional – wires git hooks that call make check
|
|
145
|
+
```
|
|
146
|
+
1. Use `uv run ...` when invoking ad-hoc scripts so everything stays inside the managed environment.
|
|
147
|
+
|
|
148
|
+
### Development Workflow
|
|
149
|
+
|
|
150
|
+
- `make format` / `make format-check` — run Ruff formatters.
|
|
151
|
+
- `make lint` / `make lint-fix` — lint with Ruff.
|
|
152
|
+
- `make typecheck` — execute Ty with warnings promoted to errors.
|
|
153
|
+
- `make test` — run pytest via `build/run_pytest.py` with `--cov-fail-under=100`.
|
|
154
|
+
- `make bandit`, `make deptry`, `make pip-audit` — security, dependency, and vulnerability audits.
|
|
155
|
+
- `make check` — aggregate the quiet quality gate; run this before every commit (git hooks enforce it).
|
|
156
|
+
|
|
157
|
+
### Project Layout
|
|
158
|
+
|
|
159
|
+
- `src/weakincentives/` — package root for the Python module.
|
|
160
|
+
- `src/weakincentives/prompts/` — prompt, section, and tool primitives.
|
|
161
|
+
- `src/weakincentives/adapters/` — optional provider integrations.
|
|
162
|
+
- `tests/` — pytest suites covering prompts, tools, and adapters.
|
|
163
|
+
- `specs/` — design docs; see `specs/PROMPTS.md` for prompt requirements.
|
|
164
|
+
- `build/` — thin wrappers that keep CLI tools quiet inside `uv`.
|
|
165
|
+
- `hooks/` — symlink-friendly git hooks (install via `./install-hooks.sh`).
|
|
166
|
+
|
|
167
|
+
### Release Notes
|
|
168
|
+
|
|
169
|
+
Version numbers come from git tags named `vX.Y.Z`. Tag the repository manually before pushing a release.
|
|
170
|
+
|
|
171
|
+
### More Documentation
|
|
172
|
+
|
|
173
|
+
`AGENTS.md` captures the full agent handbook, workflows, and TDD expectations. `ROADMAP.md` and `specs/` document upcoming work and prompt requirements.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Weak Incentives
|
|
2
|
+
|
|
3
|
+
Tools for developing and optimizing side effect free background agents. The library ships prompt composition primitives, structured tool metadata, and optional provider adapters so you can scaffold deterministic automation flows quickly. All commands below assume Astral's `uv` CLI.
|
|
4
|
+
|
|
5
|
+
## For Library Users
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
|
|
9
|
+
- `uv add weakincentives`
|
|
10
|
+
- Add `uv add "weakincentives[openai]"` (or `uv sync --extra openai` when cloning the repo) to enable the OpenAI adapter helpers.
|
|
11
|
+
|
|
12
|
+
### Key Features
|
|
13
|
+
|
|
14
|
+
- Fully typed prompt composition primitives (`Prompt`, `Section`, `TextSection`, `Tool`, `ToolResult`) for assembling deterministic Markdown prompts with attached tool metadata.
|
|
15
|
+
- Stdlib-only dataclass serde utilities (`parse`, `dump`, `clone`, `schema`) for Pydantic-like ergonomics without third-party dependencies.
|
|
16
|
+
- Optional OpenAI adapter that gates imports behind a friendly error and returns the SDK client when the extra is present.
|
|
17
|
+
- Quiet-by-default package with minimal runtime dependencies so background agents stay lean and predictable.
|
|
18
|
+
|
|
19
|
+
### Quickstart
|
|
20
|
+
|
|
21
|
+
````python
|
|
22
|
+
from dataclasses import dataclass
|
|
23
|
+
|
|
24
|
+
from weakincentives.prompts import (
|
|
25
|
+
Prompt,
|
|
26
|
+
TextSection,
|
|
27
|
+
Tool,
|
|
28
|
+
ToolResult,
|
|
29
|
+
parse_output,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class ResearchGuidance:
|
|
35
|
+
topic: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class SourceLookup:
|
|
40
|
+
source_id: str
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class SourceDetails:
|
|
45
|
+
source_id: str
|
|
46
|
+
title: str
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class ResearchSummary:
|
|
51
|
+
summary: str
|
|
52
|
+
citations: list[str]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def lookup_source(params: SourceLookup) -> ToolResult[SourceDetails]:
|
|
56
|
+
details = SourceDetails(source_id=params.source_id, title="Ada Lovelace Archive")
|
|
57
|
+
return ToolResult(message=f"Loaded {details.title}", payload=details)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
catalog_tool = Tool[SourceLookup, SourceDetails](
|
|
61
|
+
name="catalog_lookup",
|
|
62
|
+
description="Look up a primary source identifier and return structured details.",
|
|
63
|
+
handler=lookup_source,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
research_section = TextSection[ResearchGuidance](
|
|
67
|
+
title="Task",
|
|
68
|
+
body=(
|
|
69
|
+
"Research ${topic}. Use the `catalog_lookup` tool for citations and return"
|
|
70
|
+
" a JSON summary with citations."
|
|
71
|
+
),
|
|
72
|
+
tools=[catalog_tool],
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
prompt = Prompt[ResearchSummary](
|
|
76
|
+
name="research_run",
|
|
77
|
+
sections=[research_section],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
rendered = prompt.render(ResearchGuidance(topic="Ada Lovelace"))
|
|
81
|
+
print(rendered.text)
|
|
82
|
+
print([tool.name for tool in rendered.tools])
|
|
83
|
+
|
|
84
|
+
reply = """```json
|
|
85
|
+
{
|
|
86
|
+
"summary": "Ada Lovelace pioneered computing...",
|
|
87
|
+
"citations": ["catalog_lookup:ada-archive"]
|
|
88
|
+
}
|
|
89
|
+
```"""
|
|
90
|
+
|
|
91
|
+
parsed = parse_output(reply, rendered)
|
|
92
|
+
print(parsed.summary)
|
|
93
|
+
print(parsed.citations)
|
|
94
|
+
````
|
|
95
|
+
|
|
96
|
+
### Optional Extras
|
|
97
|
+
|
|
98
|
+
Use the OpenAI helpers once the extra is installed:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from weakincentives.adapters import OpenAIAdapter
|
|
102
|
+
|
|
103
|
+
adapter = OpenAIAdapter(model="gpt-4o-mini", client_kwargs={"api_key": "sk-..."})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If the dependency is missing, the adapter raises a runtime error with installation guidance.
|
|
107
|
+
|
|
108
|
+
## For Library Developers
|
|
109
|
+
|
|
110
|
+
### Environment Setup
|
|
111
|
+
|
|
112
|
+
1. Install Python 3.14 (pyenv users can run `pyenv install 3.14.0`).
|
|
113
|
+
1. Install [`uv`](https://github.com/astral-sh/uv).
|
|
114
|
+
1. Sync the virtualenv and optional git hooks:
|
|
115
|
+
```bash
|
|
116
|
+
uv sync
|
|
117
|
+
./install-hooks.sh # optional – wires git hooks that call make check
|
|
118
|
+
```
|
|
119
|
+
1. Use `uv run ...` when invoking ad-hoc scripts so everything stays inside the managed environment.
|
|
120
|
+
|
|
121
|
+
### Development Workflow
|
|
122
|
+
|
|
123
|
+
- `make format` / `make format-check` — run Ruff formatters.
|
|
124
|
+
- `make lint` / `make lint-fix` — lint with Ruff.
|
|
125
|
+
- `make typecheck` — execute Ty with warnings promoted to errors.
|
|
126
|
+
- `make test` — run pytest via `build/run_pytest.py` with `--cov-fail-under=100`.
|
|
127
|
+
- `make bandit`, `make deptry`, `make pip-audit` — security, dependency, and vulnerability audits.
|
|
128
|
+
- `make check` — aggregate the quiet quality gate; run this before every commit (git hooks enforce it).
|
|
129
|
+
|
|
130
|
+
### Project Layout
|
|
131
|
+
|
|
132
|
+
- `src/weakincentives/` — package root for the Python module.
|
|
133
|
+
- `src/weakincentives/prompts/` — prompt, section, and tool primitives.
|
|
134
|
+
- `src/weakincentives/adapters/` — optional provider integrations.
|
|
135
|
+
- `tests/` — pytest suites covering prompts, tools, and adapters.
|
|
136
|
+
- `specs/` — design docs; see `specs/PROMPTS.md` for prompt requirements.
|
|
137
|
+
- `build/` — thin wrappers that keep CLI tools quiet inside `uv`.
|
|
138
|
+
- `hooks/` — symlink-friendly git hooks (install via `./install-hooks.sh`).
|
|
139
|
+
|
|
140
|
+
### Release Notes
|
|
141
|
+
|
|
142
|
+
Version numbers come from git tags named `vX.Y.Z`. Tag the repository manually before pushing a release.
|
|
143
|
+
|
|
144
|
+
### More Documentation
|
|
145
|
+
|
|
146
|
+
`AGENTS.md` captures the full agent handbook, workflows, and TDD expectations. `ROADMAP.md` and `specs/` document upcoming work and prompt requirements.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
## Near-Term Initiatives
|
|
4
|
+
|
|
5
|
+
### Session State Container
|
|
6
|
+
|
|
7
|
+
- Formalize a `Session` abstraction that captures conversation state, tool outputs, and transient metadata.
|
|
8
|
+
- Define serialization hooks so sessions can persist across process restarts without leaking sensitive data.
|
|
9
|
+
- Thread the session object through existing prompt and tool layers, backed by integration tests that assert idempotent replay.
|
|
10
|
+
|
|
11
|
+
### Notes System Retrospectives
|
|
12
|
+
|
|
13
|
+
- Establish a notes pattern that captures retrospectives for individual prompt invocations and entire sessions.
|
|
14
|
+
- Model notes as entities that can attach to `Section` objects and `Tool` objects to preserve context.
|
|
15
|
+
- Outline lifecycle and storage expectations so notes integrate cleanly with existing session state abstractions.
|
|
16
|
+
|
|
17
|
+
### Single Turn Prompt Optimizations
|
|
18
|
+
|
|
19
|
+
- Profile current single-turn flows to surface latency and token usage hot spots.
|
|
20
|
+
- Experiment with prompt compression techniques and instruction restructuring to maintain quality while reducing cost.
|
|
21
|
+
- Add benchmarks or harness scripts that assert improvements before regression.
|
|
22
|
+
|
|
23
|
+
### Named Entities Handling (Input and Output)
|
|
24
|
+
|
|
25
|
+
- Introduce utilities for detecting and tagging named entities across inputs.
|
|
26
|
+
- Preserve, normalize, or obfuscate entities in outputs according to privacy and compliance guidelines.
|
|
27
|
+
- Validate the pipeline with targeted tests that cover multilingual and domain-specific vocabularies.
|
|
28
|
+
|
|
29
|
+
### Built-In Planning & Virtual Filesystem Tools
|
|
30
|
+
|
|
31
|
+
- Provide first-class tool definitions for planning/todo workflows and virtual filesystem operations for agents.
|
|
32
|
+
- Establish section templates that ensure tools render consistently in prompts and downstream telemetry.
|
|
33
|
+
- Ship representative examples and regression tests demonstrating safe defaults and extensibility points.
|
|
34
|
+
|
|
35
|
+
### Sandboxed Code Execution
|
|
36
|
+
|
|
37
|
+
- Provide hardened sandboxes so agents can run generated code with strict CPU, memory, filesystem, and network guardrails.
|
|
38
|
+
- Surface sandbox lifecycle APIs that expose logs, artifacts, and exit metadata without leaking host resources.
|
|
39
|
+
- Add validation suites and stress tests that assert isolation boundaries hold across supported runtimes.
|
|
40
|
+
|
|
41
|
+
### Agentic Reasoning Loop
|
|
42
|
+
|
|
43
|
+
- Design an orchestrator that coordinates system prompts, user turns, tool routing, and session state updates.
|
|
44
|
+
- Integrate entity resolvers and named-entity policies to normalize inputs before tool calls and responses.
|
|
45
|
+
- Document the execution phases (think, act, observe) with diagrams and tests that enforce correct transitions.
|
|
46
|
+
|
|
47
|
+
### Tracing & Observability
|
|
48
|
+
|
|
49
|
+
- Capture structured trace data from agent runs, including tool calls and message content classification.
|
|
50
|
+
- Export telemetry to persistent storage with configurable redaction for sensitive fields and PII.
|
|
51
|
+
- Provide replay and visualization utilities that allow developers to inspect state transitions and timing.
|
|
52
|
+
|
|
53
|
+
### Subagents & Parallel Execution
|
|
54
|
+
|
|
55
|
+
- Enable the primary agent to spawn scoped subagents with dedicated sessions for independent objectives.
|
|
56
|
+
- Coordinate concurrent execution, result aggregation, and conflict resolution when subagents touch shared resources.
|
|
57
|
+
- Provide lifecycle hooks so subagents inherit policies, tools, and logging while remaining cancellable.
|
|
58
|
+
|
|
59
|
+
## Out of Scope (For Now)
|
|
60
|
+
|
|
61
|
+
- Graph-based agent composers—current focus is flexible orchestration over rigid node/edge pipelines.
|
|
62
|
+
- Retrieval and memory connectors—the library assumes ambient context rather than external knowledge stores.
|
|
63
|
+
- Human-in-the-loop gating—agents should operate autonomously once launched inside controlled environments.
|
|
64
|
+
- Evaluation frameworks beyond prompt optimization—the only supported eval loops will target prompt tuning scenarios.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
# you may not use this file except in compliance with the License.
|
|
4
|
+
# You may obtain a copy of the License at
|
|
5
|
+
#
|
|
6
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
# See the License for the specific language governing permissions and
|
|
12
|
+
# limitations under the License.
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def iter_project_files(target: Path) -> list[Path]:
|
|
21
|
+
if not target.exists():
|
|
22
|
+
return []
|
|
23
|
+
return [
|
|
24
|
+
path
|
|
25
|
+
for path in sorted(target.rglob("*"))
|
|
26
|
+
if path.is_file() and path.suffix != ".pyc"
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def emit_file(path: Path, project_root: Path) -> None:
|
|
31
|
+
relative_path = path.relative_to(project_root).as_posix()
|
|
32
|
+
sys.stdout.write(f"{relative_path}\n")
|
|
33
|
+
with path.open("r", encoding="utf-8", errors="replace") as stream:
|
|
34
|
+
contents = stream.read()
|
|
35
|
+
sys.stdout.write(contents)
|
|
36
|
+
if not contents.endswith("\n"):
|
|
37
|
+
sys.stdout.write("\n")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def main() -> None:
|
|
41
|
+
project_root = Path(__file__).resolve().parent
|
|
42
|
+
prelude_files = [project_root / "README.md", project_root / "ROADMAP.md"]
|
|
43
|
+
postlude_files = [
|
|
44
|
+
project_root / "pyproject.toml",
|
|
45
|
+
project_root / "openai_example.py",
|
|
46
|
+
]
|
|
47
|
+
targets = [project_root / "specs", project_root / "src"]
|
|
48
|
+
|
|
49
|
+
for path in prelude_files:
|
|
50
|
+
if path.exists():
|
|
51
|
+
emit_file(path, project_root)
|
|
52
|
+
|
|
53
|
+
for target in targets:
|
|
54
|
+
for path in iter_project_files(target):
|
|
55
|
+
emit_file(path, project_root)
|
|
56
|
+
|
|
57
|
+
for path in postlude_files:
|
|
58
|
+
if path.exists():
|
|
59
|
+
emit_file(path, project_root)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
main()
|