backstop-ai 0.6.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.
Files changed (160) hide show
  1. backstop_ai-0.6.0/.github/ISSUE_TEMPLATE/benchmark_report.yml +26 -0
  2. backstop_ai-0.6.0/.github/ISSUE_TEMPLATE/bug_report.yml +42 -0
  3. backstop_ai-0.6.0/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
  4. backstop_ai-0.6.0/.github/ISSUE_TEMPLATE/provider_compatibility.yml +37 -0
  5. backstop_ai-0.6.0/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  6. backstop_ai-0.6.0/.github/workflows/ci.yml +88 -0
  7. backstop_ai-0.6.0/.gitignore +31 -0
  8. backstop_ai-0.6.0/=0.40 +0 -0
  9. backstop_ai-0.6.0/CHANGELOG.md +190 -0
  10. backstop_ai-0.6.0/CODE_OF_CONDUCT.md +29 -0
  11. backstop_ai-0.6.0/CONTRIBUTING.md +43 -0
  12. backstop_ai-0.6.0/LICENSE.txt +21 -0
  13. backstop_ai-0.6.0/PKG-INFO +308 -0
  14. backstop_ai-0.6.0/README.md +263 -0
  15. backstop_ai-0.6.0/SECURITY.md +36 -0
  16. backstop_ai-0.6.0/benchmarks/local_overhead.py +150 -0
  17. backstop_ai-0.6.0/demo.gif +0 -0
  18. backstop_ai-0.6.0/docs/architecture.md +94 -0
  19. backstop_ai-0.6.0/docs/assets/backstop-logo.svg +15 -0
  20. backstop_ai-0.6.0/docs/benchmark-results-2026-07-20.md +30 -0
  21. backstop_ai-0.6.0/docs/benchmarks.md +46 -0
  22. backstop_ai-0.6.0/docs/compatibility.md +84 -0
  23. backstop_ai-0.6.0/docs/concurrency.md +82 -0
  24. backstop_ai-0.6.0/docs/dashboard.md +137 -0
  25. backstop_ai-0.6.0/docs/install.md +170 -0
  26. backstop_ai-0.6.0/docs/quickstart.md +68 -0
  27. backstop_ai-0.6.0/docs/sdk-matrix.md +51 -0
  28. backstop_ai-0.6.0/docs/threat-model.md +85 -0
  29. backstop_ai-0.6.0/examples/agent_loop_guard.py +77 -0
  30. backstop_ai-0.6.0/examples/anthropic_async.py +33 -0
  31. backstop_ai-0.6.0/examples/anthropic_budget.py +71 -0
  32. backstop_ai-0.6.0/examples/anthropic_sync.py +32 -0
  33. backstop_ai-0.6.0/examples/background_priority.py +38 -0
  34. backstop_ai-0.6.0/examples/basic.py +27 -0
  35. backstop_ai-0.6.0/examples/budget_blocking_demo.py +66 -0
  36. backstop_ai-0.6.0/examples/fastapi_tenants.py +56 -0
  37. backstop_ai-0.6.0/examples/openai_async.py +32 -0
  38. backstop_ai-0.6.0/examples/openai_sync.py +31 -0
  39. backstop_ai-0.6.0/examples/prometheus_metrics.py +13 -0
  40. backstop_ai-0.6.0/examples/wedge_basic.py +63 -0
  41. backstop_ai-0.6.0/examples/wedge_openai.py +62 -0
  42. backstop_ai-0.6.0/fix_wrapper.py +45 -0
  43. backstop_ai-0.6.0/install.sh +136 -0
  44. backstop_ai-0.6.0/llms.txt +79 -0
  45. backstop_ai-0.6.0/observability/prometheus-alerts.yml +38 -0
  46. backstop_ai-0.6.0/proofs/README.md +43 -0
  47. backstop_ai-0.6.0/proofs/proof_budget_exhaustion.py +110 -0
  48. backstop_ai-0.6.0/proofs/proof_budget_webhook.py +92 -0
  49. backstop_ai-0.6.0/proofs/proof_hierarchical.py +60 -0
  50. backstop_ai-0.6.0/proofs/proof_multi_agent_isolation.py +100 -0
  51. backstop_ai-0.6.0/proofs/proof_real_overhead.py +132 -0
  52. backstop_ai-0.6.0/proofs/proof_secrets.py +59 -0
  53. backstop_ai-0.6.0/proofs/proof_semantic_cache.py +153 -0
  54. backstop_ai-0.6.0/proofs/run_all.py +166 -0
  55. backstop_ai-0.6.0/proofs/wedge_e2e_demo.py +101 -0
  56. backstop_ai-0.6.0/pyproject.toml +72 -0
  57. backstop_ai-0.6.0/src/backstop/__init__.py +43 -0
  58. backstop_ai-0.6.0/src/backstop/__main__.py +4 -0
  59. backstop_ai-0.6.0/src/backstop/_httpcompat.py +119 -0
  60. backstop_ai-0.6.0/src/backstop/adapters/__init__.py +73 -0
  61. backstop_ai-0.6.0/src/backstop/admission.py +114 -0
  62. backstop_ai-0.6.0/src/backstop/agent_guard.py +54 -0
  63. backstop_ai-0.6.0/src/backstop/aimd.py +61 -0
  64. backstop_ai-0.6.0/src/backstop/audit.py +79 -0
  65. backstop_ai-0.6.0/src/backstop/audit_sink.py +212 -0
  66. backstop_ai-0.6.0/src/backstop/budget.py +79 -0
  67. backstop_ai-0.6.0/src/backstop/cache.py +157 -0
  68. backstop_ai-0.6.0/src/backstop/circuit.py +85 -0
  69. backstop_ai-0.6.0/src/backstop/cli.py +546 -0
  70. backstop_ai-0.6.0/src/backstop/config.py +313 -0
  71. backstop_ai-0.6.0/src/backstop/cost.py +36 -0
  72. backstop_ai-0.6.0/src/backstop/dashboard_app.py +381 -0
  73. backstop_ai-0.6.0/src/backstop/dashboard_demo.py +386 -0
  74. backstop_ai-0.6.0/src/backstop/dashboard_ui.py +1356 -0
  75. backstop_ai-0.6.0/src/backstop/demo.py +347 -0
  76. backstop_ai-0.6.0/src/backstop/exceptions.py +77 -0
  77. backstop_ai-0.6.0/src/backstop/extract.py +248 -0
  78. backstop_ai-0.6.0/src/backstop/forecast.py +62 -0
  79. backstop_ai-0.6.0/src/backstop/gateway.py +117 -0
  80. backstop_ai-0.6.0/src/backstop/harness.py +225 -0
  81. backstop_ai-0.6.0/src/backstop/hierarchical.py +167 -0
  82. backstop_ai-0.6.0/src/backstop/hooks.py +29 -0
  83. backstop_ai-0.6.0/src/backstop/latency.py +78 -0
  84. backstop_ai-0.6.0/src/backstop/ledger.py +112 -0
  85. backstop_ai-0.6.0/src/backstop/limiter.py +38 -0
  86. backstop_ai-0.6.0/src/backstop/metrics.py +154 -0
  87. backstop_ai-0.6.0/src/backstop/notifications.py +188 -0
  88. backstop_ai-0.6.0/src/backstop/otel.py +179 -0
  89. backstop_ai-0.6.0/src/backstop/pricing.py +299 -0
  90. backstop_ai-0.6.0/src/backstop/quotas.py +86 -0
  91. backstop_ai-0.6.0/src/backstop/real_anthropic.py +170 -0
  92. backstop_ai-0.6.0/src/backstop/real_openai.py +202 -0
  93. backstop_ai-0.6.0/src/backstop/retry.py +17 -0
  94. backstop_ai-0.6.0/src/backstop/rollout.py +106 -0
  95. backstop_ai-0.6.0/src/backstop/secrets.py +66 -0
  96. backstop_ai-0.6.0/src/backstop/state.py +73 -0
  97. backstop_ai-0.6.0/src/backstop/state_backends.py +201 -0
  98. backstop_ai-0.6.0/src/backstop/streaming.py +196 -0
  99. backstop_ai-0.6.0/src/backstop/telemetry.py +833 -0
  100. backstop_ai-0.6.0/src/backstop/transports.py +1092 -0
  101. backstop_ai-0.6.0/src/backstop/verify.py +705 -0
  102. backstop_ai-0.6.0/src/backstop/wrapper.py +314 -0
  103. backstop_ai-0.6.0/src/backstop/wrapper.py.backup +245 -0
  104. backstop_ai-0.6.0/src/backstop/wrapper.py.backup2 +253 -0
  105. backstop_ai-0.6.0/src/wedge/__init__.py +2 -0
  106. backstop_ai-0.6.0/src/wedge/cli.py +87 -0
  107. backstop_ai-0.6.0/src/wedge/diff_engine.py +126 -0
  108. backstop_ai-0.6.0/src/wedge/report.py +80 -0
  109. backstop_ai-0.6.0/src/wedge/runner.py +563 -0
  110. backstop_ai-0.6.0/tests/test_audit_sink.py +72 -0
  111. backstop_ai-0.6.0/tests/test_budget.py +43 -0
  112. backstop_ai-0.6.0/tests/test_budget_stress.py +111 -0
  113. backstop_ai-0.6.0/tests/test_cache_gzip_replay.py +79 -0
  114. backstop_ai-0.6.0/tests/test_cache_semantic.py +110 -0
  115. backstop_ai-0.6.0/tests/test_cli.py +97 -0
  116. backstop_ai-0.6.0/tests/test_config.py +26 -0
  117. backstop_ai-0.6.0/tests/test_dashboard_wsgi.py +273 -0
  118. backstop_ai-0.6.0/tests/test_deep_research.py +408 -0
  119. backstop_ai-0.6.0/tests/test_demo.py +105 -0
  120. backstop_ai-0.6.0/tests/test_extract.py +163 -0
  121. backstop_ai-0.6.0/tests/test_fallback_chain.py +291 -0
  122. backstop_ai-0.6.0/tests/test_guardrail_visibility.py +51 -0
  123. backstop_ai-0.6.0/tests/test_hierarchical.py +150 -0
  124. backstop_ai-0.6.0/tests/test_installer.py +49 -0
  125. backstop_ai-0.6.0/tests/test_ledger.py +227 -0
  126. backstop_ai-0.6.0/tests/test_notifications.py +97 -0
  127. backstop_ai-0.6.0/tests/test_otel.py +57 -0
  128. backstop_ai-0.6.0/tests/test_real_anthropic.py +52 -0
  129. backstop_ai-0.6.0/tests/test_real_openai.py +39 -0
  130. backstop_ai-0.6.0/tests/test_retry_aimd_circuit.py +60 -0
  131. backstop_ai-0.6.0/tests/test_secrets.py +92 -0
  132. backstop_ai-0.6.0/tests/test_streaming_budget.py +165 -0
  133. backstop_ai-0.6.0/tests/test_telemetry.py +499 -0
  134. backstop_ai-0.6.0/tests/test_transport.py +235 -0
  135. backstop_ai-0.6.0/tests/test_verify.py +149 -0
  136. backstop_ai-0.6.0/tests/test_wrapper.py +201 -0
  137. backstop_ai-0.6.0/tests/wedge/test_diff_engine.py +48 -0
  138. backstop_ai-0.6.0/tests/wedge/test_report.py +26 -0
  139. backstop_ai-0.6.0/tests/wedge/test_runner_offline.py +285 -0
  140. backstop_ai-0.6.0/ts/backstop/README.md +65 -0
  141. backstop_ai-0.6.0/ts/backstop/package-lock.json +604 -0
  142. backstop_ai-0.6.0/ts/backstop/package.json +37 -0
  143. backstop_ai-0.6.0/ts/backstop/src/admission.ts +162 -0
  144. backstop_ai-0.6.0/ts/backstop/src/agent.ts +38 -0
  145. backstop_ai-0.6.0/ts/backstop/src/audit.ts +70 -0
  146. backstop_ai-0.6.0/ts/backstop/src/budget.ts +104 -0
  147. backstop_ai-0.6.0/ts/backstop/src/cache.ts +123 -0
  148. backstop_ai-0.6.0/ts/backstop/src/circuit.ts +52 -0
  149. backstop_ai-0.6.0/ts/backstop/src/forecast.ts +18 -0
  150. backstop_ai-0.6.0/ts/backstop/src/index.ts +21 -0
  151. backstop_ai-0.6.0/ts/backstop/src/quotas.ts +33 -0
  152. backstop_ai-0.6.0/ts/backstop/src/types.ts +118 -0
  153. backstop_ai-0.6.0/ts/backstop/src/wrap.ts +250 -0
  154. backstop_ai-0.6.0/ts/backstop/tests/features.test.ts +110 -0
  155. backstop_ai-0.6.0/ts/backstop/tests/wrap.test.ts +134 -0
  156. backstop_ai-0.6.0/ts/backstop/tsconfig.json +17 -0
  157. backstop_ai-0.6.0/wedge-test-fixture/README.md +12 -0
  158. backstop_ai-0.6.0/wedge-test-fixture/src/main.py +25 -0
  159. backstop_ai-0.6.0/wedge-test-fixture/task.yaml +12 -0
  160. backstop_ai-0.6.0/wedge-test-fixture/tests/test_main.py +45 -0
