purrcept-core 0.5.1__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 (139) hide show
  1. purrcept_core-0.5.1/.github/workflows/ci.yml +65 -0
  2. purrcept_core-0.5.1/.github/workflows/publish.yml +76 -0
  3. purrcept_core-0.5.1/.gitignore +13 -0
  4. purrcept_core-0.5.1/AGENTS.md +115 -0
  5. purrcept_core-0.5.1/CHANGELOG.md +158 -0
  6. purrcept_core-0.5.1/CONTRIBUTING.md +221 -0
  7. purrcept_core-0.5.1/PKG-INFO +264 -0
  8. purrcept_core-0.5.1/README.md +246 -0
  9. purrcept_core-0.5.1/README.zh-CN.md +239 -0
  10. purrcept_core-0.5.1/RELEASING.md +40 -0
  11. purrcept_core-0.5.1/adr/0001-core-boundary.md +21 -0
  12. purrcept_core-0.5.1/adr/0002-effect-flow-semantics.md +18 -0
  13. purrcept_core-0.5.1/adr/0003-agent-run-protocol.md +15 -0
  14. purrcept_core-0.5.1/adr/0004-executor-and-context.md +19 -0
  15. purrcept_core-0.5.1/adr/0005-extension-model.md +15 -0
  16. purrcept_core-0.5.1/adr/0006-model-standard-library.md +114 -0
  17. purrcept_core-0.5.1/adr/0007-prompt-control-state.md +101 -0
  18. purrcept_core-0.5.1/assets/readme/architecture.svg +181 -0
  19. purrcept_core-0.5.1/assets/readme/hero.svg +158 -0
  20. purrcept_core-0.5.1/docs/api.md +580 -0
  21. purrcept_core-0.5.1/docs/compatibility.md +267 -0
  22. purrcept_core-0.5.1/docs/concepts.md +57 -0
  23. purrcept_core-0.5.1/docs/effects.md +71 -0
  24. purrcept_core-0.5.1/docs/events.md +62 -0
  25. purrcept_core-0.5.1/docs/executors.md +41 -0
  26. purrcept_core-0.5.1/docs/extension-packages.md +163 -0
  27. purrcept_core-0.5.1/docs/middleware.md +18 -0
  28. purrcept_core-0.5.1/docs/models.md +633 -0
  29. purrcept_core-0.5.1/docs/runtime-boundary.md +42 -0
  30. purrcept_core-0.5.1/docs/testing.md +23 -0
  31. purrcept_core-0.5.1/examples/01_inline_effect.py +44 -0
  32. purrcept_core-0.5.1/examples/02_declarative_effect.py +49 -0
  33. purrcept_core-0.5.1/examples/03_error_recovery.py +55 -0
  34. purrcept_core-0.5.1/examples/04_nested_flow.py +48 -0
  35. purrcept_core-0.5.1/examples/05_progress_events.py +54 -0
  36. purrcept_core-0.5.1/examples/06_model_conversation.py +120 -0
  37. purrcept_core-0.5.1/examples/07_prompt_templates.py +57 -0
  38. purrcept_core-0.5.1/examples/08_prompt_control_state.py +174 -0
  39. purrcept_core-0.5.1/examples/plugin_package/README.md +20 -0
  40. purrcept_core-0.5.1/examples/plugin_package/demo.py +87 -0
  41. purrcept_core-0.5.1/examples/plugin_package/pyproject.toml +13 -0
  42. purrcept_core-0.5.1/examples/plugin_package/src/purrcept_demo_plugin/__init__.py +155 -0
  43. purrcept_core-0.5.1/pyproject.toml +82 -0
  44. purrcept_core-0.5.1/src/purrcept_core/__init__.py +102 -0
  45. purrcept_core-0.5.1/src/purrcept_core/context.py +67 -0
  46. purrcept_core-0.5.1/src/purrcept_core/driver.py +383 -0
  47. purrcept_core-0.5.1/src/purrcept_core/effect.py +27 -0
  48. purrcept_core-0.5.1/src/purrcept_core/errors.py +51 -0
  49. purrcept_core-0.5.1/src/purrcept_core/events.py +254 -0
  50. purrcept_core-0.5.1/src/purrcept_core/executor.py +141 -0
  51. purrcept_core-0.5.1/src/purrcept_core/flow.py +36 -0
  52. purrcept_core-0.5.1/src/purrcept_core/middleware.py +284 -0
  53. purrcept_core-0.5.1/src/purrcept_core/models/__init__.py +226 -0
  54. purrcept_core-0.5.1/src/purrcept_core/models/_utils.py +122 -0
  55. purrcept_core-0.5.1/src/purrcept_core/models/backend.py +59 -0
  56. purrcept_core-0.5.1/src/purrcept_core/models/caching.py +74 -0
  57. purrcept_core-0.5.1/src/purrcept_core/models/conformance.py +703 -0
  58. purrcept_core-0.5.1/src/purrcept_core/models/content.py +175 -0
  59. purrcept_core-0.5.1/src/purrcept_core/models/context_policy.py +367 -0
  60. purrcept_core-0.5.1/src/purrcept_core/models/continuation.py +42 -0
  61. purrcept_core-0.5.1/src/purrcept_core/models/conversation.py +735 -0
  62. purrcept_core-0.5.1/src/purrcept_core/models/effects.py +150 -0
  63. purrcept_core-0.5.1/src/purrcept_core/models/errors.py +95 -0
  64. purrcept_core-0.5.1/src/purrcept_core/models/instructions.py +67 -0
  65. purrcept_core-0.5.1/src/purrcept_core/models/loop.py +318 -0
  66. purrcept_core-0.5.1/src/purrcept_core/models/messages.py +160 -0
  67. purrcept_core-0.5.1/src/purrcept_core/models/model.py +116 -0
  68. purrcept_core-0.5.1/src/purrcept_core/models/prompt/__init__.py +65 -0
  69. purrcept_core-0.5.1/src/purrcept_core/models/prompt/compiler.py +539 -0
  70. purrcept_core-0.5.1/src/purrcept_core/models/prompt/errors.py +86 -0
  71. purrcept_core-0.5.1/src/purrcept_core/models/prompt/library.py +75 -0
  72. purrcept_core-0.5.1/src/purrcept_core/models/prompt/policies.py +174 -0
  73. purrcept_core-0.5.1/src/purrcept_core/models/prompt/template.py +430 -0
  74. purrcept_core-0.5.1/src/purrcept_core/models/prompt/tracing.py +122 -0
  75. purrcept_core-0.5.1/src/purrcept_core/models/reminder_sources.py +136 -0
  76. purrcept_core-0.5.1/src/purrcept_core/models/reminders.py +177 -0
  77. purrcept_core-0.5.1/src/purrcept_core/models/requests.py +188 -0
  78. purrcept_core-0.5.1/src/purrcept_core/models/responses.py +138 -0
  79. purrcept_core-0.5.1/src/purrcept_core/models/settings.py +90 -0
  80. purrcept_core-0.5.1/src/purrcept_core/models/streaming.py +162 -0
  81. purrcept_core-0.5.1/src/purrcept_core/models/tools/__init__.py +35 -0
  82. purrcept_core-0.5.1/src/purrcept_core/models/tools/_documentation.py +146 -0
  83. purrcept_core-0.5.1/src/purrcept_core/models/tools/_encoding.py +156 -0
  84. purrcept_core-0.5.1/src/purrcept_core/models/tools/_schema.py +277 -0
  85. purrcept_core-0.5.1/src/purrcept_core/models/tools/effects.py +57 -0
  86. purrcept_core-0.5.1/src/purrcept_core/models/tools/errors.py +87 -0
  87. purrcept_core-0.5.1/src/purrcept_core/models/tools/function.py +244 -0
  88. purrcept_core-0.5.1/src/purrcept_core/models/tools/toolset.py +104 -0
  89. purrcept_core-0.5.1/src/purrcept_core/models/tools/values.py +189 -0
  90. purrcept_core-0.5.1/src/purrcept_core/py.typed +1 -0
  91. purrcept_core-0.5.1/src/purrcept_core/run.py +202 -0
  92. purrcept_core-0.5.1/src/purrcept_core/testing.py +141 -0
  93. purrcept_core-0.5.1/tests/models/prompt/__init__.py +1 -0
  94. purrcept_core-0.5.1/tests/models/prompt/test_compiler.py +463 -0
  95. purrcept_core-0.5.1/tests/models/prompt/test_errors.py +122 -0
  96. purrcept_core-0.5.1/tests/models/prompt/test_library.py +105 -0
  97. purrcept_core-0.5.1/tests/models/prompt/test_policies.py +120 -0
  98. purrcept_core-0.5.1/tests/models/prompt/test_template.py +342 -0
  99. purrcept_core-0.5.1/tests/models/prompt/test_tracing.py +165 -0
  100. purrcept_core-0.5.1/tests/models/test_backend.py +25 -0
  101. purrcept_core-0.5.1/tests/models/test_caching.py +95 -0
  102. purrcept_core-0.5.1/tests/models/test_conformance.py +654 -0
  103. purrcept_core-0.5.1/tests/models/test_content.py +171 -0
  104. purrcept_core-0.5.1/tests/models/test_context_policy.py +435 -0
  105. purrcept_core-0.5.1/tests/models/test_continuation.py +62 -0
  106. purrcept_core-0.5.1/tests/models/test_conversation.py +627 -0
  107. purrcept_core-0.5.1/tests/models/test_errors.py +106 -0
  108. purrcept_core-0.5.1/tests/models/test_generate_effect.py +381 -0
  109. purrcept_core-0.5.1/tests/models/test_instructions.py +81 -0
  110. purrcept_core-0.5.1/tests/models/test_messages.py +126 -0
  111. purrcept_core-0.5.1/tests/models/test_model.py +127 -0
  112. purrcept_core-0.5.1/tests/models/test_model_loop.py +774 -0
  113. purrcept_core-0.5.1/tests/models/test_models_public_api.py +157 -0
  114. purrcept_core-0.5.1/tests/models/test_reasoning_stream.py +35 -0
  115. purrcept_core-0.5.1/tests/models/test_reminder_sources.py +264 -0
  116. purrcept_core-0.5.1/tests/models/test_reminders.py +226 -0
  117. purrcept_core-0.5.1/tests/models/test_requests_responses.py +425 -0
  118. purrcept_core-0.5.1/tests/models/test_settings.py +113 -0
  119. purrcept_core-0.5.1/tests/models/test_streaming.py +122 -0
  120. purrcept_core-0.5.1/tests/models/tools/__init__.py +1 -0
  121. purrcept_core-0.5.1/tests/models/tools/test_function_schema_and_docs.py +437 -0
  122. purrcept_core-0.5.1/tests/models/tools/test_invocation_and_encoding.py +410 -0
  123. purrcept_core-0.5.1/tests/models/tools/test_toolset_and_public_api.py +141 -0
  124. purrcept_core-0.5.1/tests/models/tools/test_values_and_errors.py +306 -0
  125. purrcept_core-0.5.1/tests/test_context.py +81 -0
  126. purrcept_core-0.5.1/tests/test_dispatch_executor.py +134 -0
  127. purrcept_core-0.5.1/tests/test_driver_cancellation.py +114 -0
  128. purrcept_core-0.5.1/tests/test_driver_errors.py +497 -0
  129. purrcept_core-0.5.1/tests/test_driver_success.py +231 -0
  130. purrcept_core-0.5.1/tests/test_events.py +155 -0
  131. purrcept_core-0.5.1/tests/test_flow.py +105 -0
  132. purrcept_core-0.5.1/tests/test_generator_run.py +204 -0
  133. purrcept_core-0.5.1/tests/test_inline_executor.py +91 -0
  134. purrcept_core-0.5.1/tests/test_middleware.py +409 -0
  135. purrcept_core-0.5.1/tests/test_public_api.py +42 -0
  136. purrcept_core-0.5.1/tests/test_testing_helpers.py +81 -0
  137. purrcept_core-0.5.1/typing_samples/host_protocols.py +152 -0
  138. purrcept_core-0.5.1/typing_samples/perform.py +34 -0
  139. purrcept_core-0.5.1/uv.lock +484 -0
