schemarouter 0.2.0a1__tar.gz → 0.3.0a1__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.
- schemarouter-0.3.0a1/.github/workflows/auto-tag-release.yml +99 -0
- schemarouter-0.3.0a1/.github/workflows/ci.yml +205 -0
- schemarouter-0.3.0a1/.github/workflows/release.yml +161 -0
- schemarouter-0.3.0a1/CHANGELOG.md +103 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/CONTRIBUTING.md +16 -9
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/PKG-INFO +125 -11
- schemarouter-0.3.0a1/README.ko.md +365 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/README.md +113 -10
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/SECURITY.md +35 -8
- schemarouter-0.3.0a1/benchmarks/decision-routing-v1.json +1010 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/adapter-authoring.md +20 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/architecture.md +68 -8
- schemarouter-0.3.0a1/docs/changelog.md +103 -0
- schemarouter-0.3.0a1/docs/compatibility.md +113 -0
- schemarouter-0.3.0a1/docs/concepts/decision-backends.md +100 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/contributing.md +16 -9
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/framework-maturity.md +49 -26
- schemarouter-0.3.0a1/docs/getting-started/installation.md +81 -0
- schemarouter-0.3.0a1/docs/guides/adapter-plugins.md +76 -0
- schemarouter-0.3.0a1/docs/guides/decision-benchmark.md +116 -0
- schemarouter-0.3.0a1/docs/guides/execution-policy.md +139 -0
- schemarouter-0.3.0a1/docs/guides/mcp.md +109 -0
- schemarouter-0.3.0a1/docs/guides/openapi-compatibility.md +60 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/openapi.md +10 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/runtime.md +18 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/index.md +20 -8
- schemarouter-0.3.0a1/docs/integrations/jev.md +132 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/integrations/langchain.md +28 -1
- schemarouter-0.3.0a1/docs/integrations/llamaindex.md +57 -0
- schemarouter-0.3.0a1/docs/integrations/opentelemetry.md +67 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/reference/api.md +25 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/reference/runtime.md +4 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/release-checklist.md +29 -6
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/releases/0.2.0a1.md +2 -2
- schemarouter-0.3.0a1/docs/releases/0.3.0a1.md +108 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/security/threat-model.md +36 -9
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/versioning.md +25 -2
- schemarouter-0.3.0a1/examples/langchain_quickstart.py +25 -0
- schemarouter-0.3.0a1/examples/llamaindex_quickstart.py +25 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/mkdocs.yml +7 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/pyproject.toml +30 -1
- schemarouter-0.3.0a1/scripts/benchmark_decision_routing.py +548 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/__init__.py +54 -2
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/__init__.py +27 -1
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/base.py +1 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/mcp.py +119 -19
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/openapi.py +71 -15
- schemarouter-0.3.0a1/src/schemarouter/adapters/plugins.py +133 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/python.py +3 -2
- schemarouter-0.3.0a1/src/schemarouter/decision_policy.py +28 -0
- schemarouter-0.3.0a1/src/schemarouter/decisions.py +178 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/errors.py +8 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/executor.py +173 -12
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/ingestion.py +14 -6
- schemarouter-0.3.0a1/src/schemarouter/integrations/__init__.py +14 -0
- schemarouter-0.3.0a1/src/schemarouter/integrations/jev.py +227 -0
- schemarouter-0.3.0a1/src/schemarouter/integrations/llamaindex.py +173 -0
- schemarouter-0.3.0a1/src/schemarouter/integrations/opentelemetry.py +179 -0
- schemarouter-0.3.0a1/src/schemarouter/openapi_compatibility.py +423 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/planner.py +156 -5
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/policy.py +34 -10
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/runs.py +32 -1
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/runtime.py +61 -11
- schemarouter-0.3.0a1/tests/test_adapter_plugins.py +126 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_adapters.py +152 -0
- schemarouter-0.3.0a1/tests/test_benchmark_corpus.py +69 -0
- schemarouter-0.3.0a1/tests/test_decision_policy.py +21 -0
- schemarouter-0.3.0a1/tests/test_decisions.py +114 -0
- schemarouter-0.3.0a1/tests/test_execution_controls.py +355 -0
- schemarouter-0.3.0a1/tests/test_jev_integration.py +216 -0
- schemarouter-0.3.0a1/tests/test_llamaindex_integration.py +81 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_mcp_integration.py +3 -0
- schemarouter-0.3.0a1/tests/test_mcp_transport.py +134 -0
- schemarouter-0.3.0a1/tests/test_openapi_compatibility.py +149 -0
- schemarouter-0.3.0a1/tests/test_opentelemetry_integration.py +152 -0
- schemarouter-0.3.0a1/tests/test_package_metadata.py +7 -0
- schemarouter-0.3.0a1/tests/test_planner.py +218 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_public_api.py +25 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_registry.py +66 -0
- schemarouter-0.3.0a1/tests/test_release_metadata.py +123 -0
- schemarouter-0.2.0a1/.github/workflows/ci.yml +0 -90
- schemarouter-0.2.0a1/.github/workflows/release.yml +0 -113
- schemarouter-0.2.0a1/CHANGELOG.md +0 -45
- schemarouter-0.2.0a1/docs/changelog.md +0 -36
- schemarouter-0.2.0a1/docs/compatibility.md +0 -48
- schemarouter-0.2.0a1/docs/getting-started/installation.md +0 -61
- schemarouter-0.2.0a1/docs/guides/execution-policy.md +0 -58
- schemarouter-0.2.0a1/docs/guides/mcp.md +0 -62
- schemarouter-0.2.0a1/src/schemarouter/integrations/__init__.py +0 -3
- schemarouter-0.2.0a1/tests/test_package_metadata.py +0 -5
- schemarouter-0.2.0a1/tests/test_planner.py +0 -79
- schemarouter-0.2.0a1/tests/test_release_metadata.py +0 -47
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/.github/dependabot.yml +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/.github/workflows/compatibility.yml +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/.github/workflows/docs.yml +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/.gitignore +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/LICENSE +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/README.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/schemarouter-lockup-dark.svg +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/schemarouter-lockup-light.svg +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/schemarouter-mark-dark.svg +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/schemarouter-mark-light.svg +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/assets/brand/schemarouter-social-preview.svg +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/adapters.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/execution.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/planning.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/registry.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/schema-router.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/concepts/tool-endpoint.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/getting-started/ingestion-paths.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/getting-started/quickstart.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/html-documentation.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/model-analyzer.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/optimade.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/python-tools.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/guides/retry.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/license.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/project/brand.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/recipes/many-tools.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/recipes/mcp-agent.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/recipes/openapi-agent.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/reference/models.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/reference/planning.md +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/docs/stylesheets/brand.css +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/examples/quickstart.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/scripts/live_openapi_smoke.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/scripts/live_optimade_smoke.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/_version.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/adapters/optimade.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/analyzers/__init__.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/analyzers/model.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/integrations/langchain.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/models.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/proposals.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/py.typed +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/registry.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/src/schemarouter/validation.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/fixtures/mcp_http_server.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_adapter_registry.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_brand_assets.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_executor.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_ingestion.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_langchain_integration.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_model_analyzer.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_optimade_adapter.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_optimade_security.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_policy.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_proposals.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_python_adapter.py +0 -0
- {schemarouter-0.2.0a1 → schemarouter-0.3.0a1}/tests/test_runtime_interface.py +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
name: Auto Tag Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
workflows: ["CI"]
|
|
6
|
+
types: [completed]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: auto-tag-release-${{ github.event.workflow_run.head_sha }}
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
tag:
|
|
17
|
+
if: >-
|
|
18
|
+
github.event.workflow_run.conclusion == 'success' &&
|
|
19
|
+
github.event.workflow_run.head_branch == 'main'
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
with:
|
|
24
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
25
|
+
fetch-depth: 0
|
|
26
|
+
|
|
27
|
+
- name: Verify release commit is still current main
|
|
28
|
+
env:
|
|
29
|
+
RELEASE_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
30
|
+
run: |
|
|
31
|
+
git fetch origin main --depth=1
|
|
32
|
+
current_main="$(git rev-parse origin/main)"
|
|
33
|
+
if [[ "$current_main" != "$RELEASE_SHA" ]]; then
|
|
34
|
+
echo "CI succeeded for $RELEASE_SHA, but current main is $current_main; skipping stale run."
|
|
35
|
+
echo "SKIP_RELEASE_TAG=true" >> "$GITHUB_ENV"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
- name: Resolve release metadata
|
|
39
|
+
if: env.SKIP_RELEASE_TAG != 'true'
|
|
40
|
+
id: metadata
|
|
41
|
+
run: |
|
|
42
|
+
python - <<'PY'
|
|
43
|
+
import os
|
|
44
|
+
import re
|
|
45
|
+
import tomllib
|
|
46
|
+
from pathlib import Path
|
|
47
|
+
|
|
48
|
+
version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
|
|
49
|
+
if ".dev" in version:
|
|
50
|
+
with Path(os.environ["GITHUB_OUTPUT"]).open("a", encoding="utf-8") as output:
|
|
51
|
+
print("releasable=false", file=output)
|
|
52
|
+
raise SystemExit(0)
|
|
53
|
+
|
|
54
|
+
release_notes = Path("docs") / "releases" / f"{version}.md"
|
|
55
|
+
if not release_notes.is_file():
|
|
56
|
+
raise SystemExit(f"missing release notes for releasable version: {release_notes}")
|
|
57
|
+
|
|
58
|
+
changelog = Path("CHANGELOG.md").read_text(encoding="utf-8")
|
|
59
|
+
if f"## {version} -" not in changelog:
|
|
60
|
+
raise SystemExit(f"CHANGELOG.md is missing a dated {version} release heading")
|
|
61
|
+
|
|
62
|
+
if not re.fullmatch(r"\d+\.\d+\.\d+(?:(?:a|b|rc)\d+)?", version):
|
|
63
|
+
raise SystemExit(f"unsupported automatic release version format: {version!r}")
|
|
64
|
+
|
|
65
|
+
with Path(os.environ["GITHUB_OUTPUT"]).open("a", encoding="utf-8") as output:
|
|
66
|
+
print("releasable=true", file=output)
|
|
67
|
+
print(f"version={version}", file=output)
|
|
68
|
+
print(f"tag=v{version}", file=output)
|
|
69
|
+
PY
|
|
70
|
+
|
|
71
|
+
- name: Check whether release tag already exists
|
|
72
|
+
if: >-
|
|
73
|
+
env.SKIP_RELEASE_TAG != 'true' &&
|
|
74
|
+
steps.metadata.outputs.releasable == 'true'
|
|
75
|
+
id: existing
|
|
76
|
+
env:
|
|
77
|
+
RELEASE_TAG: ${{ steps.metadata.outputs.tag }}
|
|
78
|
+
run: |
|
|
79
|
+
if git ls-remote --exit-code --tags origin "refs/tags/$RELEASE_TAG" >/dev/null 2>&1; then
|
|
80
|
+
echo "exists=true" >> "$GITHUB_OUTPUT"
|
|
81
|
+
echo "$RELEASE_TAG already exists; nothing to do."
|
|
82
|
+
else
|
|
83
|
+
echo "exists=false" >> "$GITHUB_OUTPUT"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
- name: Create annotated release tag
|
|
87
|
+
if: >-
|
|
88
|
+
env.SKIP_RELEASE_TAG != 'true' &&
|
|
89
|
+
steps.metadata.outputs.releasable == 'true' &&
|
|
90
|
+
steps.existing.outputs.exists == 'false'
|
|
91
|
+
env:
|
|
92
|
+
RELEASE_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
93
|
+
RELEASE_TAG: ${{ steps.metadata.outputs.tag }}
|
|
94
|
+
RELEASE_VERSION: ${{ steps.metadata.outputs.version }}
|
|
95
|
+
run: |
|
|
96
|
+
git config user.name "github-actions[bot]"
|
|
97
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
98
|
+
git tag -a "$RELEASE_TAG" "$RELEASE_SHA" -m "SchemaRouter $RELEASE_VERSION"
|
|
99
|
+
git push origin "refs/tags/$RELEASE_TAG"
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
|
+
- uses: actions/setup-python@v7
|
|
26
|
+
with:
|
|
27
|
+
python-version: ${{ matrix.python-version }}
|
|
28
|
+
- run: python -m pip install --upgrade pip
|
|
29
|
+
- run: pip install -e ".[dev]"
|
|
30
|
+
- run: ruff check .
|
|
31
|
+
- run: pytest -q -m "not mcp_integration"
|
|
32
|
+
- run: python examples/quickstart.py
|
|
33
|
+
|
|
34
|
+
python-preview:
|
|
35
|
+
continue-on-error: true
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v7
|
|
39
|
+
- uses: actions/setup-python@v7
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.15.0-rc.2"
|
|
42
|
+
allow-prereleases: true
|
|
43
|
+
- run: python -m pip install --upgrade pip
|
|
44
|
+
- run: pip install -e ".[dev]"
|
|
45
|
+
- run: ruff check .
|
|
46
|
+
- run: pytest -q -m "not mcp_integration"
|
|
47
|
+
- run: python examples/quickstart.py
|
|
48
|
+
|
|
49
|
+
windows-smoke:
|
|
50
|
+
runs-on: windows-latest
|
|
51
|
+
steps:
|
|
52
|
+
- uses: actions/checkout@v7
|
|
53
|
+
- uses: actions/setup-python@v7
|
|
54
|
+
with:
|
|
55
|
+
python-version: "3.14"
|
|
56
|
+
- run: python -m pip install --upgrade pip
|
|
57
|
+
- run: pip install -e ".[dev]"
|
|
58
|
+
- run: ruff check .
|
|
59
|
+
- run: pytest -q -m "not mcp_integration"
|
|
60
|
+
- run: python examples/quickstart.py
|
|
61
|
+
|
|
62
|
+
typecheck:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v7
|
|
66
|
+
- uses: actions/setup-python@v7
|
|
67
|
+
with:
|
|
68
|
+
python-version: "3.12"
|
|
69
|
+
- run: python -m pip install --upgrade pip
|
|
70
|
+
- run: pip install -e ".[dev,mcp,langchain,llamaindex,jev,otel]"
|
|
71
|
+
- run: pyright
|
|
72
|
+
|
|
73
|
+
coverage:
|
|
74
|
+
runs-on: ubuntu-latest
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/checkout@v7
|
|
77
|
+
- uses: actions/setup-python@v7
|
|
78
|
+
with:
|
|
79
|
+
python-version: "3.12"
|
|
80
|
+
- run: python -m pip install --upgrade pip
|
|
81
|
+
- run: pip install -e ".[dev,mcp,langchain,llamaindex,jev,otel]"
|
|
82
|
+
- run: pytest -q --cov=schemarouter --cov-branch --cov-report=term-missing --cov-report=xml:coverage.xml
|
|
83
|
+
- uses: actions/upload-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: coverage-report
|
|
86
|
+
path: coverage.xml
|
|
87
|
+
if-no-files-found: error
|
|
88
|
+
retention-days: 14
|
|
89
|
+
|
|
90
|
+
minimum-dependencies:
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
steps:
|
|
93
|
+
- uses: actions/checkout@v7
|
|
94
|
+
- uses: actions/setup-python@v7
|
|
95
|
+
with:
|
|
96
|
+
python-version: "3.10"
|
|
97
|
+
- run: python -m pip install --upgrade pip
|
|
98
|
+
- run: pip install "pytest>=8.2" "pytest-asyncio>=0.23"
|
|
99
|
+
- run: pip install "httpx==0.27.0" "jsonschema==4.23.0" "pydantic==2.8.0" "pyyaml==6.0.0"
|
|
100
|
+
- run: pip install -e . --no-deps
|
|
101
|
+
- run: pytest -q -m "not mcp_integration"
|
|
102
|
+
- run: python examples/quickstart.py
|
|
103
|
+
|
|
104
|
+
package:
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v7
|
|
108
|
+
- uses: actions/setup-python@v7
|
|
109
|
+
with:
|
|
110
|
+
python-version: "3.12"
|
|
111
|
+
- run: python -m pip install --upgrade pip
|
|
112
|
+
- run: pip install build twine
|
|
113
|
+
- run: python -m build
|
|
114
|
+
- run: twine check dist/*
|
|
115
|
+
- name: Verify license is packaged
|
|
116
|
+
run: |
|
|
117
|
+
python - <<'PY'
|
|
118
|
+
import glob
|
|
119
|
+
import zipfile
|
|
120
|
+
|
|
121
|
+
wheel = glob.glob("dist/*.whl")[0]
|
|
122
|
+
names = zipfile.ZipFile(wheel).namelist()
|
|
123
|
+
assert any(name.endswith("/licenses/LICENSE") for name in names), names
|
|
124
|
+
PY
|
|
125
|
+
- run: python -m venv /tmp/schemarouter-wheel
|
|
126
|
+
- run: /tmp/schemarouter-wheel/bin/python -m pip install --upgrade pip
|
|
127
|
+
- run: /tmp/schemarouter-wheel/bin/pip install dist/*.whl
|
|
128
|
+
- run: /tmp/schemarouter-wheel/bin/python -c "from importlib.metadata import version; import schemarouter; assert schemarouter.__version__ == version('schemarouter')"
|
|
129
|
+
- run: /tmp/schemarouter-wheel/bin/python examples/quickstart.py
|
|
130
|
+
- run: /tmp/schemarouter-wheel/bin/python scripts/benchmark_decision_routing.py
|
|
131
|
+
- run: python -m venv /tmp/schemarouter-sdist
|
|
132
|
+
- run: /tmp/schemarouter-sdist/bin/python -m pip install --upgrade pip
|
|
133
|
+
- run: /tmp/schemarouter-sdist/bin/pip install dist/*.tar.gz
|
|
134
|
+
- run: /tmp/schemarouter-sdist/bin/python -c "from importlib.metadata import version; import schemarouter; assert schemarouter.__version__ == version('schemarouter')"
|
|
135
|
+
- run: /tmp/schemarouter-sdist/bin/python examples/quickstart.py
|
|
136
|
+
|
|
137
|
+
langchain-integration:
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
steps:
|
|
140
|
+
- uses: actions/checkout@v7
|
|
141
|
+
- uses: actions/setup-python@v7
|
|
142
|
+
with:
|
|
143
|
+
python-version: "3.12"
|
|
144
|
+
- run: python -m pip install --upgrade pip
|
|
145
|
+
- run: pip install -e ".[dev,langchain]"
|
|
146
|
+
- run: pytest -q tests/test_langchain_integration.py
|
|
147
|
+
- run: python examples/langchain_quickstart.py
|
|
148
|
+
|
|
149
|
+
llamaindex-integration:
|
|
150
|
+
runs-on: ubuntu-latest
|
|
151
|
+
steps:
|
|
152
|
+
- uses: actions/checkout@v7
|
|
153
|
+
- uses: actions/setup-python@v7
|
|
154
|
+
with:
|
|
155
|
+
python-version: "3.12"
|
|
156
|
+
- run: python -m pip install --upgrade pip
|
|
157
|
+
- run: pip install -e ".[dev,llamaindex]"
|
|
158
|
+
- run: pytest -q tests/test_llamaindex_integration.py
|
|
159
|
+
- run: python examples/llamaindex_quickstart.py
|
|
160
|
+
|
|
161
|
+
jev-integration:
|
|
162
|
+
runs-on: ubuntu-latest
|
|
163
|
+
steps:
|
|
164
|
+
- uses: actions/checkout@v7
|
|
165
|
+
- uses: actions/setup-python@v7
|
|
166
|
+
with:
|
|
167
|
+
python-version: "3.12"
|
|
168
|
+
- run: python -m pip install --upgrade pip
|
|
169
|
+
- run: pip install -e ".[dev,jev]"
|
|
170
|
+
- run: pytest -q tests/test_jev_integration.py
|
|
171
|
+
|
|
172
|
+
otel-integration:
|
|
173
|
+
runs-on: ubuntu-latest
|
|
174
|
+
steps:
|
|
175
|
+
- uses: actions/checkout@v7
|
|
176
|
+
- uses: actions/setup-python@v7
|
|
177
|
+
with:
|
|
178
|
+
python-version: "3.12"
|
|
179
|
+
- run: python -m pip install --upgrade pip
|
|
180
|
+
- run: pip install -e ".[dev,otel]"
|
|
181
|
+
- run: pytest -q tests/test_opentelemetry_integration.py
|
|
182
|
+
|
|
183
|
+
mcp-integration:
|
|
184
|
+
runs-on: ubuntu-latest
|
|
185
|
+
steps:
|
|
186
|
+
- uses: actions/checkout@v7
|
|
187
|
+
- uses: actions/setup-python@v7
|
|
188
|
+
with:
|
|
189
|
+
python-version: "3.12"
|
|
190
|
+
- run: python -m pip install --upgrade pip
|
|
191
|
+
- run: pip install -e ".[dev,mcp]"
|
|
192
|
+
- run: pytest -q tests/test_mcp_integration.py
|
|
193
|
+
|
|
194
|
+
docs:
|
|
195
|
+
runs-on: ubuntu-latest
|
|
196
|
+
steps:
|
|
197
|
+
- uses: actions/checkout@v7
|
|
198
|
+
- uses: actions/setup-python@v7
|
|
199
|
+
with:
|
|
200
|
+
python-version: "3.12"
|
|
201
|
+
- run: python -m pip install --upgrade pip
|
|
202
|
+
- run: pip install -e ".[docs]"
|
|
203
|
+
- run: mkdocs build --strict
|
|
204
|
+
env:
|
|
205
|
+
NO_MKDOCS_2_WARNING: "1"
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
quality:
|
|
13
|
+
uses: ./.github/workflows/ci.yml
|
|
14
|
+
|
|
15
|
+
build:
|
|
16
|
+
needs: quality
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
outputs:
|
|
19
|
+
version: ${{ steps.metadata.outputs.version }}
|
|
20
|
+
release_notes: ${{ steps.metadata.outputs.release_notes }}
|
|
21
|
+
prerelease: ${{ steps.metadata.outputs.prerelease }}
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- uses: actions/setup-python@v7
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
- name: Resolve and verify release metadata
|
|
28
|
+
id: metadata
|
|
29
|
+
run: |
|
|
30
|
+
python - <<'PY'
|
|
31
|
+
import os
|
|
32
|
+
import re
|
|
33
|
+
import tomllib
|
|
34
|
+
from pathlib import Path
|
|
35
|
+
|
|
36
|
+
version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
|
|
37
|
+
tag = os.environ["GITHUB_REF_NAME"]
|
|
38
|
+
expected = f"v{version}"
|
|
39
|
+
if tag != expected:
|
|
40
|
+
raise SystemExit(f"tag {tag!r} does not match package version {expected!r}")
|
|
41
|
+
if ".dev" in version:
|
|
42
|
+
raise SystemExit("development versions cannot be published by the release workflow")
|
|
43
|
+
|
|
44
|
+
release_notes = Path("docs") / "releases" / f"{version}.md"
|
|
45
|
+
if not release_notes.is_file():
|
|
46
|
+
raise SystemExit(f"missing release notes: {release_notes}")
|
|
47
|
+
|
|
48
|
+
prerelease = bool(re.search(r"(?:a|b|rc)\d+(?:$|[.+-])", version))
|
|
49
|
+
with Path(os.environ["GITHUB_OUTPUT"]).open("a", encoding="utf-8") as output:
|
|
50
|
+
print(f"version={version}", file=output)
|
|
51
|
+
print(f"release_notes={release_notes.as_posix()}", file=output)
|
|
52
|
+
print(f"prerelease={'true' if prerelease else 'false'}", file=output)
|
|
53
|
+
PY
|
|
54
|
+
- run: python -m pip install --upgrade pip
|
|
55
|
+
- run: pip install build twine
|
|
56
|
+
- run: python -m build
|
|
57
|
+
- run: twine check dist/*
|
|
58
|
+
- name: Verify release artifact
|
|
59
|
+
env:
|
|
60
|
+
RELEASE_VERSION: ${{ steps.metadata.outputs.version }}
|
|
61
|
+
run: |
|
|
62
|
+
python - <<'PY'
|
|
63
|
+
import glob
|
|
64
|
+
import os
|
|
65
|
+
import subprocess
|
|
66
|
+
import sys
|
|
67
|
+
import tempfile
|
|
68
|
+
import venv
|
|
69
|
+
import zipfile
|
|
70
|
+
from pathlib import Path
|
|
71
|
+
|
|
72
|
+
wheel = glob.glob("dist/*.whl")[0]
|
|
73
|
+
sdist = glob.glob("dist/*.tar.gz")[0]
|
|
74
|
+
|
|
75
|
+
wheel_names = zipfile.ZipFile(wheel).namelist()
|
|
76
|
+
assert any(name.endswith("/licenses/LICENSE") for name in wheel_names), wheel_names
|
|
77
|
+
|
|
78
|
+
import tarfile
|
|
79
|
+
|
|
80
|
+
with tarfile.open(sdist, "r:gz") as archive:
|
|
81
|
+
sdist_names = archive.getnames()
|
|
82
|
+
assert any(name.endswith("/LICENSE") for name in sdist_names), sdist_names
|
|
83
|
+
|
|
84
|
+
for artifact in (wheel, sdist):
|
|
85
|
+
with tempfile.TemporaryDirectory() as root:
|
|
86
|
+
env = Path(root) / "venv"
|
|
87
|
+
venv.EnvBuilder(with_pip=True).create(env)
|
|
88
|
+
python = env / ("Scripts/python.exe" if sys.platform == "win32" else "bin/python")
|
|
89
|
+
subprocess.check_call([str(python), "-m", "pip", "install", artifact])
|
|
90
|
+
subprocess.check_call([
|
|
91
|
+
str(python),
|
|
92
|
+
"-c",
|
|
93
|
+
(
|
|
94
|
+
"from importlib.metadata import version; "
|
|
95
|
+
"import schemarouter; "
|
|
96
|
+
f"assert schemarouter.__version__ == {os.environ['RELEASE_VERSION']!r}; "
|
|
97
|
+
f"assert version('schemarouter') == {os.environ['RELEASE_VERSION']!r}"
|
|
98
|
+
),
|
|
99
|
+
])
|
|
100
|
+
subprocess.check_call([str(python), "examples/quickstart.py"])
|
|
101
|
+
PY
|
|
102
|
+
- uses: actions/upload-artifact@v4
|
|
103
|
+
with:
|
|
104
|
+
name: python-dist
|
|
105
|
+
path: dist/
|
|
106
|
+
if-no-files-found: error
|
|
107
|
+
retention-days: 7
|
|
108
|
+
|
|
109
|
+
github-release:
|
|
110
|
+
needs: build
|
|
111
|
+
permissions:
|
|
112
|
+
contents: write
|
|
113
|
+
runs-on: ubuntu-latest
|
|
114
|
+
steps:
|
|
115
|
+
- uses: actions/checkout@v7
|
|
116
|
+
- uses: actions/download-artifact@v4
|
|
117
|
+
with:
|
|
118
|
+
name: python-dist
|
|
119
|
+
path: dist
|
|
120
|
+
- name: Create or update GitHub release
|
|
121
|
+
env:
|
|
122
|
+
GH_TOKEN: ${{ github.token }}
|
|
123
|
+
RELEASE_VERSION: ${{ needs.build.outputs.version }}
|
|
124
|
+
RELEASE_NOTES: ${{ needs.build.outputs.release_notes }}
|
|
125
|
+
IS_PRERELEASE: ${{ needs.build.outputs.prerelease }}
|
|
126
|
+
run: |
|
|
127
|
+
prerelease_args=()
|
|
128
|
+
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
|
129
|
+
prerelease_args+=(--prerelease)
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
|
|
133
|
+
gh release upload "$GITHUB_REF_NAME" dist/* --clobber
|
|
134
|
+
gh release edit "$GITHUB_REF_NAME" \
|
|
135
|
+
--title "SchemaRouter $RELEASE_VERSION" \
|
|
136
|
+
--notes-file "$RELEASE_NOTES" \
|
|
137
|
+
"${prerelease_args[@]}"
|
|
138
|
+
else
|
|
139
|
+
gh release create "$GITHUB_REF_NAME" dist/* \
|
|
140
|
+
--title "SchemaRouter $RELEASE_VERSION" \
|
|
141
|
+
--notes-file "$RELEASE_NOTES" \
|
|
142
|
+
"${prerelease_args[@]}" \
|
|
143
|
+
--verify-tag
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
pypi:
|
|
147
|
+
needs: build
|
|
148
|
+
permissions:
|
|
149
|
+
id-token: write
|
|
150
|
+
runs-on: ubuntu-latest
|
|
151
|
+
environment:
|
|
152
|
+
name: pypi
|
|
153
|
+
url: https://pypi.org/project/schemarouter/
|
|
154
|
+
steps:
|
|
155
|
+
- uses: actions/download-artifact@v4
|
|
156
|
+
with:
|
|
157
|
+
name: python-dist
|
|
158
|
+
path: dist
|
|
159
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
160
|
+
with:
|
|
161
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to SchemaRouter are documented here.
|
|
4
|
+
|
|
5
|
+
The project is pre-1.0 and follows the compatibility rules in
|
|
6
|
+
[`docs/versioning.md`](docs/versioning.md).
|
|
7
|
+
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
No unreleased changes yet.
|
|
11
|
+
|
|
12
|
+
## 0.3.0a1 - 2026-09-22
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- provider-neutral bounded `DecisionBackend` contracts with deterministic fallback;
|
|
17
|
+
- optional `JevDecisionBackend` backed by TypeSafe System One through `schemarouter[jev]`;
|
|
18
|
+
- optional LlamaIndex `FunctionTool` integration;
|
|
19
|
+
- runnable LangChain and LlamaIndex integration examples enforced in CI;
|
|
20
|
+
- provider-neutral decision-routing benchmark harness covering accuracy, abstention, latency,
|
|
21
|
+
token usage, and optional cost estimation;
|
|
22
|
+
- explicit ecosystem compatibility matrix and integration maintenance policy;
|
|
23
|
+
- Korean project overview in `README.ko.md`;
|
|
24
|
+
- Python 3.13 and 3.14 core CI coverage;
|
|
25
|
+
- a non-blocking Python 3.15 release-candidate preview;
|
|
26
|
+
- a Windows + Python 3.14 smoke surface;
|
|
27
|
+
- a Pyright static-type gate for the typed package surface;
|
|
28
|
+
- full-suite branch-coverage reporting with an 82% blocking floor;
|
|
29
|
+
- declared lower-bound runtime dependency testing;
|
|
30
|
+
- clean wheel and sdist installation smoke tests;
|
|
31
|
+
- a checked-in 144-case multilingual/adversarial decision-routing corpus with JSON/CSV output,
|
|
32
|
+
category metrics, invalid-plan rate, abstention/fallback tracking, and p50/p95 latency;
|
|
33
|
+
- machine-readable OpenAPI compatibility reports for partial/unsupported constructs;
|
|
34
|
+
- authenticated MCP trusted-header and custom client-factory transport boundaries;
|
|
35
|
+
- trusted sync/async per-call approval callbacks;
|
|
36
|
+
- per-run execution budgets for logical calls, attempts, remote attempts, elapsed time, per-tool
|
|
37
|
+
quotas, and application-defined cost units;
|
|
38
|
+
- optional privacy-preserving OpenTelemetry run/tool span export;
|
|
39
|
+
- explicit allowlisted third-party adapter plugins through `schemarouter.adapters` entry points.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- current `main` now identifies as `0.3.0.dev0`, separating unreleased development builds from
|
|
44
|
+
the published `0.2.0a1` alpha;
|
|
45
|
+
- release automation now derives version, release title, release-note path, prerelease state, and
|
|
46
|
+
artifact verification from `pyproject.toml` instead of hard-coded release literals;
|
|
47
|
+
- tag releases reuse the same full CI quality workflow as pull requests and verify both wheel and
|
|
48
|
+
sdist artifacts in clean environments before publication;
|
|
49
|
+
- superseded pull-request CI runs are cancelled automatically to avoid stale validation consuming
|
|
50
|
+
runner capacity;
|
|
51
|
+
- releasable `main` commits are automatically annotated with `v<version>` only after green CI,
|
|
52
|
+
current-head verification, release-note/changelog validation, and duplicate-tag checks.
|
|
53
|
+
|
|
54
|
+
### Security
|
|
55
|
+
|
|
56
|
+
- OpenAPI runtime responses are now streamed through a bounded reader with a 16 MiB default limit,
|
|
57
|
+
enforcing the bound both from declared `Content-Length` and actual bytes received;
|
|
58
|
+
- Jev option IDs are validated before confidence-based abstention, so unknown IDs always fail
|
|
59
|
+
closed;
|
|
60
|
+
- Jev credentials remain SDK client configuration and are never placed in model state;
|
|
61
|
+
- `DecisionOption.metadata` is not forwarded to Jev;
|
|
62
|
+
- provider failures can deterministically fall back without weakening execution policy;
|
|
63
|
+
- MCP credentials are rejected in URLs and remain outside tool/planner metadata;
|
|
64
|
+
- MCP protocol-controlled headers cannot be overridden through trusted runtime headers;
|
|
65
|
+
- adapter entry points are metadata-only during discovery and are never auto-imported;
|
|
66
|
+
- OpenTelemetry export omits payload values, RunConfig metadata, tags, and exception messages;
|
|
67
|
+
- approval callback failures and execution budget exhaustion fail closed.
|
|
68
|
+
|
|
69
|
+
## 0.2.0a1 - 2026-09-20
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- pluggable structured-source `AdapterRegistry` with explicit and priority-based auto discovery;
|
|
74
|
+
- OPTIMADE v1 discovery through base and entry-type info endpoints;
|
|
75
|
+
- OPTIMADE field-aware execution that maps planned fields to `response_fields`;
|
|
76
|
+
- call-aware invoker support for protocol adapters that need the full `ToolCall`;
|
|
77
|
+
- typed tool, endpoint, parameter, response-field, plan, and result contracts;
|
|
78
|
+
- namespaced versioned registry;
|
|
79
|
+
- schema-aware planning with recall-preserving field projection;
|
|
80
|
+
- provider-neutral model-assisted query analysis;
|
|
81
|
+
- OpenAPI 3.x URL ingestion and guarded HTTP execution;
|
|
82
|
+
- MCP tool discovery and execution;
|
|
83
|
+
- evidence-grounded proposals for human-readable API documentation;
|
|
84
|
+
- runtime JSON Schema validation for arguments and raw outputs;
|
|
85
|
+
- schema and invoker-binding drift detection;
|
|
86
|
+
- fail-closed execution policy for mutations, destructive calls, and unclassified remote tools;
|
|
87
|
+
- Runnable-style `invoke`, `batch`, `stream`, and typed event APIs;
|
|
88
|
+
- run configuration, concurrency control, and safe retry policy;
|
|
89
|
+
- typed Python callable registration with `@schema_tool`;
|
|
90
|
+
- optional LangChain `StructuredTool` integration;
|
|
91
|
+
- framework maturity, architecture, release, and versioning documentation;
|
|
92
|
+
- MIT licensing and package metadata;
|
|
93
|
+
- MkDocs Material documentation site with guides, recipes, and generated API reference;
|
|
94
|
+
- SchemaRouter brace-and-routing-hub brand system with light/dark marks, lockups, favicon, and
|
|
95
|
+
social preview source artwork.
|
|
96
|
+
|
|
97
|
+
### Security
|
|
98
|
+
|
|
99
|
+
- separated schema-fetch credentials from runtime API credentials;
|
|
100
|
+
- restricted schema redirects and runtime API origins;
|
|
101
|
+
- blocked model/tool control of sensitive runtime headers;
|
|
102
|
+
- redacted event payloads by default;
|
|
103
|
+
- prevented automatic retries for non-read-only calls.
|
|
@@ -10,17 +10,19 @@ python -m venv .venv
|
|
|
10
10
|
source .venv/bin/activate
|
|
11
11
|
pip install -e ".[dev]"
|
|
12
12
|
ruff check .
|
|
13
|
-
pytest -q
|
|
13
|
+
pytest -q -m "not mcp_integration"
|
|
14
14
|
python examples/quickstart.py
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Optional integrations have separate extras and tests. For example:
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
pip install -e ".[dev,langchain]"
|
|
21
|
-
|
|
16
|
+
# Check the complete typed surface and optional integrations.
|
|
17
|
+
pip install -e ".[dev,mcp,langchain,llamaindex,jev,otel]"
|
|
18
|
+
pyright
|
|
19
|
+
pytest -q --cov=schemarouter --cov-branch --cov-report=term-missing
|
|
22
20
|
```
|
|
23
21
|
|
|
22
|
+
Optional integrations have separate extras and focused tests. The required CI exercises
|
|
23
|
+
LangChain, LlamaIndex, Jev/TypeSafe, MCP, and OpenTelemetry independently in addition to the full
|
|
24
|
+
coverage run.
|
|
25
|
+
|
|
24
26
|
## Design rules
|
|
25
27
|
|
|
26
28
|
Changes must preserve these principles:
|
|
@@ -32,7 +34,9 @@ Changes must preserve these principles:
|
|
|
32
34
|
5. raw input/output values are validated before crossing the trusted execution boundary;
|
|
33
35
|
6. mutations, destructive calls, and ambiguous remote side effects require local policy;
|
|
34
36
|
7. observability must not expose payloads by default;
|
|
35
|
-
8. integrations must call through SchemaRouter execution rather than bypassing it
|
|
37
|
+
8. integrations must call through SchemaRouter execution rather than bypassing it;
|
|
38
|
+
9. installed adapter plugins must never be auto-imported from discovery alone;
|
|
39
|
+
10. approval and execution-budget failures must remain fail-closed.
|
|
36
40
|
|
|
37
41
|
## Adding an adapter
|
|
38
42
|
|
|
@@ -65,7 +69,10 @@ A change is not complete until:
|
|
|
65
69
|
|
|
66
70
|
- tests cover its public behavior and adversarial failure cases;
|
|
67
71
|
- warnings remain clean;
|
|
68
|
-
- supported Python versions pass;
|
|
72
|
+
- supported Python versions pass, including the Windows smoke surface;
|
|
73
|
+
- Pyright and the 82% branch-coverage floor pass;
|
|
74
|
+
- minimum declared runtime dependencies remain usable;
|
|
75
|
+
- wheel and sdist clean-install smokes pass;
|
|
69
76
|
- public behavior is documented;
|
|
70
77
|
- new optional dependencies are isolated behind extras;
|
|
71
78
|
- breaking API changes include a changelog and migration note.
|