@@ -0,0 +1,26 @@
1
+ name: Benchmark report
2
+ description: Share benchmark results or report benchmark issues
3
+ title: "[Benchmark]: "
4
+ labels: ["benchmark"]
5
+ body:
6
+ - type: textarea
7
+ id: command
8
+ attributes:
9
+ label: Command
10
+ render: shell
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: environment
15
+ attributes:
16
+ label: Environment
17
+ description: OS, Python version, CPU, provider SDK versions, and whether a local mock provider or real provider was used.
18
+ validations:
19
+ required: true
20
+ - type: textarea
21
+ id: results
22
+ attributes:
23
+ label: Results
24
+ render: text
25
+ validations:
26
+ required: true
@@ -0,0 +1,42 @@
1
+ name: Bug report
2
+ description: Report a Backstop bug
3
+ title: "[Bug]: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: textarea
7
+ id: summary
8
+ attributes:
9
+ label: Summary
10
+ description: What happened?
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: reproduce
15
+ attributes:
16
+ label: Reproduction
17
+ description: Minimal code or commands that reproduce the issue.
18
+ render: python
19
+ validations:
20
+ required: true
21
+ - type: input
22
+ id: version
23
+ attributes:
24
+ label: Backstop version or commit
25
+ validations:
26
+ required: true
27
+ - type: input
28
+ id: provider
29
+ attributes:
30
+ label: Provider SDK and version
31
+ placeholder: openai 1.x, anthropic 0.x
32
+ - type: textarea
33
+ id: expected
34
+ attributes:
35
+ label: Expected behavior
36
+ validations:
37
+ required: true
38
+ - type: textarea
39
+ id: notes
40
+ attributes:
41
+ label: Notes
42
+ description: Do not include API keys, real prompts, real responses, or customer data.
@@ -0,0 +1,37 @@
1
+ name: Feature request
2
+ description: Suggest an improvement to Backstop
3
+ title: "[Feature]: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: textarea
7
+ id: problem
8
+ attributes:
9
+ label: Problem
10
+ description: What LLM spend, latency, reliability, or provider-control problem does this solve?
11
+ validations:
12
+ required: true
13
+ - type: textarea
14
+ id: proposal
15
+ attributes:
16
+ label: Proposal
17
+ description: What should Backstop do?
18
+ validations:
19
+ required: true
20
+ - type: dropdown
21
+ id: area
22
+ attributes:
23
+ label: Area
24
+ options:
25
+ - Budget enforcement
26
+ - Distributed state
27
+ - Provider compatibility
28
+ - Metrics or telemetry
29
+ - Retry or circuit breaking
30
+ - Documentation
31
+ - Other
32
+ validations:
33
+ required: true
34
+ - type: textarea
35
+ id: alternatives
36
+ attributes:
37
+ label: Alternatives considered
@@ -0,0 +1,37 @@
1
+ name: Provider compatibility
2
+ description: Report a provider SDK compatibility issue
3
+ title: "[Provider]: "
4
+ labels: ["provider-compatibility"]
5
+ body:
6
+ - type: input
7
+ id: provider
8
+ attributes:
9
+ label: Provider
10
+ placeholder: OpenAI, Anthropic
11
+ validations:
12
+ required: true
13
+ - type: input
14
+ id: sdk_version
15
+ attributes:
16
+ label: SDK version
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: code
21
+ attributes:
22
+ label: Minimal code
23
+ render: python
24
+ validations:
25
+ required: true
26
+ - type: textarea
27
+ id: behavior
28
+ attributes:
29
+ label: Behavior
30
+ description: What failed, and what did you expect?
31
+ validations:
32
+ required: true
33
+ - type: textarea
34
+ id: privacy
35
+ attributes:
36
+ label: Privacy note
37
+ description: Do not include API keys, real prompts, real responses, or customer data.
@@ -0,0 +1,22 @@
1
+ ## Summary
2
+
3
+ Describe the change and why it is needed.
4
+
5
+ ## Tests
6
+
7
+ - [ ] `pytest`
8
+ - [ ] Real OpenAI smoke test, if OpenAI SDK behavior changed
9
+ - [ ] Real Anthropic smoke test, if Anthropic SDK behavior changed
10
+ - [ ] Benchmark run, if latency or throughput changed
11
+
12
+ ## Compatibility
13
+
14
+ - Provider SDK impact:
15
+ - Public API impact:
16
+ - Migration notes:
17
+
18
+ ## Security And Privacy
19
+
20
+ - [ ] Does not send prompt payloads to external services by default
21
+ - [ ] Does not log secrets, prompts, or responses
22
+ - [ ] Budget enforcement failure behavior is explicit
@@ -0,0 +1,88 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+ # Pins must (a) be compatible with httpx>=0.28, which removed the
16
+ # `proxies` kwarg (openai<1.90 / anthropic<0.40 crash on it), and
17
+ # (b) stop relabelling transport exceptions: below openai 2.37 /
18
+ # anthropic 0.98 the SDK catches Backstop's BudgetExceededError and
19
+ # re-raises it as APIConnectionError, so the guardrail is invisible
20
+ # to user code. Floors in src/backstop/wrapper.py must match.
21
+ openai-version: ["2.37.0", "3.14.0"]
22
+ anthropic-version: ["0.99.0", "1.6.0"]
23
+ # Cross-check: newest openai against the oldest supported anthropic.
24
+ include:
25
+ - python-version: "3.12"
26
+ openai-version: "latest"
27
+ anthropic-version: "0.99.0"
28
+ fail-fast: false
29
+
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ - name: Set up Python ${{ matrix.python-version }}
33
+ uses: actions/setup-python@v5
34
+ with:
35
+ python-version: ${{ matrix.python-version }}
36
+ - name: Install dependencies
37
+ run: |
38
+ pip install -e ".[test,metrics,anthropic]"
39
+ if [ "${{ matrix.openai-version }}" != "latest" ]; then
40
+ pip install "openai==${{ matrix.openai-version }}"
41
+ fi
42
+ if [ "${{ matrix.anthropic-version }}" != "latest" ]; then
43
+ pip install "anthropic==${{ matrix.anthropic-version }}"
44
+ fi
45
+ - name: Run tests
46
+ run: pytest
47
+ - name: Run benchmark smoke
48
+ run: python -m backstop benchmark
49
+
50
+ build:
51
+ needs: test
52
+ runs-on: ubuntu-latest
53
+ permissions:
54
+ contents: write
55
+ id-token: write
56
+
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - name: Set up Python
60
+ uses: actions/setup-python@v5
61
+ with:
62
+ python-version: "3.12"
63
+ - name: Install build tools
64
+ run: pip install build twine
65
+ - name: Build package
66
+ run: python -m build
67
+ - name: Validate package
68
+ run: python -m twine check dist/*
69
+ # Supply chain hardening: cosign signing, SLSA provenance (slsa-framework), SBOM generation
70
+ - name: Upload build artifacts
71
+ uses: actions/upload-artifact@v4
72
+ with:
73
+ name: dist
74
+ path: dist/
75
+ - name: Create GitHub Release
76
+ if: startsWith(github.ref, 'refs/tags/v')
77
+ run: |
78
+ gh release create "${{ github.ref_name }}" \
79
+ --repo "${{ github.repository }}" \
80
+ --notes "Backstop ${{ github.ref_name }}" \
81
+ dist/*
82
+ env:
83
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84
+ - name: Publish to PyPI
85
+ if: startsWith(github.ref, 'refs/tags/v')
86
+ uses: pypa/gh-action-pypi-publish@release/v1
87
+ with:
88
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,31 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ __pycache__/
4
+ *.py[cod]
5
+
6
+ # Secrets / environment files — NEVER commit (see .agents/AGENTS.md)
7
+ .env
8
+ .env.*
9
+ *.env
10
+ !.env.example
11
+ .coverage
12
+ htmlcov/
13
+ dist/
14
+ build/
15
+ *.egg-info/
16
+ .kilo/
17
+ node_modules/
18
+ *.tsbuildinfo
19
+ ts/backstop/dist/
20
+ wedge_report.md
21
+ benchmarks/competitive/compose/
22
+ benchmarks/competitive/*.json
23
+ benchmarks/competitive/__pycache__/
24
+
25
+ # Internal working artifacts — never publish (see PLAN.md §0 rule 9)
26
+ artifacts/
27
+ agent/
28
+ .claude/
29
+ .agents/skills/
30
+ skills-lock.json
31
+ docs/internal/
File without changes
@@ -0,0 +1,190 @@
1
+ <div align="center">
2
+ <p>
3
+ <a href="README.md">README</a> •
4
+ <a href="CODE_OF_CONDUCT.md">Code of Conduct</a>
5
+ </p>
6
+ </div>
7
+
8
+ # Changelog
9
+
10
+ All notable changes to Backstop should be documented in this file.
11
+
12
+ ## 0.6.0 — Unreleased
13
+
14
+ - Renamed the Python distribution to `backstop-ai`; `import backstop` and the
15
+ `backstop` / `wedge` console commands are unchanged.
16
+ - Added repository metadata, Python classifiers, and package keywords; aligned
17
+ package and installer versions at `0.6.0`.
18
+ - Corrected install examples and removed unsupported PyPI verification claims.
19
+ Historical install strings below are retained as history, not current guidance;
20
+ see [the install guide](docs/install.md).
21
+ - Release preparation only: PyPI publication and clean-environment installation
22
+ from PyPI are pending. Provider SDK compatibility and enforcement-error
23
+ propagation remain unresolved; SDK dependency bounds are unchanged.
24
+
25
+ ## Unreleased
26
+
27
+ - **Custom dashboard hardened (visual audit follow-up).** Fixed the topbar
28
+ collision between the mode badge and wordmark at phone widths (≤640px: the
29
+ brand row now wraps onto its own line); fixed keyboard focus being dropped to
30
+ `<body>` on every table re-render (row focus is restored across polls); grew
31
+ the refresh control and badges to comfortable touch-target sizes under
32
+ `pointer: coarse`.
33
+ - **Dashboard theme control.** `backstop dashboard --theme auto|dark|light`
34
+ sets the initial theme (default `auto` follows the OS), and a new **theme**
35
+ button in the topbar cycles auto → dark → light per browser, persisted in
36
+ `localStorage`.
37
+ - **Grafana export removed.** `backstop.dashboard` (the JSON spec module),
38
+ `tests/test_dashboard.py`, and `observability/grafana/` are gone — the
39
+ built-in dashboard is the single custom ops surface. Prometheus metrics and
40
+ `observability/prometheus-alerts.yml` are unchanged.
41
+
42
+ ## v0.5.0 — 10× Better
43
+
44
+ Closes the gap between Backstop and proxy gateways (LiteLLM / BricksLLM) while
45
+ staying in-process and drop-in. All new infrastructure is opt-in; existing
46
+ installs keep their default behavior.
47
+
48
+ - **Competitive benchmark** — Firecrawl-sourced feature matrix vs LiteLLM /
49
+ BricksLLM and the "10× better" wedge (`docs/competitive-benchmark-2026-07-20.md`).
50
+ - **Deep Research: 10× Better** — exhaustive 6-agent Firecrawl synthesis
51
+ (gateways, observability, frameworks, clouds, in-process techniques, risks)
52
+ with a prioritized 13-item roadmap (`docs/deep-research-10x-better-2026-07-20.md`).
53
+
54
+ - **P0#1 Semantic cache (near-duplicate)** — opt-in pluggable embedder +
55
+ cosine `cache_similarity_threshold`. Exact match stays the zero-cost fast path;
56
+ on a miss, the prompt embedding is compared against cached entries and a
57
+ `>= threshold` match is short-circuited. Biggest single cost lever (50–80%
58
+ savings at typical hit rates) — `BackstopConfig(cache_enabled=True,
59
+ cache_semantic=True, cache_embedder=<callable>, cache_similarity_threshold=0.95)`.
60
+ - **P0#2 Fallback chain + priority routing** — the single `fallback_model` is
61
+ promoted to an ordered `fallback_chain` (list of `{model, base_url?}`) walked
62
+ in-process on circuit-open; `fallback_chain_for_priority` gives critical traffic
63
+ its own chain. Also fixes a latent bug where the single-model fallback silently
64
+ no-op'd (`httpx.Request` has no `copy()` in this httpx version).
65
+ - **P1 Shared (Redis) budget** — one token budget enforced across processes and
66
+ replicas via atomic Lua scripts. `BackstopConfig(shared_budget=True, redis_url=...)`
67
+ with `pip install "backstop[redis]"`.
68
+ - **P2 OpenTelemetry export** — mirrors the Prometheus series to a vendor-neutral
69
+ OTel meter. `BackstopConfig(otel_enabled=True)` with `pip install "backstop[otel]"`.
70
+ - **P3 In-process fallback** — retries once against a backup model/deployment when
71
+ the circuit opens, no proxy required. `BackstopConfig(fallback_model=...)`.
72
+ - **P4 Wedge semantic diff v2** — token/line-normalized similarity (identifier
73
+ Dice + line ratio) that is format/whitespace/removal-immune; report now carries
74
+ per-runner budget-isolation evidence and a cost estimate.
75
+ - **P5 Deterministic benchmarks** — seeded, reproducible `backstop benchmark`
76
+ (seed `0xC0FFEE`) with a `--publish` flag; published results in
77
+ `docs/benchmark-results-2026-07-20.md`.
78
+ - **P6 Accurate pricing** — maintained 2026 price table (Claude 4/3.5/3,
79
+ GPT 4.1/4o/o1/o3) with prefix+family resolution and offline-cached
80
+ `refresh_pricing()`.
81
+ - **P8 CLI ergonomics** — `backstop doctor` validates install/SDKs/keys and runs a
82
+ wrap smoke test; `backstop benchmark` produces reproducible proof.
83
+ - **P7 Doc drift fixes** — README benchmarks, features, and "what this is NOT"
84
+ corrected against current behavior.
85
+ - **P9 TypeScript SDK scaffold** — `@ravanish/backstop` mirrors `wrap()` (budget +
86
+ circuit breaker + retry + fallback) for Node.js agents (`ts/backstop`).
87
+ - **P10 Concurrency ceiling** — configurable `max_wrap_sessions` soft cap with a
88
+ warning, plus `docs/concurrency.md` guidance on the GIL ceiling and when to use
89
+ a proxy gateway.
90
+ - **Housekeeping** — deleted the superseded `docs/research` deep-research dump;
91
+ added `redis`/`otel` install extras.
92
+
93
+ ### 10× Better — roadmap follow-up (this pass)
94
+
95
+ - **P1#3 Virtual keys + hierarchical budgets** — `virtual_keys` maps an API key
96
+ header (`virtual_key_header`) to a tenant, and `TenantBudget(parent=...)` rolls
97
+ spend up a team/org tree so a child budget can never exceed its parent.
98
+ - **P1#4 True per-tenant circuit breaker** — `per_tenant_circuit` keeps a separate
99
+ breaker per tenant (falls back to the global one); failures from one tenant no
100
+ longer trip the breaker for everyone.
101
+ - **P1#5 Cloud-quota-aware auto-tuning** — ingests provider `x-ratelimit-*` /
102
+ `anthropic-ratelimit-*` headers and proactively clamps the AIMD concurrency
103
+ limit (`apply_external_decrease`) before 429s hit, instead of reacting to them.
104
+ - **P1#6 Framework adapters** — `backstop.adapters` lazily bridges LangChain /
105
+ LlamaIndex callbacks to Backstop's hooks/metrics/tenant scoping so Backstop
106
+ becomes the guardrail *inside* the framework. Framework imports are deferred, so
107
+ importing the module never requires the framework installed.
108
+ - **P1#7 Cost forecasting + anomaly detection** — `backstop.forecast` projects
109
+ budget exhaustion from a measured burn rate and flags spend anomalies, turning
110
+ ledger data into an enforcement-triggering signal.
111
+ - **P1#12 Pluggable rate limiter + tiktoken pre-estimation** — `rate_limiter`
112
+ accepts any `allow(tokens) -> bool` object (e.g. `TokenBucketLimiter`, a
113
+ variable-cost token bucket charged by estimated tokens); `auto_token_count`
114
+ (opt-in) switches pre-dispatch estimates from the chars/4 heuristic to tiktoken;
115
+ `compress` is a pre-send `callable(body, model) -> body` hook.
116
+ - **P2#8 Tamper-evident audit log** — `audit_enabled` writes a chained,
117
+ HMAC-verifiable JSONL of every enforcement decision (`deny` / `fallback` /
118
+ `downgrade` / `shadow`) via `AuditLog.verify()`; the enterprise "escape hatch"
119
+ that makes in-process enforcement audit-ready.
120
+ - **P2#9 Secret provider** — `secret_provider` resolves virtual keys / tenant ids
121
+ to provider secrets at call time (env + static ships; cloud vaults implement the
122
+ same interface), avoiding plaintext key handling in-process.
123
+ - **P2#10 Gateway / sidecar mode** — `backstop gateway` (`backstop serve`) runs an
124
+ OpenAI-compatible reverse proxy so policy is non-bypassable for non-Python
125
+ services; `pip install "backstop[fastapi]"`.
126
+ - **P2#11 Agent guardrails** — `agent_guard` (`AgentGuard`) fences runaway agent
127
+ loops per agent id via sliding-window call/token ceilings.
128
+ - **P2#13 Safe rollout: shadow / canary** — `shadow_policy` (`ShadowPolicy` /
129
+ `CanaryRouter`) samples traffic to a candidate config/policy and records
130
+ reason-coded decisions before any hard cutover.
131
+
132
+ ### v0.5.0 — Launch Readiness (2026-08-10)
133
+
134
+ Production-readiness pass: every claim is now backed by proof, every stale
135
+ doc is corrected, and the TypeScript SDK reaches full feature parity.
136
+
137
+ - **Proof infrastructure** — runnable proof scripts (`proofs/`) demonstrate
138
+ budget exhaustion prevention, multi-agent isolation, real-provider overhead,
139
+ and semantic cache savings against live providers.
140
+ - **Wedge fixed** — patch extraction now handles markdown code blocks, `FILE:`
141
+ headers, and multi-line LLM output (was unified-diff-only). Agent loop with
142
+ retry/fix on test failure. Per-runner test timeout.
143
+ - **Bundled test fixture** — `wedge-test-fixture/` gives `wedge run task.yaml`
144
+ a real repo to run against out of the box.
145
+ - **Docs corrected** — README benchmark table regenerated dynamically (was
146
+ stale), benchmark overhead measured live, version strings unified at `0.5.0`
147
+ across `pyproject.toml`, `wedge/__init__.py`, `install.sh`, and `docs/install.md`.
148
+ - **Gateway hardened** — auth (`--api-keys`), per-key rate limiting, 1 MB body
149
+ size guard, path traversal rejection, and error handling.
150
+ - **Cost forecasting → enforcement** — `forecast_horizon_seconds` proactively
151
+ tightens AIMD concurrency when burn rate projects exhaustion.
152
+ - **Secret provider wired** — virtual keys resolve to provider secrets at call
153
+ time in the transport, not just at wrap time.
154
+ - **TypeScript SDK v0.5.0** — full parity: priority admission, AIMD concurrency,
155
+ fallback chains, response cache (exact + semantic), hooks, audit log, agent
156
+ guardrails, quota-aware auto-tuning, cost forecasting, and `shadow/canary`.
157
+ - **Concurrent budget stress tests** — 20-thread hammer proves the no-overspend
158
+ invariant. CI matrix tests multiple SDK versions.
159
+
160
+ ## v0.4.0
161
+
162
+ - Integrated the `wedge` tool directly into the `backstop` codebase as an executable package script (`wedge run task.yaml`).
163
+ - **Isolation Harness**: Built per-runner Git worktree simulation and task execution.
164
+ - **Diff Engine**: Added `difflib`-based patch similarity scoring (`CONVERGED`, `PARTIAL`, `DIVERGED`).
165
+ - **Reporting Engine**: Added terminal summary and Markdown report generation (`wedge_report.md`).
166
+ - Fully un-mocked and configured the Anthropic and OpenAI wrapper handlers for production-ready API integration.
167
+ - Added Phase 0 trust assets: security policy, contribution guide, code of conduct, public docs, examples, benchmark scaffold, and GitHub templates.
168
+
169
+ ## v0.3.0
170
+
171
+ - Added per-tenant budget buckets.
172
+ - Added cost estimation helpers.
173
+ - Added downgrade behavior for exhausted tenant budgets.
174
+
175
+ ## v0.2.0
176
+
177
+ - Added latency metadata.
178
+ - Added streaming handling.
179
+ - Added middleware hooks.
180
+ - Added request timeout support.
181
+ - Added response caching.
182
+ - Added token counting improvements.
183
+ - Removed dead `priority_weights` behavior.
184
+
185
+ ## v0.1.0
186
+
187
+ - Added the initial Backstop package.
188
+ - Added OpenAI SDK wrapping.
189
+ - Added Anthropic SDK compatibility.
190
+ - Added budget enforcement, priority admission, AIMD concurrency, retry handling, circuit breaking, metrics, and CLI harness support.
@@ -0,0 +1,29 @@
1
+ # Code Of Conduct
2
+
3
+ Backstop follows the Contributor Covenant Code of Conduct, version 2.1.
4
+
5
+ ## Our Pledge
6
+
7
+ We pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
8
+
9
+ ## Expected Behavior
10
+
11
+ - Be respectful and direct.
12
+ - Focus criticism on technical work and project outcomes.
13
+ - Assume maintainers and contributors are balancing tradeoffs.
14
+ - Keep security-sensitive details out of public threads.
15
+
16
+ ## Unacceptable Behavior
17
+
18
+ - Harassment, insults, or personal attacks.
19
+ - Publishing private information without permission.
20
+ - Sexualized language or attention.
21
+ - Trolling or sustained disruption.
22
+
23
+ ## Enforcement
24
+
25
+ Maintainers may remove comments, close issues, reject contributions, or ban participants who violate this code of conduct.
26
+
27
+ ## Attribution
28
+
29
+ This Code of Conduct is adapted from the Contributor Covenant, version 2.1.
@@ -0,0 +1,43 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve Backstop. This project is optimized for practical LLM spend control: budgets, backpressure, retries, circuit breaking, fallbacks, metrics, and provider SDK compatibility.
4
+
5
+ ## Local Setup
6
+
7
+ ```bash
8
+ python3 -m venv .venv
9
+ . .venv/bin/activate
10
+ pip install -e ".[test,metrics,anthropic]"
11
+ pytest
12
+ ```
13
+
14
+ ## Development Guidelines
15
+
16
+ - Keep the local SDK path useful without a hosted service.
17
+ - Do not send prompt payloads to external services by default.
18
+ - Prefer provider SDK compatibility over custom HTTP API abstractions.
19
+ - Add tests for budget, retry, circuit, streaming, metrics, or wrapper behavior when changing those paths.
20
+ - Keep public APIs typed and documented.
21
+ - Avoid broad refactors in feature PRs.
22
+
23
+ ## Pull Request Checklist
24
+
25
+ - Tests pass with `pytest`.
26
+ - New behavior has tests or a clear reason tests are not practical.
27
+ - Docs or examples are updated when public behavior changes.
28
+ - Security and privacy implications are called out.
29
+ - Provider SDK compatibility impact is described.
30
+
31
+ ## Real Provider Tests
32
+
33
+ Real API tests are opt-in and require credentials:
34
+
35
+ ```bash
36
+ export OPENAI_API_KEY="..."
37
+ pytest -m real_openai
38
+
39
+ export ANTHROPIC_API_KEY="..."
40
+ pytest -m real_anthropic
41
+ ```
42
+
43
+ Do not include real API keys, prompts, responses, or customer data in issues, tests, fixtures, screenshots, or logs.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Backstop Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.