django-pydantic-agent 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_pydantic_agent-0.1.0/.github/CODEOWNERS +1 -0
- django_pydantic_agent-0.1.0/.github/SECURITY.md +9 -0
- django_pydantic_agent-0.1.0/.github/dependabot.yml +16 -0
- django_pydantic_agent-0.1.0/.github/workflows/release.yml +81 -0
- django_pydantic_agent-0.1.0/.github/workflows/tests.yml +250 -0
- django_pydantic_agent-0.1.0/.gitignore +122 -0
- django_pydantic_agent-0.1.0/.pre-commit-config.yaml +50 -0
- django_pydantic_agent-0.1.0/CHANGELOG.md +30 -0
- django_pydantic_agent-0.1.0/CLAUDE.md +182 -0
- django_pydantic_agent-0.1.0/LICENSE +21 -0
- django_pydantic_agent-0.1.0/Makefile +79 -0
- django_pydantic_agent-0.1.0/PKG-INFO +81 -0
- django_pydantic_agent-0.1.0/README.md +33 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/__init__.py +81 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/agent_factory.py +66 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/attachment_toolset.py +78 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/build_model.py +66 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/build_tool_catalog.py +81 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/types/agent_config.py +56 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/agent/types/agent_factory_fn.py +29 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/constants.py +60 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/apps.py +25 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/default_attachment_store.py +85 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/default_conversation_store.py +101 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/default_step_store.py +297 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/migrations/0001_initial.py +261 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/migrations/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/contrib/store/models.py +215 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/integrations/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/integrations/build_spec_capability.py +53 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/integrations/drf_mcp.py +233 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/anonymous_operation_error.py +15 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/django_session_conversation_store.py +109 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/model_attachment_store.py +95 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/model_conversation_store.py +139 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/null_attachment_store.py +34 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/null_conversation_store.py +36 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/scoped_conversation_store.py +95 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/attachment_ref.py +32 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/attachment_store.py +45 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/conversation.py +27 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/conversation_meta.py +34 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/conversation_store.py +44 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/types/opened_attachment.py +29 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/persistence/utils.py +108 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/audit_capability.py +121 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/logging_audit_logger.py +59 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/null_audit_logger.py +13 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/types/audit_event.py +45 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/audit/types/audit_logger.py +22 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/guard/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/guard/tool_guard.py +82 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/guard/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/policy/guard/types/tool_guard_config.py +36 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/py.typed +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/build_input_schema.py +123 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/decorator.py +62 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/tool_registry.py +97 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/types/tool_binding.py +22 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/registry/types/tool_spec.py +52 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/utils.py +150 -0
- django_pydantic_agent-0.1.0/django_pydantic_agent/version.py +5 -0
- django_pydantic_agent-0.1.0/docs/index.md +14 -0
- django_pydantic_agent-0.1.0/mkdocs.yml +75 -0
- django_pydantic_agent-0.1.0/pyproject.toml +164 -0
- django_pydantic_agent-0.1.0/scripts/release-publish.sh +211 -0
- django_pydantic_agent-0.1.0/tests/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/agent/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/agent/catalog_server.py +45 -0
- django_pydantic_agent-0.1.0/tests/agent/factories.py +27 -0
- django_pydantic_agent-0.1.0/tests/agent/test_agent_factory.py +183 -0
- django_pydantic_agent-0.1.0/tests/agent/test_attachment_toolset.py +71 -0
- django_pydantic_agent-0.1.0/tests/agent/test_build_model.py +74 -0
- django_pydantic_agent-0.1.0/tests/agent/test_build_tool_catalog.py +92 -0
- django_pydantic_agent-0.1.0/tests/conftest_settings.py +36 -0
- django_pydantic_agent-0.1.0/tests/contrib/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/contrib/store/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/contrib/store/test_default_attachment_store.py +102 -0
- django_pydantic_agent-0.1.0/tests/contrib/store/test_default_conversation_store.py +113 -0
- django_pydantic_agent-0.1.0/tests/contrib/store/test_default_step_store.py +292 -0
- django_pydantic_agent-0.1.0/tests/contrib/store/test_models.py +43 -0
- django_pydantic_agent-0.1.0/tests/integrations/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/integrations/drf_server.py +44 -0
- django_pydantic_agent-0.1.0/tests/integrations/drf_server_typed.py +47 -0
- django_pydantic_agent-0.1.0/tests/integrations/drf_specs.py +15 -0
- django_pydantic_agent-0.1.0/tests/integrations/drf_specs_colliding.py +25 -0
- django_pydantic_agent-0.1.0/tests/integrations/test_build_spec_capability.py +63 -0
- django_pydantic_agent-0.1.0/tests/integrations/test_drf_mcp.py +239 -0
- django_pydantic_agent-0.1.0/tests/persistence/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_django_session_conversation_store.py +144 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_model_attachment_store.py +66 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_model_conversation_store.py +99 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_null_attachment_store.py +24 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_null_conversation_store.py +27 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_scoped_conversation_store.py +99 -0
- django_pydantic_agent-0.1.0/tests/persistence/test_utils.py +137 -0
- django_pydantic_agent-0.1.0/tests/persistence/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/persistence/types/test_attachment_ref.py +24 -0
- django_pydantic_agent-0.1.0/tests/persistence/types/test_conversation_meta.py +24 -0
- django_pydantic_agent-0.1.0/tests/persistence/types/test_opened_attachment.py +11 -0
- django_pydantic_agent-0.1.0/tests/policy/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/test_audit_capability.py +110 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/test_logging_audit_logger.py +75 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/test_null_audit_logger.py +10 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/policy/audit/types/test_audit_event.py +19 -0
- django_pydantic_agent-0.1.0/tests/policy/guard/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/policy/guard/test_tool_guard.py +116 -0
- django_pydantic_agent-0.1.0/tests/policy/guard/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/registry/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/registry/test_build_input_schema.py +136 -0
- django_pydantic_agent-0.1.0/tests/registry/test_decorator.py +88 -0
- django_pydantic_agent-0.1.0/tests/registry/test_tool_registry.py +70 -0
- django_pydantic_agent-0.1.0/tests/registry/types/__init__.py +0 -0
- django_pydantic_agent-0.1.0/tests/registry/types/test_tool_spec.py +25 -0
- django_pydantic_agent-0.1.0/tests/test_constants.py +24 -0
- django_pydantic_agent-0.1.0/tests/test_utils.py +156 -0
- django_pydantic_agent-0.1.0/tests/test_version.py +8 -0
- django_pydantic_agent-0.1.0/uv.lock +2475 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @Artui
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a Vulnerability
|
|
4
|
+
|
|
5
|
+
Please report security issues **privately** via GitHub's
|
|
6
|
+
[Report a vulnerability](../../security/advisories/new) button rather than opening a public issue.
|
|
7
|
+
I aim to acknowledge reports within 72 hours.
|
|
8
|
+
|
|
9
|
+
Supported: the latest released version on the default branch.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "github-actions"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
groups:
|
|
8
|
+
actions:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
- package-ecosystem: "uv"
|
|
11
|
+
directory: "/"
|
|
12
|
+
schedule:
|
|
13
|
+
interval: "weekly"
|
|
14
|
+
groups:
|
|
15
|
+
python:
|
|
16
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Main-triggered: every merge to `main` runs `release-publish-prepare`, which
|
|
4
|
+
# short-circuits to a no-op unless the version in source has been bumped past
|
|
5
|
+
# the most recent `vX.Y.Z` tag.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: release-main
|
|
12
|
+
cancel-in-progress: false
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
release:
|
|
16
|
+
name: release
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
environment:
|
|
19
|
+
name: pypi
|
|
20
|
+
url: https://pypi.org/p/django-pydantic-agent
|
|
21
|
+
permissions:
|
|
22
|
+
id-token: write # PyPI OIDC trusted publishing
|
|
23
|
+
contents: write # tag push + gh release create
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v7
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0
|
|
28
|
+
- uses: astral-sh/setup-uv@v7
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
- name: Install
|
|
32
|
+
run: uv sync --all-groups
|
|
33
|
+
|
|
34
|
+
- name: Prepare release (version check, test, build dist)
|
|
35
|
+
id: prepare
|
|
36
|
+
run: make release-publish-prepare
|
|
37
|
+
|
|
38
|
+
- name: Publish to PyPI
|
|
39
|
+
if: steps.prepare.outputs.released == 'true'
|
|
40
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
41
|
+
|
|
42
|
+
- name: Tag + GitHub Release
|
|
43
|
+
if: steps.prepare.outputs.released == 'true'
|
|
44
|
+
env:
|
|
45
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
46
|
+
run: make release-publish-finalize
|
|
47
|
+
|
|
48
|
+
# Embed a coverage-badge JSON into the docs build so `mkdocs gh-deploy`
|
|
49
|
+
# carries it to the gh-pages root, where the README's shields.io endpoint
|
|
50
|
+
# badge reads it. `release-publish-prepare`'s pytest run wrote .coverage
|
|
51
|
+
# to the workspace root.
|
|
52
|
+
- name: Render coverage badge for the docs site
|
|
53
|
+
if: steps.prepare.outputs.released == 'true' && hashFiles('mkdocs.yml') != ''
|
|
54
|
+
run: |
|
|
55
|
+
set -euo pipefail
|
|
56
|
+
uv run coverage xml -o coverage.xml
|
|
57
|
+
python - <<'PY'
|
|
58
|
+
import json
|
|
59
|
+
import xml.etree.ElementTree as ET
|
|
60
|
+
|
|
61
|
+
pct = round(float(ET.parse("coverage.xml").getroot().attrib["line-rate"]) * 100, 1)
|
|
62
|
+
color = (
|
|
63
|
+
"brightgreen" if pct >= 95
|
|
64
|
+
else "green" if pct >= 85
|
|
65
|
+
else "yellow" if pct >= 70
|
|
66
|
+
else "red"
|
|
67
|
+
)
|
|
68
|
+
payload = {"schemaVersion": 1, "label": "coverage", "message": f"{pct}%", "color": color}
|
|
69
|
+
with open("docs/coverage.json", "w") as fh:
|
|
70
|
+
json.dump(payload, fh)
|
|
71
|
+
fh.write("\n")
|
|
72
|
+
print(json.dumps(payload))
|
|
73
|
+
PY
|
|
74
|
+
|
|
75
|
+
- name: Deploy docs + coverage badge to gh-pages
|
|
76
|
+
if: steps.prepare.outputs.released == 'true' && hashFiles('mkdocs.yml') != ''
|
|
77
|
+
run: |
|
|
78
|
+
git config user.name 'github-actions[bot]'
|
|
79
|
+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
80
|
+
DJANGO_SETTINGS_MODULE=tests.conftest_settings \
|
|
81
|
+
uv run mkdocs gh-deploy --force --clean --config-file mkdocs.yml
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: tests-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
name: lint
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
- uses: astral-sh/setup-uv@v7
|
|
19
|
+
with:
|
|
20
|
+
enable-cache: true
|
|
21
|
+
- name: Install
|
|
22
|
+
run: uv sync --all-groups
|
|
23
|
+
- name: ruff check
|
|
24
|
+
run: uv run ruff check .
|
|
25
|
+
- name: ruff format check
|
|
26
|
+
run: uv run ruff format --check --diff .
|
|
27
|
+
- name: ty
|
|
28
|
+
run: uv run ty check django_pydantic_agent
|
|
29
|
+
|
|
30
|
+
docs:
|
|
31
|
+
name: docs build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v7
|
|
35
|
+
- uses: astral-sh/setup-uv@v7
|
|
36
|
+
with:
|
|
37
|
+
enable-cache: true
|
|
38
|
+
- name: Install with docs group
|
|
39
|
+
run: uv sync --all-groups
|
|
40
|
+
- name: mkdocs build --strict
|
|
41
|
+
run: DJANGO_SETTINGS_MODULE=tests.conftest_settings uv run mkdocs build --strict
|
|
42
|
+
|
|
43
|
+
test:
|
|
44
|
+
name: ${{ matrix.python-version }} / Django ${{ matrix.django-version }}
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
strategy:
|
|
47
|
+
fail-fast: false
|
|
48
|
+
matrix:
|
|
49
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
50
|
+
django-version: ["4.2", "5.0", "5.1", "5.2", "6.0"]
|
|
51
|
+
exclude:
|
|
52
|
+
# Django 4.2 supports Python 3.8–3.12
|
|
53
|
+
- python-version: "3.13"
|
|
54
|
+
django-version: "4.2"
|
|
55
|
+
- python-version: "3.14"
|
|
56
|
+
django-version: "4.2"
|
|
57
|
+
# Django 5.0 supports Python 3.10–3.12
|
|
58
|
+
- python-version: "3.13"
|
|
59
|
+
django-version: "5.0"
|
|
60
|
+
- python-version: "3.14"
|
|
61
|
+
django-version: "5.0"
|
|
62
|
+
# Django 5.1 supports Python 3.10–3.13
|
|
63
|
+
- python-version: "3.14"
|
|
64
|
+
django-version: "5.1"
|
|
65
|
+
# Django 6.0 requires Python 3.12+
|
|
66
|
+
- python-version: "3.10"
|
|
67
|
+
django-version: "6.0"
|
|
68
|
+
- python-version: "3.11"
|
|
69
|
+
django-version: "6.0"
|
|
70
|
+
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v7
|
|
73
|
+
- uses: astral-sh/setup-uv@v7
|
|
74
|
+
with:
|
|
75
|
+
enable-cache: true
|
|
76
|
+
- name: Install Python ${{ matrix.python-version }}
|
|
77
|
+
run: uv python install ${{ matrix.python-version }}
|
|
78
|
+
- name: Sync dev deps
|
|
79
|
+
run: uv sync --all-groups --python ${{ matrix.python-version }}
|
|
80
|
+
- name: Pin Django ${{ matrix.django-version }}
|
|
81
|
+
run: uv pip install --reinstall-package django "django~=${{ matrix.django-version }}.0"
|
|
82
|
+
- name: pytest
|
|
83
|
+
run: |
|
|
84
|
+
uv run --no-sync pytest \
|
|
85
|
+
--cov-report=xml:coverage.xml \
|
|
86
|
+
--cov-report=html:htmlcov
|
|
87
|
+
- name: Upload coverage artifact
|
|
88
|
+
if: always()
|
|
89
|
+
uses: actions/upload-artifact@v7
|
|
90
|
+
with:
|
|
91
|
+
name: coverage-py${{ matrix.python-version }}-django${{ matrix.django-version }}
|
|
92
|
+
path: |
|
|
93
|
+
coverage.xml
|
|
94
|
+
htmlcov/
|
|
95
|
+
if-no-files-found: ignore
|
|
96
|
+
|
|
97
|
+
coverage-badge:
|
|
98
|
+
# Publishes a shields.io-compatible coverage.json to gh-pages so the README
|
|
99
|
+
# badge reflects reality. Runs only on push to main, after the matrix has
|
|
100
|
+
# produced an artifact we can read from.
|
|
101
|
+
name: coverage badge
|
|
102
|
+
needs: test
|
|
103
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
104
|
+
runs-on: ubuntu-latest
|
|
105
|
+
permissions:
|
|
106
|
+
contents: write
|
|
107
|
+
steps:
|
|
108
|
+
- uses: actions/checkout@v7
|
|
109
|
+
with:
|
|
110
|
+
# Need the parent commit so the gate step below can diff
|
|
111
|
+
# version.py against ${{ github.event.before }}. The default
|
|
112
|
+
# shallow checkout (depth 1) would make `git show "$before:…"`
|
|
113
|
+
# fail with exit 128 and turn the whole job red.
|
|
114
|
+
fetch-depth: 2
|
|
115
|
+
# release.yml runs in parallel on the same push and owns gh-pages
|
|
116
|
+
# publishing on release commits (it bundles coverage.json into the
|
|
117
|
+
# mkdocs gh-deploy). If we also push here we get a second built-in
|
|
118
|
+
# "pages build and deployment" run that the first one cancels. The
|
|
119
|
+
# version-diff against ${{ github.event.before }} is the reliable
|
|
120
|
+
# signal — release.yml's tag isn't pushed until after PyPI publish,
|
|
121
|
+
# so a tag-existence check would race.
|
|
122
|
+
- name: Skip when release.yml owns this push
|
|
123
|
+
id: gate
|
|
124
|
+
run: |
|
|
125
|
+
set -euo pipefail
|
|
126
|
+
before="${{ github.event.before }}"
|
|
127
|
+
if [[ -z "$before" || "$before" =~ ^0+$ ]]; then
|
|
128
|
+
# First push to main on a brand-new repo — no prior state to diff.
|
|
129
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
130
|
+
exit 0
|
|
131
|
+
fi
|
|
132
|
+
# `before` may not be in the local object DB if the push
|
|
133
|
+
# contained more than one commit (fetch-depth: 2 only guarantees
|
|
134
|
+
# HEAD + 1 parent). Try to fetch just that commit; if it's not
|
|
135
|
+
# reachable, fall back to "don't skip" — better to double-push
|
|
136
|
+
# to gh-pages once than to turn the pipeline red.
|
|
137
|
+
if ! git cat-file -e "$before^{commit}" 2>/dev/null; then
|
|
138
|
+
git fetch --depth=1 origin "$before" 2>/dev/null || true
|
|
139
|
+
fi
|
|
140
|
+
old=""
|
|
141
|
+
if git cat-file -e "$before:django_pydantic_agent/version.py" 2>/dev/null; then
|
|
142
|
+
old="$(git show "$before:django_pydantic_agent/version.py" \
|
|
143
|
+
| awk -F'"' '/^__version__/ { print $2; exit }')"
|
|
144
|
+
fi
|
|
145
|
+
new="$(awk -F'"' '/^__version__/ { print $2; exit }' \
|
|
146
|
+
django_pydantic_agent/version.py)"
|
|
147
|
+
if [[ -n "$old" && "$old" != "$new" ]]; then
|
|
148
|
+
echo "Version bumped $old → $new; release.yml will deploy gh-pages."
|
|
149
|
+
echo "skip=true" >> "$GITHUB_OUTPUT"
|
|
150
|
+
else
|
|
151
|
+
echo "skip=false" >> "$GITHUB_OUTPUT"
|
|
152
|
+
fi
|
|
153
|
+
- name: Download canonical coverage artifact
|
|
154
|
+
if: steps.gate.outputs.skip != 'true'
|
|
155
|
+
uses: actions/download-artifact@v8
|
|
156
|
+
with:
|
|
157
|
+
# Pin to one cell of the matrix — coverage is the same shape across
|
|
158
|
+
# all cells and we only need one number.
|
|
159
|
+
name: coverage-py3.13-django5.2
|
|
160
|
+
path: coverage-artifact/
|
|
161
|
+
- name: Render coverage.json
|
|
162
|
+
if: steps.gate.outputs.skip != 'true'
|
|
163
|
+
run: |
|
|
164
|
+
python - <<'PY'
|
|
165
|
+
import json
|
|
166
|
+
import xml.etree.ElementTree as ET
|
|
167
|
+
|
|
168
|
+
tree = ET.parse("coverage-artifact/coverage.xml")
|
|
169
|
+
pct = round(float(tree.getroot().attrib["line-rate"]) * 100, 1)
|
|
170
|
+
if pct >= 95:
|
|
171
|
+
color = "brightgreen"
|
|
172
|
+
elif pct >= 85:
|
|
173
|
+
color = "green"
|
|
174
|
+
elif pct >= 70:
|
|
175
|
+
color = "yellow"
|
|
176
|
+
else:
|
|
177
|
+
color = "red"
|
|
178
|
+
payload = {
|
|
179
|
+
"schemaVersion": 1,
|
|
180
|
+
"label": "coverage",
|
|
181
|
+
"message": f"{pct}%",
|
|
182
|
+
"color": color,
|
|
183
|
+
}
|
|
184
|
+
with open("coverage.json", "w") as fh:
|
|
185
|
+
json.dump(payload, fh)
|
|
186
|
+
fh.write("\n")
|
|
187
|
+
print(json.dumps(payload))
|
|
188
|
+
PY
|
|
189
|
+
- name: Publish coverage.json to gh-pages
|
|
190
|
+
if: steps.gate.outputs.skip != 'true'
|
|
191
|
+
env:
|
|
192
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
193
|
+
run: |
|
|
194
|
+
set -euo pipefail
|
|
195
|
+
git config user.name 'github-actions[bot]'
|
|
196
|
+
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
197
|
+
|
|
198
|
+
tmp="$(mktemp -d)"
|
|
199
|
+
cp coverage.json "$tmp/coverage.json"
|
|
200
|
+
|
|
201
|
+
git fetch origin gh-pages --depth=1 2>/dev/null || true
|
|
202
|
+
if git rev-parse --verify origin/gh-pages >/dev/null 2>&1; then
|
|
203
|
+
git worktree add gh-pages origin/gh-pages
|
|
204
|
+
cp "$tmp/coverage.json" gh-pages/coverage.json
|
|
205
|
+
cd gh-pages
|
|
206
|
+
if [[ -n "$(git status --porcelain coverage.json)" ]]; then
|
|
207
|
+
git add coverage.json
|
|
208
|
+
git commit -m "coverage badge: update from ${GITHUB_SHA::7}"
|
|
209
|
+
git push origin HEAD:gh-pages
|
|
210
|
+
else
|
|
211
|
+
echo "coverage.json unchanged, skipping push"
|
|
212
|
+
fi
|
|
213
|
+
else
|
|
214
|
+
# First run before docs deploy. Lay down an orphan gh-pages with
|
|
215
|
+
# just the badge file; the docs deploy will overwrite the rest.
|
|
216
|
+
git worktree add --detach gh-pages
|
|
217
|
+
cd gh-pages
|
|
218
|
+
git checkout --orphan gh-pages
|
|
219
|
+
git rm -rf . >/dev/null 2>&1 || true
|
|
220
|
+
cp "$tmp/coverage.json" coverage.json
|
|
221
|
+
git add coverage.json
|
|
222
|
+
git commit -m "coverage badge: initial publish from ${GITHUB_SHA::7}"
|
|
223
|
+
git push origin gh-pages
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
secrets:
|
|
227
|
+
name: secret scan
|
|
228
|
+
runs-on: ubuntu-latest
|
|
229
|
+
steps:
|
|
230
|
+
- uses: actions/checkout@v7
|
|
231
|
+
with:
|
|
232
|
+
fetch-depth: 0
|
|
233
|
+
- name: Install gitleaks
|
|
234
|
+
run: |
|
|
235
|
+
curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz | tar -xz gitleaks
|
|
236
|
+
sudo mv gitleaks /usr/local/bin/
|
|
237
|
+
- name: Scan repo + history
|
|
238
|
+
run: gitleaks git --redact --no-banner .
|
|
239
|
+
|
|
240
|
+
tests-passed:
|
|
241
|
+
name: tests
|
|
242
|
+
if: always()
|
|
243
|
+
needs: [lint, docs, test]
|
|
244
|
+
runs-on: ubuntu-latest
|
|
245
|
+
steps:
|
|
246
|
+
- name: Verify required jobs succeeded
|
|
247
|
+
run: |
|
|
248
|
+
if [ "${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}" = "true" ]; then
|
|
249
|
+
echo "a required job failed"; exit 1
|
|
250
|
+
fi
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
*.manifest
|
|
31
|
+
*.spec
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
|
|
37
|
+
# Unit test / coverage reports
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
*.py,cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
cover/
|
|
51
|
+
coverage*.json
|
|
52
|
+
coverage*.xml
|
|
53
|
+
|
|
54
|
+
# release.yml renders this at workflow-time and drops it under docs/ so
|
|
55
|
+
# mkdocs gh-deploy carries it to the gh-pages root.
|
|
56
|
+
docs/coverage.json
|
|
57
|
+
|
|
58
|
+
# Translations
|
|
59
|
+
*.mo
|
|
60
|
+
*.pot
|
|
61
|
+
|
|
62
|
+
# Django stuff
|
|
63
|
+
*.log
|
|
64
|
+
local_settings.py
|
|
65
|
+
db.sqlite3
|
|
66
|
+
db.sqlite3-journal
|
|
67
|
+
|
|
68
|
+
# Sphinx documentation
|
|
69
|
+
docs/_build/
|
|
70
|
+
|
|
71
|
+
# Environments
|
|
72
|
+
.env
|
|
73
|
+
.venv
|
|
74
|
+
env/
|
|
75
|
+
venv/
|
|
76
|
+
ENV/
|
|
77
|
+
env.bak/
|
|
78
|
+
venv.bak/
|
|
79
|
+
|
|
80
|
+
# Virtualenv-style scripts dirs (we re-include the repo-root scripts/ directory).
|
|
81
|
+
[Ss]cripts
|
|
82
|
+
!/scripts/
|
|
83
|
+
pyvenv.cfg
|
|
84
|
+
.Python
|
|
85
|
+
[Bb]in
|
|
86
|
+
[Ii]nclude
|
|
87
|
+
[Ll]ib
|
|
88
|
+
[Ll]ib64
|
|
89
|
+
[Ll]ocal
|
|
90
|
+
|
|
91
|
+
# uv
|
|
92
|
+
.uv-cache/
|
|
93
|
+
|
|
94
|
+
# mkdocs
|
|
95
|
+
/site
|
|
96
|
+
|
|
97
|
+
# Type checkers
|
|
98
|
+
.mypy_cache/
|
|
99
|
+
.dmypy.json
|
|
100
|
+
dmypy.json
|
|
101
|
+
.pyre/
|
|
102
|
+
.pytype/
|
|
103
|
+
.ruff_cache/
|
|
104
|
+
.ty_cache/
|
|
105
|
+
|
|
106
|
+
# IDE
|
|
107
|
+
.vscode/
|
|
108
|
+
.idea/
|
|
109
|
+
*.iml
|
|
110
|
+
*.code-workspace
|
|
111
|
+
.history/
|
|
112
|
+
|
|
113
|
+
# OS
|
|
114
|
+
.DS_Store
|
|
115
|
+
Thumbs.db
|
|
116
|
+
|
|
117
|
+
# Release metadata (rendered by scripts/release-publish.sh during CI)
|
|
118
|
+
.release-metadata/
|
|
119
|
+
|
|
120
|
+
# AI-specific items
|
|
121
|
+
.ai/
|
|
122
|
+
.claude/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
3
|
+
rev: v8.30.1
|
|
4
|
+
hooks:
|
|
5
|
+
- id: gitleaks
|
|
6
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
+
rev: v6.0.0
|
|
8
|
+
hooks:
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: check-added-large-files
|
|
13
|
+
args: ["--maxkb=2000"]
|
|
14
|
+
|
|
15
|
+
- repo: local
|
|
16
|
+
hooks:
|
|
17
|
+
- id: ruff-check
|
|
18
|
+
name: "ruff check --fix"
|
|
19
|
+
entry: make lint-fix
|
|
20
|
+
pass_filenames: false
|
|
21
|
+
language: system
|
|
22
|
+
stages: [pre-commit]
|
|
23
|
+
|
|
24
|
+
- id: ruff-format
|
|
25
|
+
name: "ruff format"
|
|
26
|
+
entry: make format
|
|
27
|
+
pass_filenames: false
|
|
28
|
+
language: system
|
|
29
|
+
stages: [pre-commit]
|
|
30
|
+
|
|
31
|
+
- id: backend-type-check
|
|
32
|
+
name: "type check (ty)"
|
|
33
|
+
entry: make type-check
|
|
34
|
+
pass_filenames: false
|
|
35
|
+
language: system
|
|
36
|
+
stages: [pre-commit]
|
|
37
|
+
|
|
38
|
+
- id: forbid-local-paths
|
|
39
|
+
name: "forbid local filesystem paths / personal handles"
|
|
40
|
+
entry: "/Users/|arturveres"
|
|
41
|
+
language: pygrep
|
|
42
|
+
types: [text]
|
|
43
|
+
exclude: '^\.pre-commit-config\.yaml$'
|
|
44
|
+
|
|
45
|
+
- id: forbid-plan-labels
|
|
46
|
+
name: "forbid internal plan-step labels"
|
|
47
|
+
entry: '(?<![A-Za-z0-9])(SPEC|SURF|DISP|KEY|FILT|BULK|NEST|NAME|THINK|VOICE|THEME|WELL|PAGE|CARD|REST|I18N|CUST|TOOL|PAI|AUTHZ|CONF|AGH|OAS|WCH|HYG|ADOPT|ANNO|ASYNC|ERR|DUP|PROTO|SEC|VER|GATE|STATE|SESS|CTX|AUDIT|HITL|CODE|STEP|SHARE|SKILL|CAP|MOUNT|SAN|PF|PROV|SCH|LIFE|SUB|CI|DOC|EX)-\d|(?<![A-Za-z0-9])(Phase|Wave)\s\d'
|
|
48
|
+
language: pygrep
|
|
49
|
+
types: [text]
|
|
50
|
+
exclude: '^\.pre-commit-config\.yaml$'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] — 2026-07-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Initial extraction** of the settings-agnostic agent-host substrate from
|
|
15
|
+
`django-ag-ui`: `AgentConfig` + `build_agent`, the `ToolRegistry` / `@tool`
|
|
16
|
+
registry and typed schema derivation, toolset & capability composition
|
|
17
|
+
(including the optional `[drf-mcp]` bridge and `[spec-tools]` capability), the
|
|
18
|
+
`AuditLogger` protocol and audit capability, the `ToolGuard` policy, the
|
|
19
|
+
`get_user` / authorization helpers, the `ConversationStore` / `AttachmentStore`
|
|
20
|
+
/ `StepStore` contracts, and the reference `contrib.store` models and stores.
|
|
21
|
+
- **The core reads no Django settings.** Anything that previously resolved from
|
|
22
|
+
`DJANGO_AG_UI` is now an explicit argument — notably the model stores take
|
|
23
|
+
`allow_anonymous: bool = False` rather than consulting a settings key.
|
|
24
|
+
- **`Conversation.messages` is transport-owned.** The core persists and returns
|
|
25
|
+
JSON-serialisable message records verbatim and never interprets them, so it
|
|
26
|
+
carries no dependency on any wire format; the calling transport validates its
|
|
27
|
+
own shape (and its message ids survive a round trip untouched).
|
|
28
|
+
|
|
29
|
+
[Unreleased]: https://github.com/Artui/django-pydantic-agent/compare/v0.1.0...HEAD
|
|
30
|
+
[0.1.0]: https://github.com/Artui/django-pydantic-agent/releases/tag/v0.1.0
|