@@ -0,0 +1,65 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ quality:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: astral-sh/setup-uv@v6
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ enable-cache: true
20
+ - run: uv sync --all-groups
21
+ - run: uv run ruff check .
22
+ - run: uv run ruff format --check .
23
+ - run: uv run pyright
24
+ - run: uv run pytest --cov=purrcept_core --cov-report=term-missing
25
+ - name: Run examples
26
+ run: |
27
+ uv run python examples/01_inline_effect.py
28
+ uv run python examples/02_declarative_effect.py
29
+ uv run python examples/03_error_recovery.py
30
+ uv run python examples/04_nested_flow.py
31
+ uv run python examples/05_progress_events.py
32
+ uv run python examples/06_model_conversation.py
33
+ - if: matrix.python-version == '3.11'
34
+ name: Run external extension-package example
35
+ run: >-
36
+ uv run
37
+ --with-editable .
38
+ --with-editable ./examples/plugin_package
39
+ python examples/plugin_package/demo.py
40
+ - if: matrix.python-version == '3.11'
41
+ name: Build Core and extension distributions
42
+ run: |
43
+ uv build
44
+ uv build --project ./examples/plugin_package --out-dir ./dist/plugin_package
45
+ - if: matrix.python-version == '3.11'
46
+ name: Install wheels in a clean environment
47
+ run: |
48
+ uv venv --python 3.11 .wheel-venv
49
+ uv pip install --python .wheel-venv/bin/python \
50
+ dist/purrcept_core-*-py3-none-any.whl \
51
+ dist/plugin_package/purrcept_demo_plugin-*-py3-none-any.whl
52
+ uv pip check --python .wheel-venv/bin/python
53
+ .wheel-venv/bin/python -c "from importlib.resources import files; assert files('purrcept_core').joinpath('py.typed').is_file()"
54
+ .wheel-venv/bin/python examples/plugin_package/demo.py
55
+ - if: matrix.python-version == '3.11'
56
+ name: Install source distributions in a clean environment
57
+ run: |
58
+ uv venv --python 3.11 .sdist-venv
59
+ uv pip install --python .sdist-venv/bin/python \
60
+ dist/purrcept_core-*.tar.gz
61
+ uv pip install --python .sdist-venv/bin/python \
62
+ dist/plugin_package/purrcept_demo_plugin-*.tar.gz
63
+ uv pip check --python .sdist-venv/bin/python
64
+ .sdist-venv/bin/python -c "from importlib.resources import files; assert files('purrcept_core').joinpath('py.typed').is_file()"
65
+ .sdist-venv/bin/python examples/plugin_package/demo.py
@@ -0,0 +1,76 @@
1
+ # Build and validate the release tag before granting a separate job PyPI access.
2
+ # The publisher consumes only the checked distribution artifacts, not source code.
3
+ name: Publish to PyPI
4
+
5
+ on:
6
+ release:
7
+ types: [published]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: pypi-${{ github.event.release.tag_name }}
14
+ cancel-in-progress: false
15
+
16
+ jobs:
17
+ build:
18
+ name: Validate and build distributions
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 20
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ ref: ${{ github.event.release.tag_name }}
25
+ persist-credentials: false
26
+ - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
27
+ with:
28
+ python-version: "3.11"
29
+ enable-cache: false
30
+ - name: Check release tag against package version
31
+ env:
32
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
33
+ run: |
34
+ uv run --no-project python - <<'PY'
35
+ import os
36
+ import tomllib
37
+ from pathlib import Path
38
+
39
+ version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
40
+ tag = os.environ["RELEASE_TAG"]
41
+ if tag != f"v{version}":
42
+ raise SystemExit(f"Release tag {tag!r} does not match package version {version!r}.")
43
+ PY
44
+ # Resolve published dependencies; a developer's sibling editable checkout must
45
+ # never supply a dependency that users cannot install from PyPI.
46
+ - run: uv sync --no-sources --all-groups
47
+ - run: uv run --no-sync ruff check .
48
+ - run: uv run --no-sync ruff format --check .
49
+ - run: uv run --no-sync pyright
50
+ - run: uv run --no-sync pytest --cov=purrcept_core --cov-report=term-missing
51
+ - run: uv build --no-sources
52
+ - run: uvx --from twine twine check --strict dist/*
53
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
54
+ with:
55
+ name: distributions
56
+ path: dist/*
57
+ if-no-files-found: error
58
+ retention-days: 7
59
+
60
+ publish:
61
+ name: Publish distributions
62
+ needs: build
63
+ runs-on: ubuntu-latest
64
+ timeout-minutes: 10
65
+ environment:
66
+ name: pypi
67
+ url: https://pypi.org/project/purrcept-core/
68
+ permissions:
69
+ id-token: write
70
+ steps:
71
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
72
+ with:
73
+ name: distributions
74
+ path: dist/
75
+ - name: Publish with PyPI Trusted Publishing
76
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .venv/
8
+ .wheel-venv/
9
+ .sdist-venv/
10
+ .pyright/
11
+ build/
12
+ dist/
13
+ htmlcov/
@@ -0,0 +1,115 @@
1
+ ## Git commit messages
2
+
3
+ Write all new Git commit subjects and bodies in Chinese. Technical names, code
4
+ identifiers, and commands may retain their original spelling.
5
+
6
+ ## Source narrative and commenting style
7
+
8
+ Purrcept Core is an abstraction-heavy SDK. Source code must be optimized for
9
+ guided reading and long-term maintenance, not for minimum line count.
10
+
11
+ ### General principle
12
+
13
+ A reader should be able to understand the responsibility, control flow,
14
+ invariants, and extension points of a module without repeatedly searching
15
+ through unrelated files.
16
+
17
+ Comments must explain semantic intent, constraints, ordering, lifecycle, or
18
+ design rationale. Do not add comments that merely restate the code.
19
+
20
+ ### Module documentation
21
+
22
+ Every non-trivial module must begin with a module docstring that explains:
23
+
24
+ - What the module owns.
25
+ - What the module intentionally does not own.
26
+ - Its primary entry points.
27
+ - Its major processing stages.
28
+ - Its important invariants.
29
+ - Its relationship to neighboring modules.
30
+
31
+ Small data-only or re-export modules may use a shorter docstring.
32
+
33
+ ### Abstract interfaces
34
+
35
+ Every public Protocol, ABC, abstract class, and extension interface must
36
+ document:
37
+
38
+ - Who creates it.
39
+ - Who calls it.
40
+ - When it is called.
41
+ - Preconditions and postconditions.
42
+ - State ownership and lifecycle.
43
+ - Ordering and mutation rules.
44
+ - Error behavior.
45
+ - Built-in implementations.
46
+ - How an implementation is selected.
47
+
48
+ The abstraction owns the shared contract. Concrete implementations should
49
+ document only behavior that differs from that contract.
50
+
51
+ ### Functions and methods
52
+
53
+ All public functions and methods require docstrings.
54
+
55
+ Private functions also require a docstring or an immediately adjacent block
56
+ comment when they involve non-obvious behavior, state changes, ordering,
57
+ caching, concurrency, lifecycle, error handling, or algorithmic decisions.
58
+
59
+ Trivial private helpers whose complete semantics are obvious from their name,
60
+ signature, and body do not require a docstring.
61
+
62
+ ### Narrative flow
63
+
64
+ Functions containing multiple conceptual phases must separate those phases
65
+ with blank lines.
66
+
67
+ Add a short block comment before a phase when its purpose or ordering is not
68
+ obvious. Phase comments should explain why the phase exists or why it occurs
69
+ at that point, rather than paraphrasing its statements.
70
+
71
+ The main orchestration path must remain visible. Do not extract small private
72
+ helpers solely to reduce function length when doing so hides the overall flow.
73
+
74
+ ### Section boundaries
75
+
76
+ Long modules should use restrained semantic section headings:
77
+
78
+ # ---------------------------------------------------------------------------
79
+ # Reminder resolution
80
+ # ---------------------------------------------------------------------------
81
+
82
+ Use section headings only for substantial conceptual regions. Prefer domain
83
+ names such as "Context budget allocation" over structural names such as
84
+ "Private helpers".
85
+
86
+ ### Required rationale comments
87
+
88
+ Explicitly document:
89
+
90
+ - Invariants and state transitions.
91
+ - Order-dependent behavior.
92
+ - Cache-key and stable-prefix decisions.
93
+ - Ownership and concurrency assumptions.
94
+ - Retry, suppression, and exception translation.
95
+ - Provider compatibility workarounds.
96
+ - Deliberate rejection of an obvious alternative.
97
+ - Cross-module hand-off points.
98
+ - Non-obvious performance tradeoffs.
99
+
100
+ Critical comments may begin with `Invariant:`, `Ordering:`, `Cache:`,
101
+ `Compatibility:`, or `Lifecycle:`.
102
+
103
+ ### Style
104
+
105
+ Write comments as complete sentences. Keep them close to the behavior they
106
+ explain. Use paragraphs for multi-sentence explanations.
107
+
108
+ Do not repeat type hints, signatures, or obvious operations.
109
+
110
+ When changing behavior, update or remove affected comments in the same change.
111
+ A stale comment is a correctness defect.
112
+
113
+ Before completing a change, read every modified file from top to bottom as a
114
+ new maintainer. Add enough orientation that the main control flow can be
115
+ understood before opening helper implementations.
@@ -0,0 +1,158 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## Unreleased
6
+
7
+ ## 0.5.1 - 2026-09-08
8
+
9
+ - Resolve callable instance annotations from `__call__` explicitly on Python 3.14,
10
+ preserving FunctionTool support across the advertised Python versions.
11
+ - Publish validated wheel and source distributions automatically when a GitHub Release
12
+ is published, using PyPI Trusted Publishing and an isolated publishing job.
13
+
14
+ - Add `ReasoningDelta` as an immutable, separately indexed stream of provider-exposed
15
+ readable reasoning or summaries. It never contains opaque continuation state.
16
+ - Restore the documented default of eight model rounds in both conversation factories;
17
+ the previous zero default contradicted the positive-round validator.
18
+
19
+ ### Clarified
20
+
21
+ - Reminder placement is position relative to history, not wire role. Provider
22
+ adapters must not serialize `SystemReminder` as the system role; that role is
23
+ reserved for `SystemInstruction`. Chat Completions adapters emit reminders as
24
+ user messages.
25
+
26
+ ## 0.5.0 - 2026-07-28
27
+
28
+ ### Added
29
+
30
+ - Immutable `ReminderState` and complete `ConversationCheckpoint` values so prompt-control state
31
+ can be snapshotted, restored, forked, and cleared independently from committed history.
32
+ - A deterministic `PromptCompiler` boundary with `PromptDraft`, `CompiledPrompt`, metadata-only
33
+ `PromptDiagnostics`, and optional synchronous prompt trace events.
34
+ - Synchronous, conversation-local `ReminderSource` projections that are resolved before every
35
+ model request and naturally refresh after tool execution without weakening the busy guard.
36
+ - `RequestTokenBudget` and `RequestTokenCounter` for budgeting the complete `ModelRequest`,
37
+ including instructions, tools, messages, reminders, and provider-neutral request overhead.
38
+ - Multi-request Provider Conformance scenarios for reminder removal and keyed replacement, plus
39
+ explicit reminder order and placement fixtures.
40
+
41
+ ### Changed
42
+
43
+ - `NEXT_REQUEST` reminders are consumed only after a request has compiled and passed its request
44
+ budget; `TURN` reminders are acquired when the turn Flow first advances and expire on every
45
+ ending path.
46
+ - `CONVERSATION` reminders now require a non-empty key.
47
+ - `Conversation.snapshot()` now returns `ConversationCheckpoint`. Use `history_snapshot()` and
48
+ `restore_history()` when only committed transcript state is intended.
49
+ - `Conversation.fork()` copies complete mutable state while retaining the same reusable
50
+ configuration. Full checkpoints and state mutations remain unavailable while a turn is busy.
51
+ - `TokenBudgetContext` is explicitly transcript-only; complete prompt budgeting uses
52
+ `RequestTokenBudget`.
53
+
54
+ ### Deprecated
55
+
56
+ - `Conversation.clear()` is retained as a warning-emitting alias for `clear_history()`. Use
57
+ `reset()` to clear both committed history and stored reminders.
58
+
59
+ ### Design
60
+
61
+ - Reminders remain prompt-control state and never become canonical conversation messages.
62
+ - Dynamic source output and reusable configuration are deliberately excluded from checkpoints.
63
+ - Provider continuations must not retain reminders that are absent or replaced in a later
64
+ `ModelRequest`.
65
+
66
+ ## 0.4.0 - 2026-07-28
67
+
68
+ ### Added
69
+
70
+ - Immutable `PromptTemplate` values with strict and partial rendering, exact dotted placeholder
71
+ keys, immutable value binding, and direct compilation to `SystemInstruction`, `Message`, or
72
+ `SystemReminder`.
73
+ - Composable synchronous `RenderPolicy` values and built-in `optional`, `trim`, `header`, `wrap`,
74
+ `join_blocks`, and `min_len` policies.
75
+ - `PromptLibrary`, an immutable local named template registry, plus structured prompt definition,
76
+ lookup, and rendering errors.
77
+ - First-class template inputs for `model.conversation()`, `conversation.ask()`, and
78
+ `conversation.remind()`.
79
+
80
+ ### Design
81
+
82
+ - Prompt authoring is compiled before the Provider boundary, so `ModelRequest` remains a
83
+ provider-neutral transport value.
84
+ - Core intentionally has no global prompt manager, import-time template registration, global
85
+ build event, or hidden reminder content.
86
+ - Existing `SystemReminder` scope, placement, priority, replacement, and consumption behavior is
87
+ unchanged.
88
+
89
+ ## 0.3.0 - 2026-07-26
90
+
91
+ ### Added
92
+
93
+ - `Model`, an explicit binding between a runtime-owned backend and one model name.
94
+ - `Conversation`, immutable `ConversationState`, transactional turns, snapshots, restore, fork,
95
+ and the official observable tool-loop Flow.
96
+ - `FunctionTool`, `ToolSet`, `ToolContext`, `InvokeTool`, `ToolParameter`, tool policies, and
97
+ provider-neutral tool results and errors.
98
+ - Pydantic v2-powered internal JSON Schema generation and argument validation without exposing
99
+ Pydantic types in the public protocol.
100
+ - `SystemInstruction`, scoped `SystemReminder`, prompt cache/stability policies, model settings,
101
+ and opaque Provider continuation state.
102
+ - Append-only, complete-turn sliding-window, and injected token-budget context policies.
103
+ - Expanded token usage for cache reads, cache writes, and reasoning tokens.
104
+ - A deterministic Provider Backend Conformance Kit covering request semantics, streaming,
105
+ model errors, and cancellation.
106
+
107
+ ### Changed
108
+
109
+ - The documented default path is now
110
+ `Model → Conversation → FunctionTool → SystemReminder`; low-level requests and `Generate`
111
+ remain the escape hatch.
112
+ - `Generate` now carries an explicit `Model`, and `model.generate(request)` is the preferred
113
+ one-shot constructor.
114
+ - `ModelBackend.generate()` now receives the selected model name as a required keyword argument.
115
+ - System-level prompt content is represented separately from conversational messages.
116
+ - Common generation controls now live in `ModelSettings`; tools use `ToolSpec`.
117
+ - Each model generation and Python tool invocation in the automatic loop remains an independent
118
+ Effect.
119
+
120
+ ### Removed
121
+
122
+ - The implicit single-backend host binding used by model generation.
123
+ - The system role and system-message convenience constructor.
124
+ - Model-name and common generation-setting fields from the flat request surface.
125
+
126
+ ### Compatibility
127
+
128
+ - This is an intentional alpha breaking release. See
129
+ [`docs/compatibility.md`](docs/compatibility.md) for the migration guide.
130
+ - Purrcept Core now has a runtime dependency on Pydantic v2.
131
+
132
+ ## 0.2.0 - 2026-07-26
133
+
134
+ ### Added
135
+
136
+ - Provider-neutral model contracts in the `purrcept_core.models` capability layer.
137
+ - Immutable message, content block, request, response, usage, and streaming event types.
138
+ - A shared model error hierarchy for provider-independent retry and recovery policies.
139
+ - A self-executing one-shot model-generation Effect and runtime-owned Backend protocol.
140
+ - Runtime validation for Backend responses and ordered stream-event lifecycles.
141
+
142
+ ### Changed
143
+
144
+ - Model contracts ship in the same distribution while remaining isolated from the generic
145
+ Effect/Driver kernel.
146
+ - The external extension example implements the official model protocol instead of defining
147
+ its own contract.
148
+
149
+ ## 0.1.0 - 2026-07-26
150
+
151
+ ### Added
152
+
153
+ - Effect and generator-flow primitives.
154
+ - Generator-backed and protocol-based agent runs.
155
+ - Inline, dispatch, and middleware executors.
156
+ - Deterministic lifecycle events and progress reporting.
157
+ - Async agent driver with explicit error and cancellation semantics.
158
+ - Testing helpers, runnable examples, and an external extension-package example.
@@ -0,0 +1,221 @@
1
+ # Contributing
2
+
3
+ Purrcept Core 保持两条清晰边界:
4
+
5
+ - 通用内核中,Flow 决定下一步,Effect 描述一次操作,Executor 执行,Driver 推进 Run;
6
+ - 模型标准库中,Conversation 编排独立的 Generate / InvokeTool Effect,并面向统一的
7
+ Provider 协议。
8
+
9
+ 平台会话、数据库、持久化、调度、网络、Provider client、凭据、平台工具和业务权限仍
10
+ 属于 Runtime 或独立扩展包。不要通过全局 Registry、import-time 注册、隐藏重试或隐藏
11
+ 模型调用跨越边界。
12
+
13
+ 开发环境使用 Python 3.11+ 和 `uv`:
14
+
15
+ ```bash
16
+ uv sync --all-groups
17
+ uv run ruff check .
18
+ uv run ruff format --check .
19
+ uv run pyright
20
+ uv run pytest
21
+ uv run python -m build
22
+ ```
23
+
24
+ 新增公共行为应包含聚焦测试和对应文档,并维持分支覆盖率门禁。模型值对象应保持不可变、
25
+ Provider 无关和 keyword-only 可扩展性。新的自动化步骤必须继续以可观察 Effect 表达。
26
+
27
+ 函数工具可以在内部使用 Pydantic v2,但公共注解、Protocol、值对象和错误不能暴露
28
+ Pydantic 类型。涉及 Python 3.11 `TypedDict` 的工具测试应优先使用
29
+ `typing_extensions.TypedDict`。
30
+
31
+ Provider 适配变更应运行标准 Backend Conformance Kit,并在扩展包中补充供应商
32
+ wire-format、SDK 版本、认证和特殊能力测试。新增运行时依赖需要说明维护成本、替换边界
33
+ 和为什么现有能力不足。
34
+
35
+ ## Source Readability and Narrative Documentation
36
+
37
+ Repository-specific instructions take precedence over this section.
38
+
39
+ Treat source code as a technical document for future maintainers. Optimize for
40
+ guided reading, clear control flow, and explicit design intent rather than
41
+ minimum line count or maximum compactness.
42
+
43
+ Types describe data shape. Names describe local actions. Documentation and
44
+ comments must explain semantics, contracts, constraints, ordering, lifecycle,
45
+ ownership, and design rationale.
46
+
47
+ ### General requirements
48
+
49
+ - Preserve the repository's established documentation language and style.
50
+ - If no documentation language is established, use English.
51
+ - Write comments and documentation as complete, precise sentences.
52
+ - Do not add comments merely to increase comment coverage.
53
+ - Do not assume that clean naming, type hints, or private visibility make
54
+ non-obvious behavior self-explanatory.
55
+ - Documentation is part of correctness. Stale or misleading comments are
56
+ defects and must be updated with the code.
57
+
58
+ ### Files and modules
59
+
60
+ Every non-trivial source file or module must provide an opening documentation
61
+ comment or module docstring that gives the reader an initial mental model.
62
+
63
+ When relevant, explain:
64
+
65
+ - What the module owns.
66
+ - What it intentionally does not own.
67
+ - Its primary entry points.
68
+ - Its major processing stages.
69
+ - Its important invariants.
70
+ - Its relationship to neighboring modules.
71
+ - Where concrete implementations or extension points can be found.
72
+
73
+ Small data-only modules, generated files, re-export modules, and obvious
74
+ single-purpose wrappers may use shorter documentation.
75
+
76
+ ### Public APIs and abstractions
77
+
78
+ Document all public APIs and all extension-facing abstractions.
79
+
80
+ Protocols, abstract classes, interfaces, hooks, policies, strategies, and
81
+ lifecycle components must document their shared contract, including relevant
82
+ details such as:
83
+
84
+ - Who creates the object.
85
+ - Who calls it.
86
+ - When it is called.
87
+ - Preconditions and postconditions.
88
+ - State ownership and mutation rules.
89
+ - Ordering guarantees.
90
+ - Concurrency and reuse assumptions.
91
+ - Error behavior.
92
+ - Built-in implementations.
93
+ - How an implementation is selected or registered.
94
+
95
+ The abstraction should own the shared contract. Concrete implementations
96
+ should document only behavior that differs from or extends that contract.
97
+
98
+ Do not write documentation that merely repeats a function signature, type
99
+ annotation, field name, or return type. Explain what the values mean and what
100
+ callers may rely on.
101
+
102
+ ### Private functions
103
+
104
+ Private visibility does not remove the need for explanation.
105
+
106
+ A private function requires a docstring or a nearby rationale comment when it
107
+ contains non-obvious:
108
+
109
+ - State changes.
110
+ - Ordering dependencies.
111
+ - Cache behavior.
112
+ - Lifecycle behavior.
113
+ - Ownership or concurrency assumptions.
114
+ - Failure, retry, fallback, or suppression behavior.
115
+ - Algorithms or heuristics.
116
+ - Compatibility workarounds.
117
+ - Cross-module hand-offs.
118
+ - Semantics that cannot be inferred from its name, signature, and body at a
119
+ glance.
120
+
121
+ Trivial private helpers whose complete behavior is obvious may omit a
122
+ docstring.
123
+
124
+ ### Narrative control flow
125
+
126
+ The main orchestration path should read from top to bottom like an outline of
127
+ the operation.
128
+
129
+ - Keep major processing stages visible in the main function.
130
+ - Use meaningful intermediate variables instead of deeply nested expressions
131
+ when they represent distinct concepts.
132
+ - Separate conceptual phases with blank lines.
133
+ - Add a short block comment before a phase when its purpose or position is not
134
+ obvious.
135
+ - Explain why a phase exists or why it must occur at that point. Do not merely
136
+ paraphrase the statements below it.
137
+ - Extract helpers only when they represent a meaningful concept, isolate real
138
+ complexity, enable reuse, improve testing, or hide irrelevant detail.
139
+ - Do not split a readable workflow into many tiny private methods solely to
140
+ reduce function length.
141
+ - Do not compress multiple semantic operations into one expression solely to
142
+ reduce line count.
143
+
144
+ A reader should be able to understand the overall workflow before opening
145
+ every helper implementation.
146
+
147
+ ### Required rationale comments
148
+
149
+ Explicitly document behavior involving:
150
+
151
+ - Invariants and state transitions.
152
+ - Steps whose order must not change.
153
+ - Stable prefixes, cache keys, invalidation, or cache boundaries.
154
+ - Object ownership, resource lifetime, or concurrency.
155
+ - Exception translation, ignored failures, retries, and fallbacks.
156
+ - Provider, platform, protocol, or version compatibility.
157
+ - Non-obvious performance or memory tradeoffs.
158
+ - Security-sensitive decisions.
159
+ - Deliberate rejection of a simpler-looking alternative.
160
+ - Code that appears redundant but must not be removed.
161
+ - Handoffs between subsystems.
162
+
163
+ Critical comments may begin with labels such as:
164
+
165
+ - `Invariant:`
166
+ - `Ordering:`
167
+ - `Cache:`
168
+ - `Lifecycle:`
169
+ - `Concurrency:`
170
+ - `Compatibility:`
171
+ - `Security:`
172
+
173
+ Use these labels selectively, only when they improve discoverability.
174
+
175
+ ### File structure and visual rhythm
176
+
177
+ Long files may use restrained semantic section headings, for example:
178
+
179
+ # ---------------------------------------------------------------------------
180
+ # Context budget allocation
181
+ # ---------------------------------------------------------------------------
182
+
183
+ Use section headings only for substantial conceptual regions. Prefer domain
184
+ headings such as `Reminder resolution` over structural headings such as
185
+ `Private helpers`.
186
+
187
+ Use whitespace to communicate changes in thought. Code should not appear as
188
+ an uninterrupted dense block when it contains multiple conceptual stages.
189
+
190
+ ### Avoid
191
+
192
+ Do not write comments that:
193
+
194
+ - Restate obvious code.
195
+ - Repeat type annotations.
196
+ - Use vague verbs such as "handle", "process", or "manage" without explaining
197
+ the actual semantics.
198
+ - Describe fragile line-by-line implementation details instead of stable
199
+ intent.
200
+ - Compensate for poor names or unclear abstractions.
201
+ - Duplicate large amounts of documentation across an interface and all its
202
+ implementations.
203
+ - Claim behavior that is not enforced by the implementation or tests.
204
+
205
+ ### Completion check
206
+
207
+ Before completing a change, read every modified file from top to bottom as a
208
+ new maintainer.
209
+
210
+ Verify that:
211
+
212
+ - The file's responsibility and entry points are quickly understandable.
213
+ - The main control flow is visible without excessive navigation.
214
+ - Abstract contracts and extension points are documented.
215
+ - Important ordering, state, cache, lifecycle, and concurrency rules are
216
+ explained.
217
+ - Dense expressions have not hidden distinct conceptual steps.
218
+ - Comments explain information that the code alone does not communicate.
219
+ - All affected documentation and comments still match the implementation.
220
+
221
+ Improve the narrative readability before considering the task complete.