weakincentives 0.2.0__tar.gz → 0.3.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.

Files changed (165) hide show
  1. weakincentives-0.3.0/.vscode/settings.json +3 -0
  2. weakincentives-0.3.0/CHANGELOG.md +91 -0
  3. {weakincentives-0.2.0 → weakincentives-0.3.0}/Makefile +11 -3
  4. weakincentives-0.3.0/PKG-INFO +231 -0
  5. weakincentives-0.3.0/README.md +200 -0
  6. {weakincentives-0.2.0 → weakincentives-0.3.0}/ROADMAP.md +4 -16
  7. {weakincentives-0.2.0 → weakincentives-0.3.0}/concat_all.py +1 -0
  8. weakincentives-0.3.0/docs/api/weakincentives/tools/planning.md +90 -0
  9. weakincentives-0.3.0/integration-tests/test_litellm_adapter_integration.py +224 -0
  10. weakincentives-0.3.0/integration-tests/test_openai_adapter_integration.py +288 -0
  11. weakincentives-0.3.0/litellm_example.py +58 -0
  12. weakincentives-0.3.0/openai_example.py +49 -0
  13. {weakincentives-0.2.0 → weakincentives-0.3.0}/pyproject.toml +21 -2
  14. {weakincentives-0.2.0 → weakincentives-0.3.0}/specs/ADAPTERS.md +21 -25
  15. weakincentives-0.3.0/specs/EVENTS.md +69 -0
  16. weakincentives-0.3.0/specs/LITE_LLM_ADAPTER.md +56 -0
  17. weakincentives-0.3.0/specs/NATIVE_OPENAI_STRUCTURED_OUTPUTS.md +51 -0
  18. weakincentives-0.3.0/specs/PLANNING_TOOL.md +196 -0
  19. {weakincentives-0.2.0 → weakincentives-0.3.0}/specs/PROMPTS.md +61 -27
  20. weakincentives-0.3.0/specs/PROMPTS_VERSIONING.md +222 -0
  21. weakincentives-0.3.0/specs/SESSIONS.md +147 -0
  22. {weakincentives-0.2.0 → weakincentives-0.3.0}/specs/STRUCTURED_OUTPUT.md +17 -13
  23. {weakincentives-0.2.0 → weakincentives-0.3.0}/specs/TOOLS.md +11 -11
  24. weakincentives-0.3.0/specs/TOOL_AWARE_PROMPT_VERSIONING.md +104 -0
  25. weakincentives-0.3.0/specs/VFS_TOOLS.md +228 -0
  26. weakincentives-0.3.0/src/weakincentives/__init__.py +39 -0
  27. {weakincentives-0.2.0 → weakincentives-0.3.0}/src/weakincentives/adapters/__init__.py +6 -5
  28. {weakincentives-0.2.0 → weakincentives-0.3.0}/src/weakincentives/adapters/core.py +7 -17
  29. weakincentives-0.3.0/src/weakincentives/adapters/litellm.py +594 -0
  30. weakincentives-0.3.0/src/weakincentives/adapters/openai.py +590 -0
  31. weakincentives-0.3.0/src/weakincentives/events.py +103 -0
  32. weakincentives-0.3.0/src/weakincentives/examples/__init__.py +67 -0
  33. weakincentives-0.3.0/src/weakincentives/examples/code_review_prompt.py +118 -0
  34. weakincentives-0.3.0/src/weakincentives/examples/code_review_session.py +171 -0
  35. weakincentives-0.3.0/src/weakincentives/examples/code_review_tools.py +376 -0
  36. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/__init__.py +6 -8
  37. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/_types.py +1 -1
  38. weakincentives-0.2.0/src/weakincentives/prompts/text.py → weakincentives-0.3.0/src/weakincentives/prompt/markdown.py +19 -9
  39. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/prompt.py +216 -66
  40. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/response_format.py +9 -6
  41. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/section.py +25 -4
  42. weakincentives-0.2.0/src/weakincentives/prompts/structured.py → weakincentives-0.3.0/src/weakincentives/prompt/structured_output.py +16 -5
  43. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/tool.py +6 -6
  44. weakincentives-0.3.0/src/weakincentives/prompt/versioning.py +144 -0
  45. weakincentives-0.3.0/src/weakincentives/serde/__init__.py +17 -0
  46. {weakincentives-0.2.0 → weakincentives-0.3.0}/src/weakincentives/serde/dataclass_serde.py +3 -17
  47. weakincentives-0.3.0/src/weakincentives/session/__init__.py +31 -0
  48. weakincentives-0.3.0/src/weakincentives/session/reducers.py +60 -0
  49. weakincentives-0.3.0/src/weakincentives/session/selectors.py +45 -0
  50. weakincentives-0.3.0/src/weakincentives/session/session.py +168 -0
  51. weakincentives-0.3.0/src/weakincentives/tools/__init__.py +69 -0
  52. weakincentives-0.3.0/src/weakincentives/tools/errors.py +22 -0
  53. weakincentives-0.3.0/src/weakincentives/tools/planning.py +538 -0
  54. weakincentives-0.3.0/src/weakincentives/tools/vfs.py +590 -0
  55. weakincentives-0.3.0/test-repositories/sunfish/.github/workflows/python-app.yml +37 -0
  56. weakincentives-0.3.0/test-repositories/sunfish/.gitignore +59 -0
  57. weakincentives-0.3.0/test-repositories/sunfish/LICENSE.md +596 -0
  58. weakincentives-0.3.0/test-repositories/sunfish/README.md +123 -0
  59. weakincentives-0.3.0/test-repositories/sunfish/docs/logo/sunfish_large.png +0 -0
  60. weakincentives-0.3.0/test-repositories/sunfish/docs/logo/sunfish_small.bmp +0 -0
  61. weakincentives-0.3.0/test-repositories/sunfish/docs/sunfish.6 +75 -0
  62. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/color.pickle +0 -0
  63. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/color2.pickle +0 -0
  64. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/color2_v2.pickle +0 -0
  65. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/color2_v3.pickle +0 -0
  66. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model.pickle +0 -0
  67. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model_19.pickle +0 -0
  68. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model_39.pickle +0 -0
  69. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model_59.pickle +0 -0
  70. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model_79.pickle +0 -0
  71. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/model_99.pickle +0 -0
  72. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/nnue1.pickle +0 -0
  73. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/tanh.pickle +0 -0
  74. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/tanh2.pickle +0 -0
  75. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/tanh_139.pickle +0 -0
  76. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/tanh_199.pickle +0 -0
  77. weakincentives-0.3.0/test-repositories/sunfish/nnue/models/tanh_79.pickle +0 -0
  78. weakincentives-0.3.0/test-repositories/sunfish/nnue/nnue_bug_fens +1 -0
  79. weakincentives-0.3.0/test-repositories/sunfish/nnue/speed_tests.py +97 -0
  80. weakincentives-0.3.0/test-repositories/sunfish/nnue/sunfish2.py +543 -0
  81. weakincentives-0.3.0/test-repositories/sunfish/nnue/sunfish_king.py +439 -0
  82. weakincentives-0.3.0/test-repositories/sunfish/sunfish.py +500 -0
  83. weakincentives-0.3.0/test-repositories/sunfish/sunfish_nnue.py +719 -0
  84. weakincentives-0.3.0/test-repositories/sunfish/tools/clean_draws.py +19 -0
  85. weakincentives-0.3.0/test-repositories/sunfish/tools/fancy.py +286 -0
  86. weakincentives-0.3.0/test-repositories/sunfish/tools/quick_tests.sh +53 -0
  87. weakincentives-0.3.0/test-repositories/sunfish/tools/test.sh +20 -0
  88. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/3fold.epd +4 -0
  89. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/3fold.pgn +36148 -0
  90. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/3fold_do.pgn +9397 -0
  91. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/3fold_dont.pgn +4222 -0
  92. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/avoid_mate.epd +1 -0
  93. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/bratko_kopec_test.epd +24 -0
  94. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/ccr_one_hour_test.epd +25 -0
  95. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/chessathome_openings.fen +4000 -0
  96. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/gaviota-starters.pgn +33009 -0
  97. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/mate1.fen +8 -0
  98. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/mate2.fen +212 -0
  99. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/mate3.fen +14 -0
  100. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/mate4.fen +47 -0
  101. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/nullmove_mates.fen +1 -0
  102. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/perft.epd +127 -0
  103. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/pgns.pgn +278 -0
  104. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/queen.fen +132 -0
  105. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/stalemate0.fen +4 -0
  106. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/stalemate1.fen +4 -0
  107. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/stalemate2.fen +130 -0
  108. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/unstable1 +1 -0
  109. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/unstable_positions +218 -0
  110. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/unstable_positions2 +24 -0
  111. weakincentives-0.3.0/test-repositories/sunfish/tools/test_files/win_at_chess_test.epd +300 -0
  112. weakincentives-0.3.0/test-repositories/sunfish/tools/tester.py +461 -0
  113. weakincentives-0.3.0/test-repositories/sunfish/tools/uci.py +345 -0
  114. {weakincentives-0.2.0/src/weakincentives → weakincentives-0.3.0/tests}/__init__.py +1 -3
  115. weakincentives-0.3.0/tests/adapters/_test_stubs.py +181 -0
  116. weakincentives-0.3.0/tests/adapters/test_litellm_adapter.py +1262 -0
  117. weakincentives-0.3.0/tests/adapters/test_openai_adapter.py +1220 -0
  118. weakincentives-0.3.0/tests/examples/test_code_review_prompt.py +27 -0
  119. weakincentives-0.3.0/tests/examples/test_code_review_session.py +114 -0
  120. weakincentives-0.3.0/tests/examples/test_code_review_tools.py +143 -0
  121. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_exceptions.py +2 -2
  122. weakincentives-0.3.0/tests/prompts/test_planning_section.py +43 -0
  123. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_edge_cases.py +66 -32
  124. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_init.py +83 -37
  125. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_integration.py +19 -16
  126. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_render.py +48 -27
  127. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_tools.py +67 -35
  128. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_prompt_tools_integration.py +15 -8
  129. weakincentives-0.3.0/tests/prompts/test_prompt_versioning.py +288 -0
  130. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_section_base.py +24 -5
  131. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_section_tools.py +20 -9
  132. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_structured_output.py +144 -44
  133. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_text_section.py +13 -9
  134. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_tool_dataclass.py +12 -12
  135. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/prompts/test_typing_specializations.py +3 -3
  136. weakincentives-0.3.0/tests/test_events.py +135 -0
  137. weakincentives-0.3.0/tests/test_session.py +234 -0
  138. weakincentives-0.3.0/tests/tools/__init__.py +12 -0
  139. weakincentives-0.3.0/tests/tools/test_planning_end_to_end.py +131 -0
  140. weakincentives-0.3.0/tests/tools/test_planning_tools.py +517 -0
  141. weakincentives-0.3.0/tests/tools/test_vfs_tools.py +868 -0
  142. weakincentives-0.3.0/uv.lock +2063 -0
  143. weakincentives-0.2.0/CHANGELOG.md +0 -29
  144. weakincentives-0.2.0/PKG-INFO +0 -173
  145. weakincentives-0.2.0/README.md +0 -146
  146. weakincentives-0.2.0/openai_example.py +0 -278
  147. weakincentives-0.2.0/src/weakincentives/adapters/openai.py +0 -361
  148. weakincentives-0.2.0/src/weakincentives/serde/__init__.py +0 -31
  149. weakincentives-0.2.0/tests/adapters/test_openai_adapter.py +0 -717
  150. weakincentives-0.2.0/tests/test_openai_example.py +0 -158
  151. weakincentives-0.2.0/uv.lock +0 -865
  152. {weakincentives-0.2.0 → weakincentives-0.3.0}/.github/workflows/ci.yml +0 -0
  153. {weakincentives-0.2.0 → weakincentives-0.3.0}/.github/workflows/release.yml +0 -0
  154. {weakincentives-0.2.0 → weakincentives-0.3.0}/.gitignore +0 -0
  155. {weakincentives-0.2.0 → weakincentives-0.3.0}/.python-version +0 -0
  156. {weakincentives-0.2.0 → weakincentives-0.3.0}/AGENTS.md +0 -0
  157. {weakincentives-0.2.0 → weakincentives-0.3.0}/LICENSE +0 -0
  158. {weakincentives-0.2.0 → weakincentives-0.3.0}/WARP.md +0 -0
  159. {weakincentives-0.2.0 → weakincentives-0.3.0}/hooks/pre-commit +0 -0
  160. {weakincentives-0.2.0 → weakincentives-0.3.0}/install-hooks.sh +0 -0
  161. {weakincentives-0.2.0 → weakincentives-0.3.0}/specs/DATACLASS_SERDE.md +0 -0
  162. {weakincentives-0.2.0/src/weakincentives/prompts → weakincentives-0.3.0/src/weakincentives/prompt}/errors.py +0 -0
  163. {weakincentives-0.2.0 → weakincentives-0.3.0}/src/weakincentives/py.typed +0 -0
  164. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/serde/test_dataclass_serde.py +0 -0
  165. {weakincentives-0.2.0 → weakincentives-0.3.0}/tests/test_example.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ "makefile.configureOnOpen": false
