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.
- purrcept_core-0.5.1/.github/workflows/ci.yml +65 -0
- purrcept_core-0.5.1/.github/workflows/publish.yml +76 -0
- purrcept_core-0.5.1/.gitignore +13 -0
- purrcept_core-0.5.1/AGENTS.md +115 -0
- purrcept_core-0.5.1/CHANGELOG.md +158 -0
- purrcept_core-0.5.1/CONTRIBUTING.md +221 -0
- purrcept_core-0.5.1/PKG-INFO +264 -0
- purrcept_core-0.5.1/README.md +246 -0
- purrcept_core-0.5.1/README.zh-CN.md +239 -0
- purrcept_core-0.5.1/RELEASING.md +40 -0
- purrcept_core-0.5.1/adr/0001-core-boundary.md +21 -0
- purrcept_core-0.5.1/adr/0002-effect-flow-semantics.md +18 -0
- purrcept_core-0.5.1/adr/0003-agent-run-protocol.md +15 -0
- purrcept_core-0.5.1/adr/0004-executor-and-context.md +19 -0
- purrcept_core-0.5.1/adr/0005-extension-model.md +15 -0
- purrcept_core-0.5.1/adr/0006-model-standard-library.md +114 -0
- purrcept_core-0.5.1/adr/0007-prompt-control-state.md +101 -0
- purrcept_core-0.5.1/assets/readme/architecture.svg +181 -0
- purrcept_core-0.5.1/assets/readme/hero.svg +158 -0
- purrcept_core-0.5.1/docs/api.md +580 -0
- purrcept_core-0.5.1/docs/compatibility.md +267 -0
- purrcept_core-0.5.1/docs/concepts.md +57 -0
- purrcept_core-0.5.1/docs/effects.md +71 -0
- purrcept_core-0.5.1/docs/events.md +62 -0
- purrcept_core-0.5.1/docs/executors.md +41 -0
- purrcept_core-0.5.1/docs/extension-packages.md +163 -0
- purrcept_core-0.5.1/docs/middleware.md +18 -0
- purrcept_core-0.5.1/docs/models.md +633 -0
- purrcept_core-0.5.1/docs/runtime-boundary.md +42 -0
- purrcept_core-0.5.1/docs/testing.md +23 -0
- purrcept_core-0.5.1/examples/01_inline_effect.py +44 -0
- purrcept_core-0.5.1/examples/02_declarative_effect.py +49 -0
- purrcept_core-0.5.1/examples/03_error_recovery.py +55 -0
- purrcept_core-0.5.1/examples/04_nested_flow.py +48 -0
- purrcept_core-0.5.1/examples/05_progress_events.py +54 -0
- purrcept_core-0.5.1/examples/06_model_conversation.py +120 -0
- purrcept_core-0.5.1/examples/07_prompt_templates.py +57 -0
- purrcept_core-0.5.1/examples/08_prompt_control_state.py +174 -0
- purrcept_core-0.5.1/examples/plugin_package/README.md +20 -0
- purrcept_core-0.5.1/examples/plugin_package/demo.py +87 -0
- purrcept_core-0.5.1/examples/plugin_package/pyproject.toml +13 -0
- purrcept_core-0.5.1/examples/plugin_package/src/purrcept_demo_plugin/__init__.py +155 -0
- purrcept_core-0.5.1/pyproject.toml +82 -0
- purrcept_core-0.5.1/src/purrcept_core/__init__.py +102 -0
- purrcept_core-0.5.1/src/purrcept_core/context.py +67 -0
- purrcept_core-0.5.1/src/purrcept_core/driver.py +383 -0
- purrcept_core-0.5.1/src/purrcept_core/effect.py +27 -0
- purrcept_core-0.5.1/src/purrcept_core/errors.py +51 -0
- purrcept_core-0.5.1/src/purrcept_core/events.py +254 -0
- purrcept_core-0.5.1/src/purrcept_core/executor.py +141 -0
- purrcept_core-0.5.1/src/purrcept_core/flow.py +36 -0
- purrcept_core-0.5.1/src/purrcept_core/middleware.py +284 -0
- purrcept_core-0.5.1/src/purrcept_core/models/__init__.py +226 -0
- purrcept_core-0.5.1/src/purrcept_core/models/_utils.py +122 -0
- purrcept_core-0.5.1/src/purrcept_core/models/backend.py +59 -0
- purrcept_core-0.5.1/src/purrcept_core/models/caching.py +74 -0
- purrcept_core-0.5.1/src/purrcept_core/models/conformance.py +703 -0
- purrcept_core-0.5.1/src/purrcept_core/models/content.py +175 -0
- purrcept_core-0.5.1/src/purrcept_core/models/context_policy.py +367 -0
- purrcept_core-0.5.1/src/purrcept_core/models/continuation.py +42 -0
- purrcept_core-0.5.1/src/purrcept_core/models/conversation.py +735 -0
- purrcept_core-0.5.1/src/purrcept_core/models/effects.py +150 -0
- purrcept_core-0.5.1/src/purrcept_core/models/errors.py +95 -0
- purrcept_core-0.5.1/src/purrcept_core/models/instructions.py +67 -0
- purrcept_core-0.5.1/src/purrcept_core/models/loop.py +318 -0
- purrcept_core-0.5.1/src/purrcept_core/models/messages.py +160 -0
- purrcept_core-0.5.1/src/purrcept_core/models/model.py +116 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/__init__.py +65 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/compiler.py +539 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/errors.py +86 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/library.py +75 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/policies.py +174 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/template.py +430 -0
- purrcept_core-0.5.1/src/purrcept_core/models/prompt/tracing.py +122 -0
- purrcept_core-0.5.1/src/purrcept_core/models/reminder_sources.py +136 -0
- purrcept_core-0.5.1/src/purrcept_core/models/reminders.py +177 -0
- purrcept_core-0.5.1/src/purrcept_core/models/requests.py +188 -0
- purrcept_core-0.5.1/src/purrcept_core/models/responses.py +138 -0
- purrcept_core-0.5.1/src/purrcept_core/models/settings.py +90 -0
- purrcept_core-0.5.1/src/purrcept_core/models/streaming.py +162 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/__init__.py +35 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/_documentation.py +146 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/_encoding.py +156 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/_schema.py +277 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/effects.py +57 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/errors.py +87 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/function.py +244 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/toolset.py +104 -0
- purrcept_core-0.5.1/src/purrcept_core/models/tools/values.py +189 -0
- purrcept_core-0.5.1/src/purrcept_core/py.typed +1 -0
- purrcept_core-0.5.1/src/purrcept_core/run.py +202 -0
- purrcept_core-0.5.1/src/purrcept_core/testing.py +141 -0
- purrcept_core-0.5.1/tests/models/prompt/__init__.py +1 -0
- purrcept_core-0.5.1/tests/models/prompt/test_compiler.py +463 -0
- purrcept_core-0.5.1/tests/models/prompt/test_errors.py +122 -0
- purrcept_core-0.5.1/tests/models/prompt/test_library.py +105 -0
- purrcept_core-0.5.1/tests/models/prompt/test_policies.py +120 -0
- purrcept_core-0.5.1/tests/models/prompt/test_template.py +342 -0
- purrcept_core-0.5.1/tests/models/prompt/test_tracing.py +165 -0
- purrcept_core-0.5.1/tests/models/test_backend.py +25 -0
- purrcept_core-0.5.1/tests/models/test_caching.py +95 -0
- purrcept_core-0.5.1/tests/models/test_conformance.py +654 -0
- purrcept_core-0.5.1/tests/models/test_content.py +171 -0
- purrcept_core-0.5.1/tests/models/test_context_policy.py +435 -0
- purrcept_core-0.5.1/tests/models/test_continuation.py +62 -0
- purrcept_core-0.5.1/tests/models/test_conversation.py +627 -0
- purrcept_core-0.5.1/tests/models/test_errors.py +106 -0
- purrcept_core-0.5.1/tests/models/test_generate_effect.py +381 -0
- purrcept_core-0.5.1/tests/models/test_instructions.py +81 -0
- purrcept_core-0.5.1/tests/models/test_messages.py +126 -0
- purrcept_core-0.5.1/tests/models/test_model.py +127 -0
- purrcept_core-0.5.1/tests/models/test_model_loop.py +774 -0
- purrcept_core-0.5.1/tests/models/test_models_public_api.py +157 -0
- purrcept_core-0.5.1/tests/models/test_reasoning_stream.py +35 -0
- purrcept_core-0.5.1/tests/models/test_reminder_sources.py +264 -0
- purrcept_core-0.5.1/tests/models/test_reminders.py +226 -0
- purrcept_core-0.5.1/tests/models/test_requests_responses.py +425 -0
- purrcept_core-0.5.1/tests/models/test_settings.py +113 -0
- purrcept_core-0.5.1/tests/models/test_streaming.py +122 -0
- purrcept_core-0.5.1/tests/models/tools/__init__.py +1 -0
- purrcept_core-0.5.1/tests/models/tools/test_function_schema_and_docs.py +437 -0
- purrcept_core-0.5.1/tests/models/tools/test_invocation_and_encoding.py +410 -0
- purrcept_core-0.5.1/tests/models/tools/test_toolset_and_public_api.py +141 -0
- purrcept_core-0.5.1/tests/models/tools/test_values_and_errors.py +306 -0
- purrcept_core-0.5.1/tests/test_context.py +81 -0
- purrcept_core-0.5.1/tests/test_dispatch_executor.py +134 -0
- purrcept_core-0.5.1/tests/test_driver_cancellation.py +114 -0
- purrcept_core-0.5.1/tests/test_driver_errors.py +497 -0
- purrcept_core-0.5.1/tests/test_driver_success.py +231 -0
- purrcept_core-0.5.1/tests/test_events.py +155 -0
- purrcept_core-0.5.1/tests/test_flow.py +105 -0
- purrcept_core-0.5.1/tests/test_generator_run.py +204 -0
- purrcept_core-0.5.1/tests/test_inline_executor.py +91 -0
- purrcept_core-0.5.1/tests/test_middleware.py +409 -0
- purrcept_core-0.5.1/tests/test_public_api.py +42 -0
- purrcept_core-0.5.1/tests/test_testing_helpers.py +81 -0
- purrcept_core-0.5.1/typing_samples/host_protocols.py +152 -0
- purrcept_core-0.5.1/typing_samples/perform.py +34 -0
- 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,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.
|