agentframe-py 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.
- agentframe_py-0.1.0/.github/actions/check-wheel/action.yml +47 -0
- agentframe_py-0.1.0/.github/workflows/ci.yml +39 -0
- agentframe_py-0.1.0/.github/workflows/foundry.yml +47 -0
- agentframe_py-0.1.0/.github/workflows/release.yml +234 -0
- agentframe_py-0.1.0/.gitignore +220 -0
- agentframe_py-0.1.0/.pre-commit-config.yaml +18 -0
- agentframe_py-0.1.0/.python-version +1 -0
- agentframe_py-0.1.0/AGENTS.md +596 -0
- agentframe_py-0.1.0/CHANGELOG.md +48 -0
- agentframe_py-0.1.0/LICENSE +201 -0
- agentframe_py-0.1.0/PKG-INFO +570 -0
- agentframe_py-0.1.0/README.md +539 -0
- agentframe_py-0.1.0/docs/README.md +120 -0
- agentframe_py-0.1.0/docs/api/README.md +209 -0
- agentframe_py-0.1.0/docs/api/agents.md +502 -0
- agentframe_py-0.1.0/docs/api/authorization.md +698 -0
- agentframe_py-0.1.0/docs/api/configuration.md +295 -0
- agentframe_py-0.1.0/docs/api/decorators.md +342 -0
- agentframe_py-0.1.0/docs/api/discovery.md +760 -0
- agentframe_py-0.1.0/docs/api/hosting.md +1130 -0
- agentframe_py-0.1.0/docs/api/models.md +990 -0
- agentframe_py-0.1.0/docs/api/runtime.md +765 -0
- agentframe_py-0.1.0/docs/api/streaming.md +124 -0
- agentframe_py-0.1.0/docs/design/base-classes.md +328 -0
- agentframe_py-0.1.0/docs/design/discovery.md +439 -0
- agentframe_py-0.1.0/docs/design/mcp-skills.md +311 -0
- agentframe_py-0.1.0/docs/design/prompt-safeguarding.md +127 -0
- agentframe_py-0.1.0/docs/design/streaming.md +191 -0
- agentframe_py-0.1.0/docs/design/tracing.md +141 -0
- agentframe_py-0.1.0/docs/guides/agent-examples.md +498 -0
- agentframe_py-0.1.0/docs/guides/annotations.md +233 -0
- agentframe_py-0.1.0/docs/guides/authorization.md +294 -0
- agentframe_py-0.1.0/docs/guides/development.md +117 -0
- agentframe_py-0.1.0/docs/guides/limits.md +403 -0
- agentframe_py-0.1.0/docs/guides/releasing.md +81 -0
- agentframe_py-0.1.0/docs/roadmap.md +591 -0
- agentframe_py-0.1.0/examples/__init__.py +1 -0
- agentframe_py-0.1.0/examples/assistant.py +124 -0
- agentframe_py-0.1.0/examples/echo.py +85 -0
- agentframe_py-0.1.0/examples/orders.py +149 -0
- agentframe_py-0.1.0/examples/routed_assistant.py +84 -0
- agentframe_py-0.1.0/examples/smoke.py +219 -0
- agentframe_py-0.1.0/pyproject.toml +101 -0
- agentframe_py-0.1.0/src/agentframe/__init__.py +170 -0
- agentframe_py-0.1.0/src/agentframe/authoring/__init__.py +1 -0
- agentframe_py-0.1.0/src/agentframe/authoring/agent.py +75 -0
- agentframe_py-0.1.0/src/agentframe/authoring/context.py +123 -0
- agentframe_py-0.1.0/src/agentframe/authoring/decorators.py +202 -0
- agentframe_py-0.1.0/src/agentframe/authoring/definitions.py +372 -0
- agentframe_py-0.1.0/src/agentframe/authoring/services.py +176 -0
- agentframe_py-0.1.0/src/agentframe/cli.py +293 -0
- agentframe_py-0.1.0/src/agentframe/errors.py +194 -0
- agentframe_py-0.1.0/src/agentframe/hosting/__init__.py +1 -0
- agentframe_py-0.1.0/src/agentframe/hosting/a2a_executor.py +569 -0
- agentframe_py-0.1.0/src/agentframe/hosting/admission.py +69 -0
- agentframe_py-0.1.0/src/agentframe/hosting/app.py +617 -0
- agentframe_py-0.1.0/src/agentframe/hosting/card.py +138 -0
- agentframe_py-0.1.0/src/agentframe/hosting/dedup.py +193 -0
- agentframe_py-0.1.0/src/agentframe/hosting/draining_server.py +47 -0
- agentframe_py-0.1.0/src/agentframe/hosting/host.py +143 -0
- agentframe_py-0.1.0/src/agentframe/hosting/lifecycle.py +81 -0
- agentframe_py-0.1.0/src/agentframe/hosting/model_router.py +407 -0
- agentframe_py-0.1.0/src/agentframe/hosting/request_size.py +52 -0
- agentframe_py-0.1.0/src/agentframe/hosting/routing.py +349 -0
- agentframe_py-0.1.0/src/agentframe/models/__init__.py +1 -0
- agentframe_py-0.1.0/src/agentframe/models/base.py +264 -0
- agentframe_py-0.1.0/src/agentframe/models/foundry.py +570 -0
- agentframe_py-0.1.0/src/agentframe/models/ollama.py +320 -0
- agentframe_py-0.1.0/src/agentframe/models/strict_schema.py +211 -0
- agentframe_py-0.1.0/src/agentframe/py.typed +0 -0
- agentframe_py-0.1.0/src/agentframe/runtime/__init__.py +1 -0
- agentframe_py-0.1.0/src/agentframe/runtime/generation.py +725 -0
- agentframe_py-0.1.0/src/agentframe/runtime/limits.py +124 -0
- agentframe_py-0.1.0/src/agentframe/runtime/options.py +50 -0
- agentframe_py-0.1.0/src/agentframe/runtime/runtime.py +449 -0
- agentframe_py-0.1.0/src/agentframe/runtime/tools.py +216 -0
- agentframe_py-0.1.0/src/agentframe/runtime/usage.py +40 -0
- agentframe_py-0.1.0/src/agentframe/security/__init__.py +1 -0
- agentframe_py-0.1.0/src/agentframe/security/authentication.py +265 -0
- agentframe_py-0.1.0/src/agentframe/security/authorization.py +66 -0
- agentframe_py-0.1.0/src/agentframe/security/entra.py +260 -0
- agentframe_py-0.1.0/src/agentframe/security/execution_policy.py +241 -0
- agentframe_py-0.1.0/src/agentframe/security/principal.py +16 -0
- agentframe_py-0.1.0/src/agentframe/testing.py +135 -0
- agentframe_py-0.1.0/tests/conftest.py +11 -0
- agentframe_py-0.1.0/tests/integration/test_entra_interoperability.py +145 -0
- agentframe_py-0.1.0/tests/integration/test_example.py +65 -0
- agentframe_py-0.1.0/tests/integration/test_graceful_shutdown.py +95 -0
- agentframe_py-0.1.0/tests/integration/test_hardening.py +1098 -0
- agentframe_py-0.1.0/tests/integration/test_interoperability.py +405 -0
- agentframe_py-0.1.0/tests/integration/test_providers.py +481 -0
- agentframe_py-0.1.0/tests/integration/test_routing_example.py +237 -0
- agentframe_py-0.1.0/tests/integration/test_smoke.py +12 -0
- agentframe_py-0.1.0/tests/integration/test_structured_example.py +117 -0
- agentframe_py-0.1.0/tests/integration/test_success_criterion.py +100 -0
- agentframe_py-0.1.0/tests/integration/test_tools_example.py +255 -0
- agentframe_py-0.1.0/tests/support/a2a_client.py +122 -0
- agentframe_py-0.1.0/tests/support/cli_targets.py +78 -0
- agentframe_py-0.1.0/tests/support/fake_entra.py +94 -0
- agentframe_py-0.1.0/tests/support/local_server.py +106 -0
- agentframe_py-0.1.0/tests/unit/authoring/test_decorators.py +321 -0
- agentframe_py-0.1.0/tests/unit/authoring/test_services.py +169 -0
- agentframe_py-0.1.0/tests/unit/authoring/test_tool_registration.py +166 -0
- agentframe_py-0.1.0/tests/unit/authoring/test_tools.py +273 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_a2a_binding.py +158 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_a2a_executor.py +194 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_admission.py +349 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_app.py +691 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_card.py +316 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_dedup.py +390 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_limits_ceiling.py +295 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_model_router.py +734 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_routing.py +718 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_shutdown.py +354 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_size_limits.py +301 -0
- agentframe_py-0.1.0/tests/unit/hosting/test_task_operations.py +304 -0
- agentframe_py-0.1.0/tests/unit/models/test_foundry.py +1117 -0
- agentframe_py-0.1.0/tests/unit/models/test_models.py +248 -0
- agentframe_py-0.1.0/tests/unit/models/test_ollama.py +615 -0
- agentframe_py-0.1.0/tests/unit/models/test_strict_schema.py +276 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_generation.py +767 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_limits.py +403 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_options.py +240 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_retries.py +261 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_runtime.py +168 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_structured_output.py +401 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_tool_loop.py +627 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_tool_replay.py +198 -0
- agentframe_py-0.1.0/tests/unit/runtime/test_validation.py +123 -0
- agentframe_py-0.1.0/tests/unit/security/test_authentication.py +179 -0
- agentframe_py-0.1.0/tests/unit/security/test_authorization.py +249 -0
- agentframe_py-0.1.0/tests/unit/security/test_entra.py +270 -0
- agentframe_py-0.1.0/tests/unit/security/test_execution_policy.py +821 -0
- agentframe_py-0.1.0/tests/unit/security/test_tool_authorization.py +363 -0
- agentframe_py-0.1.0/tests/unit/test_cli.py +199 -0
- agentframe_py-0.1.0/tests/unit/test_package.py +19 -0
- agentframe_py-0.1.0/tests/unit/test_testing.py +118 -0
- agentframe_py-0.1.0/uv.lock +1967 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Checks a built wheel the way a user installs it: from a directory outside the
|
|
2
|
+
# checkout, so src/ can never shadow the installed package. Used by the CI
|
|
3
|
+
# build job and by the release workflow, so a release ships only a wheel that
|
|
4
|
+
# passed the same checks. Expects uv to be installed and exactly one wheel in
|
|
5
|
+
# the workspace's dist/.
|
|
6
|
+
name: Check the built wheel
|
|
7
|
+
description: Import, CLI and examples smoke checks against the installed wheel.
|
|
8
|
+
|
|
9
|
+
runs:
|
|
10
|
+
using: composite
|
|
11
|
+
steps:
|
|
12
|
+
- name: Import the installed wheel and its A2A server binding
|
|
13
|
+
shell: bash
|
|
14
|
+
working-directory: ${{ runner.temp }}
|
|
15
|
+
run: >-
|
|
16
|
+
uv run --isolated --no-project --python 3.13
|
|
17
|
+
--with "${GITHUB_WORKSPACE}"/dist/*.whl
|
|
18
|
+
python -c "import agentframe, starlette, sse_starlette;
|
|
19
|
+
from a2a.server.routes import create_jsonrpc_routes;
|
|
20
|
+
print(agentframe.__version__)"
|
|
21
|
+
- name: Import the base install without provider extras
|
|
22
|
+
shell: bash
|
|
23
|
+
working-directory: ${{ runner.temp }}
|
|
24
|
+
run: >-
|
|
25
|
+
uv run --isolated --no-project --python 3.13
|
|
26
|
+
--with "${GITHUB_WORKSPACE}"/dist/*.whl
|
|
27
|
+
python -c "import importlib.util, agentframe;
|
|
28
|
+
assert importlib.util.find_spec('ollama') is None, 'ollama installed';
|
|
29
|
+
assert importlib.util.find_spec('openai') is None, 'openai installed';
|
|
30
|
+
assert importlib.util.find_spec('azure') is None, 'azure-identity installed';
|
|
31
|
+
assert importlib.util.find_spec('jwt') is None, 'PyJWT installed';
|
|
32
|
+
print('base install imports without provider extras')"
|
|
33
|
+
- name: Run the agentframe command from the wheel's server extra
|
|
34
|
+
shell: bash
|
|
35
|
+
working-directory: ${{ runner.temp }}
|
|
36
|
+
run: >-
|
|
37
|
+
uv run --isolated --no-project --python 3.13
|
|
38
|
+
--with "$(ls "${GITHUB_WORKSPACE}"/dist/*.whl)[server]"
|
|
39
|
+
agentframe run --help
|
|
40
|
+
- name: Smoke-test the examples against the installed wheel
|
|
41
|
+
shell: bash
|
|
42
|
+
run: |
|
|
43
|
+
cp -R examples "${RUNNER_TEMP}/examples"
|
|
44
|
+
cd "${RUNNER_TEMP}"
|
|
45
|
+
uv run --isolated --no-project --python 3.13 \
|
|
46
|
+
--with "$(ls "${GITHUB_WORKSPACE}"/dist/*.whl)[server]" \
|
|
47
|
+
python -m examples.smoke
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
check:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.13", "3.14", "3.15"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
21
|
+
with:
|
|
22
|
+
version: "0.13.1"
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
# Provider extras are installed so model adapter unit tests always run.
|
|
25
|
+
- run: uv sync --locked --all-extras
|
|
26
|
+
- run: uv run ruff format --check
|
|
27
|
+
- run: uv run ruff check
|
|
28
|
+
- run: uv run mypy
|
|
29
|
+
- run: uv run pytest
|
|
30
|
+
|
|
31
|
+
build:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v7
|
|
35
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
36
|
+
with:
|
|
37
|
+
version: "0.13.1"
|
|
38
|
+
- run: uv build
|
|
39
|
+
- uses: ./.github/actions/check-wheel
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Runs the opt-in Foundry tests against a real deployment, on demand only.
|
|
2
|
+
# Foundry calls cost money, so this never runs on push or pull request. The
|
|
3
|
+
# `foundry` environment requires reviewer approval and holds the Azure IDs and
|
|
4
|
+
# endpoint as variables; sign-in uses OpenID Connect, so there is no secret.
|
|
5
|
+
# One-time setup: README.md, "Real-provider tests".
|
|
6
|
+
name: Foundry provider tests
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: foundry
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
foundry:
|
|
20
|
+
# Forks have no access to the environment; skip instead of failing.
|
|
21
|
+
if: github.repository == 'malcmiller/agentframe'
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
timeout-minutes: 20
|
|
24
|
+
environment: foundry
|
|
25
|
+
permissions:
|
|
26
|
+
id-token: write
|
|
27
|
+
contents: read
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v7
|
|
30
|
+
with:
|
|
31
|
+
persist-credentials: false
|
|
32
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
33
|
+
with:
|
|
34
|
+
version: "0.13.1"
|
|
35
|
+
python-version: "3.13"
|
|
36
|
+
- run: uv sync --locked --all-extras
|
|
37
|
+
# The tests use AzureCliCredential, which reads this CLI sign-in.
|
|
38
|
+
- uses: azure/login@v3.1.0
|
|
39
|
+
with:
|
|
40
|
+
client-id: ${{ vars.AZURE_CLIENT_ID }}
|
|
41
|
+
tenant-id: ${{ vars.AZURE_TENANT_ID }}
|
|
42
|
+
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
|
|
43
|
+
- run: uv run pytest -m foundry
|
|
44
|
+
env:
|
|
45
|
+
AGENTFRAME_TEST_FOUNDRY: "1"
|
|
46
|
+
AGENTFRAME_FOUNDRY_ENDPOINT: ${{ vars.AGENTFRAME_FOUNDRY_ENDPOINT }}
|
|
47
|
+
AGENTFRAME_FOUNDRY_DEPLOYMENT: ${{ vars.AGENTFRAME_FOUNDRY_DEPLOYMENT }}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Publishes agentframe-py to TestPyPI, then PyPI, when the maintainer publishes a
|
|
2
|
+
# GitHub release for a v* tag on main. The distributions are built once, checked,
|
|
3
|
+
# and the same files are uploaded to both indexes. Uploads use PyPI trusted
|
|
4
|
+
# publishing (OpenID Connect), so no API token is stored anywhere; the PyPI
|
|
5
|
+
# upload also waits for approval in the `pypi` environment.
|
|
6
|
+
# One-time setup and the release steps: docs/guides/releasing.md.
|
|
7
|
+
name: Release
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
release:
|
|
11
|
+
types: [published]
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: release
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
check:
|
|
22
|
+
name: Check the release commit
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 20
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v7
|
|
27
|
+
with:
|
|
28
|
+
fetch-depth: 0
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
- name: Require the tag to point at a commit on main
|
|
31
|
+
run: git merge-base --is-ancestor "${GITHUB_SHA}" origin/main
|
|
32
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
33
|
+
with:
|
|
34
|
+
version: "0.13.1"
|
|
35
|
+
python-version: "3.13"
|
|
36
|
+
- run: uv sync --locked --all-extras
|
|
37
|
+
- run: uv run ruff format --check
|
|
38
|
+
- run: uv run ruff check
|
|
39
|
+
- run: uv run mypy
|
|
40
|
+
- run: uv run pytest
|
|
41
|
+
|
|
42
|
+
build:
|
|
43
|
+
name: Build and check the distributions
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
timeout-minutes: 20
|
|
46
|
+
outputs:
|
|
47
|
+
version: ${{ steps.version.outputs.version }}
|
|
48
|
+
checksums: ${{ steps.checksums.outputs.checksums }}
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v7
|
|
51
|
+
with:
|
|
52
|
+
persist-credentials: false
|
|
53
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
54
|
+
with:
|
|
55
|
+
version: "0.13.1"
|
|
56
|
+
- name: Require the tag to equal v + the project version
|
|
57
|
+
id: version
|
|
58
|
+
env:
|
|
59
|
+
TAG: ${{ github.event.release.tag_name }}
|
|
60
|
+
run: |
|
|
61
|
+
version="$(uv run --no-project --python 3.13 python -c \
|
|
62
|
+
'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')"
|
|
63
|
+
if [ "${TAG}" != "v${version}" ]; then
|
|
64
|
+
echo "::error::Release tag ${TAG} does not equal v${version} from pyproject.toml"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
echo "version=${version}" >> "${GITHUB_OUTPUT}"
|
|
68
|
+
# A version on PyPI or TestPyPI can never be uploaded again.
|
|
69
|
+
- name: Refuse a version that is already on PyPI or TestPyPI
|
|
70
|
+
env:
|
|
71
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
72
|
+
run: |
|
|
73
|
+
for index in https://pypi.org https://test.pypi.org; do
|
|
74
|
+
status="$(curl --silent --output /dev/null --write-out '%{http_code}' \
|
|
75
|
+
"${index}/pypi/agentframe-py/${VERSION}/json")"
|
|
76
|
+
if [ "${status}" != "404" ]; then
|
|
77
|
+
echo "::error::agentframe-py ${VERSION} exists on ${index} or it is unreachable (HTTP ${status})"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
- run: uv build
|
|
82
|
+
- name: Require exactly the expected wheel and sdist
|
|
83
|
+
env:
|
|
84
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
85
|
+
run: |
|
|
86
|
+
files=(dist/*)
|
|
87
|
+
printf '%s\n' "${files[@]}"
|
|
88
|
+
test "${#files[@]}" -eq 2
|
|
89
|
+
test -f "dist/agentframe_py-${VERSION}-py3-none-any.whl"
|
|
90
|
+
test -f "dist/agentframe_py-${VERSION}.tar.gz"
|
|
91
|
+
- uses: ./.github/actions/check-wheel
|
|
92
|
+
# Passed to the upload jobs as a job output, separately from the
|
|
93
|
+
# artifact, so they can confirm they upload exactly these files.
|
|
94
|
+
- name: Record the distribution checksums
|
|
95
|
+
id: checksums
|
|
96
|
+
run: |
|
|
97
|
+
{
|
|
98
|
+
echo "checksums<<EOF"
|
|
99
|
+
(cd dist && sha256sum -- *)
|
|
100
|
+
echo "EOF"
|
|
101
|
+
} >> "${GITHUB_OUTPUT}"
|
|
102
|
+
- uses: actions/upload-artifact@v7
|
|
103
|
+
with:
|
|
104
|
+
name: dist
|
|
105
|
+
path: dist/
|
|
106
|
+
if-no-files-found: error
|
|
107
|
+
|
|
108
|
+
publish-testpypi:
|
|
109
|
+
name: Publish to TestPyPI
|
|
110
|
+
needs: [check, build]
|
|
111
|
+
# Forks have no trusted publisher or environments; skip instead of failing.
|
|
112
|
+
if: github.repository == 'malcmiller/agentframe'
|
|
113
|
+
runs-on: ubuntu-latest
|
|
114
|
+
timeout-minutes: 10
|
|
115
|
+
environment:
|
|
116
|
+
name: testpypi
|
|
117
|
+
url: https://test.pypi.org/project/agentframe-py/${{ needs.build.outputs.version }}/
|
|
118
|
+
permissions:
|
|
119
|
+
id-token: write
|
|
120
|
+
steps:
|
|
121
|
+
- uses: actions/download-artifact@v8
|
|
122
|
+
with:
|
|
123
|
+
name: dist
|
|
124
|
+
path: dist/
|
|
125
|
+
- name: Confirm these are the files that were built and checked
|
|
126
|
+
env:
|
|
127
|
+
CHECKSUMS: ${{ needs.build.outputs.checksums }}
|
|
128
|
+
run: cd dist && sha256sum --check --strict <<< "${CHECKSUMS}"
|
|
129
|
+
# Pinned to a commit because this action handles the upload credential.
|
|
130
|
+
# It also uploads PEP 740 attestations (signed provenance) by default.
|
|
131
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
132
|
+
with:
|
|
133
|
+
repository-url: https://test.pypi.org/legacy/
|
|
134
|
+
|
|
135
|
+
verify-testpypi:
|
|
136
|
+
name: Install from TestPyPI and run the examples
|
|
137
|
+
needs: [build, publish-testpypi]
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
timeout-minutes: 20
|
|
140
|
+
env:
|
|
141
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
142
|
+
steps:
|
|
143
|
+
- uses: actions/checkout@v7
|
|
144
|
+
with:
|
|
145
|
+
persist-credentials: false
|
|
146
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
147
|
+
with:
|
|
148
|
+
version: "0.13.1"
|
|
149
|
+
- name: Create a clean Python 3.13 environment
|
|
150
|
+
working-directory: ${{ runner.temp }}
|
|
151
|
+
run: uv venv --seed --python 3.13 venv
|
|
152
|
+
# Only agentframe-py comes from TestPyPI, so look-alike packages there can
|
|
153
|
+
# never replace its dependencies. Retried while the index catches up.
|
|
154
|
+
- name: Install agentframe-py from TestPyPI
|
|
155
|
+
working-directory: ${{ runner.temp }}
|
|
156
|
+
run: |
|
|
157
|
+
for attempt in 1 2 3 4 5 6; do
|
|
158
|
+
if venv/bin/pip install --no-deps \
|
|
159
|
+
--index-url https://test.pypi.org/simple/ "agentframe-py==${VERSION}"; then
|
|
160
|
+
exit 0
|
|
161
|
+
fi
|
|
162
|
+
echo "Not installable yet (attempt ${attempt}); retrying in 30 seconds"
|
|
163
|
+
sleep 30
|
|
164
|
+
done
|
|
165
|
+
exit 1
|
|
166
|
+
- name: Install its dependencies from PyPI
|
|
167
|
+
working-directory: ${{ runner.temp }}
|
|
168
|
+
run: venv/bin/pip install "agentframe-py[server]==${VERSION}"
|
|
169
|
+
# A copy outside the checkout, so src/ can never shadow the install.
|
|
170
|
+
- name: Smoke-test the examples against the TestPyPI install
|
|
171
|
+
run: |
|
|
172
|
+
cp -R examples "${RUNNER_TEMP}/examples"
|
|
173
|
+
cd "${RUNNER_TEMP}"
|
|
174
|
+
venv/bin/python -m examples.smoke
|
|
175
|
+
|
|
176
|
+
publish-pypi:
|
|
177
|
+
name: Publish to PyPI
|
|
178
|
+
needs: [build, verify-testpypi]
|
|
179
|
+
if: github.repository == 'malcmiller/agentframe'
|
|
180
|
+
runs-on: ubuntu-latest
|
|
181
|
+
timeout-minutes: 10
|
|
182
|
+
environment:
|
|
183
|
+
name: pypi
|
|
184
|
+
url: https://pypi.org/project/agentframe-py/${{ needs.build.outputs.version }}/
|
|
185
|
+
permissions:
|
|
186
|
+
id-token: write
|
|
187
|
+
steps:
|
|
188
|
+
- uses: actions/download-artifact@v8
|
|
189
|
+
with:
|
|
190
|
+
name: dist
|
|
191
|
+
path: dist/
|
|
192
|
+
- name: Confirm these are the files that were built and checked
|
|
193
|
+
env:
|
|
194
|
+
CHECKSUMS: ${{ needs.build.outputs.checksums }}
|
|
195
|
+
run: cd dist && sha256sum --check --strict <<< "${CHECKSUMS}"
|
|
196
|
+
- uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
|
|
197
|
+
|
|
198
|
+
verify-pypi:
|
|
199
|
+
name: Install from PyPI on Python ${{ matrix.python-version }}
|
|
200
|
+
needs: [build, publish-pypi]
|
|
201
|
+
runs-on: ubuntu-latest
|
|
202
|
+
timeout-minutes: 20
|
|
203
|
+
strategy:
|
|
204
|
+
fail-fast: false
|
|
205
|
+
matrix:
|
|
206
|
+
python-version: ["3.13", "3.14", "3.15"]
|
|
207
|
+
env:
|
|
208
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
209
|
+
steps:
|
|
210
|
+
- uses: actions/checkout@v7
|
|
211
|
+
with:
|
|
212
|
+
persist-credentials: false
|
|
213
|
+
- uses: astral-sh/setup-uv@v10.3.3
|
|
214
|
+
with:
|
|
215
|
+
version: "0.13.1"
|
|
216
|
+
- name: Create a clean Python ${{ matrix.python-version }} environment
|
|
217
|
+
working-directory: ${{ runner.temp }}
|
|
218
|
+
run: uv venv --seed --python "${{ matrix.python-version }}" venv
|
|
219
|
+
- name: pip install agentframe-py from PyPI
|
|
220
|
+
working-directory: ${{ runner.temp }}
|
|
221
|
+
run: |
|
|
222
|
+
for attempt in 1 2 3 4 5 6; do
|
|
223
|
+
if venv/bin/pip install "agentframe-py[server]==${VERSION}"; then
|
|
224
|
+
exit 0
|
|
225
|
+
fi
|
|
226
|
+
echo "Not installable yet (attempt ${attempt}); retrying in 30 seconds"
|
|
227
|
+
sleep 30
|
|
228
|
+
done
|
|
229
|
+
exit 1
|
|
230
|
+
- name: Smoke-test the examples against the PyPI install
|
|
231
|
+
run: |
|
|
232
|
+
cp -R examples "${RUNNER_TEMP}/examples"
|
|
233
|
+
cd "${RUNNER_TEMP}"
|
|
234
|
+
venv/bin/python -m examples.smoke
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
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
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# uv
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs/Zensical documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
.idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
201
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
203
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.17.4
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff-check
|
|
6
|
+
args: [--fix]
|
|
7
|
+
types_or: [python, pyi]
|
|
8
|
+
- id: ruff-format
|
|
9
|
+
types_or: [python, pyi]
|
|
10
|
+
|
|
11
|
+
- repo: local
|
|
12
|
+
hooks:
|
|
13
|
+
- id: mypy
|
|
14
|
+
name: mypy
|
|
15
|
+
entry: uv run mypy
|
|
16
|
+
language: system
|
|
17
|
+
types: [python]
|
|
18
|
+
pass_filenames: false
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|