3
+ }
@@ -0,0 +1,91 @@
1
+ # Changelog
2
+
3
+ Release highlights for weakincentives.
4
+
5
+ ## Unreleased
6
+
7
+ - No changes yet.
8
+
9
+ ## v0.3.0 - 2025-11-01
10
+
11
+ ### Prompt & Rendering
12
+
13
+ - Renamed and reorganized the prompt authoring primitives (`MarkdownSection`,
14
+ `SectionNode`, `Tool`, `ToolResult`, `parse_structured_output`, …) under the
15
+ consolidated `weakincentives.prompt` surface.
16
+ - Prompts now require namespaces and explicit section keys so overrides line up with
17
+ rendered content and structured response formats.
18
+ - Added tool-aware prompt version metadata and the `PromptVersionStore` override
19
+ workflow to track section edits and tool changes across revisions.
20
+
21
+ ### Session & State
22
+
23
+ - Introduced the `Session` container with typed reducers/selectors that capture prompt
24
+ outputs and tool payloads directly from emitted events.
25
+ - Added helper reducers (`append`, `replace_latest`, `upsert_by`) and selectors
26
+ (`select_latest`, `select_where`) to simplify downstream state management.
27
+
28
+ ### Built-in Tools
29
+
30
+ - Shipped the planning tool suite (`PlanningToolsSection` plus typed plan dataclasses)
31
+ for creating, updating, and tracking multi-step execution plans inside a session.
32
+ - Added the virtual filesystem tool suite (`VfsToolsSection`) with host-mount
33
+ materialization, ASCII write limits, and reducers that maintain a versioned snapshot.
34
+
35
+ ### Events & Telemetry
36
+
37
+ - Implemented the event bus with `ToolInvoked` and `PromptExecuted` payloads and wired
38
+ adapters/examples to publish them for sessions or external observers.
39
+
40
+ ### Adapters
41
+
42
+ - Added a LiteLLM adapter behind the `litellm` extra with tool execution parity and
43
+ structured output parsing.
44
+ - Updated the OpenAI adapter to emit native JSON schema response formats, tighten
45
+ `tool_choice` handling, avoid echoing tool payloads, and surface richer telemetry.
46
+
47
+ ### Examples
48
+
49
+ - Rebuilt the OpenAI and LiteLLM demos as shared CLI entry points powered by the new
50
+ code review agent scaffold, complete with planning and virtual filesystem sections.
51
+
52
+ ### Tooling & Packaging
53
+
54
+ - Lowered the supported Python baseline to 3.12 (the repository now pins 3.14 for
55
+ development) and curated package exports to match the reorganized modules.
56
+ - Added OpenAI integration tests and stabilized the tool execution loop used by the
57
+ adapters.
58
+ - Raised the optional `litellm` extra to require the latest upstream release.
59
+
60
+ ### Documentation
61
+
62
+ - Documented the planning and virtual filesystem tool suites, optional provider extras,
63
+ and updated installation guidance.
64
+ - Refreshed the README and supporting docs to highlight the new prompt workflow,
65
+ adapters, and development tooling expectations.
66
+
67
+ ## v0.2.0 - 2025-10-29
68
+
69
+ ### Highlights
70
+
71
+ - Launched the prompt composition system with typed `Prompt`, `Section`, and `TextSection` building blocks, structured rendering, and placeholder validation backed by comprehensive tests.
72
+ - Added tool orchestration primitives including the `Tool` dataclass, shared dataclass handling, duplicate detection, and prompt-level aggregation utilities.
73
+ - Delivered stdlib-only dataclass serde helpers (`parse`, `dump`, `clone`, `schema`) for lightweight validation and JSON serialization.
74
+
75
+ ### Integrations
76
+
77
+ - Introduced an optional OpenAI adapter behind the `openai` extra that builds configured clients and provides friendly guidance when the dependency is missing.
78
+
79
+ ### Developer Experience
80
+
81
+ - Tightened the quality gate with quiet wrappers for Ruff, Ty, pytest (100% coverage), Bandit, Deptry, and pip-audit, all wired through `make check`.
82
+ - Adopted Hatch VCS versioning, refreshed `pyproject.toml` metadata, and standardized automation scripts for releases.
83
+
84
+ ### Documentation
85
+
86
+ - Replaced `WARP.md` with a comprehensive `AGENTS.md` handbook describing workflows, TDD guidance, and integration expectations.
87
+ - Added prompt and tool specifications under `specs/` and refreshed the README to highlight the new primitives and developer tooling.
88
+
89
+ ## v0.1.0 - 2025-10-22
90
+
91
+ Initial repository bootstrap with the package scaffold, testing and linting toolchain, CI configuration, and contributor documentation.
@@ -1,4 +1,4 @@
1
- .PHONY: format check test lint typecheck bandit deptry pip-audit markdown-check all clean
1
+ .PHONY: format check test lint typecheck bandit deptry pip-audit markdown-check integration-tests all clean
2
2
 
3
3
  # Format code with ruff
4
4
  format:
@@ -34,9 +34,9 @@ markdown-check:
34
34
 
35
35
  # Run type checkers
36
36
  typecheck:
37
- @uv run --all-extras ty check --error-on-warning -qq . || \
37
+ @uv run --all-extras ty check --error-on-warning -qq --exclude 'test-repositories/**' . || \
38
38
  (echo "ty check failed; rerunning with verbose output..." >&2; \
39
- uv run --all-extras ty check --error-on-warning .)
39
+ uv run --all-extras ty check --error-on-warning --exclude 'test-repositories/**' .)
40
40
  @uv run --all-extras pyright --project pyproject.toml || \
41
41
  (echo "pyright failed; rerunning with verbose output..." >&2; \
42
42
  uv run --all-extras pyright --project pyproject.toml --verbose)
@@ -45,6 +45,14 @@ typecheck:
45
45
  test:
46
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
47
 
48
+ # Run OpenAI integration tests
49
+ integration-tests:
50
+ @if [ -z "$$OPENAI_API_KEY" ]; then \
51
+ echo "OPENAI_API_KEY is not set; export it to run integration tests." >&2; \
52
+ exit 1; \
53
+ fi
54
+ @uv run --all-extras pytest --no-cov --strict-config --strict-markers -vv --maxfail=1 integration-tests
55
+
48
56
  # Run all checks (format check, lint, typecheck, bandit, deptry, pip-audit, markdown, test)
49
57
  check: format-check lint typecheck bandit deptry pip-audit markdown-check test
50
58
 
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: weakincentives
3
+ Version: 0.3.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.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.12
26
+ Provides-Extra: litellm
27
+ Requires-Dist: litellm>=1.79.0; extra == 'litellm'
28
+ Provides-Extra: openai
29
+ Requires-Dist: openai>=2.6.1; extra == 'openai'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Weak Incentives
33
+
34
+ **Lean, typed building blocks for side-effect-free background agents.**
35
+ Compose deterministic prompts, run typed tools, and parse strict JSON replies without
36
+ heavy dependencies. Optional adapters snap in when you need a model provider.
37
+
38
+ ## Highlights
39
+
40
+ - Namespaced prompt trees with deterministic Markdown renders, placeholder
41
+ verification, and tool-aware versioning metadata.
42
+ - Stdlib-only dataclass serde (`parse`, `dump`, `clone`, `schema`) keeps request and
43
+ response types honest end-to-end.
44
+ - Session state container and event bus collect prompt and tool telemetry for
45
+ downstream automation.
46
+ - Built-in planning and virtual filesystem tool suites give agents durable plans and
47
+ sandboxed edits backed by reducers and selectors.
48
+ - Optional OpenAI and LiteLLM adapters integrate structured output parsing, tool
49
+ orchestration, and telemetry hooks.
50
+
51
+ ## Requirements
52
+
53
+ - Python 3.12+ (the repository pins 3.14 in `.python-version` for development)
54
+ - [`uv`](https://github.com/astral-sh/uv) CLI
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ uv add weakincentives
60
+ # optional provider adapters
61
+ uv add "weakincentives[openai]"
62
+ uv add "weakincentives[litellm]"
63
+ # cloning the repo? use: uv sync --extra openai --extra litellm
64
+ ```
65
+
66
+ ## Quickstart
67
+
68
+ ````python
69
+ from dataclasses import dataclass
70
+ from weakincentives import (
71
+ MarkdownSection,
72
+ Prompt,
73
+ Tool,
74
+ ToolResult,
75
+ parse_structured_output,
76
+ )
77
+
78
+ @dataclass
79
+ class ResearchGuidance:
80
+ topic: str
81
+
82
+ @dataclass
83
+ class SourceLookup:
84
+ source_id: str
85
+
86
+ @dataclass
87
+ class SourceDetails:
88
+ source_id: str
89
+ title: str
90
+
91
+ @dataclass
92
+ class ResearchSummary:
93
+ summary: str
94
+ citations: list[str]
95
+
96
+ def lookup_source(params: SourceLookup) -> ToolResult[SourceDetails]:
97
+ details = SourceDetails(source_id=params.source_id, title="Ada Lovelace Archive")
98
+ return ToolResult(message=f"Loaded {details.title}", value=details)
99
+
100
+ catalog_tool = Tool[SourceLookup, SourceDetails](
101
+ name="catalog_lookup",
102
+ description="Look up a primary source identifier and return details.",
103
+ handler=lookup_source,
104
+ )
105
+
106
+ task_section = MarkdownSection[ResearchGuidance](
107
+ title="Task",
108
+ template=(
109
+ "Research ${topic}. Use `catalog_lookup` for citations and reply with a "
110
+ "JSON summary."
111
+ ),
112
+ key="research.task",
113
+ tools=[catalog_tool],
114
+ )
115
+
116
+ prompt = Prompt[ResearchSummary](
117
+ ns="examples/research",
118
+ key="research.run",
119
+ name="research_prompt",
120
+ sections=[task_section],
121
+ )
122
+
123
+ rendered = prompt.render(ResearchGuidance(topic="Ada Lovelace"))
124
+ print(rendered.text)
125
+ print([tool.name for tool in rendered.tools])
126
+
127
+ reply = """```json
128
+ {
129
+ "summary": "Ada Lovelace pioneered computing...",
130
+ "citations": ["catalog_lookup:ada-archive"]
131
+ }
132
+ ```"""
133
+ result = parse_structured_output(reply, rendered)
134
+ print(result.summary)
135
+ print(result.citations)
136
+ ````
137
+
138
+ The rendered prompt text stays deterministic, tool metadata travels with the prompt,
139
+ and `parse_structured_output` enforces your dataclass contract.
140
+
141
+ ## Sessions and Built-in Tools
142
+
143
+ Session state turns prompt output and tool calls into durable data. Built-in planning
144
+ and virtual filesystem sections register reducers on the provided session.
145
+
146
+ ```python
147
+ from weakincentives.session import Session, select_latest
148
+ from weakincentives.tools import (
149
+ PlanningToolsSection,
150
+ Plan,
151
+ VfsToolsSection,
152
+ VirtualFileSystem,
153
+ )
154
+
155
+ session = Session()
156
+ planning_section = PlanningToolsSection(session=session)
157
+ vfs_section = VfsToolsSection(session=session)
158
+
159
+ prompt = Prompt[ResearchSummary](
160
+ ns="examples/research",
161
+ key="research.session",
162
+ sections=[task_section, planning_section, vfs_section],
163
+ )
164
+
165
+ active_plan = select_latest(session, Plan)
166
+ vfs_snapshot = select_latest(session, VirtualFileSystem)
167
+ ```
168
+
169
+ Use `session.select_all(...)` or the helpers in `weakincentives.session` to drive UI
170
+ state, persistence, or audits after each adapter run.
171
+
172
+ ## Adapter Integrations
173
+
174
+ Adapters stay optional and only load their dependencies when you import them.
175
+
176
+ ```python
177
+ from weakincentives.adapters.openai import OpenAIAdapter
178
+ from weakincentives.events import InProcessEventBus
179
+ from weakincentives.session import Session
180
+ from weakincentives.tools import Plan
181
+
182
+ bus = InProcessEventBus()
183
+ session = Session(bus=bus)
184
+
185
+ adapter = OpenAIAdapter(
186
+ model="gpt-4o-mini",
187
+ client_kwargs={"api_key": "sk-..."},
188
+ )
189
+
190
+ response = adapter.evaluate(
191
+ prompt,
192
+ ResearchGuidance(topic="Ada Lovelace"),
193
+ bus=bus,
194
+ )
195
+
196
+ plan_history = session.select_all(Plan)
197
+ ```
198
+
199
+ `InProcessEventBus` publishes `ToolInvoked` and `PromptExecuted` events for the
200
+ session (or any other subscriber) to consume.
201
+
202
+ ## Development Setup
203
+
204
+ 1. Install Python 3.14 (for example with `pyenv install 3.14.0`).
205
+
206
+ 1. Install `uv`, then bootstrap the environment and hooks:
207
+
208
+ ```bash
209
+ uv sync
210
+ ./install-hooks.sh
211
+ ```
212
+
213
+ 1. Run checks with `uv run` so everything shares the managed virtualenv:
214
+
215
+ - `make format` / `make format-check`
216
+ - `make lint` / `make lint-fix`
217
+ - `make typecheck` (Ty + Pyright, warnings fail the build)
218
+ - `make test` (pytest via `build/run_pytest.py`, 100% coverage enforced)
219
+ - `make check` (aggregates the quiet checks above plus Bandit, Deptry, pip-audit,
220
+ and markdown linting)
221
+
222
+ ## Documentation
223
+
224
+ - `AGENTS.md` — operational handbook and contributor workflow.
225
+ - `specs/` — design docs for prompts, planning tools, and adapters.
226
+ - `ROADMAP.md` — upcoming feature sketches.
227
+ - `docs/api/` — API reference material.
228
+
229
+ ## License
230
+
231
+ Apache 2.0 • Status: Alpha (APIs may change between releases)
@@ -0,0 +1,200 @@
1
+ # Weak Incentives
2
+
3
+ **Lean, typed building blocks for side-effect-free background agents.**
4
+ Compose deterministic prompts, run typed tools, and parse strict JSON replies without
5
+ heavy dependencies. Optional adapters snap in when you need a model provider.
6
+
7
+ ## Highlights
8
+
9
+ - Namespaced prompt trees with deterministic Markdown renders, placeholder
10
+ verification, and tool-aware versioning metadata.
11
+ - Stdlib-only dataclass serde (`parse`, `dump`, `clone`, `schema`) keeps request and
12
+ response types honest end-to-end.
13
+ - Session state container and event bus collect prompt and tool telemetry for
14
+ downstream automation.
15
+ - Built-in planning and virtual filesystem tool suites give agents durable plans and
16
+ sandboxed edits backed by reducers and selectors.
17
+ - Optional OpenAI and LiteLLM adapters integrate structured output parsing, tool
18
+ orchestration, and telemetry hooks.
19
+
20
+ ## Requirements
21
+
22
+ - Python 3.12+ (the repository pins 3.14 in `.python-version` for development)
23
+ - [`uv`](https://github.com/astral-sh/uv) CLI
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ uv add weakincentives
29
+ # optional provider adapters
30
+ uv add "weakincentives[openai]"
31
+ uv add "weakincentives[litellm]"
32
+ # cloning the repo? use: uv sync --extra openai --extra litellm
33
+ ```
34
+
35
+ ## Quickstart
36
+
37
+ ````python
38
+ from dataclasses import dataclass
39
+ from weakincentives import (
40
+ MarkdownSection,
41
+ Prompt,
42
+ Tool,
43
+ ToolResult,
44
+ parse_structured_output,
45
+ )
46
+
47
+ @dataclass
48
+ class ResearchGuidance:
49
+ topic: str
50
+
51
+ @dataclass
52
+ class SourceLookup:
53
+ source_id: str
54
+
55
+ @dataclass
56
+ class SourceDetails:
57
+ source_id: str
58
+ title: str
59
+
60
+ @dataclass
61
+ class ResearchSummary:
62
+ summary: str
63
+ citations: list[str]
64
+
65
+ def lookup_source(params: SourceLookup) -> ToolResult[SourceDetails]:
66
+ details = SourceDetails(source_id=params.source_id, title="Ada Lovelace Archive")
67
+ return ToolResult(message=f"Loaded {details.title}", value=details)
68
+
69
+ catalog_tool = Tool[SourceLookup, SourceDetails](
70
+ name="catalog_lookup",
71
+ description="Look up a primary source identifier and return details.",
72
+ handler=lookup_source,
73
+ )
74
+
75
+ task_section = MarkdownSection[ResearchGuidance](
76
+ title="Task",
77
+ template=(
78
+ "Research ${topic}. Use `catalog_lookup` for citations and reply with a "
79
+ "JSON summary."
80
+ ),
81
+ key="research.task",
82
+ tools=[catalog_tool],
83
+ )
84
+
85
+ prompt = Prompt[ResearchSummary](
86
+ ns="examples/research",
87
+ key="research.run",
88
+ name="research_prompt",
89
+ sections=[task_section],
90
+ )
91
+
92
+ rendered = prompt.render(ResearchGuidance(topic="Ada Lovelace"))
93
+ print(rendered.text)
94
+ print([tool.name for tool in rendered.tools])
95
+
96
+ reply = """```json
97
+ {
98
+ "summary": "Ada Lovelace pioneered computing...",
99
+ "citations": ["catalog_lookup:ada-archive"]
100
+ }
101
+ ```"""
102
+ result = parse_structured_output(reply, rendered)
103
+ print(result.summary)
104
+ print(result.citations)
105
+ ````
106
+
107
+ The rendered prompt text stays deterministic, tool metadata travels with the prompt,
108
+ and `parse_structured_output` enforces your dataclass contract.
109
+
110
+ ## Sessions and Built-in Tools
111
+
112
+ Session state turns prompt output and tool calls into durable data. Built-in planning
113
+ and virtual filesystem sections register reducers on the provided session.
114
+
115
+ ```python
116
+ from weakincentives.session import Session, select_latest
117
+ from weakincentives.tools import (
118
+ PlanningToolsSection,
119
+ Plan,
120
+ VfsToolsSection,
121
+ VirtualFileSystem,
122
+ )
123
+
124
+ session = Session()
125
+ planning_section = PlanningToolsSection(session=session)
126
+ vfs_section = VfsToolsSection(session=session)
127
+
128
+ prompt = Prompt[ResearchSummary](
129
+ ns="examples/research",
130
+ key="research.session",
131
+ sections=[task_section, planning_section, vfs_section],
132
+ )
133
+
134
+ active_plan = select_latest(session, Plan)
135
+ vfs_snapshot = select_latest(session, VirtualFileSystem)
136
+ ```
137
+
138
+ Use `session.select_all(...)` or the helpers in `weakincentives.session` to drive UI
139
+ state, persistence, or audits after each adapter run.
140
+
141
+ ## Adapter Integrations
142
+
143
+ Adapters stay optional and only load their dependencies when you import them.
144
+
145
+ ```python
146
+ from weakincentives.adapters.openai import OpenAIAdapter
147
+ from weakincentives.events import InProcessEventBus
148
+ from weakincentives.session import Session
149
+ from weakincentives.tools import Plan
150
+
151
+ bus = InProcessEventBus()
152
+ session = Session(bus=bus)
153
+
154
+ adapter = OpenAIAdapter(
155
+ model="gpt-4o-mini",
156
+ client_kwargs={"api_key": "sk-..."},
157
+ )
158
+
159
+ response = adapter.evaluate(
160
+ prompt,
161
+ ResearchGuidance(topic="Ada Lovelace"),
162
+ bus=bus,
163
+ )
164
+
165
+ plan_history = session.select_all(Plan)
166
+ ```
167
+
168
+ `InProcessEventBus` publishes `ToolInvoked` and `PromptExecuted` events for the
169
+ session (or any other subscriber) to consume.
170
+
171
+ ## Development Setup
172
+
173
+ 1. Install Python 3.14 (for example with `pyenv install 3.14.0`).
174
+
175
+ 1. Install `uv`, then bootstrap the environment and hooks:
176
+
177
+ ```bash
178
+ uv sync
179
+ ./install-hooks.sh
180
+ ```
181
+
182
+ 1. Run checks with `uv run` so everything shares the managed virtualenv:
183
+
184
+ - `make format` / `make format-check`
185
+ - `make lint` / `make lint-fix`
186
+ - `make typecheck` (Ty + Pyright, warnings fail the build)
187
+ - `make test` (pytest via `build/run_pytest.py`, 100% coverage enforced)
188
+ - `make check` (aggregates the quiet checks above plus Bandit, Deptry, pip-audit,
189
+ and markdown linting)
190
+
191
+ ## Documentation
192
+
193
+ - `AGENTS.md` — operational handbook and contributor workflow.
194
+ - `specs/` — design docs for prompts, planning tools, and adapters.
195
+ - `ROADMAP.md` — upcoming feature sketches.
196
+ - `docs/api/` — API reference material.
197
+
198
+ ## License
199
+
200
+ Apache 2.0 • Status: Alpha (APIs may change between releases)
@@ -2,17 +2,11 @@
2
2
 
3
3
  ## Near-Term Initiatives
4
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
5
+ ### Built-In Planning & Virtual Filesystem Tools
12
6
 
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.
7
+ - Provide first-class tool definitions for planning/todo workflows and virtual filesystem operations for agents.
8
+ - Establish section templates that ensure tools render consistently in prompts and downstream telemetry.
9
+ - Ship representative examples and regression tests demonstrating safe defaults and extensibility points.
16
10
 
17
11
  ### Single Turn Prompt Optimizations
18
12
 
@@ -26,12 +20,6 @@
26
20
  - Preserve, normalize, or obfuscate entities in outputs according to privacy and compliance guidelines.
27
21
  - Validate the pipeline with targeted tests that cover multilingual and domain-specific vocabularies.
28
22
 
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
23
  ### Sandboxed Code Execution
36
24
 
37
25
  - Provide hardened sandboxes so agents can run generated code with strict CPU, memory, filesystem, and network guardrails.
@@ -43,6 +43,7 @@ def main() -> None:
43
43
  postlude_files = [
44
44
  project_root / "pyproject.toml",
45
45
  project_root / "openai_example.py",
46
+ project_root / "litellm_example.py",
46
47
  ]
47
48
  targets = [project_root / "specs", project_root / "src"]
48
49
 
@@ -0,0 +1,90 @@
1
+ # `weakincentives.tools.planning`
2
+
3
+ Session-scoped planning helpers for agents that need a lightweight task list.
4
+ These APIs are transient and scoped to a single `Session` instance.
5
+
6
+ ## Data classes
7
+
8
+ ### `Plan`
9
+
10
+ Tracks the current objective, overall status (`"active"`, `"completed"`, or
11
+ `"abandoned"`), and an ordered collection of `PlanStep` entries.
12
+
13
+ ### `PlanStep`
14
+
15
+ Immutable representation of an individual plan step. Includes a stable
16
+ `step_id`, a short title, optional details, current `StepStatus`, and recorded
17
+ notes.
18
+
19
+ ### `NewPlanStep`
20
+
21
+ Input payload used when creating or appending steps before they receive a
22
+ `step_id`.
23
+
24
+ ### `SetupPlan`
25
+
26
+ Parameters for `planning_setup_plan`. Captures the plan objective and optional
27
+ initial steps.
28
+
29
+ ### `AddStep`
30
+
31
+ Parameters for `planning_add_step`. Contains one or more `NewPlanStep`
32
+ instances to append to the active plan.
33
+
34
+ ### `UpdateStep`
35
+
36
+ Parameters for `planning_update_step`. Identifies an existing step and provides
37
+ updated title and/or details.
38
+
39
+ ### `MarkStep`
40
+
41
+ Parameters for `planning_mark_step`. Identifies an existing step, sets a new
42
+ status, and optionally appends a note.
43
+
44
+ ### `ClearPlan`
45
+
46
+ Parameters for `planning_clear_plan`. Signals that the current plan should be
47
+ marked as abandoned and cleared.
48
+
49
+ ### `ReadPlan`
50
+
51
+ Parameters for `planning_read_plan`. Requests the latest plan snapshot from the
52
+ session store.
53
+
54
+ ## Tools
55
+
56
+ ### `planning_setup_plan(params: SetupPlan) -> SetupPlan`
57
+
58
+ Validate and persist a new plan. Replaces any existing plan and seeds step
59
+ identifiers starting at `S001`.
60
+
61
+ ### `planning_add_step(params: AddStep) -> AddStep`
62
+
63
+ Validate appended steps and queue them for persistence. Requires an active
64
+ plan.
65
+
66
+ ### `planning_update_step(params: UpdateStep) -> UpdateStep`
67
+
68
+ Validate a step edit request and persist title/detail changes for the targeted
69
+ step.
70
+
71
+ ### `planning_mark_step(params: MarkStep) -> MarkStep`
72
+
73
+ Validate a step status change, append optional notes, and toggle the plan's
74
+ completion status when all steps are done.
75
+
76
+ ### `planning_clear_plan(params: ClearPlan) -> ClearPlan`
77
+
78
+ Mark the current plan as abandoned and reset the step list.
79
+
80
+ ### `planning_read_plan(params: ReadPlan) -> Plan`
81
+
82
+ Return the most recent plan snapshot. Raises a validation error when no plan
83
+ has been initialised.
84
+
85
+ ## Prompt integration
86
+
87
+ ### `PlanningToolsSection`
88
+
89
+ Prompt section that registers reducers on the provided `Session`, exposes all
90
+ planning tools, and renders concise usage guidance for the language model.